CallbackTestCase.prototype.tearDown = function() {
};
- var data = "X,a\,b,c\n" +
- "10,-1,1,2\n" +
- "11,0,3,1\n" +
- "12,1,4,2\n" +
- "13,0,2,3\n";
+var data = "X,a\,b,c\n" +
+ "10,-1,1,2\n" +
+ "11,0,3,1\n" +
+ "12,1,4,2\n" +
+ "13,0,2,3\n";
- /**
- * This tests that when the function idxToRow_ returns the proper row and the onHiglightCallback
- * is properly called when the first series is hidden (setVisibility = false)
- *
- */
- CallbackTestCase.prototype.testHighlightCallbackIsCalled = function() {
- var h_row;
- var h_pts;
-
- var highlightCallback = function(e, x, pts, row) {
- h_row = row;
- h_pts = pts;
- };
-
-
-
- var graph = document.getElementById("graph");
- var g = new Dygraph(graph, data,
- {
- width: 100,
- height : 100,
- visibility: [false, true, true],
- highlightCallback : highlightCallback,
- });
-
- DygraphOps.dispatchMouseMove(g, 13, 10);
-
- //check correct row is returned
- assertEquals(3, h_row);
- //check there are only two points (because first series is hidden)
- assertEquals(2, h_pts.length);
- };
+/**
+ * This tests that when the function idxToRow_ returns the proper row and the onHiglightCallback
+ * is properly called when the first series is hidden (setVisibility = false)
+ *
+ */
+CallbackTestCase.prototype.testHighlightCallbackIsCalled = function() {
+ var h_row;
+ var h_pts;
+
+ var highlightCallback = function(e, x, pts, row) {
+ h_row = row;
+ h_pts = pts;
+ };
+
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data,
+ {
+ width: 100,
+ height : 100,
+ visibility: [false, true, true],
+ highlightCallback : highlightCallback,
+ });
+
+ DygraphOps.dispatchMouseMove(g, 13, 10);
+
+ //check correct row is returned
+ assertEquals(3, h_row);
+ //check there are only two points (because first series is hidden)
+ assertEquals(2, h_pts.length);
+};
+
+
+/**
+ * Test that drawPointCallback isn't called when drawPoints is false
+ */
+CallbackTestCase.prototype.testDrawPointCallback_disabled = function() {
+ var called = false;
+
+ var callback = function() {
+ called = true;
+ };
+
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, {
+ drawPointCallback : callback,
+ });
+
+ assertFalse(called);
+};
+
+/**
+ * Test that drawPointCallback is called when drawPoints is true
+ */
+CallbackTestCase.prototype.testDrawPointCallback_enabled = function() {
+ var called = false;
+
+ var callback = function() {
+ called = true;
+ };
+
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, {
+ drawPoints : true,
+ drawPointCallback : callback
+ });
+
+ assertTrue(called);
+};
+
+/**
+ * Test that drawPointCallback is called when drawPoints is true
+ */
+CallbackTestCase.prototype.testDrawPointCallback_pointSize = function() {
+ var pointSize = 0;
+ var count = 0;
+
+ var callback = function(g, seriesName, canvasContext, cx, cy, color, pointSizeParam) {
+ pointSize = pointSizeParam;
+ count++;
+ };
+
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, {
+ drawPoints : true,
+ drawPointCallback : callback
+ });
+
+ assertEquals(1.5, pointSize);
+ assertEquals(12, count); // one call per data point.
+
+ var g = new Dygraph(graph, data, {
+ drawPoints : true,
+ drawPointCallback : callback,
+ pointSize : 8
+ });
+
+ assertEquals(8, pointSize);
+};
+
+/**
+ * This tests that when the function idxToRow_ returns the proper row and the onHiglightCallback
+ * is properly called when the first series is hidden (setVisibility = false)
+ *
+ */
+CallbackTestCase.prototype.testDrawHighlightPointCallbackIsCalled = function() {
+ var called = false;
+
+ var drawHighlightPointCallback = function() {
+ called = true;
+ };
+
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data,
+ {
+ width: 100,
+ height : 100,
+ drawHighlightPointCallback : drawHighlightPointCallback
+ });
+
+ assertFalse(called);
+ DygraphOps.dispatchMouseMove(g, 13, 10);
+ assertTrue(called);
+};
var strokeWidth = this.dygraph_.attr_("strokeWidth", setName);
// setup graphics context
+ // TODO(konigsberg): This function has ctx and context. Clarify the difference.
context.save();
var pointSize = this.dygraph_.attr_("pointSize", setName);
prevX = null;
prevY = null;
var drawPoints = this.dygraph_.attr_("drawPoints", setName);
+ var drawPointCallback = this.dygraph_.attr_("drawPointCallback", setName);
+ if (!drawPointCallback) {
+ drawPointCallback = Dygraph.Circles.DEFAULT;
+ }
+ var pointsOnLine = []; // Array of [canvasx, canvasy] pairs.
var strokePattern = this.dygraph_.attr_("strokePattern", setName);
if (!Dygraph.isArrayLike(strokePattern)) {
strokePattern = null;
}
if (drawPoints || isIsolated) {
- ctx.beginPath();
- ctx.fillStyle = color;
- ctx.arc(point.canvasx, point.canvasy, pointSize,
- 0, 2 * Math.PI, false);
- ctx.fill();
+ pointsOnLine.push([point.canvasx, point.canvasy]);
}
}
}
+ for (var idx = 0; idx < pointsOnLine.length; idx++) {
+ var cb = pointsOnLine[idx];
+ ctx.save();
+ drawPointCallback(
+ this.dygraph_, setName, ctx, cb[0], cb[1], color, pointSize);
+ ctx.restore();
+
+ }
+ firstIndexInSet = afterLastIndexInSet;
}
context.restore();
"default": "false",
"labels": ["Data Line display"],
"type": "boolean",
- "description": "Draw a small dot at each point, in addition to a line going through the point. This makes the individual data points easier to see, but can increase visual clutter in the chart."
+ "description": "Draw a small dot at each point, in addition to a line going through the point. This makes the individual data points easier to see, but can increase visual clutter in the chart. The small dot can be replaced with a custom rendering by supplying a drawPointCallback."
+ },
+ "drawPointCallback": {
+ "default": "null",
+ "labels": ["Data Line display"],
+ "type": "function(g, seriesName, canvasContext, cx, cy, color, pointSize)",
+ "description": "Draw a custom item when drawPoints is enabled. Default is a small dot matching the series color."
},
"height": {
"default": "320",
["row", "???"]
]
},
+ "drawHighlightPointCallback": {
+ "default": "null",
+ "labels": ["Data Line display"],
+ "type": "function(g, seriesName, canvasContext, cx, cy, color, pointSize)",
+ "description": "Draw a custom item when a point is highlighted. Default is a small dot matching the series color."
+ },
"includeZero": {
"default": "false",
"labels": ["Axis display"],
'clickCallback': true,
'digitsAfterDecimal': true,
'drawCallback': true,
+ 'drawHighlightPointCallback': true,
'drawPoints': true,
+ 'drawPointCallback': true,
'drawXGrid': true,
'drawYGrid': true,
'fillAlpha': true,
}
return true;
};
+
+/**
+ * ctx: the canvas context
+ * sides: the number of sides in the shape.
+ * radius: the radius of the image.
+ * cx: center x coordate
+ * cy: center y coordinate
+ * rotationRadians: the shift of the initial angle, in radians.
+ * delta: the angle shift for each line. If missing, creates a regular
+ * polygon.
+ */
+Dygraph.regularShape_ = function(
+ ctx, sides, radius, cx, cy, rotationRadians, delta) {
+ rotationRadians = rotationRadians ? rotationRadians : 0;
+ delta = delta ? delta : Math.PI * 2 / sides;
+
+ ctx.beginPath();
+ var first = true;
+ var initialAngle = rotationRadians;
+ var angle = initialAngle;
+
+ var computeCoordinates = function() {
+ var x = cx + (Math.sin(angle) * radius);
+ var y = cy + (-Math.cos(angle) * radius);
+ return [x, y];
+ };
+
+ var initialCoordinates = computeCoordinates();
+ var x = initialCoordinates[0];
+ var y = initialCoordinates[1];
+ ctx.moveTo(x, y);
+
+ for (var idx = 0; idx < sides; idx++) {
+ angle = (idx == sides - 1) ? initialAngle : (angle + delta);
+ var coords = computeCoordinates();
+ ctx.lineTo(coords[0], coords[1]);
+ }
+ ctx.stroke();
+ ctx.closePath();
+}
+
+Dygraph.shapeFunction_ = function(sides, rotationRadians, delta) {
+ return function(g, name, ctx, cx, cy, color, radius) {
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = color;
+ Dygraph.regularShape_(ctx, sides, radius, cx, cy, rotationRadians, delta);
+ };
+};
+
+Dygraph.DrawPolygon_ = function(sides, rotationRadians, ctx, cx, cy, color, radius, delta) {
+ new Dygraph.RegularShape_(sides, rotationRadians, delta).draw(ctx, cx, cy, radius);
+}
+
+Dygraph.Circles = {
+ DEFAULT : function(g, name, ctx, canvasx, canvasy, color, radius) {
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.arc(canvasx, canvasy, radius, 0, 2 * Math.PI, false);
+ ctx.fill();
+ },
+ TRIANGLE : Dygraph.shapeFunction_(3),
+ SQUARE : Dygraph.shapeFunction_(4, Math.PI / 4),
+ DIAMOND : Dygraph.shapeFunction_(4),
+ PENTAGON : Dygraph.shapeFunction_(5),
+ HEXAGON : Dygraph.shapeFunction_(6),
+ CIRCLE : function(g, name, ctx, cx, cy, color, radius) {
+ ctx.beginPath();
+ ctx.strokeStyle = color;
+ ctx.arc(cx, cy, radius, 0, 2 * Math.PI, false);
+ ctx.stroke();
+ },
+ STAR : Dygraph.shapeFunction_(5, 0, 4 * Math.PI / 5),
+ PLUS : function(g, name, ctx, cx, cy, color, radius) {
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = color;
+
+ ctx.beginPath();
+ ctx.moveTo(cx + radius, cy);
+ ctx.lineTo(cx - radius, cy);
+ ctx.closePath();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(cx, cy + radius);
+ ctx.lineTo(cx, cy - radius);
+ ctx.closePath();
+
+ ctx.stroke();
+ },
+ EX : function(g, name, ctx, cx, cy, color, radius) {
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "black";
+
+ ctx.beginPath();
+ ctx.moveTo(cx + radius, cy + radius);
+ ctx.lineTo(cx - radius, cy - radius);
+ ctx.closePath();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(cx + radius, cy - radius);
+ ctx.lineTo(cx - radius, cy + radius);
+ ctx.closePath();
+
+ ctx.stroke();
+ }
+};
if (!Dygraph.isOK(pt.canvasy)) continue;
var circleSize = this.attr_('highlightCircleSize', pt.name);
- ctx.beginPath();
- ctx.fillStyle = this.plotter_.colors[pt.name];
- ctx.arc(canvasx, pt.canvasy, circleSize, 0, 2 * Math.PI, false);
- ctx.fill();
+ var callback = this.attr_("drawHighlightPointCallback", pt.name);
+ if (!callback) {
+ callback = Dygraph.Circles.DEFAULT;
+ }
+ callback(this.g, pt.name, ctx, canvasx, pt.canvasy,
+ this.plotter_.colors[pt.name], circleSize);
}
ctx.restore();
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9">
+ <title>Custom Circles</title>
+ <!--[if IE]>
+ <script type="text/javascript" src="../excanvas.js"></script>
+ <![endif]-->
+ <!--
+ For production (minified) code, use:
+ <script type="text/javascript" src="dygraph-combined.js"></script>
+ -->
+ <script type="text/javascript" src="../dygraph-dev.js"></script>
+
+ </head>
+ <body>
+ <h2>Custom circles and hover circles</h2>
+ <div id="demodiv"></div>
+
+ <script type="text/javascript">
+ var smile = function(g, series, ctx, cx, cy, color, radius) {
+ mouthlessFace(g, series, ctx, cx, cy, color, radius);
+
+ ctx.fillStyle = "#000000";
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius - 2, .3, Math.PI - .3, false);
+ ctx.stroke();
+ };
+
+ var frown = function(g, series, ctx, cx, cy, color, radius) {
+ mouthlessFace(g, series, ctx, cx, cy, color, radius);
+
+ ctx.fillStyle = "#000000";
+ ctx.beginPath();
+ ctx.arc(cx, cy + radius, radius - 2, Math.PI + .3, -.3, false);
+ ctx.stroke();
+ };
+
+ var mouthlessFace = function(g, series, ctx, cx, cy, color, radius) {
+ ctx.strokeStyle = "#000000";
+ ctx.fillStyle = "#FFFF00";
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius, Math.PI * 2, false);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.fillStyle = "#000000";
+ ctx.beginPath();
+ ctx.arc(cx - (radius / 3) , cy - (radius / 4), 1, Math.PI * 2, false);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(cx + (radius / 3) , cy - (radius / 4), 1, Math.PI * 2, false);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.fill();
+ };
+
+ g = new Dygraph(
+ document.getElementById("demodiv"),
+ function() {
+
+ var r = "xval,default,triangle,square,diamond,pentagon,hexagon,circle,star,plus,ex,custom\n";
+ for (var i=1; i<=20; i++) {
+ r += i;
+ for (var j = 0; j < 11; j++) {
+ r += "," + j + (i / 3);
+ }
+ r += "\n";
+ }
+ return r;
+ },
+ {
+ drawPoints : true,
+ pointSize : 5,
+ highlightCircleSize : 8,
+ 'default' : {
+ drawPointCallback : Dygraph.Circles.DEFAULT,
+ drawHighlightPointCallback : Dygraph.Circles.DEFAULT
+ },
+ 'triangle' : {
+ drawPointCallback : Dygraph.Circles.TRIANGLE,
+ drawHighlightPointCallback : Dygraph.Circles.TRIANGLE
+ },
+ 'square' : {
+ drawPointCallback : Dygraph.Circles.SQUARE,
+ drawHighlightPointCallback : Dygraph.Circles.SQUARE
+ },
+ 'diamond' : {
+ drawPointCallback : Dygraph.Circles.DIAMOND,
+ drawHighlightPointCallback : Dygraph.Circles.DIAMOND
+ },
+ 'pentagon' : {
+ drawPointCallback : Dygraph.Circles.PENTAGON,
+ drawHighlightPointCallback : Dygraph.Circles.PENTAGON
+ },
+ 'hexagon' : {
+ drawPointCallback : Dygraph.Circles.HEXAGON,
+ drawHighlightPointCallback : Dygraph.Circles.HEXAGON
+ },
+ 'circle' : {
+ drawPointCallback : Dygraph.Circles.CIRCLE,
+ drawHighlightPointCallback : Dygraph.Circles.CIRCLE
+ },
+ 'star' : {
+ drawPointCallback : Dygraph.Circles.STAR,
+ drawHighlightPointCallback : Dygraph.Circles.STAR
+ },
+ 'plus' : {
+ drawPointCallback : Dygraph.Circles.PLUS,
+ drawHighlightPointCallback : Dygraph.Circles.PLUS
+ },
+ 'ex' : {
+ drawPointCallback : Dygraph.Circles.EX,
+ drawHighlightPointCallback : Dygraph.Circles.EX
+ },
+ 'custom' : {
+ drawPointCallback : frown,
+ drawHighlightPointCallback : smile
+ }
+ }
+ );
+ </script>
+</body>
+</html>