PageSourceSearch

https://app.niuhealth.com/plugins/flot-chart/jquery.flot.drawSeries.js

js niuhealth.com collected 2026-10-01 23:57:11 UTC 24,360 bytes, 663 lines download raw bytes

1/**
2## jquery.flot.drawSeries.js
3
4This plugin is used by flot for drawing lines, plots, bars or area.
5
6### Public methods
7*/
8
9(function($) {
10    "use strict";
11
12    function DrawSeries() {
13        function plotLine(datapoints, xoffset, yoffset, axisx, axisy, ctx, steps) {
14            var points = datapoints.points,
15                ps = datapoints.pointsize,
16                prevx = null,
17                prevy = null;
18            var x1 = 0.0,
19                y1 = 0.0,
20                x2 = 0.0,
21                y2 = 0.0,
22                mx = null,
23                my = null,
24                i = 0;
25
26            ctx.beginPath();
27            for (i = ps; i < points.length; i += ps) {
28                x1 = points[i - ps];
29                y1 = points[i - ps + 1];
30                x2 = points[i];
31                y2 = points[i + 1];
32
33                if (x1 === null || x2 === null) {
34                    mx = null;
35                    my = null;
36                    continue;
37                }
38
39                if (isNaN(x1) || isNaN(x2) || isNaN(y1) || isNaN(y2)) {
40                    prevx = null;
41                    prevy = null;
42                    continue;
43                }
44
45                if(steps){
46                    if (mx !== null && my !== null) {
47                        // if middle point exists, transfer p2 -> p1 and p1 -> mp
48                        x2 = x1;
49                        y2 = y1;
50                        x1 = mx;
51                        y1 = my;
52
53                        // 'remove' middle point
54                        mx = null;
55                        my = null;
56
57                        // subtract pointsize from i to have current point p1 handled again
58                        i -= ps;
59                    } else if (y1 !== y2 && x1 !== x2) {
60                        // create a middle point
61                        y2 = y1;
62                        mx = x2;
63                        my = y1;
64                    }
65                }
66
67                // clip with ymin
68                if (y1 <= y2 && y1 < axisy.min) {
69                    if (y2 < axisy.min) {
70                        // line segment is outside
71                        continue;
72                    }
73                    // compute new intersection point
74                    x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
75                    y1 = axisy.min;
76                } else if (y2 <= y1 && y2 < axisy.min) {
77                    if (y1 < axisy.min) {
78                        continue;
79                    }
80
81                    x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
82                    y2 = axisy.min;
83                }
84
85                // clip with ymax
86                if (y1 >= y2 && y1 > axisy.max) {
87                    if (y2 > axisy.max) {
88                        continue;
89                    }
90
91                    x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
92                    y1 = axisy.max;
93                } else if (y2 >= y1 && y2 > axisy.max) {
94                    if (y1 > axisy.max) {
95                        continue;
96                    }
97
98                    x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
99                    y2 = axisy.max;
100                }
101
102                // clip with xmin
103                if (x1 <= x2 && x1 < axisx.min) {
104                    if (x2 < axisx.min) {
105                        continue;
106                    }
107
108                    y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
109                    x1 = axisx.min;
110                } else if (x2 <= x1 && x2 < axisx.min) {
111                    if (x1 < axisx.min) {
112                        continue;
113                    }
114
115                    y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
116                    x2 = axisx.min;
117                }
118
119                // clip with xmax
120                if (x1 >= x2 && x1 > axisx.max) {
121                    if (x2 > axisx.max) {
122                        continue;
123                    }
124
125                    y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
126                    x1 = axisx.max;
127                } else if (x2 >= x1 && x2 > axisx.max) {
128                    if (x1 > axisx.max) {
129                        continue;
130                    }
131
132                    y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
133                    x2 = axisx.max;
134                }
135
136                if (x1 !== prevx || y1 !== prevy) {
137                    ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
138                }
139
140                prevx = x2;
141                prevy = y2;
142                ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
143            }
144            ctx.stroke();
145        }
146
147        function plotLineArea(datapoints, axisx, axisy, fillTowards, ctx, steps) {
148            var points = datapoints.points,
149                ps = datapoints.pointsize,
150                bottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min,
151                i = 0,
152                ypos = 1,
153                areaOpen = false,
154                segmentStart = 0,
155                segmentEnd = 0,
156                mx = null,
157                my = null;
158
159            // we process each segment in two turns, first forward
160            // direction to sketch out top, then once we hit the
161            // end we go backwards to sketch the bottom
162            while (true) {
163                if (ps > 0 && i > points.length + ps) {
164                    break;
165                }
166
167                i += ps; // ps is negative if going backwards
168
169                var x1 = points[i - ps],
170                    y1 = points[i - ps + ypos],
171                    x2 = points[i],
172                    y2 = points[i + ypos];
173
174                if (ps === -2) {
175                    /* going backwards and no value for the bottom provided in the series*/
176                    y1 = y2 = bottom;
177                }
178
179                if (areaOpen) {
180                    if (ps > 0 && x1 != null && x2 == null) {
181                        // at turning point
182                        segmentEnd = i;
183                        ps = -ps;
184                        ypos = 2;
185                        continue;
186                    }
187
188                    if (ps < 0 && i === segmentStart + ps) {
189                        // done with the reverse sweep
190                        ctx.fill();
191                        areaOpen = false;
192                        ps = -ps;
193                        ypos = 1;
194                        i = segmentStart = segmentEnd + ps;
195                        continue;
196                    }
197                }
198
199                if (x1 == null || x2 == null) {
200                    mx = null;
201                    my = null;
202                    continue;
203                }
204
205                if(steps){
206                    if (mx !== null && my !== null) {
207                        // if middle point exists, transfer p2 -> p1 and p1 -> mp
208                        x2 = x1;
209                        y2 = y1;
210                        x1 = mx;
211                        y1 = my;
212
213                        // 'remove' middle point
214                        mx = null;
215                        my = null;
216
217                        // subtract pointsize from i to have current point p1 handled again
218                        i -= ps;
219                    } else if (y1 !== y2 && x1 !== x2) {
220                        // create a middle point
221                        y2 = y1;
222                        mx = x2;
223                        my = y1;
224                    }
225                }
226
227                // clip x values
228
229                // clip with xmin
230                if (x1 <= x2 && x1 < axisx.min) {
231                    if (x2 < axisx.min) {
232                        continue;
233                    }
234
235                    y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
236                    x1 = axisx.min;
237                } else if (x2 <= x1 && x2 < axisx.min) {
238                    if (x1 < axisx.min) {
239                        continue;
240                    }
241
242                    y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
243                    x2 = axisx.min;
244                }
245
246                // clip with xmax
247                if (x1 >= x2 && x1 > axisx.max) {
248                    if (x2 > axisx.max) {
249                        continue;
250                    }
251
252                    y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
253                    x1 = axisx.max;
254                } else if (x2 >= x1 && x2 > axisx.max) {
255                    if (x1 > axisx.max) {
256                        continue;
257                    }
258
259                    y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
260                    x2 = axisx.max;
261                }
262
263                if (!areaOpen) {
264                    // open area
265                    ctx.beginPath();
266                    ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
267                    areaOpen = true;
268                }
269
270                // now first check the case where both is outside
271                if (y1 >= axisy.max && y2 >= axisy.max) {
272                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
273                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
274                    continue;
275                } else if (y1 <= axisy.min && y2 <= axisy.min) {
276                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
277                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
278                    continue;
279                }
280
281                // else it's a bit more complicated, there might
282                // be a flat maxed out rectangle first, then a
283                // triangular cutout or reverse; to find these
284                // keep track of the current x values
285                var x1old = x1,
286                    x2old = x2;
287
288                // clip the y values, without shortcutting, we
289                // go through all cases in turn
290
291                // clip with ymin
292                if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
293                    x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
294                    y1 = axisy.min;
295                } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
296                    x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
297                    y2 = axisy.min;
298                }
299
300                // clip with ymax
301                if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
302                    x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
303                    y1 = axisy.max;
304                } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
305                    x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
306                    y2 = axisy.max;
307                }
308
309                // if the x value was changed we got a rectangle
310                // to fill
311                if (x1 !== x1old) {
312                    ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
313                    // it goes to (x1, y1), but we fill that below
314                }
315
316                // fill triangular section, this sometimes result
317                // in redundant points if (x1, y1) hasn't changed
318                // from previous line to, but we just ignore that
319                ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
320                ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
321
322                // fill the other rectangle if it's there
323                if (x2 !== x2old) {
324                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
325                    ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
326                }
327            }
328        }
329
330        /**
331        - drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
332
333         This function is used for drawing lines or area fill.  In case the series has line decimation function
334         attached, before starting to draw, as an optimization the points will first be decimated.
335
336         The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
337         plotHeight are the corresponding parameters of flot used to determine the drawing surface.
338         The function getColorOrGradient is used to compute the fill style of lines and area.
339        */
340        function drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
341            ctx.save();
342            ctx.translate(plotOffset.left, plotOffset.top);
343            ctx.lineJoin = "round";
344
345            if (series.lines.dashes && ctx.setLineDash) {
346                ctx.setLineDash(series.lines.dashes);
347            }
348
349            var datapoints = {
350                format: series.datapoints.format,
351                points: series.datapoints.points,
352                pointsize: series.datapoints.pointsize
353            };
354
355            if (series.decimate) {
356                datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight);
357            }
358
359            var lw = series.lines.lineWidth;
360
361            ctx.lineWidth = lw;
362            ctx.strokeStyle = series.color;
363            var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight, getColorOrGradient);
364            if (fillStyle) {
365                ctx.fillStyle = fillStyle;
366                plotLineArea(datapoints, series.xaxis, series.yaxis, series.lines.fillTowards || 0, ctx, series.lines.steps);
367            }
368
369            if (lw > 0) {
370                plotLine(datapoints, 0, 0, series.xaxis, series.yaxis, ctx, series.lines.steps);
371            }
372
373            ctx.restore();
374        }
375
376        /**
377        - drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
378
379         This function is used for drawing points using a given symbol. In case the series has points decimation
380         function attached, before starting to draw, as an optimization the points will first be decimated.
381
382         The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
383         plotHeight are the corresponding parameters of flot used to determine the drawing surface.
384         The function drawSymbol is used to compute and draw the symbol chosen for the points.
385        */
386        function drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
387            function drawCircle(ctx, x, y, radius, shadow, fill) {
388                ctx.moveTo(x + radius, y);
389                ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
390            }
391            drawCircle.fill = true;
392            function plotPoints(datapoints, radius, fill, offset, shadow, axisx, axisy, drawSymbolFn) {
393                var points = datapoints.points,
394                    ps = datapoints.pointsize;
395
396                ctx.beginPath();
397                for (var i = 0; i < points.length; i += ps) {
398                    var x = points[i],
399                        y = points[i + 1];
400                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
401                        continue;
402                    }
403
404                    x = axisx.p2c(x);
405                    y = axisy.p2c(y) + offset;
406
407                    drawSymbolFn(ctx, x, y, radius, shadow, fill);
408                }
409                if (drawSymbolFn.fill && !shadow) {
410                    ctx.fill();
411                }
412                ctx.stroke();
413            }
414
415            ctx.save();
416            ctx.translate(plotOffset.left, plotOffset.top);
417
418            var datapoints = {
419                format: series.datapoints.format,
420                points: series.datapoints.points,
421                pointsize: series.datapoints.pointsize
422            };
423
424            if (series.decimatePoints) {
425                datapoints.points = series.decimatePoints(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight);
426            }
427
428            var lw = series.points.lineWidth,
429                radius = series.points.radius,
430                symbol = series.points.symbol,
431                drawSymbolFn;
432
433            if (symbol === 'circle') {
434                drawSymbolFn = drawCircle;
435            } else if (typeof symbol === 'string' && drawSymbol && drawSymbol[symbol]) {
436                drawSymbolFn = drawSymbol[symbol];
437            } else if (typeof drawSymbol === 'function') {
438                drawSymbolFn = drawSymbol;
439            }
440
441            // If the user sets the line width to 0, we change it to a very
442            // small value. A line width of 0 seems to force the default of 1.
443
444            if (lw === 0) {
445                lw = 0.0001;
446            }
447
448            ctx.lineWidth = lw;
449            ctx.fillStyle = getFillStyle(series.points, series.color, null, null, getColorOrGradient);
450            ctx.strokeStyle = series.color;
451            plotPoints(datapoints, radius,
452                true, 0, false,
453                series.xaxis, series.yaxis, drawSymbolFn);
454            ctx.restore();
455        }
456
457        function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
458            var left = x + barLeft,
459                right = x + barRight,
460                bottom = b, top = y,
461                drawLeft, drawRight, drawTop, drawBottom = false,
462                tmp;
463
464            drawLeft = drawRight = drawTop = true;
465
466            // in horizontal mode, we start the bar from the left
467            // instead of from the bottom so it appears to be
468            // horizontal rather than vertical
469            if (horizontal) {
470                drawBottom = drawRight = drawTop = true;
471                drawLeft = false;
472                left = b;
473                right = x;
474                top = y + barLeft;
475                bottom = y + barRight;
476
477                // account for negative bars
478                if (right < left) {
479                    tmp = right;
480                    right = left;
481                    left = tmp;
482                    drawLeft = true;
483                    drawRight = false;
484                }
485            }
486            else {
487                drawLeft = drawRight = drawTop = true;
488                drawBottom = false;
489                left = x + barLeft;
490                right = x + barRight;
491                bottom = b;
492                top = y;
493
494                // account for negative bars
495                if (top < bottom) {
496                    tmp = top;
497                    top = bottom;
498                    bottom = tmp;
499                    drawBottom = true;
500                    drawTop = false;
501                }
502            }
503
504            // clip
505            if (right < axisx.min || left > axisx.max ||
506                top < axisy.min || bottom > axisy.max) {
507                return;
508            }
509
510            if (left < axisx.min) {
511                left = axisx.min;
512                drawLeft = false;
513            }
514
515            if (right > axisx.max) {
516                right = axisx.max;
517                drawRight = false;
518            }
519
520            if (bottom < axisy.min) {
521                bottom = axisy.min;
522                drawBottom = false;
523            }
524
525            if (top > axisy.max) {
526                top = axisy.max;
527                drawTop = false;
528            }
529
530            left = axisx.p2c(left);
531            bottom = axisy.p2c(bottom);
532            right = axisx.p2c(right);
533            top = axisy.p2c(top);
534
535            // fill the bar
536            if (fillStyleCallback) {
537                c.fillStyle = fillStyleCallback(bottom, top);
538                c.fillRect(left, top, right - left, bottom - top)
539            }
540
541            // draw outline
542            if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
543                c.beginPath();
544
545                // FIXME: inline moveTo is buggy with excanvas
546                c.moveTo(left, bottom);
547                if (drawLeft) {
548                    c.lineTo(left, top);
549                } else {
550                    c.moveTo(left, top);
551                }
552
553                if (drawTop) {
554                    c.lineTo(right, top);
555                } else {
556                    c.moveTo(right, top);
557                }
558
559                if (drawRight) {
560                    c.lineTo(right, bottom);
561                } else {
562                    c.moveTo(right, bottom);
563                }
564
565                if (drawBottom) {
566                    c.lineTo(left, bottom);
567                } else {
568                    c.moveTo(left, bottom);
569                }
570
571                c.stroke();
572            }
573        }
574
575        /**
576        - drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
577
578         This function is used for drawing series represented as bars. In case the series has decimation
579         function attached, before starting to draw, as an optimization the points will first be decimated.
580
581         The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
582         plotHeight are the corresponding parameters of flot used to determine the drawing surface.
583         The function getColorOrGradient is used to compute the fill style of bars.
584        */
585        function drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
586            function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
587                var points = datapoints.points,
588                    ps = datapoints.pointsize,
589                    fillTowards = series.bars.fillTowards || 0,
590                    defaultBottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min;
591
592                for (var i = 0; i < points.length; i += ps) {
593                    if (points[i] == null) {
594                        continue;
595                    }
596
597                    // Use third point as bottom if pointsize is 3
598                    var bottom = ps === 3 ? points[i + 2] : defaultBottom;
599                    drawBar(points[i], points[i + 1], bottom, barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
600                }
601            }
602
603            ctx.save();
604            ctx.translate(plotOffset.left, plotOffset.top);
605
606            var datapoints = {
607                format: series.datapoints.format,
608                points: series.datapoints.points,
609                pointsize: series.datapoints.pointsize
610            };
611
612            if (series.decimate) {
613                datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth);
614            }
615
616            ctx.lineWidth = series.bars.lineWidth;
617            ctx.strokeStyle = series.color;
618
619            var barLeft;
620            var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
621            switch (series.bars.align) {
622                case "left":
623                    barLeft = 0;
624                    break;
625                case "right":
626                    barLeft = -barWidth;
627                    break;
628                default:
629                    barLeft = -barWidth / 2;
630            }
631
632            var fillStyleCallback = series.bars.fill ? function(bottom, top) {
633                return getFillStyle(series.bars, series.color, bottom, top, getColorOrGradient);
634            } : null;
635
636            plotBars(datapoints, barLeft, barLeft + barWidth, fillStyleCallback, series.xaxis, series.yaxis);
637            ctx.restore();
638        }
639
640        function getFillStyle(filloptions, seriesColor, bottom, top, getColorOrGradient) {
641            var fill = filloptions.fill;
642            if (!fill) {
643                return null;
644            }
645
646            if (filloptions.fillColor) {
647                return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
648            }
649
650            var c = $.color.parse(seriesColor);
651            c.a = typeof fill === "number" ? fill : 0.4;
652            c.normalize();
653            return c.toString();
654        }
655
656        this.drawSeriesLines = drawSeriesLines;
657        this.drawSeriesPoints = drawSeriesPoints;
658        this.drawSeriesBars = drawSeriesBars;
659        this.drawBar = drawBar;
660    };
661
662    $.plot.drawSeries = new DrawSeries();
663})(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.