You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.0 KiB
236 lines
7.0 KiB
/* |
|
* 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)
|
|
|