Browse Source

everything but legend and barchart working. two axis! woohoo!

css_transitions
Alex de Mulder 10 years ago
parent
commit
007a4a90b1
13 changed files with 904 additions and 368 deletions
  1. +1
    -0
      Jakefile.js
  2. +10
    -10
      dist/vis.css
  3. +403
    -163
      dist/vis.js
  4. +1
    -1
      dist/vis.min.css
  5. +12
    -12
      dist/vis.min.js
  6. +72
    -17
      examples/Graph2d/01_basic.html
  7. +14
    -4
      src/timeline/DataStep.js
  8. +22
    -0
      src/timeline/Graph2d.js
  9. +86
    -51
      src/timeline/component/DataAxis.js
  10. +269
    -100
      src/timeline/component/Linegraph.js
  11. +10
    -10
      src/timeline/component/css/pathStyles.css
  12. +3
    -0
      src/timeline/component/legend.js
  13. +1
    -0
      src/util.js

+ 1
- 0
Jakefile.js View File

@ -67,6 +67,7 @@ task('build', {async: true}, function () {
'./src/DataSet.js', './src/DataSet.js',
'./src/DataView.js', './src/DataView.js',
'./src/timeline/component/Legend.js',
'./src/timeline/component/DataAxis.js', './src/timeline/component/DataAxis.js',
'./src/timeline/component/Linegraph.js', './src/timeline/component/Linegraph.js',
'./src/timeline/DataStep.js', './src/timeline/DataStep.js',

+ 10
- 10
dist/vis.css View File

@ -357,70 +357,70 @@
white-space: nowrap; white-space: nowrap;
} }
.vis.timeline .group0 {
.vis.timeline .graphGroup0 {
fill:#4f81bd; fill:#4f81bd;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #4f81bd; stroke: #4f81bd;
} }
.vis.timeline .group1 {
.vis.timeline .graphGroup1 {
fill:#f79646; fill:#f79646;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #f79646; stroke: #f79646;
} }
.vis.timeline .group2 {
.vis.timeline .graphGroup2 {
fill: #8c51cf; fill: #8c51cf;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #8c51cf; stroke: #8c51cf;
} }
.vis.timeline .group3 {
.vis.timeline .graphGroup3 {
fill: #75c841; fill: #75c841;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #75c841; stroke: #75c841;
} }
.vis.timeline .group4 {
.vis.timeline .graphGroup4 {
fill: #ff0100; fill: #ff0100;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #ff0100; stroke: #ff0100;
} }
.vis.timeline .group5 {
.vis.timeline .graphGroup5 {
fill: #37d8e6; fill: #37d8e6;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #37d8e6; stroke: #37d8e6;
} }
.vis.timeline .group6 {
.vis.timeline .graphGroup6 {
fill: #042662; fill: #042662;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #042662; stroke: #042662;
} }
.vis.timeline .group7 {
.vis.timeline .graphGroup7 {
fill:#00ff26; fill:#00ff26;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #00ff26; stroke: #00ff26;
} }
.vis.timeline .group8 {
.vis.timeline .graphGroup8 {
fill:#ff00ff; fill:#ff00ff;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #ff00ff; stroke: #ff00ff;
} }
.vis.timeline .group9 {
.vis.timeline .graphGroup9 {
fill: #8f3938; fill: #8f3938;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;

+ 403
- 163
dist/vis.js View File

@ -1298,6 +1298,7 @@ util.copyObject = function(objectFrom, objectTo) {
} }
} }
} }
return objectTo;
}; };
/** /**
@ -2557,6 +2558,10 @@ DataView.prototype._trigger = DataSet.prototype._trigger;
DataView.prototype.subscribe = DataView.prototype.on; DataView.prototype.subscribe = DataView.prototype.on;
DataView.prototype.unsubscribe = DataView.prototype.off; DataView.prototype.unsubscribe = DataView.prototype.off;
/**
* Created by Alex on 6/17/14.
*/
/** /**
* A horizontal time axis * A horizontal time axis
* @param {Object} [options] See DataAxis.setOptions for the available * @param {Object} [options] See DataAxis.setOptions for the available
@ -2572,6 +2577,8 @@ function DataAxis (body, options) {
orientation: 'left', // supported: 'left' orientation: 'left', // supported: 'left'
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px', width: '50px',
height: '300px' height: '300px'
}; };
@ -2606,15 +2613,32 @@ function DataAxis (body, options) {
this.width = Number(this.options.width.replace("px","")); this.width = Number(this.options.width.replace("px",""));
this.height = Number(this.options.height.replace("px","")); this.height = Number(this.options.height.replace("px",""));
this.stepPixels = 25;
this.stepPixelsForced = 25;
this.lineOffset = 0;
this.master = true;
// create the HTML DOM // create the HTML DOM
this._create(); this._create();
} }
DataAxis.prototype = new Component(); DataAxis.prototype = new Component();
//DataAxis.prototype.setOptions = function(options) {
//
//}
DataAxis.prototype.setOptions = function(options) {
if (options) {
var redraw = false;
if (this.options.orientation != options.orientation && options.orientation !== undefined) {
redraw = true;
}
var fields = ['orientation','showMinorLabels','showMajorLabels','width','height'];
util.selectiveExtend(fields, this.options, options);
if (redraw == true && this.dom.frame) {
this.hide();
this.show();
}
}
}
/** /**
@ -2628,8 +2652,6 @@ DataAxis.prototype._create = function() {
this.dom.lineContainer = document.createElement('div'); this.dom.lineContainer = document.createElement('div');
this.dom.lineContainer.style.width = '100%'; this.dom.lineContainer.style.width = '100%';
this.dom.lineContainer.style.height = this.options.height; this.dom.lineContainer.style.height = this.options.height;
this.show();
}; };
@ -2641,7 +2663,7 @@ DataAxis.prototype.show = function() {
if (this.options.orientation == 'left') { if (this.options.orientation == 'left') {
this.body.dom.left.appendChild(this.dom.frame); this.body.dom.left.appendChild(this.dom.frame);
} }
if (this.options.orientation == 'right') {
else {
this.body.dom.right.appendChild(this.dom.frame); this.body.dom.right.appendChild(this.dom.frame);
} }
} }
@ -2698,9 +2720,9 @@ DataAxis.prototype.redraw = function () {
props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth;
props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2*this.options.minorLinesOffset;
props.minorLineHeight = 1; props.minorLineHeight = 1;
props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth;
props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2*this.options.majorLinesOffset;;
props.majorLineHeight = 1; props.majorLineHeight = 1;
// take frame offline while updating (is almost twice as fast) // take frame offline while updating (is almost twice as fast)
@ -2751,13 +2773,27 @@ DataAxis.prototype._redrawLabels = function () {
step.first(); step.first();
var stepPixels = this.dom.frame.offsetHeight / ((step.marginRange / step.step) + 1); var stepPixels = this.dom.frame.offsetHeight / ((step.marginRange / step.step) + 1);
var xFirstMajorLabel = undefined;
this.stepPixels = stepPixels;
var amountOfSteps = this.height / stepPixels;
var stepDifference = 0;
if (this.master == false) {
stepPixels = this.stepPixelsForced;
stepDifference = Math.round((this.height / stepPixels) - amountOfSteps);
for (var i = 0; i < 0.5 * stepDifference; i++) {
step.previous();
}
amountOfSteps = this.height / stepPixels;
}
var xFirstMajorLabel = undefined;
this.valueAtZero = step.marginEnd; this.valueAtZero = step.marginEnd;
var marginStartPos = 0; var marginStartPos = 0;
var max = 0; var max = 0;
while (step.hasNext() && max < 1000) {
var y = Math.round(max * stepPixels);
var y = 0;
while (max < amountOfSteps) {
y = Math.round(max * stepPixels);
marginStartPos = max * stepPixels; marginStartPos = max * stepPixels;
var isMajor = step.isMajor(); var isMajor = step.isMajor();
@ -2766,7 +2802,7 @@ DataAxis.prototype._redrawLabels = function () {
} }
if (isMajor && this.options['showMajorLabels']) { if (isMajor && this.options['showMajorLabels']) {
if (y > 0) {
if (y >= 0) {
if (xFirstMajorLabel == undefined) { if (xFirstMajorLabel == undefined) {
xFirstMajorLabel = y; xFirstMajorLabel = y;
} }
@ -2782,7 +2818,7 @@ DataAxis.prototype._redrawLabels = function () {
max++; max++;
} }
this.conversionFactor = marginStartPos/step.marginRange;
this.conversionFactor = marginStartPos/((amountOfSteps-1) * step.step);
// create a major label on the left when needed // create a major label on the left when needed
if (this.options['showMajorLabels']) { if (this.options['showMajorLabels']) {
@ -2816,7 +2852,7 @@ DataAxis.prototype.convertValues = function(data) {
DataAxis.prototype.convertValue = function(value) { DataAxis.prototype.convertValue = function(value) {
var invertedValue = this.valueAtZero - value; var invertedValue = this.valueAtZero - value;
var convertedValue = invertedValue * this.conversionFactor; var convertedValue = invertedValue * this.conversionFactor;
return convertedValue - 2; // the -2 is to compensate for the borders
return convertedValue; // the -2 is to compensate for the borders
} }
/** /**
@ -2884,7 +2920,7 @@ DataAxis.prototype._redrawMajorText = function (y, text, orientation) {
label.style.textAlign = "right"; label.style.textAlign = "right";
} }
else { else {
label.style.left = '2';
label.style.left = '2px';
label.style.textAlign = "left"; label.style.textAlign = "left";
} }
@ -2898,27 +2934,29 @@ DataAxis.prototype._redrawMajorText = function (y, text, orientation) {
* @private * @private
*/ */
DataAxis.prototype._redrawMinorLine = function (y, orientation) { DataAxis.prototype._redrawMinorLine = function (y, orientation) {
// reuse redundant line
var line = this.dom.redundant.minorLines.shift();
if (this.master == true) {
// reuse redundant line
var line = this.dom.redundant.minorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal minor';
this.dom.lineContainer.appendChild(line);
}
this.dom.minorLines.push(line);
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal minor';
this.dom.lineContainer.appendChild(line);
}
this.dom.minorLines.push(line);
var props = this.props;
if (orientation == 'left') {
line.style.left = (this.width - 15) + 'px';
}
else {
line.style.left = -1*(this.width - 15) + 'px';
}
var props = this.props;
if (orientation == 'left') {
line.style.left = (this.width - this.options.minorLinesOffset) + 'px';
}
else {
line.style.left = -1*(this.width - this.options.minorLinesOffset) + 'px';
}
line.style.width = props.minorLineWidth + 'px';
line.style.top = y + 'px';
line.style.width = props.minorLineWidth + 'px';
line.style.top = y + 'px';
}
}; };
/** /**
@ -2928,25 +2966,27 @@ DataAxis.prototype._redrawMinorLine = function (y, orientation) {
* @private * @private
*/ */
DataAxis.prototype._redrawMajorLine = function (y, orientation) { DataAxis.prototype._redrawMajorLine = function (y, orientation) {
// reuse redundant line
var line = this.dom.redundant.majorLines.shift();
if (this.master == true) {
// reuse redundant line
var line = this.dom.redundant.majorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal major';
this.dom.lineContainer.appendChild(line);
}
this.dom.majorLines.push(line);
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal major';
this.dom.lineContainer.appendChild(line);
}
this.dom.majorLines.push(line);
if (orientation == 'left') {
line.style.left = (this.width - 25) + 'px';
}
else {
line.style.left = -1*(this.width - 25) + 'px';
if (orientation == 'left') {
line.style.left = (this.width - this.options.majorLinesOffset) + 'px';
}
else {
line.style.left = -1*(this.width - this.options.mayorLinesOffset) + 'px';
}
line.style.top = y + 'px';
line.style.width = this.props.majorLineWidth + 'px';
} }
line.style.top = y + 'px';
line.style.width = this.props.majorLineWidth + 'px';
}; };
@ -3001,6 +3041,7 @@ function Linegraph(body, options) {
this.body = body; this.body = body;
this.defaultOptions = { this.defaultOptions = {
yAxisOrientation: 'left',
shaded: { shaded: {
enabled: true, enabled: true,
orientation: 'top' // top, bottom orientation: 'top' // top, bottom
@ -3044,6 +3085,19 @@ function Linegraph(body, options) {
} }
}; };
// listeners for the DataSet of the groups
this.groupListeners = {
'add': function (event, params, senderId) {
me._onAddGroups(params.items);
},
'update': function (event, params, senderId) {
me._onUpdateGroups(params.items);
},
'remove': function (event, params, senderId) {
me._onRemoveGroups(params.items);
}
};
this.items = {}; // object with an Item for every data item this.items = {}; // object with an Item for every data item
this.selection = []; // list with the ids of all selected nodes this.selection = []; // list with the ids of all selected nodes
this.lastStart = this.body.range.start; this.lastStart = this.body.range.start;
@ -3051,11 +3105,10 @@ function Linegraph(body, options) {
this.svgElements = {}; this.svgElements = {};
this.svgLegendElements = {}; this.svgLegendElements = {};
// create the HTML DOM
this.setOptions(options);
this._create();
var me = this;
var me = this;
this.body.emitter.on("rangechange",function() { this.body.emitter.on("rangechange",function() {
if (me.lastStart != 0) { if (me.lastStart != 0) {
var offset = me.body.range.start - me.lastStart; var offset = me.body.range.start - me.lastStart;
@ -3073,7 +3126,8 @@ function Linegraph(body, options) {
me.updateGraph.apply(me); me.updateGraph.apply(me);
}); });
this.setOptions(options);
// create the HTML DOM
this._create();
this.body.emitter.emit("change"); this.body.emitter.emit("change");
} }
@ -3105,10 +3159,22 @@ Linegraph.prototype._create = function(){
frame.appendChild(this.svgLegend); frame.appendChild(this.svgLegend);
// panel with time axis // panel with time axis
this.yAxis = new DataAxis(this.body, {
this.yAxisLeft = new DataAxis(this.body, {
orientation: 'left', orientation: 'left',
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px',
height: this.svg.style.height
});
this.yAxisRight = new DataAxis(this.body, {
orientation: 'right',
showMinorLabels: true,
showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px', width: '50px',
height: this.svg.style.height height: this.svg.style.height
}); });
@ -3116,22 +3182,13 @@ Linegraph.prototype._create = function(){
this.show(); this.show();
}; };
Linegraph.prototype.setOptions = function(options) { Linegraph.prototype.setOptions = function(options) {
if (options) { if (options) {
var fields = ['barGraph','catmullRom','shaded','drawPoints'];
var fields = ['yAxisOrientation'];
util.selectiveExtend(fields, this.options, options); util.selectiveExtend(fields, this.options, options);
if (options.catmullRom) { if (options.catmullRom) {
if (typeof options.catmullRom == 'boolean') {
this.options.catmullRom.enabled = options.catmullRom;
}
else {
this.options.catmullRom.enabled = true;
for (var prop in options.catmullRom) {
if (options.catmullRom.hasOwnProperty(prop)) {
this.options.catmullRom[prop] = options.catmullRom[prop];
}
}
if (typeof options.catmullRom == 'object') {
if (options.catmullRom.parametrization) { if (options.catmullRom.parametrization) {
if (options.catmullRom.parametrization == 'uniform') { if (options.catmullRom.parametrization == 'uniform') {
this.options.catmullRom.alpha = 0; this.options.catmullRom.alpha = 0;
@ -3146,36 +3203,27 @@ Linegraph.prototype.setOptions = function(options) {
} }
} }
} }
this._mergeOptions(this.options, options,'catmullRom');
this._mergeOptions(this.options, options,'drawPoints');
this._mergeOptions(this.options, options,'shaded');
}
};
if (options.drawPoints) {
if (typeof options.catmullRom == 'boolean') {
this.options.drawPoints.enabled = options.drawPoints;
}
else {
this.options.drawPoints.enabled = true;
for (prop in options.drawPoints) {
if (options.drawPoints.hasOwnProperty(prop)) {
this.options.drawPoints[prop] = options.drawPoints[prop];
}
}
}
Linegraph.prototype._mergeOptions = function (mergeTarget, options,option) {
if (options[option]) {
if (typeof options[option] == 'boolean') {
mergeTarget[option].enabled = options[option];
} }
if (options.shaded) {
if (typeof options.shaded == 'boolean') {
this.options.shaded.enabled = options.shaded;
}
else {
this.options.shaded.enabled = true;
for (prop in options.shaded) {
if (options.shaded.hasOwnProperty(prop)) {
this.options.shaded[prop] = options.shaded.drawPoints[prop];
}
else {
mergeTarget[option].enabled = true;
for (prop in options[option]) {
if (options[option].hasOwnProperty(prop)) {
mergeTarget[option][prop] = options[option][prop];
} }
} }
} }
} }
};
}
/** /**
* Hide the component from the DOM * Hide the component from the DOM
@ -3199,8 +3247,6 @@ Linegraph.prototype.show = function() {
}; };
/** /**
* Set items * Set items
* @param {vis.DataSet | null} items * @param {vis.DataSet | null} items
@ -3243,31 +3289,91 @@ Linegraph.prototype.setItems = function(items) {
ids = this.itemsData.getIds(); ids = this.itemsData.getIds();
this._onAdd(ids); this._onAdd(ids);
} }
this._updateUngrouped();
this.updateGraph();
this.redraw(); this.redraw();
}; };
/** /**
* Handle added items
* @param {Number[]} ids
* @protected
* Set groups
* @param {vis.DataSet} groups
*/ */
Linegraph.prototype.setGroups = function(groups) {
var me = this,
ids;
// unsubscribe from current dataset
if (this.groupsData) {
util.forEach(this.groupListeners, function (callback, event) {
me.groupsData.unsubscribe(event, callback);
});
// remove all drawn groups
ids = this.groupsData.getIds();
this.groupsData = null;
this._onRemoveGroups(ids); // note: this will cause a redraw
}
// replace the dataset
if (!groups) {
this.groupsData = null;
}
else if (groups instanceof DataSet || groups instanceof DataView) {
this.groupsData = groups;
}
else {
throw new TypeError('Data must be an instance of DataSet or DataView');
}
if (this.groupsData) {
// subscribe to new dataset
var id = this.id;
util.forEach(this.groupListeners, function (callback, event) {
me.groupsData.on(event, callback, id);
});
// draw all ms
ids = this.groupsData.getIds();
this._onAddGroups(ids);
}
this._updateUngrouped();
this.updateGraph();
this.redraw();
};
/**
* Handle updated items
* @param {Number[]} ids
* @protected
*/
Linegraph.prototype._onUpdate = function(ids) { Linegraph.prototype._onUpdate = function(ids) {
this.updateGraph(); this.updateGraph();
this.redraw(); this.redraw();
}; };
Linegraph.prototype._onAdd = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemove = function(ids) {};
Linegraph.prototype._onAdd = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemove = Linegraph.prototype._onUpdate;
Linegraph.prototype._onUpdateGroups = Linegraph.prototype._onUpdate;
Linegraph.prototype._onAddGroups = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemoveGroups = Linegraph.prototype._onUpdate;
/**
* Create or delete the group holding all ungrouped items. This group is used when
* there are no groups specified.
* @protected
*/
Linegraph.prototype._updateUngrouped = function() {
if (this.itemsData != null) {
var datapoints = this.itemsData.get({
filter: function (item) {return item.group === undefined;},
showInternalIds:true
});
var updateQuery = [];
for (var i = 0; i < datapoints.length; i++) {
updateQuery.push({id:datapoints[i].id, group: 'graph'});
}
this.itemsData.update(updateQuery);
}
};
/** /**
* Repaint the component * Repaint the component
* @return {boolean} Returns true if the component is resized * @return {boolean} Returns true if the component is resized
@ -3275,7 +3381,7 @@ Linegraph.prototype._onRemove = function(ids) {};
Linegraph.prototype.redraw = function() { Linegraph.prototype.redraw = function() {
var resized = false; var resized = false;
if (this.lastWidth === undefined && this.width) {
if (this.lastWidth === undefined && this.width || this.lastWidth != this.width) {
resized = true; resized = true;
} }
// check whether zoomed (in that case we need to re-stack everything) // check whether zoomed (in that case we need to re-stack everything)
@ -3287,6 +3393,7 @@ Linegraph.prototype.redraw = function() {
// calculate actual size and position // calculate actual size and position
this.width = this.dom.frame.offsetWidth; this.width = this.dom.frame.offsetWidth;
this.svgLegend.style.left = (this.width - this.svgLegend.offsetWidth - 10) + "px"; this.svgLegend.style.left = (this.width - this.svgLegend.offsetWidth - 10) + "px";
// check if this component is resized // check if this component is resized
resized = this._isResized() || resized; resized = this._isResized() || resized;
if (resized) { if (resized) {
@ -3304,42 +3411,126 @@ Linegraph.prototype.updateGraph = function () {
this._prepareSVGElements(this.svgElements); this._prepareSVGElements(this.svgElements);
if (this.width != 0 && this.itemsData != null) { if (this.width != 0 && this.itemsData != null) {
// get the range for the y Axis and draw it
var yRange = {start: this.itemsData.min('y').y, end: this.itemsData.max('y').y};
this.yAxis.setRange(yRange);
this.yAxis.redraw();
// look at different lines // look at different lines
var classes = this.itemsData.distinct('className');
if (classes.length > 0) {
for (var i = 0; i < classes.length; i++) {
this.drawGraph(classes[i], classes.length);
var groupIds = this.itemsData.distinct('group');
if (groupIds.length > 0) {
this._setYRanges(groupIds);
for (var i = 0; i < groupIds.length; i++) {
this.drawGraph(groupIds[i], i, groupIds.length);
} }
} }
else { else {
this.drawGraph('group0', 1);
this._setYRanges(groupIds);
this.drawGraph('graph', 0, 1);
} }
this.drawLegend(classes);
} }
// cleanup unused svg elements // cleanup unused svg elements
this._cleanupSVGElements(this.svgElements); this._cleanupSVGElements(this.svgElements);
}; };
Linegraph.prototype.drawGraph = function (className, amountOfGraphs) {
var datapoints = this.itemsData.get({filter: function (item) {
return item.className == className || !item.className;
}});
Linegraph.prototype._setYRanges = function(groupIds) {
var yAxisLeftUsed = false;
var yAxisRightUsed = false;
var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal;
var orientation = 'left';
if (groupIds.length > 0) {
for (var i = 0; i < groupIds.length; i++) {
orientation = 'left';
var group = this.groupsData.get(groupIds[i]);
if (group != null) {
if (group.options) {
if (group.options.yAxisOrientation == 'right') {
orientation = 'right';
}
}
}
var view = new vis.DataSet(this.itemsData.get({filter: function (item) {return item.group == groupIds[i];}}));
minVal = view.min("y").y;
maxVal = view.max("y").y;
if (orientation == 'left') {
yAxisLeftUsed = true;
if (minLeft > minVal) {minLeft = minVal;}
if (maxLeft < maxVal) {maxLeft = maxVal;}
}
else {
yAxisRightUsed = true;
if (minRight > minVal) {minRight = minVal;}
if (maxRight < maxVal) {maxRight = maxVal;}
}
delete view;
}
if (yAxisLeftUsed == true) {
this.yAxisLeft.setRange({start: minLeft, end: maxLeft});
}
if (yAxisRightUsed == true) {
this.yAxisRight.setRange({start: minRight, end: maxRight});
}
}
else {
var yRange = {start: this.itemsData.min('y').y, end: this.itemsData.max('y').y};
if (this.options.yAxisOrientation == 'left') {
this.yAxisLeft.setRange(yRange);
yAxisLeftUsed = true;
}
else {
this.yAxisRight.setRange(yRange);
yAxisRightUsed = true;
}
}
var changed = this._toggleAxisVisiblity(yAxisLeftUsed, this.yAxisLeft);
changed = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || changed;
if (changed) {
this.body.emitter.emit('change');
}
this.yAxisRight.master = !yAxisLeftUsed;
if (this.yAxisRight.master == false) {
if (yAxisRightUsed == true) {
this.yAxisLeft.lineOffset = this.yAxisRight.width;
}
this.yAxisLeft.redraw();
this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels;
this.yAxisRight.redraw();
}
else {
this.yAxisRight.redraw();
}
}
Linegraph.prototype._toggleAxisVisiblity = function(axisUsed, axis) {
var changed = false;
if (axisUsed == false) {
if (axis.dom.frame.parentNode) {
axis.hide();
changed = true;
}
}
else {
if (!axis.dom.frame.parentNode) {
axis.show();
changed = true;
}
}
return changed;
}
Linegraph.prototype.drawGraph = function (groupId, groupIndex, amountOfGraphs) {
var datapoints = this.itemsData.get({filter: function (item) {return item.group == groupId;}});
var options = this._getGroupOptions(groupId, groupIndex);
if (this.options.style == 'bar') { if (this.options.style == 'bar') {
this.drawBarGraph(datapoints, className, amountOfGraphs);
this.drawBarGraph(datapoints, options, amountOfGraphs);
} }
else { else {
this.drawLineGraph(datapoints, className);
this.drawLineGraph(datapoints, options);
} }
}; };
Linegraph.prototype.drawBarGraph = function (datapoints, className, amountOfGraphs) {
Linegraph.prototype.drawBarGraph = function (datapoints, options, amountOfGraphs) {
if (datapoints != null) { if (datapoints != null) {
if (datapoints.length > 0) { if (datapoints.length > 0) {
var dataset = this._prepareData(datapoints); var dataset = this._prepareData(datapoints);
@ -3351,7 +3542,6 @@ Linegraph.prototype.drawBarGraph = function (datapoints, className, amountOfGrap
} }
} }
}; };
Linegraph.prototype.drawBar = function (x, y, className) { Linegraph.prototype.drawBar = function (x, y, className) {
var width = 10; var width = 10;
rect = this._getSVGElement('rect',this.svgElements, this.svg); rect = this._getSVGElement('rect',this.svgElements, this.svg);
@ -3363,14 +3553,14 @@ Linegraph.prototype.drawBar = function (x, y, className) {
rect.setAttributeNS(null, "class", className + " point"); rect.setAttributeNS(null, "class", className + " point");
}; };
Linegraph.prototype.drawLineGraph = function (datapoints, className) {
Linegraph.prototype.drawLineGraph = function (datapoints, options) {
if (datapoints != null) { if (datapoints != null) {
if (datapoints.length > 0) { if (datapoints.length > 0) {
var dataset = this._prepareData(datapoints);
var dataset = this._prepareData(datapoints, options);
var path, d; var path, d;
path = this._getSVGElement('path', this.svgElements, this.svg); path = this._getSVGElement('path', this.svgElements, this.svg);
path.setAttributeNS(null, "class", className);
path.setAttributeNS(null, "class", options.className);
// construct path from dataset // construct path from dataset
@ -3382,43 +3572,40 @@ Linegraph.prototype.drawLineGraph = function (datapoints, className) {
} }
// append with points for fill and finalize the path // append with points for fill and finalize the path
if (this.options.shaded.enabled == true) {
if (options.shaded.enabled == true) {
var fillPath = this._getSVGElement('path',this.svgElements, this.svg); var fillPath = this._getSVGElement('path',this.svgElements, this.svg);
if (this.options.shaded.orientation == 'top') {
if (options.shaded.orientation == 'top') {
var dFill = "M" + dataset[0].x + "," + 0 + " " + d + "L" + dataset[dataset.length - 1].x + "," + 0; var dFill = "M" + dataset[0].x + "," + 0 + " " + d + "L" + dataset[dataset.length - 1].x + "," + 0;
} }
else { else {
var dFill = "M" + dataset[0].x + "," + this.svg.offsetHeight + " " + d + "L" + dataset[dataset.length - 1].x + "," + this.svg.offsetHeight; var dFill = "M" + dataset[0].x + "," + this.svg.offsetHeight + " " + d + "L" + dataset[dataset.length - 1].x + "," + this.svg.offsetHeight;
} }
fillPath.setAttributeNS(null, "class", className + " fill");
fillPath.setAttributeNS(null, "class", options.className + " fill");
fillPath.setAttributeNS(null, "d", dFill); fillPath.setAttributeNS(null, "d", dFill);
} }
// copy properties to path for drawing. // copy properties to path for drawing.
path.setAttributeNS(null, "d", "M" + d); path.setAttributeNS(null, "d", "M" + d);
// draw points // draw points
if (this.options.drawPoints.enabled == true) {
this.drawPoints(dataset, className, this.svgElements, this.svg);
if (options.drawPoints.enabled == true) {
this.drawPoints(dataset, options, this.svgElements, this.svg);
} }
} }
} }
}; };
Linegraph.prototype.drawPoints = function (dataset, className, container, svg) {
Linegraph.prototype.drawPoints = function (dataset, options, container, svg) {
for (var i = 0; i < dataset.length; i++) { for (var i = 0; i < dataset.length; i++) {
this.drawPoint(dataset[i].x, dataset[i].y, className, container, svg);
this.drawPoint(dataset[i].x, dataset[i].y, options, container, svg);
} }
}; };
Linegraph.prototype.drawPoint = function(x, y, className, container, svg) {
Linegraph.prototype.drawPoint = function(x, y, options, container, svg) {
var point; var point;
if (this.options.drawPoints.style == 'circle') {
if (options.drawPoints.style == 'circle') {
point = this._getSVGElement('circle',container,svg); point = this._getSVGElement('circle',container,svg);
point.setAttributeNS(null, "cx", x); point.setAttributeNS(null, "cx", x);
point.setAttributeNS(null, "cy", y); point.setAttributeNS(null, "cy", y);
point.setAttributeNS(null, "r", 0.5 * this.options.drawPoints.size);
point.setAttributeNS(null, "class", className + " point");
point.setAttributeNS(null, "r", 0.5 * options.drawPoints.size);
point.setAttributeNS(null, "class", options.className + " point");
} }
else { else {
point = this._getSVGElement('rect',container,svg); point = this._getSVGElement('rect',container,svg);
@ -3426,37 +3613,35 @@ Linegraph.prototype.drawPoint = function(x, y, className, container, svg) {
point.setAttributeNS(null, "y", y - 0.5*this.options.drawPoints.size); point.setAttributeNS(null, "y", y - 0.5*this.options.drawPoints.size);
point.setAttributeNS(null, "width", this.options.drawPoints.size); point.setAttributeNS(null, "width", this.options.drawPoints.size);
point.setAttributeNS(null, "height", this.options.drawPoints.size); point.setAttributeNS(null, "height", this.options.drawPoints.size);
point.setAttributeNS(null, "class", className + " point");
point.setAttributeNS(null, "class", options.className + " point");
} }
return point; return point;
} }
Linegraph.prototype._getSVGElement = function (elementType, container, svg) {
Linegraph.prototype._getSVGElement = function (elementType, JSONcontainer, svgContainer) {
var element; var element;
// allocate SVG element, if it doesnt yet exist, create one. // allocate SVG element, if it doesnt yet exist, create one.
if (container.hasOwnProperty(elementType)) { // this element has been created before
if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before
// check if there is an redundant element // check if there is an redundant element
if (container[elementType].redundant.length > 0) {
element = container[elementType].redundant[0];
container[elementType].redundant.shift()
if (JSONcontainer[elementType].redundant.length > 0) {
element = JSONcontainer[elementType].redundant[0];
JSONcontainer[elementType].redundant.shift()
} }
else { else {
// create a new element and add it to the SVG // create a new element and add it to the SVG
element = document.createElementNS('http://www.w3.org/2000/svg', elementType); element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
svg.appendChild(element);
svgContainer.appendChild(element);
} }
} }
else { else {
// create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
element = document.createElementNS('http://www.w3.org/2000/svg', elementType); element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
container[elementType] = {used: [], redundant: []};
svg.appendChild(element);
JSONcontainer[elementType] = {used: [], redundant: []};
svgContainer.appendChild(element);
} }
container[elementType].used.push(element);
JSONcontainer[elementType].used.push(element);
return element; return element;
}; };
Linegraph.prototype._cleanupSVGElements = function(container) { Linegraph.prototype._cleanupSVGElements = function(container) {
// cleanup the redundant svgElements; // cleanup the redundant svgElements;
for (var elementType in container) { for (var elementType in container) {
@ -3468,7 +3653,6 @@ Linegraph.prototype._cleanupSVGElements = function(container) {
} }
} }
}; };
Linegraph.prototype._prepareSVGElements = function(container) { Linegraph.prototype._prepareSVGElements = function(container) {
// cleanup the redundant svgElements; // cleanup the redundant svgElements;
for (var elementType in container) { for (var elementType in container) {
@ -3478,21 +3662,44 @@ Linegraph.prototype._prepareSVGElements = function(container) {
} }
} }
}; };
Linegraph.prototype._prepareData = function (dataset) {
Linegraph.prototype._prepareData = function (dataset, options) {
var extractedData = []; var extractedData = [];
var xValue, yValue; var xValue, yValue;
var axis = this.yAxisLeft;
var toScreen = this.body.util.toScreen;
if (options.yAxisOrientation == 'right') {
axis = this.yAxisRight;
}
for (var i = 0; i < dataset.length; i++) { for (var i = 0; i < dataset.length; i++) {
xValue = this.body.util.toScreen(new Date(dataset[i].x)) + this.width;
yValue = this.yAxis.convertValue(dataset[i].y);
xValue = toScreen(new Date(dataset[i].x)) + this.width;
yValue = axis.convertValue(dataset[i].y);
extractedData.push({x: xValue, y: yValue}); extractedData.push({x: xValue, y: yValue});
} }
// extractedData.sort(function (a,b) {return a.x - b.x;}); // extractedData.sort(function (a,b) {return a.x - b.x;});
return extractedData; return extractedData;
}; };
Linegraph.prototype._getGroupOptions = function(groupId, groupIndex) {
var group = this.groupsData.get(groupId);
var options = util.copyObject(this.options, {});
options.className = 'graphGroup' + groupIndex%10;
if (group != null) {
if (group.className) {
options.className = group.className;
}
if (group.options) {
var fields = ['yAxisOrientation'];
util.selectiveExtend(fields, options, group.options);
this._mergeOptions(options, group.options,'catmullRom');
this._mergeOptions(options, group.options,'drawPoints');
this._mergeOptions(options, group.options,'shaded');
}
}
return options;
}
Linegraph.prototype._catmullRomUniform = function(data) { Linegraph.prototype._catmullRomUniform = function(data) {
// catmull rom // catmull rom
var p0, p1, p2, p3, bp1, bp2; var p0, p1, p2, p3, bp1, bp2;
@ -3613,7 +3820,6 @@ Linegraph.prototype._linear = function(data) {
return d; return d;
}; };
Linegraph.prototype.drawLegend = function(classes) { Linegraph.prototype.drawLegend = function(classes) {
this._prepareSVGElements(this.svgLegendElements); this._prepareSVGElements(this.svgLegendElements);
var x = 0; var x = 0;
@ -3677,6 +3883,8 @@ Linegraph.prototype.drawLegend = function(classes) {
} }
/** /**
* @constructor DataStep * @constructor DataStep
* The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an * The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an
@ -3703,7 +3911,7 @@ Linegraph.prototype.drawLegend = function(classes) {
* @param {Date} [end] The end date * @param {Date} [end] The end date
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/ */
function DataStep(start, end, minimumStep, containerHeight) {
function DataStep(start, end, minimumStep, containerHeight, forcedStepSize) {
// variables // variables
this.current = 0; this.current = 0;
@ -3718,7 +3926,7 @@ function DataStep(start, end, minimumStep, containerHeight) {
this.majorSteps = [1, 2, 5, 10]; this.majorSteps = [1, 2, 5, 10];
this.minorSteps = [0.25, 0.5, 1, 2]; this.minorSteps = [0.25, 0.5, 1, 2];
this.setRange(start, end, minimumStep, containerHeight);
this.setRange(start, end, minimumStep, containerHeight, forcedStepSize);
} }
@ -3733,12 +3941,12 @@ function DataStep(start, end, minimumStep, containerHeight) {
* @param {Number} [end] The end date and time. * @param {Number} [end] The end date and time.
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/ */
DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight) {
DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, forcedStepSize) {
this._start = start; this._start = start;
this._end = end; this._end = end;
this.setFirst(); this.setFirst();
if (this.autoScale) { if (this.autoScale) {
this.setMinimumStep(minimumStep, containerHeight);
this.setMinimumStep(minimumStep, containerHeight, forcedStepSize);
} }
}; };
@ -3832,6 +4040,16 @@ DataStep.prototype.next = function() {
} }
}; };
/**
* Do the next step
*/
DataStep.prototype.previous = function() {
this.current += this.step;
this.marginEnd += this.step;
this.marginRange = this.marginEnd - this.marginStart;
};
/** /**
* Get the current datetime * Get the current datetime
@ -9351,6 +9569,28 @@ Graph2d.prototype.setItems = function(items) {
}; };
/**
* Set groups
* @param {vis.DataSet | Array | google.visualization.DataTable} groups
*/
Graph2d.prototype.setGroups = function(groups) {
// convert to type DataSet when needed
var newDataSet;
if (!groups) {
newDataSet = null;
}
else if (groups instanceof DataSet || groups instanceof DataView) {
newDataSet = groups;
}
else {
// turn an array into a dataset
newDataSet = new DataSet(groups);
}
this.groupsData = newDataSet;
this.linegraph.setGroups(newDataSet);
};
/** /**
* Clear the Graph2d. By Default, items, groups and options are cleared. * Clear the Graph2d. By Default, items, groups and options are cleared.

+ 1
- 1
dist/vis.min.css
File diff suppressed because it is too large
View File


+ 12
- 12
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 72
- 17
examples/Graph2d/01_basic.html View File

@ -16,23 +16,76 @@
<div id="visualization"></div> <div id="visualization"></div>
<script type="text/javascript"> <script type="text/javascript">
var options = {
yAxisOrientation: 'left',
shaded: {
enabled: true,
orientation: 'bottom' // top, bottom
},
drawPoints: {
enabled: false,
size: 6,
style: 'circle' // square, circle
}
};
// create a data set with groups
var names = ['John', 'Alston', 'Lee', 'Grant'];
var groups = new vis.DataSet();
groups.add({
id: 0,
content: names[0],
className: "graphGroup9",
options: {
drawPoints: {
style: 'square' // square, circle
},
shaded: {
orientation: 'bottom' // top, bottom
}
}});
groups.add({
id: 1,
content: names[1],
className: "graphGroup1",
options: {
yAxisOrientation: 'right',
drawPoints: true, // square, circle
shaded: {
orientation: 'top' // top, bottom
}
}});
groups.add({
id: 2,
content: names[2],
className: "graphGroup2",
options: {
shaded: {
enabled: false,
orientation: 'top' // top, bottom
}
}});
var container = document.getElementById('visualization'); var container = document.getElementById('visualization');
var items = [ var items = [
{x: '2014-06-11', y: 10, className: 'group0', label: 'red'},
{x: '2014-06-12', y: 25, className: 'group0', label: 'red'},
{x: '2014-06-13', y: 30, className: 'group0', label: 'red'},
{x: '2014-06-14', y: 10, className: 'group1', label: 'green'},
{x: '2014-06-15', y: 15, className: 'group1', label: 'green'},
{x: '2014-06-16', y: 30, className: 'group1', label: 'green'},
{x: '2014-06-17', y: 10, className: 'group2', label: 'green'},
{x: '2014-06-18', y: 15, className: 'group2', label: 'green'},
{x: '2014-06-19', y: 50, className: 'group2', label: 'green'},
{x: '2014-06-20', y: 10, className: 'group3', label: 'green'},
{x: '2014-06-21', y: 19, className: 'group3', label: 'green'},
{x: '2014-06-22', y: 60, className: 'group3', label: 'green'},
{x: '2014-06-23', y: 10, className: 'group4', label: 'red'},
{x: '2014-06-24', y: 25, className: 'group4', label: 'red'},
{x: '2014-06-25', y: 30, className: 'group4', label: 'red'}
{x: '2014-06-11', y: 10 },
{x: '2014-06-12', y: 25 },
{x: '2014-06-13', y: 30, group: 0},
{x: '2014-06-14', y: 10, group: 0},
{x: '2014-06-15', y: 150, group: 1},
{x: '2014-06-16', y: 300, group: 1},
{x: '2014-06-17', y: 100, group: 1},
{x: '2014-06-18', y: 150, group: 1},
{x: '2014-06-19', y: 520, group: 1},
{x: '2014-06-20', y: 100, group: 1},
{x: '2014-06-21', y: 19, group: 2},
{x: '2014-06-22', y: 60, group: 2},
{x: '2014-06-23', y: 10, group: 2},
{x: '2014-06-24', y: 25, group: 2},
{x: '2014-06-25', y: 30, group: 2}
// {x: '2014-06-11', y: 10}, // {x: '2014-06-11', y: 10},
// {x: '2014-06-12', y: 25}, // {x: '2014-06-12', y: 25},
// {x: '2014-06-13', y: 30}, // {x: '2014-06-13', y: 30},
@ -42,8 +95,10 @@
]; ];
var dataset = new vis.DataSet(items); var dataset = new vis.DataSet(items);
var options = {};
var graph2d = new vis.Graph2d(container, dataset, options);
var graph2d = new vis.Graph2d(container);
graph2d.setOptions(options);
graph2d.setGroups(groups);
graph2d.setItems(dataset);
</script> </script>
</body> </body>

+ 14
- 4
src/timeline/DataStep.js View File

@ -24,7 +24,7 @@
* @param {Date} [end] The end date * @param {Date} [end] The end date
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/ */
function DataStep(start, end, minimumStep, containerHeight) {
function DataStep(start, end, minimumStep, containerHeight, forcedStepSize) {
// variables // variables
this.current = 0; this.current = 0;
@ -39,7 +39,7 @@ function DataStep(start, end, minimumStep, containerHeight) {
this.majorSteps = [1, 2, 5, 10]; this.majorSteps = [1, 2, 5, 10];
this.minorSteps = [0.25, 0.5, 1, 2]; this.minorSteps = [0.25, 0.5, 1, 2];
this.setRange(start, end, minimumStep, containerHeight);
this.setRange(start, end, minimumStep, containerHeight, forcedStepSize);
} }
@ -54,12 +54,12 @@ function DataStep(start, end, minimumStep, containerHeight) {
* @param {Number} [end] The end date and time. * @param {Number} [end] The end date and time.
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/ */
DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight) {
DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, forcedStepSize) {
this._start = start; this._start = start;
this._end = end; this._end = end;
this.setFirst(); this.setFirst();
if (this.autoScale) { if (this.autoScale) {
this.setMinimumStep(minimumStep, containerHeight);
this.setMinimumStep(minimumStep, containerHeight, forcedStepSize);
} }
}; };
@ -153,6 +153,16 @@ DataStep.prototype.next = function() {
} }
}; };
/**
* Do the next step
*/
DataStep.prototype.previous = function() {
this.current += this.step;
this.marginEnd += this.step;
this.marginRange = this.marginEnd - this.marginStart;
};
/** /**
* Get the current datetime * Get the current datetime

+ 22
- 0
src/timeline/Graph2d.js View File

@ -290,6 +290,28 @@ Graph2d.prototype.setItems = function(items) {
}; };
/**
* Set groups
* @param {vis.DataSet | Array | google.visualization.DataTable} groups
*/
Graph2d.prototype.setGroups = function(groups) {
// convert to type DataSet when needed
var newDataSet;
if (!groups) {
newDataSet = null;
}
else if (groups instanceof DataSet || groups instanceof DataView) {
newDataSet = groups;
}
else {
// turn an array into a dataset
newDataSet = new DataSet(groups);
}
this.groupsData = newDataSet;
this.linegraph.setGroups(newDataSet);
};
/** /**
* Clear the Graph2d. By Default, items, groups and options are cleared. * Clear the Graph2d. By Default, items, groups and options are cleared.

+ 86
- 51
src/timeline/component/DataAxis.js View File

@ -13,6 +13,8 @@ function DataAxis (body, options) {
orientation: 'left', // supported: 'left' orientation: 'left', // supported: 'left'
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px', width: '50px',
height: '300px' height: '300px'
}; };
@ -47,15 +49,32 @@ function DataAxis (body, options) {
this.width = Number(this.options.width.replace("px","")); this.width = Number(this.options.width.replace("px",""));
this.height = Number(this.options.height.replace("px","")); this.height = Number(this.options.height.replace("px",""));
this.stepPixels = 25;
this.stepPixelsForced = 25;
this.lineOffset = 0;
this.master = true;
// create the HTML DOM // create the HTML DOM
this._create(); this._create();
} }
DataAxis.prototype = new Component(); DataAxis.prototype = new Component();
//DataAxis.prototype.setOptions = function(options) {
//
//}
DataAxis.prototype.setOptions = function(options) {
if (options) {
var redraw = false;
if (this.options.orientation != options.orientation && options.orientation !== undefined) {
redraw = true;
}
var fields = ['orientation','showMinorLabels','showMajorLabels','width','height'];
util.selectiveExtend(fields, this.options, options);
if (redraw == true && this.dom.frame) {
this.hide();
this.show();
}
}
}
/** /**
@ -69,8 +88,6 @@ DataAxis.prototype._create = function() {
this.dom.lineContainer = document.createElement('div'); this.dom.lineContainer = document.createElement('div');
this.dom.lineContainer.style.width = '100%'; this.dom.lineContainer.style.width = '100%';
this.dom.lineContainer.style.height = this.options.height; this.dom.lineContainer.style.height = this.options.height;
this.show();
}; };
@ -82,7 +99,7 @@ DataAxis.prototype.show = function() {
if (this.options.orientation == 'left') { if (this.options.orientation == 'left') {
this.body.dom.left.appendChild(this.dom.frame); this.body.dom.left.appendChild(this.dom.frame);
} }
if (this.options.orientation == 'right') {
else {
this.body.dom.right.appendChild(this.dom.frame); this.body.dom.right.appendChild(this.dom.frame);
} }
} }
@ -139,9 +156,9 @@ DataAxis.prototype.redraw = function () {
props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth;
props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2*this.options.minorLinesOffset;
props.minorLineHeight = 1; props.minorLineHeight = 1;
props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth;
props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2*this.options.majorLinesOffset;;
props.majorLineHeight = 1; props.majorLineHeight = 1;
// take frame offline while updating (is almost twice as fast) // take frame offline while updating (is almost twice as fast)
@ -192,13 +209,27 @@ DataAxis.prototype._redrawLabels = function () {
step.first(); step.first();
var stepPixels = this.dom.frame.offsetHeight / ((step.marginRange / step.step) + 1); var stepPixels = this.dom.frame.offsetHeight / ((step.marginRange / step.step) + 1);
var xFirstMajorLabel = undefined;
this.stepPixels = stepPixels;
var amountOfSteps = this.height / stepPixels;
var stepDifference = 0;
if (this.master == false) {
stepPixels = this.stepPixelsForced;
stepDifference = Math.round((this.height / stepPixels) - amountOfSteps);
for (var i = 0; i < 0.5 * stepDifference; i++) {
step.previous();
}
amountOfSteps = this.height / stepPixels;
}
var xFirstMajorLabel = undefined;
this.valueAtZero = step.marginEnd; this.valueAtZero = step.marginEnd;
var marginStartPos = 0; var marginStartPos = 0;
var max = 0; var max = 0;
while (step.hasNext() && max < 1000) {
var y = Math.round(max * stepPixels);
var y = 0;
while (max < amountOfSteps) {
y = Math.round(max * stepPixels);
marginStartPos = max * stepPixels; marginStartPos = max * stepPixels;
var isMajor = step.isMajor(); var isMajor = step.isMajor();
@ -207,7 +238,7 @@ DataAxis.prototype._redrawLabels = function () {
} }
if (isMajor && this.options['showMajorLabels']) { if (isMajor && this.options['showMajorLabels']) {
if (y > 0) {
if (y >= 0) {
if (xFirstMajorLabel == undefined) { if (xFirstMajorLabel == undefined) {
xFirstMajorLabel = y; xFirstMajorLabel = y;
} }
@ -223,7 +254,7 @@ DataAxis.prototype._redrawLabels = function () {
max++; max++;
} }
this.conversionFactor = marginStartPos/step.marginRange;
this.conversionFactor = marginStartPos/((amountOfSteps-1) * step.step);
// create a major label on the left when needed // create a major label on the left when needed
if (this.options['showMajorLabels']) { if (this.options['showMajorLabels']) {
@ -257,7 +288,7 @@ DataAxis.prototype.convertValues = function(data) {
DataAxis.prototype.convertValue = function(value) { DataAxis.prototype.convertValue = function(value) {
var invertedValue = this.valueAtZero - value; var invertedValue = this.valueAtZero - value;
var convertedValue = invertedValue * this.conversionFactor; var convertedValue = invertedValue * this.conversionFactor;
return convertedValue - 2; // the -2 is to compensate for the borders
return convertedValue; // the -2 is to compensate for the borders
} }
/** /**
@ -325,7 +356,7 @@ DataAxis.prototype._redrawMajorText = function (y, text, orientation) {
label.style.textAlign = "right"; label.style.textAlign = "right";
} }
else { else {
label.style.left = '2';
label.style.left = '2px';
label.style.textAlign = "left"; label.style.textAlign = "left";
} }
@ -339,27 +370,29 @@ DataAxis.prototype._redrawMajorText = function (y, text, orientation) {
* @private * @private
*/ */
DataAxis.prototype._redrawMinorLine = function (y, orientation) { DataAxis.prototype._redrawMinorLine = function (y, orientation) {
// reuse redundant line
var line = this.dom.redundant.minorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal minor';
this.dom.lineContainer.appendChild(line);
}
this.dom.minorLines.push(line);
if (this.master == true) {
// reuse redundant line
var line = this.dom.redundant.minorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal minor';
this.dom.lineContainer.appendChild(line);
}
this.dom.minorLines.push(line);
var props = this.props;
if (orientation == 'left') {
line.style.left = (this.width - 15) + 'px';
}
else {
line.style.left = -1*(this.width - 15) + 'px';
}
var props = this.props;
if (orientation == 'left') {
line.style.left = (this.width - this.options.minorLinesOffset) + 'px';
}
else {
line.style.left = -1*(this.width - this.options.minorLinesOffset) + 'px';
}
line.style.width = props.minorLineWidth + 'px';
line.style.top = y + 'px';
line.style.width = props.minorLineWidth + 'px';
line.style.top = y + 'px';
}
}; };
/** /**
@ -369,25 +402,27 @@ DataAxis.prototype._redrawMinorLine = function (y, orientation) {
* @private * @private
*/ */
DataAxis.prototype._redrawMajorLine = function (y, orientation) { DataAxis.prototype._redrawMajorLine = function (y, orientation) {
// reuse redundant line
var line = this.dom.redundant.majorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal major';
this.dom.lineContainer.appendChild(line);
}
this.dom.majorLines.push(line);
if (this.master == true) {
// reuse redundant line
var line = this.dom.redundant.majorLines.shift();
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid horizontal major';
this.dom.lineContainer.appendChild(line);
}
this.dom.majorLines.push(line);
if (orientation == 'left') {
line.style.left = (this.width - 25) + 'px';
}
else {
line.style.left = -1*(this.width - 25) + 'px';
if (orientation == 'left') {
line.style.left = (this.width - this.options.majorLinesOffset) + 'px';
}
else {
line.style.left = -1*(this.width - this.options.mayorLinesOffset) + 'px';
}
line.style.top = y + 'px';
line.style.width = this.props.majorLineWidth + 'px';
} }
line.style.top = y + 'px';
line.style.width = this.props.majorLineWidth + 'px';
}; };

