Browse Source

first working version! =]

css_transitions
Alex de Mulder 10 years ago
parent
commit
eec1de0af7
9 changed files with 485 additions and 183 deletions
  1. +1
    -0
      dist/vis.css
  2. +221
    -67
      dist/vis.js
  3. +3
    -3
      dist/vis.min.js
  4. +0
    -48
      examples/timeline/16_linegraph.html
  5. +40
    -0
      examples/timeline/20_linegraph.html
  6. +1
    -1
      src/timeline/DataStep.js
  7. +17
    -9
      src/timeline/component/DataAxis.js
  8. +201
    -55
      src/timeline/component/Linegraph.js
  9. +1
    -0
      src/timeline/component/css/itemset.css

+ 1
- 0
dist/vis.css View File

@ -88,6 +88,7 @@
} }
.vis.timeline .foreground { .vis.timeline .foreground {
padding:0; margin:0;
} }
.vis.timeline .axis { .vis.timeline .axis {

+ 221
- 67
dist/vis.js View File

@ -4,8 +4,8 @@
* *
* A dynamic, browser-based visualization library. * A dynamic, browser-based visualization library.
* *
* @version 1.0.2-SNAPSHOT
* @date 2014-05-28
* @version @@version
* @date @@date
* *
* @license * @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com * Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -3108,7 +3108,7 @@ DataStep.prototype.setFirst = function() {
this.marginEnd = this.roundToMinor(niceEnd); this.marginEnd = this.roundToMinor(niceEnd);
this.marginStart = this.roundToMinor(niceStart); this.marginStart = this.roundToMinor(niceStart);
this.marginRange = this.current - this.marginStart;
this.marginRange = this.marginEnd - this.marginStart;
this.current = this.marginEnd; this.current = this.marginEnd;
@ -4291,7 +4291,6 @@ DataAxis.prototype._create = function _create() {
* @param {Range | Object} range A Range or an object containing start and end. * @param {Range | Object} range A Range or an object containing start and end.
*/ */
DataAxis.prototype.setRange = function (range) { DataAxis.prototype.setRange = function (range) {
console.log(range, range.start, range.end, !range, !range.start, !range.end);
if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) { if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) {
throw new TypeError('Range must be an instance of Range, ' + throw new TypeError('Range must be an instance of Range, ' +
'or an object containing start and end.'); 'or an object containing start and end.');
@ -4394,7 +4393,8 @@ DataAxis.prototype._repaintLabels = function () {
var marginStartPos = 0; var marginStartPos = 0;
var max = 0; var max = 0;
while (step.hasNext() && max < 1000) { while (step.hasNext() && max < 1000) {
var y = Math.round(max * stepPixels);
var y = max * stepPixels;
y = y.toPrecision(5)
var isMajor = step.isMajor(); var isMajor = step.isMajor();
if (this.getOption('showMinorLabels') && isMajor == false) { if (this.getOption('showMinorLabels') && isMajor == false) {
@ -4420,6 +4420,7 @@ DataAxis.prototype._repaintLabels = function () {
} }
this.conversionFactor = marginStartPos/step.marginRange; this.conversionFactor = marginStartPos/step.marginRange;
console.log(marginStartPos, step.marginRange, this.conversionFactor);
@ -4445,10 +4446,17 @@ DataAxis.prototype._repaintLabels = function () {
}); });
}; };
DataAxis.prototype.convertValues = function(data) {
for (var i = 0; i < data.length; i++) {
data[i].y = this._getPos(data[i].y);
}
return data;
}
DataAxis.prototype._getPos = function(value) { DataAxis.prototype._getPos = function(value) {
var invertedValue = this.valueAtZero - value; var invertedValue = this.valueAtZero - value;
return invertedValue * this.conversionFactor;
var convertedValue = invertedValue * this.conversionFactor;
return convertedValue
} }
/** /**
@ -4524,12 +4532,12 @@ DataAxis.prototype._repaintMajorText = function (x, text, orientation) {
}; };
/** /**
* Create a minor line for the axis at position x
* @param {Number} x
* Create a minor line for the axis at position y
* @param {Number} y
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @private * @private
*/ */
DataAxis.prototype._repaintMinorLine = function (x, orientation) {
DataAxis.prototype._repaintMinorLine = function (y, orientation) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.minorLines.shift(); var line = this.dom.redundant.minorLines.shift();
@ -4550,7 +4558,7 @@ DataAxis.prototype._repaintMinorLine = function (x, orientation) {
} }
line.style.width = props.minorLineWidth + 'px'; line.style.width = props.minorLineWidth + 'px';
line.style.top = (x - props.minorLineHeight / 2) + 'px';
line.style.top = y + 'px';
}; };
/** /**
@ -4559,7 +4567,7 @@ DataAxis.prototype._repaintMinorLine = function (x, orientation) {
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @private * @private
*/ */
DataAxis.prototype._repaintMajorLine = function (x, orientation) {
DataAxis.prototype._repaintMajorLine = function (y, orientation) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.majorLines.shift(); var line = this.dom.redundant.majorLines.shift();
@ -4578,7 +4586,7 @@ DataAxis.prototype._repaintMajorLine = function (x, orientation) {
else { else {
line.style.left = -1*(this.width - 25) + 'px'; line.style.left = -1*(this.width - 25) + 'px';
} }
line.style.top = (x - props.majorLineHeight / 2) + 'px';
line.style.top = y + 'px';
line.style.width = props.majorLineWidth + 'px'; line.style.width = props.majorLineWidth + 'px';
}; };
@ -5359,7 +5367,7 @@ function Linegraph(backgroundPanel, axisPanel, sidePanel, options, timeline, sid
this.groupsData = null; // DataSet this.groupsData = null; // DataSet
this.range = null; // Range or Object {start: number, end: number} this.range = null; // Range or Object {start: number, end: number}
// listeners for the DataSet of the items
// listeners for the DataSet of the items
// this.itemListeners = { // this.itemListeners = {
// 'add': function(event, params, senderId) { // 'add': function(event, params, senderId) {
// if (senderId != me.id) me._onAdd(params.items); // if (senderId != me.id) me._onAdd(params.items);
@ -5416,6 +5424,8 @@ function Linegraph(backgroundPanel, axisPanel, sidePanel, options, timeline, sid
me.svg.style.left = util.option.asSize(-me.width); me.svg.style.left = util.option.asSize(-me.width);
me.setData.apply(me); me.setData.apply(me);
}); });
// this.data = new DataView(this.items)
} }
Linegraph.prototype = new Panel(); Linegraph.prototype = new Panel();
@ -5457,6 +5467,7 @@ Linegraph.prototype._create = function(){
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg");
this.svg.style.position = "relative" this.svg.style.position = "relative"
this.svg.style.height = "300px"; this.svg.style.height = "300px";
this.svg.style.display = "block";
this.path = document.createElementNS('http://www.w3.org/2000/svg',"path"); this.path = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path.setAttributeNS(null, "fill","none"); this.path.setAttributeNS(null, "fill","none");
@ -5466,10 +5477,16 @@ Linegraph.prototype._create = function(){
this.path2 = document.createElementNS('http://www.w3.org/2000/svg',"path"); this.path2 = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path2.setAttributeNS(null, "fill","none"); this.path2.setAttributeNS(null, "fill","none");
this.path2.setAttributeNS(null, "stroke","red"); this.path2.setAttributeNS(null, "stroke","red");
this.path2.setAttributeNS(null, "stroke-width","2");
this.path2.setAttributeNS(null, "stroke-width","1");
this.path3 = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path3.setAttributeNS(null, "fill","none");
this.path3.setAttributeNS(null, "stroke","green");
this.path3.setAttributeNS(null, "stroke-width","1");
this.dom.foreground.appendChild(this.svg); this.dom.foreground.appendChild(this.svg);
this.svg.appendChild(this.path3);
this.svg.appendChild(this.path2); this.svg.appendChild(this.path2);
this.svg.appendChild(this.path); this.svg.appendChild(this.path);
@ -5498,76 +5515,60 @@ Linegraph.prototype._createAxis = function() {
svg: this.svg svg: this.svg
}; };
this.yAxis = new DataAxis(dataAxisOptions); this.yAxis = new DataAxis(dataAxisOptions);
this.yAxis.setRange({start:-60,end:260});
this.sidePanel.frame.appendChild(this.yAxis.getFrame()); this.sidePanel.frame.appendChild(this.yAxis.getFrame());
} }
Linegraph.prototype.setData = function() { Linegraph.prototype.setData = function() {
var data = [];
this.yAxis.repaint();
if (this.width != 0) {
var dataview = new DataView(this.timeline.itemsData,
{filter: function (item) {return (item.value);}})
this.startTime = this.range.start;
var min = Date.now() - 3600000 * 24 * 30;
var max = Date.now() + 3600000 * 24 * 10;
var count = 60;
var step = (max-min) / count;
var datapoints = dataview.get();
if (datapoints != null) {
if (datapoints.length > 0) {
var dataset = this._extractData(datapoints);
var data = dataset.data;
var range = this.range.end - this.range.start;
console.log("height",data,datapoints, dataset);
this.yAxis.setRange({start:dataset.range.low,end:dataset.range.high});
this.yAxis.repaint();
data = this.yAxis.convertValues(data);
if (this.width != 0) {
var rangePerPixel = range/this.width;
var rangePerPixelInv = this.width/range;
var xOffset = -this.range.start + this.width*rangePerPixel;
var d, d2, d3;
d = this._catmullRom(data,0.5);
d3 = this._catmullRom(data,0);
d2 = this._catmullRom(data,1);
for (var i = 0; i < count; i++) {
data.push({x:(min + i*step + xOffset) * rangePerPixelInv, y: 250*(i%2) + 25})
}
// catmull rom
var p0, p1, p2, p3, bp1, bp2, bp3;
var d2 = "M" + data[0].x + "," + data[0].y + " ";
for (var i = 0; i < data.length - 2; i++) {
if (i == 0) {
p0 = data[0]
}
else {
p0 = data[i-1];
}
p1 = data[i];
p2 = data[i+1];
p3 = data[i+2];
// var data2 = [];
// this.startTime = this.range.start;
// var min = Date.now() - 3600000 * 24 * 30;
// var max = Date.now() + 3600000 * 24 * 10;
// var count = 60;
// var step = (max-min) / count;
//
// var range = this.range.end - this.range.start;
// var rangePerPixel = range/this.width;
// var rangePerPixelInv = this.width/range;
// var xOffset = -this.range.start + this.width*rangePerPixel;
//
// for (var i = 0; i < count; i++) {
// data2.push({x:(min + i*step + xOffset) * rangePerPixelInv, y: 250*(i%2) + 25})
// }
//
// var d2 = this._catmullRom(data2);
// Catmull-Rom to Cubic Bezier conversion matrix
// 0 1 0 0
// -1/6 1 1/6 0
// 0 1/6 1 -1/6
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = { x: ((-p0.x + 6*p1.x + p2.x) / 6), y: ((-p0.y + 6*p1.y + p2.y) / 6)};
bp2 = { x: ((p1.x + 6*p2.x - p3.x) / 6), y: ((p1.y + 6*p2.y - p3.y) / 6)};
bp3 = { x: p2.x, y: p2.y };
d2 += "C" + bp1.x + "," + bp1.y + " " + bp2.x + "," + bp2.y + " " + bp3.x + "," + bp3.y + " ";
}
// linear
var d = "";
for (var i = 0; i < data.length - 1; i++) {
if (i == 0) {
d += "M" + data[i].x + "," + data[i].y;
}
else {
d += " " + data[i].x + "," + data[i].y;
this.path.setAttributeNS(null, "d",d);
this.path2.setAttributeNS(null, "d",d2);
this.path3.setAttributeNS(null, "d",d3);
} }
} }
this.path.setAttributeNS(null, "d",d);
this.path2.setAttributeNS(null, "d",d2);
} }
} }
@ -5584,7 +5585,7 @@ Linegraph.prototype.setData = function() {
* Alignment for the items, only applicable for * Alignment for the items, only applicable for
* ItemBox. Choose 'center' (default), 'left', or * ItemBox. Choose 'center' (default), 'left', or
* 'right'. * 'right'.
* {String} orientation
* {String} orientation
* Orientation of the item set. Choose 'top' or * Orientation of the item set. Choose 'top' or
* 'bottom' (default). * 'bottom' (default).
* {Number} margin.axis * {Number} margin.axis
@ -5604,6 +5605,159 @@ Linegraph.prototype.setOptions = function(options) {
}; };
Linegraph.prototype._extractData = function(dataset) {
var extractedData = [];
var low = dataset[0].value;
var high = dataset[0].value;
var range = this.range.end - this.range.start;
var rangePerPixel = range/this.width;
var rangePerPixelInv = this.width/range;
var xOffset = -this.range.start + this.width*rangePerPixel;
for (var i = 0; i < dataset.length; i++) {
var val = new Date(dataset[i].start).getTime();
val += xOffset;
val *= rangePerPixelInv;
extractedData.push({x:val, y:dataset[i].value});
if (low > dataset[i].value) {
low = dataset[i].value;
}
if (high < dataset[i].value) {
high = dataset[i].value;
}
}
//extractedData.sort(function (a,b) {return a.x - b.x;})
return {range:{low:low,high:high},data:extractedData};
}
Linegraph.prototype._catmullRomUniform = function(data) {
// catmull rom
var p0, p1, p2, p3, bp1, bp2
var d = "M" + Math.round(data[0].x) + "," + Math.round(data[0].y) + " ";
var normalization = 1/6;
var length = data.length;
for (var i = 0; i < length - 1; i++) {
p0 = (i == 0) ? data[0] : data[i-1];
p1 = data[i];
p2 = data[i+1];
p3 = (i + 2 < length) ? data[i+2] : p2;
// Catmull-Rom to Cubic Bezier conversion matrix
// 0 1 0 0
// -1/6 1 1/6 0
// 0 1/6 1 -1/6
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)};
bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)};
// bp0 = { x: p2.x, y: p2.y };
d += "C" +
Math.round(bp1.x) + "," +
Math.round(bp1.y) + " " +
Math.round(bp2.x) + "," +
Math.round(bp2.y) + " " +
Math.round(p2.x) + "," +
Math.round(p2.y) + " ";
}
return d;
};
Linegraph.prototype._catmullRom = function(data, alpha) {
if (alpha == 0 || alpha === undefined) {
return this._catmullRomUniform(data);
}
else {
var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M;
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
var d = "M" + Math.round(data[0].x) + "," + Math.round(data[0].y) + " ";
var length = data.length;
for (var i = 0; i < length - 1; i++) {
p0 = (i == 0) ? data[0] : data[i-1];
p1 = data[i];
p2 = data[i+1];
p3 = (i + 2 < length) ? data[i+2] : p2;
d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2));
d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2));
d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2));
// Catmull-Rom to Cubic Bezier conversion matrix
//
// A = 2d1^2a + 3d1^a * d2^a + d3^2a
// B = 2d3^2a + 3d3^a * d2^a + d2^2a
//
// [ 0 1 0 0 ]
// [ -d2^2a/N A/N d1^2a/N 0 ]
// [ 0 d3^2a/M B/M -d2^2a/M ]
// [ 0 0 1 0 ]
// [ 0 1 0 0 ]
// [ -d2pow2a/N A/N d1pow2a/N 0 ]
// [ 0 d3pow2a/M B/M -d2pow2a/M ]
// [ 0 0 1 0 ]
d3powA = Math.pow(d3, alpha);
d3pow2A = Math.pow(d3,2*alpha);
d2powA = Math.pow(d2, alpha);
d2pow2A = Math.pow(d2,2*alpha);
d1powA = Math.pow(d1, alpha);
d1pow2A = Math.pow(d1,2*alpha);
A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A;
B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A;
N = 3*d1powA * (d1powA + d2powA);
if (N > 0) {N = 1 / N;}
M = 3*d3powA * (d3powA + d2powA);
if (M > 0) {M = 1 / M;}
bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N),
y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)};
bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M),
y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)};
if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;}
if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;}
d += "C" +
Math.round(bp1.x) + "," +
Math.round(bp1.y) + " " +
Math.round(bp2.x) + "," +
Math.round(bp2.y) + " " +
Math.round(p2.x) + "," +
Math.round(p2.y) + " ";
}
return d;
}
};
Linegraph.prototype._linear = function(data) {
// linear
var d = "";
for (var i = 0; i < data.length; i++) {
if (i == 0) {
d += "M" + data[i].x + "," + data[i].y;
}
else {
d += " " + data[i].x + "," + data[i].y;
}
}
return d;
}
/** /**
* Set range (start and end). * Set range (start and end).
* @param {Range | Object} range A Range or an object containing start and end. * @param {Range | Object} range A Range or an object containing start and end.

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


+ 0
- 48
examples/timeline/16_linegraph.html View File

@ -1,48 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Timeline | Basic demo</title>
<style type="text/css">
body, html {
font-family: sans-serif;
}
div.SVGforeground {
width:300px;
height:300px;
}
svg.svgclass {
width:300px;
height:300px;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="visualization"></div>
<script type="text/javascript">
var container = document.getElementById('visualization');
var items = [
{id: 1, content: 'item 1', start: '2014-05-20'},
{id: 2, content: 'item 2', start: '2014-05-14'},
{id: 3, content: 'item 3', start: '2014-05-18'},
{id: 4, content: 'item 4', start: '2014-05-16', end: '2014-05-19'},
{id: 5, content: 'item 5', start: '2014-05-25'},
{id: 6, content: 'item 6', start: '2014-05-27', type: 'point'},
{id: 11, start: '2014-05-20', value: 10},
{id: 12, start: '2014-05-14', value: 30},
{id: 13, start: '2014-05-18', value: 80}
];
var options = {};
var timeline = new vis.Timeline(container, items, options);
</script>
</body>
</html>

+ 40
- 0
examples/timeline/20_linegraph.html View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Timeline | Basic demo</title>
<style type="text/css">
body, html {
font-family: sans-serif;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="visualization"></div>
<script type="text/javascript">
var container = document.getElementById('visualization');
var items = [
{start: '2014-05-05', value: 80},
{start: '2014-05-18', value: 30},
{start: '2014-05-21', value: 30},
{start: '2014-07-30', value: 70},
{start: '2014-07-25', value: 65},
{start: '2014-06-30', value: 30},
{start: '2014-08-05', value: 40}
];
var options = {};
var timeline = new vis.Timeline(container, items, options);
</script>
</body>
</html>

+ 1
- 1
src/timeline/DataStep.js View File

@ -81,7 +81,7 @@ DataStep.prototype.setFirst = function() {
this.marginEnd = this.roundToMinor(niceEnd); this.marginEnd = this.roundToMinor(niceEnd);
this.marginStart = this.roundToMinor(niceStart); this.marginStart = this.roundToMinor(niceStart);
this.marginRange = this.current - this.marginStart;
this.marginRange = this.marginEnd - this.marginStart;
this.current = this.marginEnd; this.current = this.marginEnd;

+ 17
- 9
src/timeline/component/DataAxis.js View File

@ -60,7 +60,6 @@ DataAxis.prototype._create = function _create() {
* @param {Range | Object} range A Range or an object containing start and end. * @param {Range | Object} range A Range or an object containing start and end.
*/ */
DataAxis.prototype.setRange = function (range) { DataAxis.prototype.setRange = function (range) {
console.log(range, range.start, range.end, !range, !range.start, !range.end);
if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) { if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) {
throw new TypeError('Range must be an instance of Range, ' + throw new TypeError('Range must be an instance of Range, ' +
'or an object containing start and end.'); 'or an object containing start and end.');
@ -163,7 +162,8 @@ DataAxis.prototype._repaintLabels = function () {
var marginStartPos = 0; var marginStartPos = 0;
var max = 0; var max = 0;
while (step.hasNext() && max < 1000) { while (step.hasNext() && max < 1000) {
var y = Math.round(max * stepPixels);
var y = max * stepPixels;
y = y.toPrecision(5)
var isMajor = step.isMajor(); var isMajor = step.isMajor();
if (this.getOption('showMinorLabels') && isMajor == false) { if (this.getOption('showMinorLabels') && isMajor == false) {
@ -189,6 +189,7 @@ DataAxis.prototype._repaintLabels = function () {
} }
this.conversionFactor = marginStartPos/step.marginRange; this.conversionFactor = marginStartPos/step.marginRange;
console.log(marginStartPos, step.marginRange, this.conversionFactor);
@ -214,10 +215,17 @@ DataAxis.prototype._repaintLabels = function () {
}); });
}; };
DataAxis.prototype.convertValues = function(data) {
for (var i = 0; i < data.length; i++) {
data[i].y = this._getPos(data[i].y);
}
return data;
}
DataAxis.prototype._getPos = function(value) { DataAxis.prototype._getPos = function(value) {
var invertedValue = this.valueAtZero - value; var invertedValue = this.valueAtZero - value;
return invertedValue * this.conversionFactor;
var convertedValue = invertedValue * this.conversionFactor;
return convertedValue
} }
/** /**
@ -293,12 +301,12 @@ DataAxis.prototype._repaintMajorText = function (x, text, orientation) {
}; };
/** /**
* Create a minor line for the axis at position x
* @param {Number} x
* Create a minor line for the axis at position y
* @param {Number} y
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @private * @private
*/ */
DataAxis.prototype._repaintMinorLine = function (x, orientation) {
DataAxis.prototype._repaintMinorLine = function (y, orientation) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.minorLines.shift(); var line = this.dom.redundant.minorLines.shift();
@ -319,7 +327,7 @@ DataAxis.prototype._repaintMinorLine = function (x, orientation) {
} }
line.style.width = props.minorLineWidth + 'px'; line.style.width = props.minorLineWidth + 'px';
line.style.top = (x - props.minorLineHeight / 2) + 'px';
line.style.top = y + 'px';
}; };
/** /**
@ -328,7 +336,7 @@ DataAxis.prototype._repaintMinorLine = function (x, orientation) {
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @private * @private
*/ */
DataAxis.prototype._repaintMajorLine = function (x, orientation) {
DataAxis.prototype._repaintMajorLine = function (y, orientation) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.majorLines.shift(); var line = this.dom.redundant.majorLines.shift();
@ -347,7 +355,7 @@ DataAxis.prototype._repaintMajorLine = function (x, orientation) {
else { else {
line.style.left = -1*(this.width - 25) + 'px'; line.style.left = -1*(this.width - 25) + 'px';
} }
line.style.top = (x - props.majorLineHeight / 2) + 'px';
line.style.top = y + 'px';
line.style.width = props.majorLineWidth + 'px'; line.style.width = props.majorLineWidth + 'px';
}; };

