1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
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 |
|
48 | x2 = x1;
|
49 | y2 = y1;
|
50 | x1 = mx;
|
51 | y1 = my;
|
52 |
|
53 |
|
54 | mx = null;
|
55 | my = null;
|
56 |
|
57 |
|
58 | i -= ps;
|
59 | } else if (y1 !== y2 && x1 !== x2) {
|
60 |
|
61 | y2 = y1;
|
62 | mx = x2;
|
63 | my = y1;
|
64 | }
|
65 | }
|
66 |
|
67 |
|
68 | if (y1 <= y2 && y1 < axisy.min) {
|
69 | if (y2 < axisy.min) {
|
70 |
|
71 | continue;
|
72 | }
|
73 |
|
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 |
|
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 |
|
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 |
|
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 |
|
160 |
|
161 |
|
162 | while (true) {
|
163 | if (ps > 0 && i > points.length + ps) {
|
164 | break;
|
165 | }
|
166 |
|
167 | i += ps;
|
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 |
|
176 | y1 = y2 = bottom;
|
177 | }
|
178 |
|
179 | if (areaOpen) {
|
180 | if (ps > 0 && x1 != null && x2 == null) {
|
181 |
|
182 | segmentEnd = i;
|
183 | ps = -ps;
|
184 | ypos = 2;
|
185 | continue;
|
186 | }
|
187 |
|
188 | if (ps < 0 && i === segmentStart + ps) {
|
189 |
|
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 |
|
208 | x2 = x1;
|
209 | y2 = y1;
|
210 | x1 = mx;
|
211 | y1 = my;
|
212 |
|
213 |
|
214 | mx = null;
|
215 | my = null;
|
216 |
|
217 |
|
218 | i -= ps;
|
219 | } else if (y1 !== y2 && x1 !== x2) {
|
220 |
|
221 | y2 = y1;
|
222 | mx = x2;
|
223 | my = y1;
|
224 | }
|
225 | }
|
226 |
|
227 |
|
228 |
|
229 |
|
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 |
|
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 |
|
265 | ctx.beginPath();
|
266 | ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
|
267 | areaOpen = true;
|
268 | }
|
269 |
|
270 |
|
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 |
|
282 |
|
283 |
|
284 |
|
285 | var x1old = x1,
|
286 | x2old = x2;
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
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 |
|
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 |
|
310 |
|
311 | if (x1 !== x1old) {
|
312 | ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
|
313 |
|
314 | }
|
315 |
|
316 |
|
317 |
|
318 |
|
319 | ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
|
320 | ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
|
321 |
|
322 |
|
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 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
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 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
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 |
|
442 |
|
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 |
|
467 |
|
468 |
|
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 |
|
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 |
|
495 | if (top < bottom) {
|
496 | tmp = top;
|
497 | top = bottom;
|
498 | bottom = tmp;
|
499 | drawBottom = true;
|
500 | drawTop = false;
|
501 | }
|
502 | }
|
503 |
|
504 |
|
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 |
|
536 | if (fillStyleCallback) {
|
537 | c.fillStyle = fillStyleCallback(bottom, top);
|
538 | c.fillRect(left, top, right - left, bottom - top)
|
539 | }
|
540 |
|
541 |
|
542 | if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
|
543 | c.beginPath();
|
544 |
|
545 |
|
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 |
|
577 |
|
578 |
|
579 |
|
580 |
|
581 |
|
582 |
|
583 |
|
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 | calculatedBottom = 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 |
|
598 | var bottom = ps === 3 ? points[i + 2] : calculatedBottom;
|
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);
|