+ 269
- 100
src/timeline/component/Linegraph.js View File

@ -5,6 +5,7 @@ function Linegraph(body, options) {
this.body = body; this.body = body;
this.defaultOptions = { this.defaultOptions = {
yAxisOrientation: 'left',
shaded: { shaded: {
enabled: true, enabled: true,
orientation: 'top' // top, bottom orientation: 'top' // top, bottom
@ -48,6 +49,19 @@ function Linegraph(body, options) {
} }
}; };
// listeners for the DataSet of the groups
this.groupListeners = {
'add': function (event, params, senderId) {
me._onAddGroups(params.items);
},
'update': function (event, params, senderId) {
me._onUpdateGroups(params.items);
},
'remove': function (event, params, senderId) {
me._onRemoveGroups(params.items);
}
};
this.items = {}; // object with an Item for every data item this.items = {}; // object with an Item for every data item
this.selection = []; // list with the ids of all selected nodes this.selection = []; // list with the ids of all selected nodes
this.lastStart = this.body.range.start; this.lastStart = this.body.range.start;
@ -55,11 +69,10 @@ function Linegraph(body, options) {
this.svgElements = {}; this.svgElements = {};
this.svgLegendElements = {}; this.svgLegendElements = {};
// create the HTML DOM
this.setOptions(options);
this._create();
var me = this;
var me = this;
this.body.emitter.on("rangechange",function() { this.body.emitter.on("rangechange",function() {
if (me.lastStart != 0) { if (me.lastStart != 0) {
var offset = me.body.range.start - me.lastStart; var offset = me.body.range.start - me.lastStart;
@ -77,7 +90,8 @@ function Linegraph(body, options) {
me.updateGraph.apply(me); me.updateGraph.apply(me);
}); });
this.setOptions(options);
// create the HTML DOM
this._create();
this.body.emitter.emit("change"); this.body.emitter.emit("change");
} }
@ -109,10 +123,22 @@ Linegraph.prototype._create = function(){
frame.appendChild(this.svgLegend); frame.appendChild(this.svgLegend);
// panel with time axis // panel with time axis
this.yAxis = new DataAxis(this.body, {
this.yAxisLeft = new DataAxis(this.body, {
orientation: 'left', orientation: 'left',
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px',
height: this.svg.style.height
});
this.yAxisRight = new DataAxis(this.body, {
orientation: 'right',
showMinorLabels: true,
showMajorLabels: true,
majorLinesOffset: 25,
minorLinesOffset: 25,
width: '50px', width: '50px',
height: this.svg.style.height height: this.svg.style.height
}); });
@ -120,22 +146,13 @@ Linegraph.prototype._create = function(){
this.show(); this.show();
}; };
Linegraph.prototype.setOptions = function(options) { Linegraph.prototype.setOptions = function(options) {
if (options) { if (options) {
var fields = ['barGraph','catmullRom','shaded','drawPoints'];
var fields = ['yAxisOrientation'];
util.selectiveExtend(fields, this.options, options); util.selectiveExtend(fields, this.options, options);
if (options.catmullRom) { if (options.catmullRom) {
if (typeof options.catmullRom == 'boolean') {
this.options.catmullRom.enabled = options.catmullRom;
}
else {
this.options.catmullRom.enabled = true;
for (var prop in options.catmullRom) {
if (options.catmullRom.hasOwnProperty(prop)) {
this.options.catmullRom[prop] = options.catmullRom[prop];
}
}
if (typeof options.catmullRom == 'object') {
if (options.catmullRom.parametrization) { if (options.catmullRom.parametrization) {
if (options.catmullRom.parametrization == 'uniform') { if (options.catmullRom.parametrization == 'uniform') {
this.options.catmullRom.alpha = 0; this.options.catmullRom.alpha = 0;
@ -150,36 +167,27 @@ Linegraph.prototype.setOptions = function(options) {
} }
} }
} }
this._mergeOptions(this.options, options,'catmullRom');
this._mergeOptions(this.options, options,'drawPoints');
this._mergeOptions(this.options, options,'shaded');
}
};
if (options.drawPoints) {
if (typeof options.catmullRom == 'boolean') {
this.options.drawPoints.enabled = options.drawPoints;
}
else {
this.options.drawPoints.enabled = true;
for (prop in options.drawPoints) {
if (options.drawPoints.hasOwnProperty(prop)) {
this.options.drawPoints[prop] = options.drawPoints[prop];
}
}
}
Linegraph.prototype._mergeOptions = function (mergeTarget, options,option) {
if (options[option]) {
if (typeof options[option] == 'boolean') {
mergeTarget[option].enabled = options[option];
} }
if (options.shaded) {
if (typeof options.shaded == 'boolean') {
this.options.shaded.enabled = options.shaded;
}
else {
this.options.shaded.enabled = true;
for (prop in options.shaded) {
if (options.shaded.hasOwnProperty(prop)) {
this.options.shaded[prop] = options.shaded.drawPoints[prop];
}
else {
mergeTarget[option].enabled = true;
for (prop in options[option]) {
if (options[option].hasOwnProperty(prop)) {
mergeTarget[option][prop] = options[option][prop];
} }
} }
} }
} }
};
}
/** /**
* Hide the component from the DOM * Hide the component from the DOM
@ -203,8 +211,6 @@ Linegraph.prototype.show = function() {
}; };
/** /**
* Set items * Set items
* @param {vis.DataSet | null} items * @param {vis.DataSet | null} items
@ -247,31 +253,91 @@ Linegraph.prototype.setItems = function(items) {
ids = this.itemsData.getIds(); ids = this.itemsData.getIds();
this._onAdd(ids); this._onAdd(ids);
} }
this._updateUngrouped();
this.updateGraph();
this.redraw(); this.redraw();
}; };
/** /**
* Handle added items
* @param {Number[]} ids
* @protected
* Set groups
* @param {vis.DataSet} groups
*/ */
Linegraph.prototype.setGroups = function(groups) {
var me = this,
ids;
// unsubscribe from current dataset
if (this.groupsData) {
util.forEach(this.groupListeners, function (callback, event) {
me.groupsData.unsubscribe(event, callback);
});
// remove all drawn groups
ids = this.groupsData.getIds();
this.groupsData = null;
this._onRemoveGroups(ids); // note: this will cause a redraw
}
// replace the dataset
if (!groups) {
this.groupsData = null;
}
else if (groups instanceof DataSet || groups instanceof DataView) {
this.groupsData = groups;
}
else {
throw new TypeError('Data must be an instance of DataSet or DataView');
}
if (this.groupsData) {
// subscribe to new dataset
var id = this.id;
util.forEach(this.groupListeners, function (callback, event) {
me.groupsData.on(event, callback, id);
});
// draw all ms
ids = this.groupsData.getIds();
this._onAddGroups(ids);
}
this._updateUngrouped();
this.updateGraph();
this.redraw();
};
/**
* Handle updated items
* @param {Number[]} ids
* @protected
*/
Linegraph.prototype._onUpdate = function(ids) { Linegraph.prototype._onUpdate = function(ids) {
this.updateGraph(); this.updateGraph();
this.redraw(); this.redraw();
}; };
Linegraph.prototype._onAdd = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemove = function(ids) {};
Linegraph.prototype._onAdd = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemove = Linegraph.prototype._onUpdate;
Linegraph.prototype._onUpdateGroups = Linegraph.prototype._onUpdate;
Linegraph.prototype._onAddGroups = Linegraph.prototype._onUpdate;
Linegraph.prototype._onRemoveGroups = Linegraph.prototype._onUpdate;
/**
* Create or delete the group holding all ungrouped items. This group is used when
* there are no groups specified.
* @protected
*/
Linegraph.prototype._updateUngrouped = function() {
if (this.itemsData != null) {
var datapoints = this.itemsData.get({
filter: function (item) {return item.group === undefined;},
showInternalIds:true
});
var updateQuery = [];
for (var i = 0; i < datapoints.length; i++) {
updateQuery.push({id:datapoints[i].id, group: 'graph'});
}
this.itemsData.update(updateQuery);
}
};
/** /**
* Repaint the component * Repaint the component
* @return {boolean} Returns true if the component is resized * @return {boolean} Returns true if the component is resized
@ -279,7 +345,7 @@ Linegraph.prototype._onRemove = function(ids) {};
Linegraph.prototype.redraw = function() { Linegraph.prototype.redraw = function() {
var resized = false; var resized = false;
if (this.lastWidth === undefined && this.width) {
if (this.lastWidth === undefined && this.width || this.lastWidth != this.width) {
resized = true; resized = true;
} }
// check whether zoomed (in that case we need to re-stack everything) // check whether zoomed (in that case we need to re-stack everything)
@ -291,6 +357,7 @@ Linegraph.prototype.redraw = function() {
// calculate actual size and position // calculate actual size and position
this.width = this.dom.frame.offsetWidth; this.width = this.dom.frame.offsetWidth;
this.svgLegend.style.left = (this.width - this.svgLegend.offsetWidth - 10) + "px"; this.svgLegend.style.left = (this.width - this.svgLegend.offsetWidth - 10) + "px";
// check if this component is resized // check if this component is resized
resized = this._isResized() || resized; resized = this._isResized() || resized;
if (resized) { if (resized) {
@ -308,42 +375,126 @@ Linegraph.prototype.updateGraph = function () {
this._prepareSVGElements(this.svgElements); this._prepareSVGElements(this.svgElements);
if (this.width != 0 && this.itemsData != null) { if (this.width != 0 && this.itemsData != null) {
// get the range for the y Axis and draw it
var yRange = {start: this.itemsData.min('y').y, end: this.itemsData.max('y').y};
this.yAxis.setRange(yRange);
this.yAxis.redraw();
// look at different lines // look at different lines
var classes = this.itemsData.distinct('className');
if (classes.length > 0) {
for (var i = 0; i < classes.length; i++) {
this.drawGraph(classes[i], classes.length);
var groupIds = this.itemsData.distinct('group');
if (groupIds.length > 0) {
this._setYRanges(groupIds);
for (var i = 0; i < groupIds.length; i++) {
this.drawGraph(groupIds[i], i, groupIds.length);
} }
} }
else { else {
this.drawGraph('group0', 1);
this._setYRanges(groupIds);
this.drawGraph('graph', 0, 1);
} }
this.drawLegend(classes);
} }
// cleanup unused svg elements // cleanup unused svg elements
this._cleanupSVGElements(this.svgElements); this._cleanupSVGElements(this.svgElements);
}; };
Linegraph.prototype.drawGraph = function (className, amountOfGraphs) {
var datapoints = this.itemsData.get({filter: function (item) {
return item.className == className || !item.className;
}});
Linegraph.prototype._setYRanges = function(groupIds) {
var yAxisLeftUsed = false;
var yAxisRightUsed = false;
var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal;
var orientation = 'left';
if (groupIds.length > 0) {
for (var i = 0; i < groupIds.length; i++) {
orientation = 'left';
var group = this.groupsData.get(groupIds[i]);
if (group != null) {
if (group.options) {
if (group.options.yAxisOrientation == 'right') {
orientation = 'right';
}
}
}
var view = new vis.DataSet(this.itemsData.get({filter: function (item) {return item.group == groupIds[i];}}));
minVal = view.min("y").y;
maxVal = view.max("y").y;
if (orientation == 'left') {
yAxisLeftUsed = true;
if (minLeft > minVal) {minLeft = minVal;}
if (maxLeft < maxVal) {maxLeft = maxVal;}
}
else {
yAxisRightUsed = true;
if (minRight > minVal) {minRight = minVal;}
if (maxRight < maxVal) {maxRight = maxVal;}
}
delete view;
}
if (yAxisLeftUsed == true) {
this.yAxisLeft.setRange({start: minLeft, end: maxLeft});
}
if (yAxisRightUsed == true) {
this.yAxisRight.setRange({start: minRight, end: maxRight});
}
}
else {
var yRange = {start: this.itemsData.min('y').y, end: this.itemsData.max('y').y};
if (this.options.yAxisOrientation == 'left') {
this.yAxisLeft.setRange(yRange);
yAxisLeftUsed = true;
}
else {
this.yAxisRight.setRange(yRange);
yAxisRightUsed = true;
}
}
var changed = this._toggleAxisVisiblity(yAxisLeftUsed, this.yAxisLeft);
changed = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || changed;
if (changed) {
this.body.emitter.emit('change');
}
this.yAxisRight.master = !yAxisLeftUsed;
if (this.yAxisRight.master == false) {
if (yAxisRightUsed == true) {
this.yAxisLeft.lineOffset = this.yAxisRight.width;
}
this.yAxisLeft.redraw();
this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels;
this.yAxisRight.redraw();
}
else {
this.yAxisRight.redraw();
}
}
Linegraph.prototype._toggleAxisVisiblity = function(axisUsed, axis) {
var changed = false;
if (axisUsed == false) {
if (axis.dom.frame.parentNode) {
axis.hide();
changed = true;
}
}
else {
if (!axis.dom.frame.parentNode) {
axis.show();
changed = true;
}
}
return changed;
}
Linegraph.prototype.drawGraph = function (groupId, groupIndex, amountOfGraphs) {
var datapoints = this.itemsData.get({filter: function (item) {return item.group == groupId;}});
var options = this._getGroupOptions(groupId, groupIndex);
if (this.options.style == 'bar') { if (this.options.style == 'bar') {
this.drawBarGraph(datapoints, className, amountOfGraphs);
this.drawBarGraph(datapoints, options, amountOfGraphs);
} }
else { else {
this.drawLineGraph(datapoints, className);
this.drawLineGraph(datapoints, options);
} }
}; };
Linegraph.prototype.drawBarGraph = function (datapoints, className, amountOfGraphs) {
Linegraph.prototype.drawBarGraph = function (datapoints, options, amountOfGraphs) {
if (datapoints != null) { if (datapoints != null) {
if (datapoints.length > 0) { if (datapoints.length > 0) {
var dataset = this._prepareData(datapoints); var dataset = this._prepareData(datapoints);
@ -355,7 +506,6 @@ Linegraph.prototype.drawBarGraph = function (datapoints, className, amountOfGrap
} }
} }
}; };
Linegraph.prototype.drawBar = function (x, y, className) { Linegraph.prototype.drawBar = function (x, y, className) {
var width = 10; var width = 10;
rect = this._getSVGElement('rect',this.svgElements, this.svg); rect = this._getSVGElement('rect',this.svgElements, this.svg);
@ -367,14 +517,14 @@ Linegraph.prototype.drawBar = function (x, y, className) {
rect.setAttributeNS(null, "class", className + " point"); rect.setAttributeNS(null, "class", className + " point");
}; };
Linegraph.prototype.drawLineGraph = function (datapoints, className) {
Linegraph.prototype.drawLineGraph = function (datapoints, options) {
if (datapoints != null) { if (datapoints != null) {
if (datapoints.length > 0) { if (datapoints.length > 0) {
var dataset = this._prepareData(datapoints);
var dataset = this._prepareData(datapoints, options);
var path, d; var path, d;
path = this._getSVGElement('path', this.svgElements, this.svg); path = this._getSVGElement('path', this.svgElements, this.svg);
path.setAttributeNS(null, "class", className);
path.setAttributeNS(null, "class", options.className);
// construct path from dataset // construct path from dataset
@ -386,43 +536,40 @@ Linegraph.prototype.drawLineGraph = function (datapoints, className) {
} }
// append with points for fill and finalize the path // append with points for fill and finalize the path
if (this.options.shaded.enabled == true) {
if (options.shaded.enabled == true) {
var fillPath = this._getSVGElement('path',this.svgElements, this.svg); var fillPath = this._getSVGElement('path',this.svgElements, this.svg);
if (this.options.shaded.orientation == 'top') {
if (options.shaded.orientation == 'top') {
var dFill = "M" + dataset[0].x + "," + 0 + " " + d + "L" + dataset[dataset.length - 1].x + "," + 0; var dFill = "M" + dataset[0].x + "," + 0 + " " + d + "L" + dataset[dataset.length - 1].x + "," + 0;
} }
else { else {
var dFill = "M" + dataset[0].x + "," + this.svg.offsetHeight + " " + d + "L" + dataset[dataset.length - 1].x + "," + this.svg.offsetHeight; var dFill = "M" + dataset[0].x + "," + this.svg.offsetHeight + " " + d + "L" + dataset[dataset.length - 1].x + "," + this.svg.offsetHeight;
} }
fillPath.setAttributeNS(null, "class", className + " fill");
fillPath.setAttributeNS(null, "class", options.className + " fill");
fillPath.setAttributeNS(null, "d", dFill); fillPath.setAttributeNS(null, "d", dFill);
} }
// copy properties to path for drawing. // copy properties to path for drawing.
path.setAttributeNS(null, "d", "M" + d); path.setAttributeNS(null, "d", "M" + d);
// draw points // draw points
if (this.options.drawPoints.enabled == true) {
this.drawPoints(dataset, className, this.svgElements, this.svg);
if (options.drawPoints.enabled == true) {
this.drawPoints(dataset, options, this.svgElements, this.svg);
} }
} }
} }
}; };
Linegraph.prototype.drawPoints = function (dataset, className, container, svg) {
Linegraph.prototype.drawPoints = function (dataset, options, container, svg) {
for (var i = 0; i < dataset.length; i++) { for (var i = 0; i < dataset.length; i++) {
this.drawPoint(dataset[i].x, dataset[i].y, className, container, svg);
this.drawPoint(dataset[i].x, dataset[i].y, options, container, svg);
} }
}; };
Linegraph.prototype.drawPoint = function(x, y, className, container, svg) {
Linegraph.prototype.drawPoint = function(x, y, options, container, svg) {
var point; var point;
if (this.options.drawPoints.style == 'circle') {
if (options.drawPoints.style == 'circle') {
point = this._getSVGElement('circle',container,svg); point = this._getSVGElement('circle',container,svg);
point.setAttributeNS(null, "cx", x); point.setAttributeNS(null, "cx", x);
point.setAttributeNS(null, "cy", y); point.setAttributeNS(null, "cy", y);
point.setAttributeNS(null, "r", 0.5 * this.options.drawPoints.size);
point.setAttributeNS(null, "class", className + " point");
point.setAttributeNS(null, "r", 0.5 * options.drawPoints.size);
point.setAttributeNS(null, "class", options.className + " point");
} }
else { else {
point = this._getSVGElement('rect',container,svg); point = this._getSVGElement('rect',container,svg);
@ -430,7 +577,7 @@ Linegraph.prototype.drawPoint = function(x, y, className, container, svg) {
point.setAttributeNS(null, "y", y - 0.5*this.options.drawPoints.size); point.setAttributeNS(null, "y", y - 0.5*this.options.drawPoints.size);
point.setAttributeNS(null, "width", this.options.drawPoints.size); point.setAttributeNS(null, "width", this.options.drawPoints.size);
point.setAttributeNS(null, "height", this.options.drawPoints.size); point.setAttributeNS(null, "height", this.options.drawPoints.size);
point.setAttributeNS(null, "class", className + " point");
point.setAttributeNS(null, "class", options.className + " point");
} }
return point; return point;
} }
@ -459,7 +606,6 @@ Linegraph.prototype._getSVGElement = function (elementType, JSONcontainer, svgCo
JSONcontainer[elementType].used.push(element); JSONcontainer[elementType].used.push(element);
return element; return element;
}; };
Linegraph.prototype._cleanupSVGElements = function(container) { Linegraph.prototype._cleanupSVGElements = function(container) {
// cleanup the redundant svgElements; // cleanup the redundant svgElements;
for (var elementType in container) { for (var elementType in container) {
@ -471,7 +617,6 @@ Linegraph.prototype._cleanupSVGElements = function(container) {
} }
} }
}; };
Linegraph.prototype._prepareSVGElements = function(container) { Linegraph.prototype._prepareSVGElements = function(container) {
// cleanup the redundant svgElements; // cleanup the redundant svgElements;
for (var elementType in container) { for (var elementType in container) {
@ -481,21 +626,44 @@ Linegraph.prototype._prepareSVGElements = function(container) {
} }
} }
}; };
Linegraph.prototype._prepareData = function (dataset) {
Linegraph.prototype._prepareData = function (dataset, options) {
var extractedData = []; var extractedData = [];
var xValue, yValue; var xValue, yValue;
var axis = this.yAxisLeft;
var toScreen = this.body.util.toScreen;
if (options.yAxisOrientation == 'right') {
axis = this.yAxisRight;
}
for (var i = 0; i < dataset.length; i++) { for (var i = 0; i < dataset.length; i++) {
xValue = this.body.util.toScreen(new Date(dataset[i].x)) + this.width;
yValue = this.yAxis.convertValue(dataset[i].y);
xValue = toScreen(new Date(dataset[i].x)) + this.width;
yValue = axis.convertValue(dataset[i].y);
extractedData.push({x: xValue, y: yValue}); extractedData.push({x: xValue, y: yValue});
} }
// extractedData.sort(function (a,b) {return a.x - b.x;}); // extractedData.sort(function (a,b) {return a.x - b.x;});
return extractedData; return extractedData;
}; };
Linegraph.prototype._getGroupOptions = function(groupId, groupIndex) {
var group = this.groupsData.get(groupId);
var options = util.copyObject(this.options, {});
options.className = 'graphGroup' + groupIndex%10;
if (group != null) {
if (group.className) {
options.className = group.className;
}
if (group.options) {
var fields = ['yAxisOrientation'];
util.selectiveExtend(fields, options, group.options);
this._mergeOptions(options, group.options,'catmullRom');
this._mergeOptions(options, group.options,'drawPoints');
this._mergeOptions(options, group.options,'shaded');
}
}
return options;
}
Linegraph.prototype._catmullRomUniform = function(data) { Linegraph.prototype._catmullRomUniform = function(data) {
// catmull rom // catmull rom
var p0, p1, p2, p3, bp1, bp2; var p0, p1, p2, p3, bp1, bp2;
@ -616,7 +784,6 @@ Linegraph.prototype._linear = function(data) {
return d; return d;
}; };
Linegraph.prototype.drawLegend = function(classes) { Linegraph.prototype.drawLegend = function(classes) {
this._prepareSVGElements(this.svgLegendElements); this._prepareSVGElements(this.svgLegendElements);
var x = 0; var x = 0;
@ -679,3 +846,5 @@ Linegraph.prototype.drawLegend = function(classes) {
this._cleanupSVGElements(this.svgLegendElements); this._cleanupSVGElements(this.svgLegendElements);
} }

+ 10
- 10
src/timeline/component/css/pathStyles.css View File

@ -1,67 +1,67 @@
.vis.timeline .group0 {
.vis.timeline .graphGroup0 {
fill:#4f81bd; fill:#4f81bd;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #4f81bd; stroke: #4f81bd;
} }
.vis.timeline .group1 {
.vis.timeline .graphGroup1 {
fill:#f79646; fill:#f79646;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #f79646; stroke: #f79646;
} }
.vis.timeline .group2 {
.vis.timeline .graphGroup2 {
fill: #8c51cf; fill: #8c51cf;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #8c51cf; stroke: #8c51cf;
} }
.vis.timeline .group3 {
.vis.timeline .graphGroup3 {
fill: #75c841; fill: #75c841;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #75c841; stroke: #75c841;
} }
.vis.timeline .group4 {
.vis.timeline .graphGroup4 {
fill: #ff0100; fill: #ff0100;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #ff0100; stroke: #ff0100;
} }
.vis.timeline .group5 {
.vis.timeline .graphGroup5 {
fill: #37d8e6; fill: #37d8e6;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #37d8e6; stroke: #37d8e6;
} }
.vis.timeline .group6 {
.vis.timeline .graphGroup6 {
fill: #042662; fill: #042662;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #042662; stroke: #042662;
} }
.vis.timeline .group7 {
.vis.timeline .graphGroup7 {
fill:#00ff26; fill:#00ff26;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #00ff26; stroke: #00ff26;
} }
.vis.timeline .group8 {
.vis.timeline .graphGroup8 {
fill:#ff00ff; fill:#ff00ff;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;
stroke: #ff00ff; stroke: #ff00ff;
} }
.vis.timeline .group9 {
.vis.timeline .graphGroup9 {
fill: #8f3938; fill: #8f3938;
fill-opacity:0; fill-opacity:0;
stroke-width:2px; stroke-width:2px;

+ 3
- 0
src/timeline/component/legend.js View File

@ -0,0 +1,3 @@
/**
* Created by Alex on 6/17/14.
*/

+ 1
- 0
src/util.js View File

@ -988,4 +988,5 @@ util.copyObject = function(objectFrom, objectTo) {
} }
} }
} }
return objectTo;
}; };

Loading…
Cancel
Save