+ 201
- 55
src/timeline/component/Linegraph.js View File

@ -35,7 +35,7 @@ function Linegraph(backgroundPanel, axisPanel, sidePanel, options, timeline, sid
this.groupsData = null; // DataSet this.groupsData = null; // DataSet
this.range = null; // Range or Object {start: number, end: number} this.range = null; // Range or Object {start: number, end: number}
// listeners for the DataSet of the items
// listeners for the DataSet of the items
// this.itemListeners = { // this.itemListeners = {
// 'add': function(event, params, senderId) { // 'add': function(event, params, senderId) {
// if (senderId != me.id) me._onAdd(params.items); // if (senderId != me.id) me._onAdd(params.items);
@ -92,6 +92,8 @@ function Linegraph(backgroundPanel, axisPanel, sidePanel, options, timeline, sid
me.svg.style.left = util.option.asSize(-me.width); me.svg.style.left = util.option.asSize(-me.width);
me.setData.apply(me); me.setData.apply(me);
}); });
// this.data = new DataView(this.items)
} }
Linegraph.prototype = new Panel(); Linegraph.prototype = new Panel();
@ -133,6 +135,7 @@ Linegraph.prototype._create = function(){
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg");
this.svg.style.position = "relative" this.svg.style.position = "relative"
this.svg.style.height = "300px"; this.svg.style.height = "300px";
this.svg.style.display = "block";
this.path = document.createElementNS('http://www.w3.org/2000/svg',"path"); this.path = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path.setAttributeNS(null, "fill","none"); this.path.setAttributeNS(null, "fill","none");
@ -142,10 +145,16 @@ Linegraph.prototype._create = function(){
this.path2 = document.createElementNS('http://www.w3.org/2000/svg',"path"); this.path2 = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path2.setAttributeNS(null, "fill","none"); this.path2.setAttributeNS(null, "fill","none");
this.path2.setAttributeNS(null, "stroke","red"); this.path2.setAttributeNS(null, "stroke","red");
this.path2.setAttributeNS(null, "stroke-width","2");
this.path2.setAttributeNS(null, "stroke-width","1");
this.path3 = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path3.setAttributeNS(null, "fill","none");
this.path3.setAttributeNS(null, "stroke","green");
this.path3.setAttributeNS(null, "stroke-width","1");
this.dom.foreground.appendChild(this.svg); this.dom.foreground.appendChild(this.svg);
this.svg.appendChild(this.path3);
this.svg.appendChild(this.path2); this.svg.appendChild(this.path2);
this.svg.appendChild(this.path); this.svg.appendChild(this.path);
@ -174,76 +183,60 @@ Linegraph.prototype._createAxis = function() {
svg: this.svg svg: this.svg
}; };
this.yAxis = new DataAxis(dataAxisOptions); this.yAxis = new DataAxis(dataAxisOptions);
this.yAxis.setRange({start:-60,end:260});
this.sidePanel.frame.appendChild(this.yAxis.getFrame()); this.sidePanel.frame.appendChild(this.yAxis.getFrame());
} }
Linegraph.prototype.setData = function() { Linegraph.prototype.setData = function() {
var data = [];
if (this.width != 0) {
var dataview = new DataView(this.timeline.itemsData,
{filter: function (item) {return (item.value);}})
this.yAxis.repaint();
var datapoints = dataview.get();
if (datapoints != null) {
if (datapoints.length > 0) {
var dataset = this._extractData(datapoints);
var data = dataset.data;
this.startTime = this.range.start;
var min = Date.now() - 3600000 * 24 * 30;
var max = Date.now() + 3600000 * 24 * 10;
var count = 60;
var step = (max-min) / count;
console.log("height",data,datapoints, dataset);
var range = this.range.end - this.range.start;
this.yAxis.setRange({start:dataset.range.low,end:dataset.range.high});
this.yAxis.repaint();
data = this.yAxis.convertValues(data);
var d, d2, d3;
d = this._catmullRom(data,0.5);
d3 = this._catmullRom(data,0);
d2 = this._catmullRom(data,1);
if (this.width != 0) {
var rangePerPixel = range/this.width;
var rangePerPixelInv = this.width/range;
var xOffset = -this.range.start + this.width*rangePerPixel;
for (var i = 0; i < count; i++) {
data.push({x:(min + i*step + xOffset) * rangePerPixelInv, y: 250*(i%2) + 25})
}
// catmull rom
var p0, p1, p2, p3, bp1, bp2, bp3;
var d2 = "M" + data[0].x + "," + data[0].y + " ";
for (var i = 0; i < data.length - 2; i++) {
if (i == 0) {
p0 = data[0]
}
else {
p0 = data[i-1];
}
p1 = data[i];
p2 = data[i+1];
p3 = data[i+2];
// var data2 = [];
// this.startTime = this.range.start;
// var min = Date.now() - 3600000 * 24 * 30;
// var max = Date.now() + 3600000 * 24 * 10;
// var count = 60;
// var step = (max-min) / count;
//
// var range = this.range.end - this.range.start;
// var rangePerPixel = range/this.width;
// var rangePerPixelInv = this.width/range;
// var xOffset = -this.range.start + this.width*rangePerPixel;
//
// for (var i = 0; i < count; i++) {
// data2.push({x:(min + i*step + xOffset) * rangePerPixelInv, y: 250*(i%2) + 25})
// }
//
// var d2 = this._catmullRom(data2);
// Catmull-Rom to Cubic Bezier conversion matrix
// 0 1 0 0
// -1/6 1 1/6 0
// 0 1/6 1 -1/6
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = { x: ((-p0.x + 6*p1.x + p2.x) / 6), y: ((-p0.y + 6*p1.y + p2.y) / 6)};
bp2 = { x: ((p1.x + 6*p2.x - p3.x) / 6), y: ((p1.y + 6*p2.y - p3.y) / 6)};
bp3 = { x: p2.x, y: p2.y };
d2 += "C" + bp1.x + "," + bp1.y + " " + bp2.x + "," + bp2.y + " " + bp3.x + "," + bp3.y + " ";
}
// linear
var d = "";
for (var i = 0; i < data.length - 1; i++) {
if (i == 0) {
d += "M" + data[i].x + "," + data[i].y;
}
else {
d += " " + data[i].x + "," + data[i].y;
this.path.setAttributeNS(null, "d",d);
this.path2.setAttributeNS(null, "d",d2);
this.path3.setAttributeNS(null, "d",d3);
} }
} }
this.path.setAttributeNS(null, "d",d);
this.path2.setAttributeNS(null, "d",d2);
} }
} }
@ -260,7 +253,7 @@ Linegraph.prototype.setData = function() {
* Alignment for the items, only applicable for * Alignment for the items, only applicable for
* ItemBox. Choose 'center' (default), 'left', or * ItemBox. Choose 'center' (default), 'left', or
* 'right'. * 'right'.
* {String} orientation
* {String} orientation
* Orientation of the item set. Choose 'top' or * Orientation of the item set. Choose 'top' or
* 'bottom' (default). * 'bottom' (default).
* {Number} margin.axis * {Number} margin.axis
@ -280,6 +273,159 @@ Linegraph.prototype.setOptions = function(options) {
}; };
Linegraph.prototype._extractData = function(dataset) {
var extractedData = [];
var low = dataset[0].value;
var high = dataset[0].value;
var range = this.range.end - this.range.start;
var rangePerPixel = range/this.width;
var rangePerPixelInv = this.width/range;
var xOffset = -this.range.start + this.width*rangePerPixel;
for (var i = 0; i < dataset.length; i++) {
var val = new Date(dataset[i].start).getTime();
val += xOffset;
val *= rangePerPixelInv;
extractedData.push({x:val, y:dataset[i].value});
if (low > dataset[i].value) {
low = dataset[i].value;
}
if (high < dataset[i].value) {
high = dataset[i].value;
}
}
//extractedData.sort(function (a,b) {return a.x - b.x;})
return {range:{low:low,high:high},data:extractedData};
}
Linegraph.prototype._catmullRomUniform = function(data) {
// catmull rom
var p0, p1, p2, p3, bp1, bp2
var d = "M" + Math.round(data[0].x) + "," + Math.round(data[0].y) + " ";
var normalization = 1/6;
var length = data.length;
for (var i = 0; i < length - 1; i++) {
p0 = (i == 0) ? data[0] : data[i-1];
p1 = data[i];
p2 = data[i+1];
p3 = (i + 2 < length) ? data[i+2] : p2;
// Catmull-Rom to Cubic Bezier conversion matrix
// 0 1 0 0
// -1/6 1 1/6 0
// 0 1/6 1 -1/6
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)};
bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)};
// bp0 = { x: p2.x, y: p2.y };
d += "C" +
Math.round(bp1.x) + "," +
Math.round(bp1.y) + " " +
Math.round(bp2.x) + "," +
Math.round(bp2.y) + " " +
Math.round(p2.x) + "," +
Math.round(p2.y) + " ";
}
return d;
};
Linegraph.prototype._catmullRom = function(data, alpha) {
if (alpha == 0 || alpha === undefined) {
return this._catmullRomUniform(data);
}
else {
var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M;
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
var d = "M" + Math.round(data[0].x) + "," + Math.round(data[0].y) + " ";
var length = data.length;
for (var i = 0; i < length - 1; i++) {
p0 = (i == 0) ? data[0] : data[i-1];
p1 = data[i];
p2 = data[i+1];
p3 = (i + 2 < length) ? data[i+2] : p2;
d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2));
d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2));
d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2));
// Catmull-Rom to Cubic Bezier conversion matrix
//
// A = 2d1^2a + 3d1^a * d2^a + d3^2a
// B = 2d3^2a + 3d3^a * d2^a + d2^2a
//
// [ 0 1 0 0 ]
// [ -d2^2a/N A/N d1^2a/N 0 ]
// [ 0 d3^2a/M B/M -d2^2a/M ]
// [ 0 0 1 0 ]
// [ 0 1 0 0 ]
// [ -d2pow2a/N A/N d1pow2a/N 0 ]
// [ 0 d3pow2a/M B/M -d2pow2a/M ]
// [ 0 0 1 0 ]
d3powA = Math.pow(d3, alpha);
d3pow2A = Math.pow(d3,2*alpha);
d2powA = Math.pow(d2, alpha);
d2pow2A = Math.pow(d2,2*alpha);
d1powA = Math.pow(d1, alpha);
d1pow2A = Math.pow(d1,2*alpha);
A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A;
B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A;
N = 3*d1powA * (d1powA + d2powA);
if (N > 0) {N = 1 / N;}
M = 3*d3powA * (d3powA + d2powA);
if (M > 0) {M = 1 / M;}
bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N),
y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)};
bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M),
y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)};
if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;}
if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;}
d += "C" +
Math.round(bp1.x) + "," +
Math.round(bp1.y) + " " +
Math.round(bp2.x) + "," +
Math.round(bp2.y) + " " +
Math.round(p2.x) + "," +
Math.round(p2.y) + " ";
}
return d;
}
};
Linegraph.prototype._linear = function(data) {
// linear
var d = "";
for (var i = 0; i < data.length; i++) {
if (i == 0) {
d += "M" + data[i].x + "," + data[i].y;
}
else {
d += " " + data[i].x + "," + data[i].y;
}
}
return d;
}
/** /**
* Set range (start and end). * Set range (start and end).
* @param {Range | Object} range A Range or an object containing start and end. * @param {Range | Object} range A Range or an object containing start and end.

+ 1
- 0
src/timeline/component/css/itemset.css View File

@ -16,6 +16,7 @@
} }
.vis.timeline .foreground { .vis.timeline .foreground {
padding:0; margin:0;
} }
.vis.timeline .axis { .vis.timeline .axis {

Loading…
Cancel
Save