Browse Source

Merge branch 'develop' of https://github.com/almende/vis into template-fix

codeClimate
Yotam Berkowitz 8 years ago
parent
commit
249272ccc1
7 changed files with 375 additions and 394 deletions
  1. +1
    -1
      README.md
  2. +1
    -1
      docs/graph2d/index.html
  3. +11
    -9
      docs/timeline/index.html
  4. +1
    -1
      examples/timeline/items/pointItems.html
  5. +350
    -372
      lib/graph3d/Graph3d.js
  6. +5
    -6
      lib/timeline/Timeline.js
  7. +6
    -4
      misc/how_to_help.md

+ 1
- 1
README.md View File

@ -154,7 +154,7 @@ slow, so when only the non-minified library is needed, one can use the
## Custom builds ## Custom builds
The folder `dist` contains bundled versions of vis.js for direct use in the browser. These bundles contain the all visualizations and includes external dependencies such as hammer.js and moment.js.
The folder `dist` contains bundled versions of vis.js for direct use in the browser. These bundles contain all the visualizations and include external dependencies such as hammer.js and moment.js.
The source code of vis.js consists of commonjs modules, which makes it possible to create custom bundles using tools like [Browserify](http://browserify.org/) or [Webpack](http://webpack.github.io/). This can be bundling just one visualization like the Timeline, or bundling vis.js as part of your own browserified web application. The source code of vis.js consists of commonjs modules, which makes it possible to create custom bundles using tools like [Browserify](http://browserify.org/) or [Webpack](http://webpack.github.io/). This can be bundling just one visualization like the Timeline, or bundling vis.js as part of your own browserified web application.

+ 1
- 1
docs/graph2d/index.html View File

@ -1202,7 +1202,7 @@ function (option, path) {
<tr> <tr>
<td>on(event, callback)</td> <td>on(event, callback)</td>
<td>none</td> <td>none</td>
<td>Create an event listener. The callback function is invoked every time the event is triggered. Avialable events: <code>rangechange</code>, <code>rangechanged</code>, <code>select</code>. The callback function is invoked as <code>callback(properties)</code>, where <code>properties</code> is an object containing event specific properties. See section <a href="#Events">Events for more information</a>.</td>
<td>Create an event listener. The callback function is invoked every time the event is triggered. Available events: <code>rangechange</code>, <code>rangechanged</code>, <code>select</code>. The callback function is invoked as <code>callback(properties)</code>, where <code>properties</code> is an object containing event specific properties. See section <a href="#Events">Events for more information</a>.</td>
</tr> </tr>
<tr> <tr>

+ 11
- 9
docs/timeline/index.html View File

@ -680,7 +680,7 @@ function (option, path) {
<td>Boolean</td> <td>Boolean</td>
<td>false</td> <td>false</td>
<td>This option allows you to scroll horizontally to move backwards and forwards in the time range. <td>This option allows you to scroll horizontally to move backwards and forwards in the time range.
Only applicable when option <code>zoomCtrl</code> is defined or <code>zoomable</code> is <code>false</code>.
Only applicable when option <code>zoomCtrl</code> is defined or <code>zoomable</code> is <code>false</code>. Notice that defining this option as <code>true</code> will override <code>verticalScroll</code> scroll event but not eliminate the vertical scrollbar.
</td> </td>
</tr> </tr>
@ -1028,7 +1028,7 @@ function (option, path) {
<td>verticalScroll</td> <td>verticalScroll</td>
<td>Boolean</td> <td>Boolean</td>
<td>false</td> <td>false</td>
<td> Show a vertical scroll on the side of the group list.
<td> Show a vertical scroll on the side of the group list and link it to the scroll event when zoom is not triggered. Notice that defining this option as <code>true</code> will NOT override <code>horizontalScroll</code>. The scroll event will be vertically ignored, but a vertical scrollbar will be visible
</td> </td>
</tr> </tr>
@ -1211,7 +1211,7 @@ document.getElementById('myTimeline').onclick = function (event) {
<tr> <tr>
<td>on(event, callback)</td> <td>on(event, callback)</td>
<td>none</td> <td>none</td>
<td>Create an event listener. The callback function is invoked every time the event is triggered. Avialable events: <code>rangechange</code>, <code>rangechanged</code>, <code>select</code>, <code>itemover</code>, <code>itemout</code>. The callback function is invoked as <code>callback(properties)</code>, where <code>properties</code> is an object containing event specific properties. See section <a href="#Events">Events for more information</a>.</td>
<td>Create an event listener. The callback function is invoked every time the event is triggered. Available events: <code>rangechange</code>, <code>rangechanged</code>, <code>select</code>, <code>itemover</code>, <code>itemout</code>. The callback function is invoked as <code>callback(properties)</code>, where <code>properties</code> is an object containing event specific properties. See section <a href="#Events">Events for more information</a>.</td>
</tr> </tr>
<tr> <tr>
@ -1250,7 +1250,7 @@ document.getElementById('myTimeline').onclick = function (event) {
<td>none</td> <td>none</td>
<td>Adjust the time of a custom time bar. <td>Adjust the time of a custom time bar.
Parameter <code>time</code> can be a Date object, numeric timestamp, or ISO date string. Parameter <code>time</code> can be a Date object, numeric timestamp, or ISO date string.
Parameter <code>id</code> is the idof the custom time bar, and is <code>undefined</code> by default.
Parameter <code>id</code> is the id of the custom time bar, and is <code>undefined</code> by default.
</td> </td>
</tr> </tr>
@ -1574,7 +1574,9 @@ var items = new vis.DataSet([
</p> </p>
<ul> <ul>
<li><code>item</code>: the item being manipulated</li> <li><code>item</code>: the item being manipulated</li>
<li><code>callback</code>: a callback function which must be invoked to report back. The callback must be invoked as <code>callback(item or null)</code>. Here, <code>item</code> can contain changes to the passed item. Parameter `item` typically contains fields `content`, `start`, and optionally `end`. The type of `start` and `end` is determined by the DataSet type configuration and is `Date` by default. When invoked as <code>callback(null)</code>, the action will be cancelled.</li>
<li><code>callback</code>: a callback function which must be invoked to report back. The callback must be invoked as <code>callback(item)</code> or <code>callback(null)</code>.
Here, <code>item</code> can contain changes to the passed item. Parameter <code>item</code> typically contains fields `content`, `start`, and optionally `end`. The type of `start`
and `end` is determined by the DataSet type configuration and is `Date` by default. When invoked as <code>callback(null)</code>, the action will be cancelled.</li>
</ul> </ul>
<p> <p>
@ -1600,7 +1602,7 @@ var items = new vis.DataSet([
<h2 id="Templates">Templates</h2> <h2 id="Templates">Templates</h2>
<p> <p>
Timeline supports templates to format item contents. Any template engine (such as <a href="http://handlebarsjs.com/">handlebars</a> or <a href="http://mustache.github.io/">mustache</a>) can be used, and one can also manually build HTML. In the options, one can provide a template handler. This handler is a function accepting an items data as argument, and outputs formatted HTML:
Timeline supports templates to format item contents. Any template engine (such as <a href="http://handlebarsjs.com/">handlebars</a> or <a href="http://mustache.github.io/">mustache</a>) can be used, and one can also manually build HTML. In the options, one can provide a template handler. This handler is a function accepting an item's data as argument, and outputs formatted HTML:
</p> </p>
<pre class="prettyprint lang-js">var options = { <pre class="prettyprint lang-js">var options = {
@ -1697,7 +1699,7 @@ var options = {
<h3>Create a new locale</h3> <h3>Create a new locale</h3>
To load a locale into the Timeline not supported by default, one can add a new locale to the option <code>locales</code>:
To load a locale (that is not supported by default) into the Timeline, one can add a new locale to the option <code>locales</code>:
<pre class="prettyprint lang-js">var options = { <pre class="prettyprint lang-js">var options = {
locales: { locales: {
@ -1753,7 +1755,7 @@ var options = {
<h2 id="Time_zone">Time zone</h2> <h2 id="Time_zone">Time zone</h2>
<p> <p>
By default, the Timeline displays time in local time. To display a Timeline in an other time zone or in UTC, the date constructor can be overloaded via the configuration option <code>moment</code>, which by default is the constructor function of moment.js. More information about UTC with moment.js can be found in the docs: <a href="http://momentjs.com/docs/#/parsing/utc/">http://momentjs.com/docs/#/parsing/utc/</a>.
By default, the Timeline displays time in local time. To display a Timeline in another time zone or in UTC, the date constructor can be overloaded via the configuration option <code>moment</code>, which by default is the constructor function of moment.js. More information about UTC with moment.js can be found in the docs: <a href="http://momentjs.com/docs/#/parsing/utc/">http://momentjs.com/docs/#/parsing/utc/</a>.
</p> </p>
<p> <p>
@ -1827,7 +1829,7 @@ var options = {
<td>Days</td><td><code>vis-date1</code>, <code>vis-date2</code>, ..., <code>vis-date31</code></td> <td>Days</td><td><code>vis-date1</code>, <code>vis-date2</code>, ..., <code>vis-date31</code></td>
</tr> </tr>
<tr> <tr>
<td>Months</td><td><code>vis-januari</code>, <code>vis-februari</code>, <code>vis-march</code>, <code>vis-april</code>, <code>vis-may</code>, <code>vis-june</code>, <code>vis-july</code>, <code>vis-august</code>, <code>vis-september</code>, <code>vis-october</code>, <code>vis-november</code>, <code>vis-december</code></td>
<td>Months</td><td><code>vis-january</code>, <code>vis-february</code>, <code>vis-march</code>, <code>vis-april</code>, <code>vis-may</code>, <code>vis-june</code>, <code>vis-july</code>, <code>vis-august</code>, <code>vis-september</code>, <code>vis-october</code>, <code>vis-november</code>, <code>vis-december</code></td>
</tr> </tr>
<tr> <tr>
<td>Years</td><td><code>vis-year2014</code>, <code>vis-year2015</code>, ...</td> <td>Years</td><td><code>vis-year2014</code>, <code>vis-year2015</code>, ...</td>

+ 1
- 1
examples/timeline/items/pointItems.html View File

@ -49,7 +49,7 @@
var options = { var options = {
// Set global item type. Type can also be specified for items individually // Set global item type. Type can also be specified for items individually
// Available types: 'box' (default), 'point', 'range', 'rangeoverflow'
// Available types: 'box' (default), 'point', 'range'
type: 'point', type: 'point',
showMajorLabels: false showMajorLabels: false
}; };

+ 350
- 372
lib/graph3d/Graph3d.js View File

@ -804,6 +804,7 @@ Graph3d.prototype.setOptions = function (options) {
Settings.setOptions(options, this); Settings.setOptions(options, this);
this.setPointDrawingMethod();
this.setSize(this.width, this.height); this.setSize(this.width, this.height);
// re-load the data // re-load the data
@ -817,6 +818,54 @@ Graph3d.prototype.setOptions = function (options) {
} }
}; };
/**
* Determine which point drawing method to use for the current graph style.
*/
Graph3d.prototype.setPointDrawingMethod = function() {
var method = undefined;
switch (this.style) {
case Graph3d.STYLE.BAR:
method = Graph3d.prototype._redrawBarGraphPoint;
break;
case Graph3d.STYLE.BARCOLOR:
method = Graph3d.prototype._redrawBarColorGraphPoint;
break;
case Graph3d.STYLE.BARSIZE:
method = Graph3d.prototype._redrawBarSizeGraphPoint;
break;
case Graph3d.STYLE.DOT:
method = Graph3d.prototype._redrawDotGraphPoint;
break;
case Graph3d.STYLE.DOTLINE:
method = Graph3d.prototype._redrawDotLineGraphPoint;
break;
case Graph3d.STYLE.DOTCOLOR:
method = Graph3d.prototype._redrawDotColorGraphPoint;
break;
case Graph3d.STYLE.DOTSIZE:
method = Graph3d.prototype._redrawDotSizeGraphPoint;
break;
case Graph3d.STYLE.SURFACE:
method = Graph3d.prototype._redrawSurfaceGraphPoint;
break;
case Graph3d.STYLE.GRID:
method = Graph3d.prototype._redrawGridGraphPoint;
break;
case Graph3d.STYLE.LINE:
method = Graph3d.prototype._redrawLineGraphPoint;
break;
default:
throw new Error('Can not determine point drawing method '
+ 'for graph style \'' + this.style + '\'');
break;
}
this._pointDrawingMethod = method;
};
/** /**
* Redraw the Graph. * Redraw the Graph.
*/ */
@ -831,35 +880,7 @@ Graph3d.prototype.redraw = function() {
this._redrawClear(); this._redrawClear();
this._redrawAxis(); this._redrawAxis();
var pointDrawingMethod = undefined;
switch (this.style) {
case Graph3d.STYLE.BAR:
pointDrawingMethod = Graph3d.prototype._redrawBarGraphPoint;
break;
}
if (pointDrawingMethod !== undefined) {
// Use generic drawing loop
// Pass the method reference here
this._redrawDataGraph(pointDrawingMethod);
} else {
// Use the old style drawing methods
if (this.style === Graph3d.STYLE.GRID ||
this.style === Graph3d.STYLE.SURFACE) {
this._redrawDataGrid();
}
else if (this.style === Graph3d.STYLE.LINE) {
this._redrawDataLine();
} else if (this.style === Graph3d.STYLE.BARCOLOR ||
this.style === Graph3d.STYLE.BARSIZE) {
this._redrawDataBar();
}
else {
// style is DOT, DOTLINE, DOTCOLOR, DOTSIZE
this._redrawDataDot();
}
}
this._redrawDataGraph();
this._redrawInfo(); this._redrawInfo();
this._redrawLegend(); this._redrawLegend();
@ -872,6 +893,10 @@ Graph3d.prototype.redraw = function() {
Graph3d.prototype._getContext = function() { Graph3d.prototype._getContext = function() {
var canvas = this.frame.canvas; var canvas = this.frame.canvas;
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
return ctx; return ctx;
}; };
@ -1383,111 +1408,6 @@ Graph3d.prototype._hsv2rgb = function(H, S, V) {
}; };
Graph3d.prototype._drawGridLine = function(ctx, from, to) {
if (from === undefined || to === undefined) {
return;
}
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var zAvg = (from.point.z + to.point.z) / 2;
var h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240;
ctx.lineWidth = this._getStrokeWidth(from) * 2;
ctx.strokeStyle = this._hsv2rgb(h, 1, 1);
this._line(ctx, from.screen, to.screen);
};
/**
* Draw all datapoints as a grid
* This function can be used when the style is 'grid'
*/
Graph3d.prototype._redrawDataGrid = function() {
var ctx = this._getContext(),
point, right, top, cross,
i,
topSideVisible, fillStyle, strokeStyle, lineWidth,
h, s, v, zAvg;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
if (this.dataPoints === undefined || this.dataPoints.length <= 0)
return; // TODO: throw exception?
this._calcTranslations(this.dataPoints);
if (this.style === Graph3d.STYLE.SURFACE) {
for (i = 0; i < this.dataPoints.length; i++) {
point = this.dataPoints[i];
right = point.pointRight;
top = point.pointTop;
cross = point.pointCross;
if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) {
if (this.showGrayBottom || this.showShadow) {
// calculate the cross product of the two vectors from center
// to left and right, in order to know whether we are looking at the
// bottom or at the top side. We can also use the cross product
// for calculating light intensity
var aDiff = Point3d.subtract(cross.trans, point.trans);
var bDiff = Point3d.subtract(top.trans, right.trans);
var crossproduct = Point3d.crossProduct(aDiff, bDiff);
var len = crossproduct.length();
// FIXME: there is a bug with determining the surface side (shadow or colored)
topSideVisible = (crossproduct.z > 0);
}
else {
topSideVisible = true;
}
if (topSideVisible) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4;
h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240;
s = 1; // saturation
if (this.showShadow) {
v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale
fillStyle = this._hsv2rgb(h, s, v);
strokeStyle = fillStyle;
}
else {
v = 1;
fillStyle = this._hsv2rgb(h, s, v);
strokeStyle = this.axisColor; // TODO: should be customizable
}
}
else {
fillStyle = 'gray';
strokeStyle = this.axisColor;
}
ctx.lineWidth = this._getStrokeWidth(point);
ctx.fillStyle = fillStyle;
ctx.strokeStyle = strokeStyle;
ctx.beginPath();
ctx.moveTo(point.screen.x, point.screen.y);
ctx.lineTo(right.screen.x, right.screen.y);
ctx.lineTo(cross.screen.x, cross.screen.y);
ctx.lineTo(top.screen.x, top.screen.y);
ctx.closePath();
ctx.fill();
ctx.stroke(); // TODO: only draw stroke when strokeWidth > 0
}
}
}
else { // grid style
for (i = 0; i < this.dataPoints.length; i++) {
point = this.dataPoints[i];
this._drawGridLine(ctx, point, point.pointRight);
this._drawGridLine(ctx, point, point.pointTop);
}
}
};
Graph3d.prototype._getStrokeWidth = function(point) { Graph3d.prototype._getStrokeWidth = function(point) {
if (point !== undefined) { if (point !== undefined) {
if (this.showPerspective) { if (this.showPerspective) {
@ -1501,87 +1421,17 @@ Graph3d.prototype._getStrokeWidth = function(point) {
return this.dataColor.strokeWidth; return this.dataColor.strokeWidth;
}; };
/**
* Draw all datapoints as dots.
* This function can be used when the style is 'dot' or 'dot-line'
*/
Graph3d.prototype._redrawDataDot = function() {
var ctx = this._getContext();
var i;
if (this.dataPoints === undefined || this.dataPoints.length <= 0)
return; // TODO: throw exception?
this._calcTranslations(this.dataPoints);
// draw the datapoints as colored circles
var dotSize = this._dotSize();
for (i = 0; i < this.dataPoints.length; i++) {
var point = this.dataPoints[i];
if (this.style === Graph3d.STYLE.DOTLINE) {
// draw a vertical line from the bottom to the graph value
//var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin));
var from = this._convert3Dto2D(point.bottom);
ctx.lineWidth = 1;
this._line(ctx, from, point.screen, this.gridColor);
}
// calculate radius for the circle
var size;
if (this.style === Graph3d.STYLE.DOTSIZE) {
size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin);
}
else {
size = dotSize;
}
var radius;
if (this.showPerspective) {
radius = size / -point.trans.z;
}
else {
radius = size * -(this.eye.z / this.camera.getArmLength());
}
if (radius < 0) {
radius = 0;
}
var hue, color, borderColor;
if (this.style === Graph3d.STYLE.DOTCOLOR ) {
// calculate the color based on the value
hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240;
color = this._hsv2rgb(hue, 1, 1);
borderColor = this._hsv2rgb(hue, 1, 0.8);
}
else if (this.style === Graph3d.STYLE.DOTSIZE) {
color = this.dataColor.fill;
borderColor = this.dataColor.stroke;
}
else {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240;
color = this._hsv2rgb(hue, 1, 1);
borderColor = this._hsv2rgb(hue, 1, 0.8);
}
// draw the circle
ctx.lineWidth = this._getStrokeWidth(point);
ctx.strokeStyle = borderColor;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true);
ctx.fill();
ctx.stroke();
}
};
// -----------------------------------------------------------------------------
// Drawing primitives for the graphs
// -----------------------------------------------------------------------------
/** /**
* Draw a bar element in the view with the given properties. * Draw a bar element in the view with the given properties.
*/ */
Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borderColor) { Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borderColor) {
var i, j, surface, corners;
var i, j, surface;
// calculate all corner points // calculate all corner points
var me = this; var me = this;
@ -1647,225 +1497,353 @@ Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borde
// NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
for (j = 2; j < surfaces.length; j++) { for (j = 2; j < surfaces.length; j++) {
surface = surfaces[j]; surface = surfaces[j];
corners = surface.corners;
ctx.beginPath();
ctx.moveTo(corners[3].screen.x, corners[3].screen.y);
ctx.lineTo(corners[0].screen.x, corners[0].screen.y);
ctx.lineTo(corners[1].screen.x, corners[1].screen.y);
ctx.lineTo(corners[2].screen.x, corners[2].screen.y);
ctx.lineTo(corners[3].screen.x, corners[3].screen.y);
ctx.fill();
ctx.stroke();
this._polygon(ctx, surface.corners);
} }
}; };
/** /**
* Draw single datapoint for graph style 'Bar'.
* Draw a polygon using the passed points and fill it with the passed style and stroke.
*
* @param points an array of points.
* @param fillStyle optional; the fill style to set
* @param strokeStyle optional; the stroke style to set
*/ */
Graph3d.prototype._redrawBarGraphPoint = function(ctx, point) {
var i, j, surface, corners;
Graph3d.prototype._polygon = function(ctx, points, fillStyle, strokeStyle) {
if (points.length < 2) {
return;
}
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
if (fillStyle !== undefined) {
ctx.fillStyle = fillStyle;
}
if (strokeStyle !== undefined) {
ctx.strokeStyle = strokeStyle;
}
ctx.beginPath();
ctx.moveTo(points[0].screen.x, points[0].screen.y);
var xWidth = this.xBarWidth / 2;
var yWidth = this.yBarWidth / 2;
for (var i = 1; i < points.length; ++i) {
var point = points[i];
ctx.lineTo(point.screen.x, point.screen.y);
}
ctx.closePath();
ctx.fill();
ctx.stroke(); // TODO: only draw stroke when strokeWidth > 0
};
/**
* @param size optional; if not specified use value from 'this._dotSize()`
*/
Graph3d.prototype._drawCircle = function(ctx, point, color, borderColor, size) {
var radius = this._calcRadius(point, size);
ctx.lineWidth = this._getStrokeWidth(point);
ctx.strokeStyle = borderColor;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true);
ctx.fill();
ctx.stroke();
};
// determine color
var hue, color, borderColor;
/**
* Determine the colors for the 'regular' graph styles.
*/
Graph3d.prototype._getColorsRegular = function(point) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240;
color = this._hsv2rgb(hue, 1, 1);
borderColor = this._hsv2rgb(hue, 1, 0.8);
var hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240;
var color = this._hsv2rgb(hue, 1, 1);
var borderColor = this._hsv2rgb(hue, 1, 0.8);
this._redrawBar(ctx, point, xWidth, yWidth, color, borderColor);
return {
fill : color,
border: borderColor
};
}; };
/** /**
* Draw all datapoints for currently selected graph style.
*
* @param pointDrawMethod - method reference to draw a point in a specific graph style.
* Get the colors for the 'color' graph styles.
* These styles are currently: 'bar-color' and 'dot-color'
*/ */
Graph3d.prototype._redrawDataGraph = function(pointDrawMethod) {
var ctx = this._getContext();
var i;
Graph3d.prototype._getColorsColor = function(point) {
// calculate the color based on the value
var hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240;
var color = this._hsv2rgb(hue, 1, 1);
var borderColor = this._hsv2rgb(hue, 1, 0.8);
return {
fill : color,
border : borderColor
};
};
if (this.dataPoints === undefined || this.dataPoints.length <= 0)
return; // TODO: throw exception?
this._calcTranslations(this.dataPoints);
/**
* Get the colors for the 'size' graph styles.
* These styles are currently: 'bar-size' and 'dot-size'
*/
Graph3d.prototype._getColorsSize = function() {
return {
fill : this.dataColor.fill,
border : this.dataColor.stroke
};
};
for (i = 0; i < this.dataPoints.length; i++) {
var point = this.dataPoints[i];
// Using call() ensures that the correct context is used
pointDrawMethod.call(this, ctx, point);
/**
* Determine the size of a point on-screen, as determined by the
* distance to the camera.
*
* @param size the size that needs to be translated to screen coordinates.
* optional; if not passed, use the default point size.
*/
Graph3d.prototype._calcRadius = function(point, size) {
if (size === undefined) {
size = this._dotSize();
} }
var radius;
if (this.showPerspective) {
radius = size / -point.trans.z;
}
else {
radius = size * -(this.eye.z / this.camera.getArmLength());
}
if (radius < 0) {
radius = 0;
}
return radius;
}; };
// -----------------------------------------------------------------------------
// Methods for drawing points per graph style.
// -----------------------------------------------------------------------------
/** /**
* Draw all datapoints as bars.
* This function can be used when the style is 'bar', 'bar-color', or 'bar-size'
* Draw single datapoint for graph style 'bar'.
*/ */
Graph3d.prototype._redrawDataBar = function() {
var ctx = this._getContext();
var i, j, surface, corners;
if (this.dataPoints === undefined || this.dataPoints.length <= 0)
return; // TODO: throw exception?
Graph3d.prototype._redrawBarGraphPoint = function(ctx, point) {
var xWidth = this.xBarWidth / 2;
var yWidth = this.yBarWidth / 2;
var colors = this._getColorsRegular(point);
this._calcTranslations(this.dataPoints);
this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
};
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
// draw the datapoints as bars
/**
* Draw single datapoint for graph style 'bar-color'.
*/
Graph3d.prototype._redrawBarColorGraphPoint = function(ctx, point) {
var xWidth = this.xBarWidth / 2; var xWidth = this.xBarWidth / 2;
var yWidth = this.yBarWidth / 2; var yWidth = this.yBarWidth / 2;
for (i = 0; i < this.dataPoints.length; i++) {
var point = this.dataPoints[i];
var colors = this._getColorsColor(point);
// TODO: Remove code for style `Bar` here - it has been refactored to separate routine
this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
};
// determine color
var hue, color, borderColor;
if (this.style === Graph3d.STYLE.BARCOLOR ) {
// calculate the color based on the value
hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240;
color = this._hsv2rgb(hue, 1, 1);
borderColor = this._hsv2rgb(hue, 1, 0.8);
}
else if (this.style === Graph3d.STYLE.BARSIZE) {
color = this.dataColor.fill;
borderColor = this.dataColor.stroke;
/**
* Draw single datapoint for graph style 'bar-size'.
*/
Graph3d.prototype._redrawBarSizeGraphPoint = function(ctx, point) {
// calculate size for the bar
var fraction = (point.point.value - this.valueMin) / (this.valueMax - this.valueMin);
var xWidth = (this.xBarWidth / 2) * (fraction * 0.8 + 0.2);
var yWidth = (this.yBarWidth / 2) * (fraction * 0.8 + 0.2);
var colors = this._getColorsSize();
this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
};
/**
* Draw single datapoint for graph style 'dot'.
*/
Graph3d.prototype._redrawDotGraphPoint = function(ctx, point) {
var colors = this._getColorsRegular(point);
this._drawCircle(ctx, point, colors.fill, colors.border);
};
/**
* Draw single datapoint for graph style 'dot-line'.
*/
Graph3d.prototype._redrawDotLineGraphPoint = function(ctx, point) {
// draw a vertical line from the XY-plane to the graph value
var from = this._convert3Dto2D(point.bottom);
ctx.lineWidth = 1;
this._line(ctx, from, point.screen, this.gridColor);
this._redrawDotGraphPoint(ctx, point);
};
/**
* Draw single datapoint for graph style 'dot-color'.
*/
Graph3d.prototype._redrawDotColorGraphPoint = function(ctx, point) {
var colors = this._getColorsColor(point);
this._drawCircle(ctx, point, colors.fill, colors.border);
};
/**
* Draw single datapoint for graph style 'dot-size'.
*/
Graph3d.prototype._redrawDotSizeGraphPoint = function(ctx, point) {
var dotSize = this._dotSize();
var fraction = (point.point.value - this.valueMin) / (this.valueMax - this.valueMin);
var size = dotSize/2 + 2*dotSize * fraction;
var colors = this._getColorsSize();
this._drawCircle(ctx, point, colors.fill, colors.border, size);
};
/**
* Draw single datapoint for graph style 'surface'.
*/
Graph3d.prototype._redrawSurfaceGraphPoint = function(ctx, point) {
var right = point.pointRight;
var top = point.pointTop;
var cross = point.pointCross;
if (point === undefined || right === undefined || top === undefined || cross === undefined) {
return;
}
var topSideVisible = true;
var fillStyle;
var strokeStyle;
var lineWidth;
if (this.showGrayBottom || this.showShadow) {
// calculate the cross product of the two vectors from center
// to left and right, in order to know whether we are looking at the
// bottom or at the top side. We can also use the cross product
// for calculating light intensity
var aDiff = Point3d.subtract(cross.trans, point.trans);
var bDiff = Point3d.subtract(top.trans, right.trans);
var crossproduct = Point3d.crossProduct(aDiff, bDiff);
var len = crossproduct.length();
// FIXME: there is a bug with determining the surface side (shadow or colored)
topSideVisible = (crossproduct.z > 0);
}
if (topSideVisible) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4;
var h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240;
var s = 1; // saturation
var v;
if (this.showShadow) {
v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale
fillStyle = this._hsv2rgb(h, s, v);
strokeStyle = fillStyle;
} }
else {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240;
color = this._hsv2rgb(hue, 1, 1);
borderColor = this._hsv2rgb(hue, 1, 0.8);
else {
v = 1;
fillStyle = this._hsv2rgb(h, s, v);
strokeStyle = this.axisColor; // TODO: should be customizable
} }
}
else {
fillStyle = 'gray';
strokeStyle = this.axisColor;
}
// calculate size for the bar
if (this.style === Graph3d.STYLE.BARSIZE) {
xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2);
yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2);
}
ctx.lineWidth = this._getStrokeWidth(point);
// TODO: only draw stroke when strokeWidth > 0
// calculate all corner points
var me = this;
var point3d = point.point;
var top = [
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)},
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)},
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)},
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)}
];
var bottom = [
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)},
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)},
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)},
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)}
];
// calculate screen location of the points
top.forEach(function (obj) {
obj.screen = me._convert3Dto2D(obj.point);
});
bottom.forEach(function (obj) {
obj.screen = me._convert3Dto2D(obj.point);
});
// create five sides, calculate both corner points and center points
var surfaces = [
{corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)},
{corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)},
{corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)},
{corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)},
{corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)}
];
point.surfaces = surfaces;
// calculate the distance of each of the surface centers to the camera
for (j = 0; j < surfaces.length; j++) {
surface = surfaces[j];
var transCenter = this._convertPointToTranslation(surface.center);
surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z;
// TODO: this dept calculation doesn't work 100% of the cases due to perspective,
// but the current solution is fast/simple and works in 99.9% of all cases
// the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})
}
var points = [point, right, cross, top];
this._polygon(ctx, points, fillStyle, strokeStyle);
};
// order the surfaces by their (translated) depth
surfaces.sort(function (a, b) {
var diff = b.dist - a.dist;
if (diff) return diff;
// if equal depth, sort the top surface last
if (a.corners === top) return 1;
if (b.corners === top) return -1;
// both are equal
return 0;
});
// draw the ordered surfaces
ctx.lineWidth = this._getStrokeWidth(point);
ctx.strokeStyle = borderColor;
ctx.fillStyle = color;
// NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
for (j = 2; j < surfaces.length; j++) {
surface = surfaces[j];
corners = surface.corners;
ctx.beginPath();
ctx.moveTo(corners[3].screen.x, corners[3].screen.y);
ctx.lineTo(corners[0].screen.x, corners[0].screen.y);
ctx.lineTo(corners[1].screen.x, corners[1].screen.y);
ctx.lineTo(corners[2].screen.x, corners[2].screen.y);
ctx.lineTo(corners[3].screen.x, corners[3].screen.y);
ctx.fill();
ctx.stroke();
}
/**
* Helper method for _redrawGridGraphPoint()
*/
Graph3d.prototype._drawGridLine = function(ctx, from, to) {
if (from === undefined || to === undefined) {
return;
} }
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var zAvg = (from.point.z + to.point.z) / 2;
var h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240;
ctx.lineWidth = this._getStrokeWidth(from) * 2;
ctx.strokeStyle = this._hsv2rgb(h, 1, 1);
this._line(ctx, from.screen, to.screen);
}; };
/** /**
* Draw a line through all datapoints.
* This function can be used when the style is 'line'
* Draw single datapoint for graph style 'Grid'.
*/ */
Graph3d.prototype._redrawDataLine = function() {
var ctx = this._getContext(),
point, i;
Graph3d.prototype._redrawGridGraphPoint = function(ctx, point) {
this._drawGridLine(ctx, point, point.pointRight);
this._drawGridLine(ctx, point, point.pointTop);
};
/**
* Draw single datapoint for graph style 'line'.
*/
Graph3d.prototype._redrawLineGraphPoint = function(ctx, point) {
if (point.pointNext === undefined) {
return;
}
ctx.lineWidth = this._getStrokeWidth(point);
ctx.strokeStyle = this.dataColor.stroke;
this._line(ctx, point.screen, point.pointNext.screen);
};
/**
* Draw all datapoints for currently selected graph style.
*
*/
Graph3d.prototype._redrawDataGraph = function() {
var ctx = this._getContext();
var i;
if (this.dataPoints === undefined || this.dataPoints.length <= 0) if (this.dataPoints === undefined || this.dataPoints.length <= 0)
return; // TODO: throw exception? return; // TODO: throw exception?
this._calcTranslations(this.dataPoints); this._calcTranslations(this.dataPoints);
// start the line
if (this.dataPoints.length > 0) {
point = this.dataPoints[0];
ctx.lineWidth = this._getStrokeWidth(point);
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = this.dataColor.stroke;
for (i = 0; i < this.dataPoints.length; i++) {
point = this.dataPoints[i];
for (i = 0; i < this.dataPoints.length; i++) {
var point = this.dataPoints[i];
if (point.pointNext !== undefined) {
this._line(ctx, point.screen, point.pointNext.screen);
}
}
// Using call() ensures that the correct context is used
this._pointDrawingMethod.call(this, ctx, point);
} }
}; };
// -----------------------------------------------------------------------------
// End methods for drawing points per graph style.
// -----------------------------------------------------------------------------
/** /**
* Start a moving operation inside the provided parent element * Start a moving operation inside the provided parent element
* @param {Event} event The event that occurred (required for * @param {Event} event The event that occurred (required for

+ 5
- 6
lib/timeline/Timeline.js View File

@ -60,7 +60,6 @@ function Timeline (container, items, groups, options) {
minHeight: null minHeight: null
}; };
this.options = util.deepExtend({}, this.defaultOptions); this.options = util.deepExtend({}, this.defaultOptions);
this.options.rtl = options.rtl;
// Create the DOM, props, and emitter // Create the DOM, props, and emitter
this._create(container); this._create(container);
@ -105,6 +104,11 @@ function Timeline (container, items, groups, options) {
// current time bar // current time bar
this.currentTime = new CurrentTime(this.body); this.currentTime = new CurrentTime(this.body);
this.components.push(this.currentTime); this.components.push(this.currentTime);
// apply options
if (options) {
this.setOptions(options);
}
// item set // item set
this.itemSet = new ItemSet(this.body, this.options); this.itemSet = new ItemSet(this.body, this.options);
@ -145,11 +149,6 @@ function Timeline (container, items, groups, options) {
} }
}); });
// apply options
if (options) {
this.setOptions(options);
}
// IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS!
if (groups) { if (groups) {
this.setGroups(groups); this.setGroups(groups);

+ 6
- 4
misc/how_to_help.md View File

@ -6,13 +6,13 @@ The company that developed vis.js for the main part, *almende* is [not able to m
### Answering questions ### Answering questions
There are new [issues with questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion+sort%3Acreated-desc) how to use vis.js opened almost every day. Be part of the community and help answer them!
There are new [issues with questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3AQuestion+sort%3Acreated-desc) how to use vis.js opened almost every day. Be part of the community and help answer them!
A better way to ask questions on how to use vis.js is [stackoverflow](https://stackoverflow.com/tags/vis.js). Questions are posed here also and need to be answered by the community. [Please help answering questions](https://stackoverflow.com/tags/vis.js) here also. A better way to ask questions on how to use vis.js is [stackoverflow](https://stackoverflow.com/tags/vis.js). Questions are posed here also and need to be answered by the community. [Please help answering questions](https://stackoverflow.com/tags/vis.js) here also.
### Closing old issues ### Closing old issues
A new issue is often opened fast and then forgotten. Please help go trough [the old issues](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc) (especially the [questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc+label%3Aquestion)) and ask the creator of the issues if the problem still exists before closing the issue. The support team uses the **issue inactive** label to mark these issues.
A new issue is often opened fast and then forgotten. Please help go trough [the old issues](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc) (especially the [questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc+label%3AQuestion)) and ask the creator of the issues if the problem still exists before closing the issue. The support team uses the **issue inactive** label to mark these issues.
### Improve the webpage ### Improve the webpage
@ -28,14 +28,14 @@ If you use vis.js to develop something beautiful feel free to create a pull-requ
### Confirming and fixing bugs ### Confirming and fixing bugs
Every software has bugs. We also have [quite a nice collection](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) ;-)
Every software has bugs. We also have [quite a nice collection](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3ABug+sort%3Areactions-%2B1-desc) ;-)
Feel free to fix as many bugs as you want! Feel free to fix as many bugs as you want!
You can not only help by fixing bugs, but also by confirming the bug or even creating a minimal code example to prove this bug exists. You can not only help by fixing bugs, but also by confirming the bug or even creating a minimal code example to prove this bug exists.
### Implementing Feature-Requests ### Implementing Feature-Requests
A lot of people have a lot of ideas for improving vis.js. [We label these issues as **enhancement**](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement). Feel free to implement a new feature by creating a new Pull-Request.
A lot of people have a lot of ideas for improving vis.js. [We label these issues as **Feature-Request**](https://github.com/almende/vis/labels/Feature-Request). Feel free to implement a new feature by creating a new Pull-Request.
[Some issues are labeled **For everybody!**](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3A%22For+everyone%21%22+sort%3Areactions-%2B1-desc). These are a good starting point. [Some issues are labeled **For everybody!**](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3A%22For+everyone%21%22+sort%3Areactions-%2B1-desc). These are a good starting point.
@ -64,4 +64,6 @@ There are some rules for pull-request:
* Always adapt to the code style of the existing source. Never adapt existing code to your personal taste. :trollface: * Always adapt to the code style of the existing source. Never adapt existing code to your personal taste. :trollface:
* Pull-requests must be reviewed by at least two member of the support team. The First must approve the pull-request, the second can than merge after also checking it.
**Happy Helping!!** **Happy Helping!!**

Loading…
Cancel
Save