123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- /*
- * jQuery.flot.dashes
- *
- * options = {
- * series: {
- * dashes: {
- *
- * // show
- * // default: false
- * // Whether to show dashes for the series.
- * show: <boolean>,
- *
- * // lineWidth
- * // default: 2
- * // The width of the dashed line in pixels.
- * lineWidth: <number>,
- *
- * // dashLength
- * // default: 10
- * // Controls the length of the individual dashes and the amount of
- * // space between them.
- * // If this is a number, the dashes and spaces will have that length.
- * // If this is an array, it is read as [ dashLength, spaceLength ]
- * dashLength: <number> or <array[2]>
- * }
- * }
- * }
- */
- (function($){
- function init(plot) {
- plot.hooks.processDatapoints.push(function(plot, series, datapoints) {
- if (!series.dashes.show) return;
- plot.hooks.draw.push(function(plot, ctx) {
- var plotOffset = plot.getPlotOffset(),
- axisx = series.xaxis,
- axisy = series.yaxis;
- function plotDashes(xoffset, yoffset) {
- var points = datapoints.points,
- ps = datapoints.pointsize,
- prevx = null,
- prevy = null,
- dashRemainder = 0,
- dashOn = true,
- dashOnLength,
- dashOffLength;
- if (series.dashes.dashLength[0]) {
- dashOnLength = series.dashes.dashLength[0];
- if (series.dashes.dashLength[1]) {
- dashOffLength = series.dashes.dashLength[1];
- } else {
- dashOffLength = dashOnLength;
- }
- } else {
- dashOffLength = dashOnLength = series.dashes.dashLength;
- }
- ctx.beginPath();
- for (var i = ps; i < points.length; i += ps) {
- var x1 = points[i - ps],
- y1 = points[i - ps + 1],
- x2 = points[i],
- y2 = points[i + 1];
- if (x1 == null || x2 == null) continue;
- // clip with ymin
- if (y1 <= y2 && y1 < axisy.min) {
- if (y2 < axisy.min) continue; // line segment is outside
- // compute new intersection point
- x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = axisy.min;
- } else if (y2 <= y1 && y2 < axisy.min) {
- if (y1 < axisy.min) continue;
- x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = axisy.min;
- }
- // clip with ymax
- if (y1 >= y2 && y1 > axisy.max) {
- if (y2 > axisy.max) continue;
- x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y1 = axisy.max;
- } else if (y2 >= y1 && y2 > axisy.max) {
- if (y1 > axisy.max) continue;
- x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
- y2 = axisy.max;
- }
- // clip with xmin
- if (x1 <= x2 && x1 < axisx.min) {
- if (x2 < axisx.min) continue;
- y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = axisx.min;
- } else if (x2 <= x1 && x2 < axisx.min) {
- if (x1 < axisx.min) continue;
- y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = axisx.min;
- }
- // clip with xmax
- if (x1 >= x2 && x1 > axisx.max) {
- if (x2 > axisx.max) continue;
- y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x1 = axisx.max;
- } else if (x2 >= x1 && x2 > axisx.max) {
- if (x1 > axisx.max) continue;
- y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
- x2 = axisx.max;
- }
- if (x1 != prevx || y1 != prevy) {
- ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
- }
- var ax1 = axisx.p2c(x1) + xoffset,
- ay1 = axisy.p2c(y1) + yoffset,
- ax2 = axisx.p2c(x2) + xoffset,
- ay2 = axisy.p2c(y2) + yoffset,
- dashOffset;
- function lineSegmentOffset(segmentLength) {
- var c = Math.sqrt(Math.pow(ax2 - ax1, 2) + Math.pow(ay2 - ay1, 2));
- if (c <= segmentLength) {
- return {
- deltaX: ax2 - ax1,
- deltaY: ay2 - ay1,
- distance: c,
- remainder: segmentLength - c
- }
- } else {
- var xsign = ax2 > ax1 ? 1 : -1,
- ysign = ay2 > ay1 ? 1 : -1;
- return {
- deltaX: xsign * Math.sqrt(Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))),
- deltaY: ysign * Math.sqrt(Math.pow(segmentLength, 2) - Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))),
- distance: segmentLength,
- remainder: 0
- };
- }
- }
- //-end lineSegmentOffset
- do {
- dashOffset = lineSegmentOffset(
- dashRemainder > 0 ? dashRemainder :
- dashOn ? dashOnLength : dashOffLength);
- if (dashOffset.deltaX != 0 || dashOffset.deltaY != 0) {
- if (dashOn) {
- ctx.lineTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY);
- } else {
- ctx.moveTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY);
- }
- }
- dashOn = !dashOn;
- dashRemainder = dashOffset.remainder;
- ax1 += dashOffset.deltaX;
- ay1 += dashOffset.deltaY;
- } while (dashOffset.distance > 0);
- prevx = x2;
- prevy = y2;
- }
- ctx.stroke();
- }
- //-end plotDashes
- ctx.save();
- ctx.translate(plotOffset.left, plotOffset.top);
- ctx.lineJoin = 'round';
- var lw = series.dashes.lineWidth,
- sw = series.shadowSize;
- // FIXME: consider another form of shadow when filling is turned on
- if (lw > 0 && sw > 0) {
- // draw shadow as a thick and thin line with transparency
- ctx.lineWidth = sw;
- ctx.strokeStyle = "rgba(0,0,0,0.1)";
- // position shadow at angle from the mid of line
- var angle = Math.PI/18;
- plotDashes(Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2));
- ctx.lineWidth = sw/2;
- plotDashes(Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4));
- }
- ctx.lineWidth = lw;
- ctx.strokeStyle = series.color;
- if (lw > 0) {
- plotDashes(0, 0);
- }
- ctx.restore();
- });
- //-end draw hook
- });
- //-end processDatapoints hook
- }
- //-end init
- $.plot.plugins.push({
- init: init,
- options: {
- series: {
- dashes: {
- show: false,
- lineWidth: 2,
- dashLength: 10
- }
- }
- },
- name: 'dashes',
- version: '0.1'
- });
- })(jQuery)
|