1/** 2 * Flot plugin that provides spline interpolation for line graphs 3 * author: Alex Bardas < [email protected] > 4 * modified by: Avi Kohn https://github.com/AMKohn 5 * based on the spline interpolation described at: 6 * http://scaledinnovation.com/analytics/splines/aboutSplines.html 7 * 8 * Example usage: (add in plot options series object) 9 * for linespline: 10 * series: { 11 * ... 12 * lines: { 13 * show: false 14 * }, 15 * splines: { 16 * show: true, 17 * tension: x, (float between 0 and 1, defaults to 0.5), 18 * lineWidth: y (number, defaults to 2), 19 * fill: z (float between 0 .. 1 or false, as in flot documentation) 20 * }, 21 * ... 22 * } 23 * areaspline: 24 * series: { 25 * ... 26 * lines: { 27 * show: true, 28 * lineWidth: 0, (line drawing will not execute) 29 * fill: x, (float between 0 .. 1, as in flot documentation) 30 * ... 31 * }, 32 * splines: { 33 * show: true, 34 * tension: 0.5 (float between 0 and 1) 35 * }, 36 * ... 37 * } 38 * 39 */ 40 41(function($) { 42 'use strict' 43 44 /** 45 * @param {Number} x0, y0, x1, y1: coordinates of the end (knot) points of the segment 46 * @param {Number} x2, y2: the next knot (not connected, but needed to calculate p2) 47 * @param {Number} tension: control how far the control points spread 48 * @return {Array}: p1 -> control point, from x1 back toward x0 49 * p2 -> the next control point, returned to become the next segment's p1 50 * 51 * @api private 52 */ 53 function getControlPoints(x0, y0, x1, y1, x2, y2, tension) { 54 55 var pow = Math.pow, 56 sqrt = Math.sqrt, 57 d01, d12, fa, fb, p1x, p1y, p2x, p2y; 58 59 // Scaling factors: distances from this knot to the previous and following knots. 60 d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2)); 61 d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); 62 63 fa = tension * d01 / (d01 + d12); 64 fb = tension - fa; 65 66 p1x = x1 + fa * (x0 - x2); 67 p1y = y1 + fa * (y0 - y2); 68 69 p2x = x1 - fb * (x0 - x2); 70 p2y = y1 - fb * (y0 - y2); 71 72 return [p1x, p1y, p2x, p2y]; 73 } 74 75 var line = []; 76 77 function drawLine(points, ctx, height, fill, seriesColor) { 78 var c = $.color.parse(seriesColor); 79 80 c.a = typeof fill == "number" ? fill : .3; 81 c.normalize(); 82 c = c.toString(); 83 84 ctx.beginPath(); 85 ctx.moveTo(points[0][0], points[0][1]); 86 87 var plength = points.length; 88 89 for (var i = 0; i < plength; i++) { 90 ctx[points[i][3]].apply(ctx, points[i][2]); 91 } 92 93 ctx.stroke(); 94 95 ctx.lineWidth = 0; 96 ctx.lineTo(points[plength - 1][0], height); 97 ctx.lineTo(points[0][0], height); 98 99 ctx.closePath(); 100 101 if (fill !== false) { 102 ctx.fillStyle = c; 103 ctx.fill(); 104 } 105 } 106 107 /** 108 * @param {Object} ctx: canvas context 109 * @param {String} type: accepted strings: 'bezier' or 'quadratic' (defaults to quadratic) 110 * @param {Array} points: 2 points for which to draw the interpolation 111 * @param {Array} cpoints: control points for those segment points 112 * 113 * @api private 114 */ 115 function queue(ctx, type, points, cpoints) { 116 if (type === void 0 || (type !== 'bezier' && type !== 'quadratic')) { 117 type = 'quadratic'; 118 } 119 type = type + 'CurveTo'; 120 121 if (line.length == 0) line.push([points[0], points[1], cpoints.concat(points.slice(2)), type]); 122 else if (type == "quadraticCurveTo" && points.length == 2) { 123 cpoints = cpoints.slice(0, 2).concat(points); 124 125 line.push([points[0], points[1], cpoints, type]); 126 } 127 else line.push([points[2], points[3], cpoints.concat(points.slice(2)), type]); 128 } 129 130 /** 131 * @param {Object} plot 132 * @param {Object} ctx: canvas context 133 * @param {Object} series 134 * 135 * @api private 136 */ 137 138 function drawSpline(plot, ctx, series) { 139 // Not interested if spline is not requested 140 if (series.splines.show !== true) { 141 return; 142 } 143 144 var cp = [], 145 // array of control points 146 tension = series.splines.tension || 0.5, 147 idx, x, y, points = series.datapoints.points, 148 ps = series.datapoints.pointsize, 149 plotOffset = plot.getPlotOffset(), 150 len = points.length, 151 pts = []; 152 153 line = []; 154 155 // Cannot display a linespline/areaspline if there are less than 3 points 156 if (len / ps < 4) { 157 $.extend(series.lines, series.splines); 158 return; 159 } 160 161 for (idx = 0; idx < len; idx += ps) { 162 x = points[idx]; 163 y = points[idx + 1];
164 if (x == null || x < series.xaxis.min || x > series.xaxis.max || y < series.yaxis.min || y > series.yaxis.max) { 165 continue; 166 } 167 168 pts.push(series.xaxis.p2c(x) + plotOffset.left, series.yaxis.p2c(y) + plotOffset.top); 169 } 170 171 len = pts.length; 172 173 // Draw an open curve, not connected at the ends 174 for (idx = 0; idx < len - 2; idx += 2) { 175 cp = cp.concat(getControlPoints.apply(this, pts.slice(idx, idx + 6).concat([tension]))); 176 } 177 178 ctx.save(); 179 ctx.strokeStyle = series.color; 180 ctx.lineWidth = series.splines.lineWidth; 181 182 queue(ctx, 'quadratic', pts.slice(0, 4), cp.slice(0, 2)); 183 184 for (idx = 2; idx < len - 3; idx += 2) { 185 queue(ctx, 'bezier', pts.slice(idx, idx + 4), cp.slice(2 * idx - 2, 2 * idx + 2)); 186 } 187 188 queue(ctx, 'quadratic', pts.slice(len - 2, len), [cp[2 * len - 10], cp[2 * len - 9], pts[len - 4], pts[len - 3]]); 189 190 drawLine(line, ctx, plot.height() + 10, series.splines.fill, series.color); 191 192 ctx.restore(); 193 } 194 195 $.plot.plugins.push({ 196 init: function(plot) { 197 plot.hooks.drawSeries.push(drawSpline); 198 }, 199 options: { 200 series: { 201 splines: { 202 show: false, 203 lineWidth: 2, 204 tension: 0.5, 205 fill: false 206 } 207 } 208 }, 209 name: 'spline', 210 version: '0.8.2' 211 }); 212})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.