Browse Source

Split the dom for the itemset in two sets: foreground and background (instead of ugly z-index tricks)

css_transitions
josdejong 11 years ago
parent
commit
704136eec8
12 changed files with 177 additions and 88 deletions
  1. +1
    -0
      Jakefile.js
  2. +6
    -1
      src/component/css/item.css
  3. +12
    -6
      src/component/item/itembox.js
  4. +6
    -4
      src/component/item/itempoint.js
  5. +5
    -4
      src/component/item/itemrange.js
  6. +30
    -0
      src/component/itemset.js
  7. +25
    -25
      src/module.js
  8. +2
    -1
      test/dataset.html
  9. +6
    -3
      test/timeline.html
  10. +2
    -1
      test/timestep.html
  11. +79
    -40
      vis.js
  12. +3
    -3
      vis.min.js

+ 1
- 0
Jakefile.js View File

@ -58,6 +58,7 @@ task('vis', function () {
'./src/visualization/timeline.js', './src/visualization/timeline.js',
// TODO: do not package moment.js with vis.js.
'./lib/moment.js' './lib/moment.js'
], ],

+ 6
- 1
src/component/css/item.css View File

@ -3,6 +3,12 @@
position: absolute; position: absolute;
} }
.graph .background {
}
.graph .foreground {
}
.graph .item { .graph .item {
position: absolute; position: absolute;
@ -74,7 +80,6 @@
width: 0; width: 0;
border-left-width: 1px; border-left-width: 1px;
border-left-style: solid; border-left-style: solid;
z-index: -1;
} }
.graph .item .content { .graph .item .content {

+ 12
- 6
src/component/item/itembox.js View File

@ -66,21 +66,27 @@ ItemBox.prototype.repaint = function () {
if (!this.options && !this.parent) { if (!this.options && !this.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
}
var background = this.parent.getBackground();
if (!background) {
throw new Error('Cannot repaint time axis: ' +
'parent has no background container element');
} }
if (!dom.box.parentNode) { if (!dom.box.parentNode) {
parentContainer.appendChild(dom.box);
foreground.appendChild(dom.box);
changed = true; changed = true;
} }
if (!dom.line.parentNode) { if (!dom.line.parentNode) {
parentContainer.appendChild(dom.line);
background.appendChild(dom.line);
changed = true; changed = true;
} }
if (!dom.dot.parentNode) { if (!dom.dot.parentNode) {
parentContainer.appendChild(dom.dot);
foreground.appendChild(dom.dot);
changed = true; changed = true;
} }

+ 6
- 4
src/component/item/itempoint.js View File

@ -63,13 +63,15 @@ ItemPoint.prototype.repaint = function () {
if (!this.options && !this.options.parent) { if (!this.options && !this.options.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
} }
if (!dom.point.parentNode) { if (!dom.point.parentNode) {
parentContainer.appendChild(dom.point);
foreground.appendChild(dom.point);
foreground.appendChild(dom.point);
changed = true; changed = true;
} }

+ 5
- 4
src/component/item/itemrange.js View File

@ -58,13 +58,14 @@ ItemRange.prototype.repaint = function () {
if (!this.options && !this.options.parent) { if (!this.options && !this.options.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
} }
if (!dom.box.parentNode) { if (!dom.box.parentNode) {
parentContainer.appendChild(dom.box);
foreground.appendChild(dom.box);
changed = true; changed = true;
} }

+ 30
- 0
src/component/itemset.js View File

@ -27,6 +27,8 @@ function ItemSet(parent, depends, options) {
padding: 5 padding: 5
}; };
this.dom = {};
var me = this; var me = this;
this.data = null; // DataSet this.data = null; // DataSet
this.range = null; // Range or Object {start: number, end: number} this.range = null; // Range or Object {start: number, end: number}
@ -116,6 +118,18 @@ ItemSet.prototype.repaint = function () {
util.addClassName(frame, util.option.asString(options.className)); util.addClassName(frame, util.option.asString(options.className));
} }
// create background panel
var background = document.createElement('div');
background.className = 'background';
frame.appendChild(background);
this.dom.background = background;
// create foreground panel
var foreground = document.createElement('div');
foreground.className = 'foreground';
frame.appendChild(foreground);
this.dom.foreground = foreground;
this.frame = frame; this.frame = frame;
changed += 1; changed += 1;
} }
@ -218,6 +232,22 @@ ItemSet.prototype.repaint = function () {
return (changed > 0); return (changed > 0);
}; };
/**
* Get the foreground container element
* @return {HTMLElement} foreground
*/
ItemSet.prototype.getForeground = function () {
return this.dom.foreground;
};
/**
* Get the background container element
* @return {HTMLElement} background
*/
ItemSet.prototype.getBackground = function () {
return this.dom.background;
};
/** /**
* Reflow the component * Reflow the component
* @return {Boolean} resized * @return {Boolean} resized

+ 25
- 25
src/module.js View File

@ -6,31 +6,7 @@ var vis = {
}; };
/** /**
* load css from text
* @param {String} css Text containing css
*/
var loadCss = function (css) {
// get the script location, and built the css file name from the js file name
// http://stackoverflow.com/a/2161748/1262753
var scripts = document.getElementsByTagName('script');
// var jsFile = scripts[scripts.length-1].src.split('?')[0];
// var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css';
// inject css
// http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(style);
};
/**
* Define CommonJS module exports when not available
* CommonJS module exports
*/ */
if (typeof exports !== 'undefined') { if (typeof exports !== 'undefined') {
exports = vis; exports = vis;
@ -55,3 +31,27 @@ if (typeof window !== 'undefined') {
// attach the module to the window, load as a regular javascript file // attach the module to the window, load as a regular javascript file
window['vis'] = vis; window['vis'] = vis;
} }
/**
* load css from text
* @param {String} css Text containing css
*/
var loadCss = function (css) {
// get the script location, and built the css file name from the js file name
// http://stackoverflow.com/a/2161748/1262753
var scripts = document.getElementsByTagName('script');
// var jsFile = scripts[scripts.length-1].src.split('?')[0];
// var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css';
// inject css
// http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(style);
};

+ 2
- 1
test/dataset.html View File

@ -3,6 +3,7 @@
<head> <head>
<title></title> <title></title>
<script src="../lib/moment.min.js"></script> <script src="../lib/moment.min.js"></script>
<script src="../src/module.js"></script>
<script src="../src/util.js"></script> <script src="../src/util.js"></script>
<script src="../src/events.js"></script> <script src="../src/events.js"></script>
<script src="../src/range.js"></script> <script src="../src/range.js"></script>
@ -14,7 +15,7 @@
</head> </head>
<body> <body>
<script> <script>
var dataset = new DataSet({
var dataset = new vis.DataSet({
fieldId: 'id', fieldId: 'id',
fieldTypes: { fieldTypes: {
start: 'ISODate' start: 'ISODate'

+ 6
- 3
test/timeline.html View File

@ -3,6 +3,7 @@
<head> <head>
<title></title> <title></title>
<script src="../lib/moment.min.js"></script> <script src="../lib/moment.min.js"></script>
<script src="../src/module.js"></script>
<script src="../src/util.js"></script> <script src="../src/util.js"></script>
<script src="../src/events.js"></script> <script src="../src/events.js"></script>
<script src="../src/timestep.js"></script> <script src="../src/timestep.js"></script>
@ -54,7 +55,7 @@
<script> <script>
// create a dataset with items // create a dataset with items
var now = moment().minutes(0).seconds(0).milliseconds(0); var now = moment().minutes(0).seconds(0).milliseconds(0);
var data = new DataSet({
var data = new vis.DataSet({
fieldTypes: { fieldTypes: {
start: 'Date', start: 'Date',
end: 'Date' end: 'Date'
@ -64,7 +65,9 @@
{id: 1, content: 'item 1<br>start', start: now.clone().add('days', 4).toDate()}, {id: 1, content: 'item 1<br>start', start: now.clone().add('days', 4).toDate()},
{id: 2, content: 'item 2', start: now.clone().add('days', -2).toDate() }, {id: 2, content: 'item 2', start: now.clone().add('days', -2).toDate() },
{id: 3, content: 'item 3', start: now.clone().add('days', 2).toDate()}, {id: 3, content: 'item 3', start: now.clone().add('days', 2).toDate()},
{id: 4, content: 'item 4', start: now.clone().add('days', 0).toDate(), end: now.clone().add('days', 7).toDate()},
{id: 4, content: 'item 4',
start: now.clone().add('days', 0).toDate(),
end: now.clone().add('days', 17).toDate()},
{id: 5, content: 'item 5', start: now.clone().add('days', 9).toDate(), type:'point'}, {id: 5, content: 'item 5', start: now.clone().add('days', 9).toDate(), type:'point'},
{id: 6, content: 'item 6', start: now.clone().add('days', 11).toDate()} {id: 6, content: 'item 6', start: now.clone().add('days', 11).toDate()}
]); ]);
@ -79,7 +82,7 @@
zoomMax: 1000 * 60 * 60 * 24 * 30 * 6 // 6 months zoomMax: 1000 * 60 * 60 * 24 * 30 * 6 // 6 months
}; };
var timeline = new Timeline(container, data, options);
var timeline = new vis.Timeline(container, data, options);
</script> </script>
</body> </body>

+ 2
- 1
test/timestep.html View File

@ -3,6 +3,7 @@
<head> <head>
<title></title> <title></title>
<script src="../lib/moment.min.js"></script> <script src="../lib/moment.min.js"></script>
<script src="../src/module.js"></script>
<script src="../src/util.js"></script> <script src="../src/util.js"></script>
<script src="../src/events.js"></script> <script src="../src/events.js"></script>
<script src="../src/component/panel.js"></script> <script src="../src/component/panel.js"></script>
@ -22,7 +23,7 @@
]; ];
diffs.forEach(function (diff) { diffs.forEach(function (diff) {
var step = new TimeStep(new Date(), new Date((new Date()).valueOf() + diff), diff / 40);
var step = new vis.TimeStep(new Date(), new Date((new Date()).valueOf() + diff), diff / 40);
console.log(diff, step._start.toLocaleString(), step._end.toLocaleString(), step.scale, step.step); console.log(diff, step._start.toLocaleString(), step._end.toLocaleString(), step.scale, step.step);
step.first(); step.first();
while (step.hasNext()) { while (step.hasNext()) {

+ 79
- 40
vis.js View File

@ -32,31 +32,7 @@ var vis = {
}; };
/** /**
* load css from text
* @param {String} css Text containing css
*/
var loadCss = function (css) {
// get the script location, and built the css file name from the js file name
// http://stackoverflow.com/a/2161748/1262753
var scripts = document.getElementsByTagName('script');
// var jsFile = scripts[scripts.length-1].src.split('?')[0];
// var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css';
// inject css
// http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(style);
};
/**
* Define CommonJS module exports when not available
* CommonJS module exports
*/ */
if (typeof exports !== 'undefined') { if (typeof exports !== 'undefined') {
exports = vis; exports = vis;
@ -82,6 +58,30 @@ if (typeof window !== 'undefined') {
window['vis'] = vis; window['vis'] = vis;
} }
/**
* load css from text
* @param {String} css Text containing css
*/
var loadCss = function (css) {
// get the script location, and built the css file name from the js file name
// http://stackoverflow.com/a/2161748/1262753
var scripts = document.getElementsByTagName('script');
// var jsFile = scripts[scripts.length-1].src.split('?')[0];
// var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css';
// inject css
// http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(style);
};
// create namespace // create namespace
var util = {}; var util = {};
@ -3793,6 +3793,8 @@ function ItemSet(parent, depends, options) {
padding: 5 padding: 5
}; };
this.dom = {};
var me = this; var me = this;
this.data = null; // DataSet this.data = null; // DataSet
this.range = null; // Range or Object {start: number, end: number} this.range = null; // Range or Object {start: number, end: number}
@ -3882,6 +3884,18 @@ ItemSet.prototype.repaint = function () {
util.addClassName(frame, util.option.asString(options.className)); util.addClassName(frame, util.option.asString(options.className));
} }
// create background panel
var background = document.createElement('div');
background.className = 'background';
frame.appendChild(background);
this.dom.background = background;
// create foreground panel
var foreground = document.createElement('div');
foreground.className = 'foreground';
frame.appendChild(foreground);
this.dom.foreground = foreground;
this.frame = frame; this.frame = frame;
changed += 1; changed += 1;
} }
@ -3984,6 +3998,22 @@ ItemSet.prototype.repaint = function () {
return (changed > 0); return (changed > 0);
}; };
/**
* Get the foreground container element
* @return {HTMLElement} foreground
*/
ItemSet.prototype.getForeground = function () {
return this.dom.foreground;
};
/**
* Get the background container element
* @return {HTMLElement} background
*/
ItemSet.prototype.getBackground = function () {
return this.dom.background;
};
/** /**
* Reflow the component * Reflow the component
* @return {Boolean} resized * @return {Boolean} resized
@ -4315,21 +4345,27 @@ ItemBox.prototype.repaint = function () {
if (!this.options && !this.parent) { if (!this.options && !this.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
}
var background = this.parent.getBackground();
if (!background) {
throw new Error('Cannot repaint time axis: ' +
'parent has no background container element');
} }
if (!dom.box.parentNode) { if (!dom.box.parentNode) {
parentContainer.appendChild(dom.box);
foreground.appendChild(dom.box);
changed = true; changed = true;
} }
if (!dom.line.parentNode) { if (!dom.line.parentNode) {
parentContainer.appendChild(dom.line);
background.appendChild(dom.line);
changed = true; changed = true;
} }
if (!dom.dot.parentNode) { if (!dom.dot.parentNode) {
parentContainer.appendChild(dom.dot);
foreground.appendChild(dom.dot);
changed = true; changed = true;
} }
@ -4582,13 +4618,15 @@ ItemPoint.prototype.repaint = function () {
if (!this.options && !this.options.parent) { if (!this.options && !this.options.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
} }
if (!dom.point.parentNode) { if (!dom.point.parentNode) {
parentContainer.appendChild(dom.point);
foreground.appendChild(dom.point);
foreground.appendChild(dom.point);
changed = true; changed = true;
} }
@ -4787,13 +4825,14 @@ ItemRange.prototype.repaint = function () {
if (!this.options && !this.options.parent) { if (!this.options && !this.options.parent) {
throw new Error('Cannot repaint item: no parent attached'); throw new Error('Cannot repaint item: no parent attached');
} }
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint time axis: parent has no container element');
var foreground = this.parent.getForeground();
if (!foreground) {
throw new Error('Cannot repaint time axis: ' +
'parent has no foreground container element');
} }
if (!dom.box.parentNode) { if (!dom.box.parentNode) {
parentContainer.appendChild(dom.box);
foreground.appendChild(dom.box);
changed = true; changed = true;
} }
@ -6492,5 +6531,5 @@ vis.Timeline = Timeline;
} }
}).call(this); }).call(this);
loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .itemset {\n position: absolute;\n}\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n z-index: -1;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n");
loadCss("/* vis.js stylesheet */\n\n.graph {\n position: relative;\n border: 1px solid #bfbfbf;\n}\n\n.graph .panel {\n position: absolute;\n}\n\n.graph .itemset {\n position: absolute;\n}\n\n.graph .background {\n}\n\n.graph .foreground {\n}\n\n\n.graph .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.graph .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.graph .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.graph .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.graph .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.point {\n background: none;\n}\n\n.graph .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.graph .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.graph .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.graph .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.graph .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.graph .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n/* TODO: better css name, 'graph' is way to generic */\n\n.graph {\n overflow: hidden;\n}\n\n.graph .axis {\n position: relative;\n}\n\n.graph .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.graph .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.graph .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.graph .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.graph .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.graph .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n");
})(); })();

+ 3
- 3
vis.min.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save