PageSourceSearch

https://zan.kz/lib/flot/jquery.flot.spline.js

js zan.kz collected 2026-10-02 02:28:37 UTC 6,464 bytes, 212 lines download raw bytes

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.