]> ToastFreeware Gitweb - chrisu/seepark.git/blob - web/static/c3.js
change chart type for air temperature to 'spline'
[chrisu/seepark.git] / web / static / c3.js
1 /* @license C3.js v0.6.9 | (c) C3 Team and other contributors | http://c3js.org/ */
2 (function (global, factory) {
3   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4   typeof define === 'function' && define.amd ? define(factory) :
5   (global.c3 = factory());
6 }(this, (function () { 'use strict';
7
8   function _typeof(obj) {
9     if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
10       _typeof = function (obj) {
11         return typeof obj;
12       };
13     } else {
14       _typeof = function (obj) {
15         return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
16       };
17     }
18
19     return _typeof(obj);
20   }
21
22   function _classCallCheck(instance, Constructor) {
23     if (!(instance instanceof Constructor)) {
24       throw new TypeError("Cannot call a class as a function");
25     }
26   }
27
28   function _defineProperty(obj, key, value) {
29     if (key in obj) {
30       Object.defineProperty(obj, key, {
31         value: value,
32         enumerable: true,
33         configurable: true,
34         writable: true
35       });
36     } else {
37       obj[key] = value;
38     }
39
40     return obj;
41   }
42
43   function ChartInternal(api) {
44     var $$ = this;
45     $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
46     $$.api = api;
47     $$.config = $$.getDefaultConfig();
48     $$.data = {};
49     $$.cache = {};
50     $$.axes = {};
51   }
52
53   function Chart(config) {
54     var $$ = this.internal = new ChartInternal(this);
55     $$.loadConfig(config);
56     $$.beforeInit(config);
57     $$.init();
58     $$.afterInit(config); // bind "this" to nested API
59
60     (function bindThis(fn, target, argThis) {
61       Object.keys(fn).forEach(function (key) {
62         target[key] = fn[key].bind(argThis);
63
64         if (Object.keys(fn[key]).length > 0) {
65           bindThis(fn[key], target[key], argThis);
66         }
67       });
68     })(Chart.prototype, this, this);
69   }
70
71   function AxisInternal(component, params) {
72     var internal = this;
73     internal.component = component;
74     internal.params = params || {};
75     internal.d3 = component.d3;
76     internal.scale = internal.d3.scaleLinear();
77     internal.range;
78     internal.orient = "bottom";
79     internal.innerTickSize = 6;
80     internal.outerTickSize = this.params.withOuterTick ? 6 : 0;
81     internal.tickPadding = 3;
82     internal.tickValues = null;
83     internal.tickFormat;
84     internal.tickArguments;
85     internal.tickOffset = 0;
86     internal.tickCulling = true;
87     internal.tickCentered;
88     internal.tickTextCharSize;
89     internal.tickTextRotate = internal.params.tickTextRotate;
90     internal.tickLength;
91     internal.axis = internal.generateAxis();
92   }
93
94   AxisInternal.prototype.axisX = function (selection, x, tickOffset) {
95     selection.attr("transform", function (d) {
96       return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
97     });
98   };
99
100   AxisInternal.prototype.axisY = function (selection, y) {
101     selection.attr("transform", function (d) {
102       return "translate(0," + Math.ceil(y(d)) + ")";
103     });
104   };
105
106   AxisInternal.prototype.scaleExtent = function (domain) {
107     var start = domain[0],
108         stop = domain[domain.length - 1];
109     return start < stop ? [start, stop] : [stop, start];
110   };
111
112   AxisInternal.prototype.generateTicks = function (scale) {
113     var internal = this;
114     var i,
115         domain,
116         ticks = [];
117
118     if (scale.ticks) {
119       return scale.ticks.apply(scale, internal.tickArguments);
120     }
121
122     domain = scale.domain();
123
124     for (i = Math.ceil(domain[0]); i < domain[1]; i++) {
125       ticks.push(i);
126     }
127
128     if (ticks.length > 0 && ticks[0] > 0) {
129       ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
130     }
131
132     return ticks;
133   };
134
135   AxisInternal.prototype.copyScale = function () {
136     var internal = this;
137     var newScale = internal.scale.copy(),
138         domain;
139
140     if (internal.params.isCategory) {
141       domain = internal.scale.domain();
142       newScale.domain([domain[0], domain[1] - 1]);
143     }
144
145     return newScale;
146   };
147
148   AxisInternal.prototype.textFormatted = function (v) {
149     var internal = this,
150         formatted = internal.tickFormat ? internal.tickFormat(v) : v;
151     return typeof formatted !== 'undefined' ? formatted : '';
152   };
153
154   AxisInternal.prototype.updateRange = function () {
155     var internal = this;
156     internal.range = internal.scale.rangeExtent ? internal.scale.rangeExtent() : internal.scaleExtent(internal.scale.range());
157     return internal.range;
158   };
159
160   AxisInternal.prototype.updateTickTextCharSize = function (tick) {
161     var internal = this;
162
163     if (internal.tickTextCharSize) {
164       return internal.tickTextCharSize;
165     }
166
167     var size = {
168       h: 11.5,
169       w: 5.5
170     };
171     tick.select('text').text(function (d) {
172       return internal.textFormatted(d);
173     }).each(function (d) {
174       var box = this.getBoundingClientRect(),
175           text = internal.textFormatted(d),
176           h = box.height,
177           w = text ? box.width / text.length : undefined;
178
179       if (h && w) {
180         size.h = h;
181         size.w = w;
182       }
183     }).text('');
184     internal.tickTextCharSize = size;
185     return size;
186   };
187
188   AxisInternal.prototype.isVertical = function () {
189     return this.orient === 'left' || this.orient === 'right';
190   };
191
192   AxisInternal.prototype.tspanData = function (d, i, scale) {
193     var internal = this;
194     var splitted = internal.params.tickMultiline ? internal.splitTickText(d, scale) : [].concat(internal.textFormatted(d));
195
196     if (internal.params.tickMultiline && internal.params.tickMultilineMax > 0) {
197       splitted = internal.ellipsify(splitted, internal.params.tickMultilineMax);
198     }
199
200     return splitted.map(function (s) {
201       return {
202         index: i,
203         splitted: s,
204         length: splitted.length
205       };
206     });
207   };
208
209   AxisInternal.prototype.splitTickText = function (d, scale) {
210     var internal = this,
211         tickText = internal.textFormatted(d),
212         maxWidth = internal.params.tickWidth,
213         subtext,
214         spaceIndex,
215         textWidth,
216         splitted = [];
217
218     if (Object.prototype.toString.call(tickText) === "[object Array]") {
219       return tickText;
220     }
221
222     if (!maxWidth || maxWidth <= 0) {
223       maxWidth = internal.isVertical() ? 95 : internal.params.isCategory ? Math.ceil(scale(1) - scale(0)) - 12 : 110;
224     }
225
226     function split(splitted, text) {
227       spaceIndex = undefined;
228
229       for (var i = 1; i < text.length; i++) {
230         if (text.charAt(i) === ' ') {
231           spaceIndex = i;
232         }
233
234         subtext = text.substr(0, i + 1);
235         textWidth = internal.tickTextCharSize.w * subtext.length; // if text width gets over tick width, split by space index or crrent index
236
237         if (maxWidth < textWidth) {
238           return split(splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)), text.slice(spaceIndex ? spaceIndex + 1 : i));
239         }
240       }
241
242       return splitted.concat(text);
243     }
244
245     return split(splitted, tickText + "");
246   };
247
248   AxisInternal.prototype.ellipsify = function (splitted, max) {
249     if (splitted.length <= max) {
250       return splitted;
251     }
252
253     var ellipsified = splitted.slice(0, max);
254     var remaining = 3;
255
256     for (var i = max - 1; i >= 0; i--) {
257       var available = ellipsified[i].length;
258       ellipsified[i] = ellipsified[i].substr(0, available - remaining).padEnd(available, '.');
259       remaining -= available;
260
261       if (remaining <= 0) {
262         break;
263       }
264     }
265
266     return ellipsified;
267   };
268
269   AxisInternal.prototype.updateTickLength = function () {
270     var internal = this;
271     internal.tickLength = Math.max(internal.innerTickSize, 0) + internal.tickPadding;
272   };
273
274   AxisInternal.prototype.lineY2 = function (d) {
275     var internal = this,
276         tickPosition = internal.scale(d) + (internal.tickCentered ? 0 : internal.tickOffset);
277     return internal.range[0] < tickPosition && tickPosition < internal.range[1] ? internal.innerTickSize : 0;
278   };
279
280   AxisInternal.prototype.textY = function () {
281     var internal = this,
282         rotate = internal.tickTextRotate;
283     return rotate ? 11.5 - 2.5 * (rotate / 15) * (rotate > 0 ? 1 : -1) : internal.tickLength;
284   };
285
286   AxisInternal.prototype.textTransform = function () {
287     var internal = this,
288         rotate = internal.tickTextRotate;
289     return rotate ? "rotate(" + rotate + ")" : "";
290   };
291
292   AxisInternal.prototype.textTextAnchor = function () {
293     var internal = this,
294         rotate = internal.tickTextRotate;
295     return rotate ? rotate > 0 ? "start" : "end" : "middle";
296   };
297
298   AxisInternal.prototype.tspanDx = function () {
299     var internal = this,
300         rotate = internal.tickTextRotate;
301     return rotate ? 8 * Math.sin(Math.PI * (rotate / 180)) : 0;
302   };
303
304   AxisInternal.prototype.tspanDy = function (d, i) {
305     var internal = this,
306         dy = internal.tickTextCharSize.h;
307
308     if (i === 0) {
309       if (internal.isVertical()) {
310         dy = -((d.length - 1) * (internal.tickTextCharSize.h / 2) - 3);
311       } else {
312         dy = ".71em";
313       }
314     }
315
316     return dy;
317   };
318
319   AxisInternal.prototype.generateAxis = function () {
320     var internal = this,
321         d3 = internal.d3,
322         params = internal.params;
323
324     function axis(g, transition) {
325       var self;
326       g.each(function () {
327         var g = axis.g = d3.select(this);
328         var scale0 = this.__chart__ || internal.scale,
329             scale1 = this.__chart__ = internal.copyScale();
330         var ticksValues = internal.tickValues ? internal.tickValues : internal.generateTicks(scale1),
331             ticks = g.selectAll(".tick").data(ticksValues, scale1),
332             tickEnter = ticks.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
333             // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
334         tickExit = ticks.exit().remove(),
335             tickUpdate = ticks.merge(tickEnter),
336             tickTransform,
337             tickX,
338             tickY;
339
340         if (params.isCategory) {
341           internal.tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
342           tickX = internal.tickCentered ? 0 : internal.tickOffset;
343           tickY = internal.tickCentered ? internal.tickOffset : 0;
344         } else {
345           internal.tickOffset = tickX = 0;
346         }
347
348         internal.updateRange();
349         internal.updateTickLength();
350         internal.updateTickTextCharSize(g.select('.tick'));
351         var lineUpdate = tickUpdate.select("line").merge(tickEnter.append("line")),
352             textUpdate = tickUpdate.select("text").merge(tickEnter.append("text"));
353         var tspans = tickUpdate.selectAll('text').selectAll('tspan').data(function (d, i) {
354           return internal.tspanData(d, i, scale1);
355         }),
356             tspanEnter = tspans.enter().append('tspan'),
357             tspanUpdate = tspanEnter.merge(tspans).text(function (d) {
358           return d.splitted;
359         });
360         tspans.exit().remove();
361         var path = g.selectAll(".domain").data([0]),
362             pathUpdate = path.enter().append("path").merge(path).attr("class", "domain"); // TODO: each attr should be one function and change its behavior by internal.orient, probably
363
364         switch (internal.orient) {
365           case "bottom":
366             {
367               tickTransform = internal.axisX;
368               lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", function (d, i) {
369                 return internal.lineY2(d, i);
370               });
371               textUpdate.attr("x", 0).attr("y", function (d, i) {
372                 return internal.textY(d, i);
373               }).attr("transform", function (d, i) {
374                 return internal.textTransform(d, i);
375               }).style("text-anchor", function (d, i) {
376                 return internal.textTextAnchor(d, i);
377               });
378               tspanUpdate.attr('x', 0).attr("dy", function (d, i) {
379                 return internal.tspanDy(d, i);
380               }).attr('dx', function (d, i) {
381                 return internal.tspanDx(d, i);
382               });
383               pathUpdate.attr("d", "M" + internal.range[0] + "," + internal.outerTickSize + "V0H" + internal.range[1] + "V" + internal.outerTickSize);
384               break;
385             }
386
387           case "top":
388             {
389               // TODO: rotated tick text
390               tickTransform = internal.axisX;
391               lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", function (d, i) {
392                 return -1 * internal.lineY2(d, i);
393               });
394               textUpdate.attr("x", 0).attr("y", function (d, i) {
395                 return -1 * internal.textY(d, i) - (params.isCategory ? 2 : internal.tickLength - 2);
396               }).attr("transform", function (d, i) {
397                 return internal.textTransform(d, i);
398               }).style("text-anchor", function (d, i) {
399                 return internal.textTextAnchor(d, i);
400               });
401               tspanUpdate.attr('x', 0).attr("dy", function (d, i) {
402                 return internal.tspanDy(d, i);
403               }).attr('dx', function (d, i) {
404                 return internal.tspanDx(d, i);
405               });
406               pathUpdate.attr("d", "M" + internal.range[0] + "," + -internal.outerTickSize + "V0H" + internal.range[1] + "V" + -internal.outerTickSize);
407               break;
408             }
409
410           case "left":
411             {
412               tickTransform = internal.axisY;
413               lineUpdate.attr("x2", -internal.innerTickSize).attr("y1", tickY).attr("y2", tickY);
414               textUpdate.attr("x", -internal.tickLength).attr("y", internal.tickOffset).style("text-anchor", "end");
415               tspanUpdate.attr('x', -internal.tickLength).attr("dy", function (d, i) {
416                 return internal.tspanDy(d, i);
417               });
418               pathUpdate.attr("d", "M" + -internal.outerTickSize + "," + internal.range[0] + "H0V" + internal.range[1] + "H" + -internal.outerTickSize);
419               break;
420             }
421
422           case "right":
423             {
424               tickTransform = internal.axisY;
425               lineUpdate.attr("x2", internal.innerTickSize).attr("y1", tickY).attr("y2", tickY);
426               textUpdate.attr("x", internal.tickLength).attr("y", internal.tickOffset).style("text-anchor", "start");
427               tspanUpdate.attr('x', internal.tickLength).attr("dy", function (d, i) {
428                 return internal.tspanDy(d, i);
429               });
430               pathUpdate.attr("d", "M" + internal.outerTickSize + "," + internal.range[0] + "H0V" + internal.range[1] + "H" + internal.outerTickSize);
431               break;
432             }
433         }
434
435         if (scale1.rangeBand) {
436           var x = scale1,
437               dx = x.rangeBand() / 2;
438
439           scale0 = scale1 = function scale1(d) {
440             return x(d) + dx;
441           };
442         } else if (scale0.rangeBand) {
443           scale0 = scale1;
444         } else {
445           tickExit.call(tickTransform, scale1, internal.tickOffset);
446         }
447
448         tickEnter.call(tickTransform, scale0, internal.tickOffset);
449         self = (transition ? tickUpdate.transition(transition) : tickUpdate).style('opacity', 1).call(tickTransform, scale1, internal.tickOffset);
450       });
451       return self;
452     }
453
454     axis.scale = function (x) {
455       if (!arguments.length) {
456         return internal.scale;
457       }
458
459       internal.scale = x;
460       return axis;
461     };
462
463     axis.orient = function (x) {
464       if (!arguments.length) {
465         return internal.orient;
466       }
467
468       internal.orient = x in {
469         top: 1,
470         right: 1,
471         bottom: 1,
472         left: 1
473       } ? x + "" : "bottom";
474       return axis;
475     };
476
477     axis.tickFormat = function (format) {
478       if (!arguments.length) {
479         return internal.tickFormat;
480       }
481
482       internal.tickFormat = format;
483       return axis;
484     };
485
486     axis.tickCentered = function (isCentered) {
487       if (!arguments.length) {
488         return internal.tickCentered;
489       }
490
491       internal.tickCentered = isCentered;
492       return axis;
493     };
494
495     axis.tickOffset = function () {
496       return internal.tickOffset;
497     };
498
499     axis.tickInterval = function () {
500       var interval, length;
501
502       if (params.isCategory) {
503         interval = internal.tickOffset * 2;
504       } else {
505         length = axis.g.select('path.domain').node().getTotalLength() - internal.outerTickSize * 2;
506         interval = length / axis.g.selectAll('line').size();
507       }
508
509       return interval === Infinity ? 0 : interval;
510     };
511
512     axis.ticks = function () {
513       if (!arguments.length) {
514         return internal.tickArguments;
515       }
516
517       internal.tickArguments = arguments;
518       return axis;
519     };
520
521     axis.tickCulling = function (culling) {
522       if (!arguments.length) {
523         return internal.tickCulling;
524       }
525
526       internal.tickCulling = culling;
527       return axis;
528     };
529
530     axis.tickValues = function (x) {
531       if (typeof x === 'function') {
532         internal.tickValues = function () {
533           return x(internal.scale.domain());
534         };
535       } else {
536         if (!arguments.length) {
537           return internal.tickValues;
538         }
539
540         internal.tickValues = x;
541       }
542
543       return axis;
544     };
545
546     return axis;
547   };
548
549   var CLASS = {
550     target: 'c3-target',
551     chart: 'c3-chart',
552     chartLine: 'c3-chart-line',
553     chartLines: 'c3-chart-lines',
554     chartBar: 'c3-chart-bar',
555     chartBars: 'c3-chart-bars',
556     chartText: 'c3-chart-text',
557     chartTexts: 'c3-chart-texts',
558     chartArc: 'c3-chart-arc',
559     chartArcs: 'c3-chart-arcs',
560     chartArcsTitle: 'c3-chart-arcs-title',
561     chartArcsBackground: 'c3-chart-arcs-background',
562     chartArcsGaugeUnit: 'c3-chart-arcs-gauge-unit',
563     chartArcsGaugeMax: 'c3-chart-arcs-gauge-max',
564     chartArcsGaugeMin: 'c3-chart-arcs-gauge-min',
565     selectedCircle: 'c3-selected-circle',
566     selectedCircles: 'c3-selected-circles',
567     eventRect: 'c3-event-rect',
568     eventRects: 'c3-event-rects',
569     eventRectsSingle: 'c3-event-rects-single',
570     eventRectsMultiple: 'c3-event-rects-multiple',
571     zoomRect: 'c3-zoom-rect',
572     brush: 'c3-brush',
573     dragZoom: 'c3-drag-zoom',
574     focused: 'c3-focused',
575     defocused: 'c3-defocused',
576     region: 'c3-region',
577     regions: 'c3-regions',
578     title: 'c3-title',
579     tooltipContainer: 'c3-tooltip-container',
580     tooltip: 'c3-tooltip',
581     tooltipName: 'c3-tooltip-name',
582     shape: 'c3-shape',
583     shapes: 'c3-shapes',
584     line: 'c3-line',
585     lines: 'c3-lines',
586     bar: 'c3-bar',
587     bars: 'c3-bars',
588     circle: 'c3-circle',
589     circles: 'c3-circles',
590     arc: 'c3-arc',
591     arcLabelLine: 'c3-arc-label-line',
592     arcs: 'c3-arcs',
593     area: 'c3-area',
594     areas: 'c3-areas',
595     empty: 'c3-empty',
596     text: 'c3-text',
597     texts: 'c3-texts',
598     gaugeValue: 'c3-gauge-value',
599     grid: 'c3-grid',
600     gridLines: 'c3-grid-lines',
601     xgrid: 'c3-xgrid',
602     xgrids: 'c3-xgrids',
603     xgridLine: 'c3-xgrid-line',
604     xgridLines: 'c3-xgrid-lines',
605     xgridFocus: 'c3-xgrid-focus',
606     ygrid: 'c3-ygrid',
607     ygrids: 'c3-ygrids',
608     ygridLine: 'c3-ygrid-line',
609     ygridLines: 'c3-ygrid-lines',
610     axis: 'c3-axis',
611     axisX: 'c3-axis-x',
612     axisXLabel: 'c3-axis-x-label',
613     axisY: 'c3-axis-y',
614     axisYLabel: 'c3-axis-y-label',
615     axisY2: 'c3-axis-y2',
616     axisY2Label: 'c3-axis-y2-label',
617     legendBackground: 'c3-legend-background',
618     legendItem: 'c3-legend-item',
619     legendItemEvent: 'c3-legend-item-event',
620     legendItemTile: 'c3-legend-item-tile',
621     legendItemHidden: 'c3-legend-item-hidden',
622     legendItemFocused: 'c3-legend-item-focused',
623     dragarea: 'c3-dragarea',
624     EXPANDED: '_expanded_',
625     SELECTED: '_selected_',
626     INCLUDED: '_included_'
627   };
628
629   var asHalfPixel = function asHalfPixel(n) {
630     return Math.ceil(n) + 0.5;
631   };
632   var ceil10 = function ceil10(v) {
633     return Math.ceil(v / 10) * 10;
634   };
635   var diffDomain = function diffDomain(d) {
636     return d[1] - d[0];
637   };
638   var getOption = function getOption(options, key, defaultValue) {
639     return isDefined(options[key]) ? options[key] : defaultValue;
640   };
641   var getPathBox = function getPathBox(path) {
642     var box = path.getBoundingClientRect(),
643         items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
644         minX = items[0].x,
645         minY = Math.min(items[0].y, items[1].y);
646     return {
647       x: minX,
648       y: minY,
649       width: box.width,
650       height: box.height
651     };
652   };
653   var hasValue = function hasValue(dict, value) {
654     var found = false;
655     Object.keys(dict).forEach(function (key) {
656       if (dict[key] === value) {
657         found = true;
658       }
659     });
660     return found;
661   };
662   var isArray = function isArray(o) {
663     return Array.isArray(o);
664   };
665   var isDefined = function isDefined(v) {
666     return typeof v !== 'undefined';
667   };
668   var isEmpty = function isEmpty(o) {
669     return typeof o === 'undefined' || o === null || isString(o) && o.length === 0 || _typeof(o) === 'object' && Object.keys(o).length === 0;
670   };
671   var isFunction = function isFunction(o) {
672     return typeof o === 'function';
673   };
674   var isString = function isString(o) {
675     return typeof o === 'string';
676   };
677   var isUndefined = function isUndefined(v) {
678     return typeof v === 'undefined';
679   };
680   var isValue = function isValue(v) {
681     return v || v === 0;
682   };
683   var notEmpty = function notEmpty(o) {
684     return !isEmpty(o);
685   };
686   var sanitise = function sanitise(str) {
687     return typeof str === 'string' ? str.replace(/</g, '&lt;').replace(/>/g, '&gt;') : str;
688   };
689
690   var Axis = function Axis(owner) {
691     _classCallCheck(this, Axis);
692
693     this.owner = owner;
694     this.d3 = owner.d3;
695     this.internal = AxisInternal;
696   };
697
698   Axis.prototype.init = function init() {
699     var $$ = this.owner,
700         config = $$.config,
701         main = $$.main;
702     $$.axes.x = main.append("g").attr("class", CLASS.axis + ' ' + CLASS.axisX).attr("clip-path", config.axis_x_inner ? "" : $$.clipPathForXAxis).attr("transform", $$.getTranslate('x')).style("visibility", config.axis_x_show ? 'visible' : 'hidden');
703     $$.axes.x.append("text").attr("class", CLASS.axisXLabel).attr("transform", config.axis_rotated ? "rotate(-90)" : "").style("text-anchor", this.textAnchorForXAxisLabel.bind(this));
704     $$.axes.y = main.append("g").attr("class", CLASS.axis + ' ' + CLASS.axisY).attr("clip-path", config.axis_y_inner ? "" : $$.clipPathForYAxis).attr("transform", $$.getTranslate('y')).style("visibility", config.axis_y_show ? 'visible' : 'hidden');
705     $$.axes.y.append("text").attr("class", CLASS.axisYLabel).attr("transform", config.axis_rotated ? "" : "rotate(-90)").style("text-anchor", this.textAnchorForYAxisLabel.bind(this));
706     $$.axes.y2 = main.append("g").attr("class", CLASS.axis + ' ' + CLASS.axisY2) // clip-path?
707     .attr("transform", $$.getTranslate('y2')).style("visibility", config.axis_y2_show ? 'visible' : 'hidden');
708     $$.axes.y2.append("text").attr("class", CLASS.axisY2Label).attr("transform", config.axis_rotated ? "" : "rotate(-90)").style("text-anchor", this.textAnchorForY2AxisLabel.bind(this));
709   };
710
711   Axis.prototype.getXAxis = function getXAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
712     var $$ = this.owner,
713         config = $$.config,
714         axisParams = {
715       isCategory: $$.isCategorized(),
716       withOuterTick: withOuterTick,
717       tickMultiline: config.axis_x_tick_multiline,
718       tickMultilineMax: config.axis_x_tick_multiline ? Number(config.axis_x_tick_multilineMax) : 0,
719       tickWidth: config.axis_x_tick_width,
720       tickTextRotate: withoutRotateTickText ? 0 : config.axis_x_tick_rotate,
721       withoutTransition: withoutTransition
722     },
723         axis = new this.internal(this, axisParams).axis.scale(scale).orient(orient);
724
725     if ($$.isTimeSeries() && tickValues && typeof tickValues !== "function") {
726       tickValues = tickValues.map(function (v) {
727         return $$.parseDate(v);
728       });
729     } // Set tick
730
731
732     axis.tickFormat(tickFormat).tickValues(tickValues);
733
734     if ($$.isCategorized()) {
735       axis.tickCentered(config.axis_x_tick_centered);
736
737       if (isEmpty(config.axis_x_tick_culling)) {
738         config.axis_x_tick_culling = false;
739       }
740     }
741
742     return axis;
743   };
744
745   Axis.prototype.updateXAxisTickValues = function updateXAxisTickValues(targets, axis) {
746     var $$ = this.owner,
747         config = $$.config,
748         tickValues;
749
750     if (config.axis_x_tick_fit || config.axis_x_tick_count) {
751       tickValues = this.generateTickValues($$.mapTargetsToUniqueXs(targets), config.axis_x_tick_count, $$.isTimeSeries());
752     }
753
754     if (axis) {
755       axis.tickValues(tickValues);
756     } else {
757       $$.xAxis.tickValues(tickValues);
758       $$.subXAxis.tickValues(tickValues);
759     }
760
761     return tickValues;
762   };
763
764   Axis.prototype.getYAxis = function getYAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
765     var $$ = this.owner,
766         config = $$.config,
767         axisParams = {
768       withOuterTick: withOuterTick,
769       withoutTransition: withoutTransition,
770       tickTextRotate: withoutRotateTickText ? 0 : config.axis_y_tick_rotate
771     },
772         axis = new this.internal(this, axisParams).axis.scale(scale).orient(orient).tickFormat(tickFormat);
773
774     if ($$.isTimeSeriesY()) {
775       axis.ticks(config.axis_y_tick_time_type, config.axis_y_tick_time_interval);
776     } else {
777       axis.tickValues(tickValues);
778     }
779
780     return axis;
781   };
782
783   Axis.prototype.getId = function getId(id) {
784     var config = this.owner.config;
785     return id in config.data_axes ? config.data_axes[id] : 'y';
786   };
787
788   Axis.prototype.getXAxisTickFormat = function getXAxisTickFormat() {
789     // #2251 previously set any negative values to a whole number,
790     // however both should be truncated according to the users format specification
791     var $$ = this.owner,
792         config = $$.config;
793     var format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) {
794       return v;
795     };
796
797     if (config.axis_x_tick_format) {
798       if (isFunction(config.axis_x_tick_format)) {
799         format = config.axis_x_tick_format;
800       } else if ($$.isTimeSeries()) {
801         format = function format(date) {
802           return date ? $$.axisTimeFormat(config.axis_x_tick_format)(date) : "";
803         };
804       }
805     }
806
807     return isFunction(format) ? function (v) {
808       return format.call($$, v);
809     } : format;
810   };
811
812   Axis.prototype.getTickValues = function getTickValues(tickValues, axis) {
813     return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
814   };
815
816   Axis.prototype.getXAxisTickValues = function getXAxisTickValues() {
817     return this.getTickValues(this.owner.config.axis_x_tick_values, this.owner.xAxis);
818   };
819
820   Axis.prototype.getYAxisTickValues = function getYAxisTickValues() {
821     return this.getTickValues(this.owner.config.axis_y_tick_values, this.owner.yAxis);
822   };
823
824   Axis.prototype.getY2AxisTickValues = function getY2AxisTickValues() {
825     return this.getTickValues(this.owner.config.axis_y2_tick_values, this.owner.y2Axis);
826   };
827
828   Axis.prototype.getLabelOptionByAxisId = function getLabelOptionByAxisId(axisId) {
829     var $$ = this.owner,
830         config = $$.config,
831         option;
832
833     if (axisId === 'y') {
834       option = config.axis_y_label;
835     } else if (axisId === 'y2') {
836       option = config.axis_y2_label;
837     } else if (axisId === 'x') {
838       option = config.axis_x_label;
839     }
840
841     return option;
842   };
843
844   Axis.prototype.getLabelText = function getLabelText(axisId) {
845     var option = this.getLabelOptionByAxisId(axisId);
846     return isString(option) ? option : option ? option.text : null;
847   };
848
849   Axis.prototype.setLabelText = function setLabelText(axisId, text) {
850     var $$ = this.owner,
851         config = $$.config,
852         option = this.getLabelOptionByAxisId(axisId);
853
854     if (isString(option)) {
855       if (axisId === 'y') {
856         config.axis_y_label = text;
857       } else if (axisId === 'y2') {
858         config.axis_y2_label = text;
859       } else if (axisId === 'x') {
860         config.axis_x_label = text;
861       }
862     } else if (option) {
863       option.text = text;
864     }
865   };
866
867   Axis.prototype.getLabelPosition = function getLabelPosition(axisId, defaultPosition) {
868     var option = this.getLabelOptionByAxisId(axisId),
869         position = option && _typeof(option) === 'object' && option.position ? option.position : defaultPosition;
870     return {
871       isInner: position.indexOf('inner') >= 0,
872       isOuter: position.indexOf('outer') >= 0,
873       isLeft: position.indexOf('left') >= 0,
874       isCenter: position.indexOf('center') >= 0,
875       isRight: position.indexOf('right') >= 0,
876       isTop: position.indexOf('top') >= 0,
877       isMiddle: position.indexOf('middle') >= 0,
878       isBottom: position.indexOf('bottom') >= 0
879     };
880   };
881
882   Axis.prototype.getXAxisLabelPosition = function getXAxisLabelPosition() {
883     return this.getLabelPosition('x', this.owner.config.axis_rotated ? 'inner-top' : 'inner-right');
884   };
885
886   Axis.prototype.getYAxisLabelPosition = function getYAxisLabelPosition() {
887     return this.getLabelPosition('y', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
888   };
889
890   Axis.prototype.getY2AxisLabelPosition = function getY2AxisLabelPosition() {
891     return this.getLabelPosition('y2', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
892   };
893
894   Axis.prototype.getLabelPositionById = function getLabelPositionById(id) {
895     return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
896   };
897
898   Axis.prototype.textForXAxisLabel = function textForXAxisLabel() {
899     return this.getLabelText('x');
900   };
901
902   Axis.prototype.textForYAxisLabel = function textForYAxisLabel() {
903     return this.getLabelText('y');
904   };
905
906   Axis.prototype.textForY2AxisLabel = function textForY2AxisLabel() {
907     return this.getLabelText('y2');
908   };
909
910   Axis.prototype.xForAxisLabel = function xForAxisLabel(forHorizontal, position) {
911     var $$ = this.owner;
912
913     if (forHorizontal) {
914       return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
915     } else {
916       return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
917     }
918   };
919
920   Axis.prototype.dxForAxisLabel = function dxForAxisLabel(forHorizontal, position) {
921     if (forHorizontal) {
922       return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
923     } else {
924       return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
925     }
926   };
927
928   Axis.prototype.textAnchorForAxisLabel = function textAnchorForAxisLabel(forHorizontal, position) {
929     if (forHorizontal) {
930       return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
931     } else {
932       return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
933     }
934   };
935
936   Axis.prototype.xForXAxisLabel = function xForXAxisLabel() {
937     return this.xForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
938   };
939
940   Axis.prototype.xForYAxisLabel = function xForYAxisLabel() {
941     return this.xForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
942   };
943
944   Axis.prototype.xForY2AxisLabel = function xForY2AxisLabel() {
945     return this.xForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
946   };
947
948   Axis.prototype.dxForXAxisLabel = function dxForXAxisLabel() {
949     return this.dxForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
950   };
951
952   Axis.prototype.dxForYAxisLabel = function dxForYAxisLabel() {
953     return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
954   };
955
956   Axis.prototype.dxForY2AxisLabel = function dxForY2AxisLabel() {
957     return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
958   };
959
960   Axis.prototype.dyForXAxisLabel = function dyForXAxisLabel() {
961     var $$ = this.owner,
962         config = $$.config,
963         position = this.getXAxisLabelPosition();
964
965     if (config.axis_rotated) {
966       return position.isInner ? "1.2em" : -25 - ($$.config.axis_x_inner ? 0 : this.getMaxTickWidth('x'));
967     } else {
968       return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
969     }
970   };
971
972   Axis.prototype.dyForYAxisLabel = function dyForYAxisLabel() {
973     var $$ = this.owner,
974         position = this.getYAxisLabelPosition();
975
976     if ($$.config.axis_rotated) {
977       return position.isInner ? "-0.5em" : "3em";
978     } else {
979       return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : this.getMaxTickWidth('y') + 10);
980     }
981   };
982
983   Axis.prototype.dyForY2AxisLabel = function dyForY2AxisLabel() {
984     var $$ = this.owner,
985         position = this.getY2AxisLabelPosition();
986
987     if ($$.config.axis_rotated) {
988       return position.isInner ? "1.2em" : "-2.2em";
989     } else {
990       return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : this.getMaxTickWidth('y2') + 15);
991     }
992   };
993
994   Axis.prototype.textAnchorForXAxisLabel = function textAnchorForXAxisLabel() {
995     var $$ = this.owner;
996     return this.textAnchorForAxisLabel(!$$.config.axis_rotated, this.getXAxisLabelPosition());
997   };
998
999   Axis.prototype.textAnchorForYAxisLabel = function textAnchorForYAxisLabel() {
1000     var $$ = this.owner;
1001     return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getYAxisLabelPosition());
1002   };
1003
1004   Axis.prototype.textAnchorForY2AxisLabel = function textAnchorForY2AxisLabel() {
1005     var $$ = this.owner;
1006     return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getY2AxisLabelPosition());
1007   };
1008
1009   Axis.prototype.getMaxTickWidth = function getMaxTickWidth(id, withoutRecompute) {
1010     var $$ = this.owner,
1011         config = $$.config,
1012         maxWidth = 0,
1013         targetsToShow,
1014         scale,
1015         axis,
1016         dummy,
1017         svg;
1018
1019     if (withoutRecompute && $$.currentMaxTickWidths[id]) {
1020       return $$.currentMaxTickWidths[id];
1021     }
1022
1023     if ($$.svg) {
1024       targetsToShow = $$.filterTargetsToShow($$.data.targets);
1025
1026       if (id === 'y') {
1027         scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
1028         axis = this.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, false, true, true);
1029       } else if (id === 'y2') {
1030         scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
1031         axis = this.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, false, true, true);
1032       } else {
1033         scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
1034         axis = this.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, false, true, true);
1035         this.updateXAxisTickValues(targetsToShow, axis);
1036       }
1037
1038       dummy = $$.d3.select('body').append('div').classed('c3', true);
1039       svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0), svg.append('g').call(axis).each(function () {
1040         $$.d3.select(this).selectAll('text').each(function () {
1041           var box = this.getBoundingClientRect();
1042
1043           if (maxWidth < box.width) {
1044             maxWidth = box.width;
1045           }
1046         });
1047         dummy.remove();
1048       });
1049     }
1050
1051     $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
1052     return $$.currentMaxTickWidths[id];
1053   };
1054
1055   Axis.prototype.updateLabels = function updateLabels(withTransition) {
1056     var $$ = this.owner;
1057     var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
1058         axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
1059         axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
1060     (withTransition ? axisXLabel.transition() : axisXLabel).attr("x", this.xForXAxisLabel.bind(this)).attr("dx", this.dxForXAxisLabel.bind(this)).attr("dy", this.dyForXAxisLabel.bind(this)).text(this.textForXAxisLabel.bind(this));
1061     (withTransition ? axisYLabel.transition() : axisYLabel).attr("x", this.xForYAxisLabel.bind(this)).attr("dx", this.dxForYAxisLabel.bind(this)).attr("dy", this.dyForYAxisLabel.bind(this)).text(this.textForYAxisLabel.bind(this));
1062     (withTransition ? axisY2Label.transition() : axisY2Label).attr("x", this.xForY2AxisLabel.bind(this)).attr("dx", this.dxForY2AxisLabel.bind(this)).attr("dy", this.dyForY2AxisLabel.bind(this)).text(this.textForY2AxisLabel.bind(this));
1063   };
1064
1065   Axis.prototype.getPadding = function getPadding(padding, key, defaultValue, domainLength) {
1066     var p = typeof padding === 'number' ? padding : padding[key];
1067
1068     if (!isValue(p)) {
1069       return defaultValue;
1070     }
1071
1072     if (padding.unit === 'ratio') {
1073       return padding[key] * domainLength;
1074     } // assume padding is pixels if unit is not specified
1075
1076
1077     return this.convertPixelsToAxisPadding(p, domainLength);
1078   };
1079
1080   Axis.prototype.convertPixelsToAxisPadding = function convertPixelsToAxisPadding(pixels, domainLength) {
1081     var $$ = this.owner,
1082         length = $$.config.axis_rotated ? $$.width : $$.height;
1083     return domainLength * (pixels / length);
1084   };
1085
1086   Axis.prototype.generateTickValues = function generateTickValues(values, tickCount, forTimeSeries) {
1087     var tickValues = values,
1088         targetCount,
1089         start,
1090         end,
1091         count,
1092         interval,
1093         i,
1094         tickValue;
1095
1096     if (tickCount) {
1097       targetCount = isFunction(tickCount) ? tickCount() : tickCount; // compute ticks according to tickCount
1098
1099       if (targetCount === 1) {
1100         tickValues = [values[0]];
1101       } else if (targetCount === 2) {
1102         tickValues = [values[0], values[values.length - 1]];
1103       } else if (targetCount > 2) {
1104         count = targetCount - 2;
1105         start = values[0];
1106         end = values[values.length - 1];
1107         interval = (end - start) / (count + 1); // re-construct unique values
1108
1109         tickValues = [start];
1110
1111         for (i = 0; i < count; i++) {
1112           tickValue = +start + interval * (i + 1);
1113           tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
1114         }
1115
1116         tickValues.push(end);
1117       }
1118     }
1119
1120     if (!forTimeSeries) {
1121       tickValues = tickValues.sort(function (a, b) {
1122         return a - b;
1123       });
1124     }
1125
1126     return tickValues;
1127   };
1128
1129   Axis.prototype.generateTransitions = function generateTransitions(duration) {
1130     var $$ = this.owner,
1131         axes = $$.axes;
1132     return {
1133       axisX: duration ? axes.x.transition().duration(duration) : axes.x,
1134       axisY: duration ? axes.y.transition().duration(duration) : axes.y,
1135       axisY2: duration ? axes.y2.transition().duration(duration) : axes.y2,
1136       axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
1137     };
1138   };
1139
1140   Axis.prototype.redraw = function redraw(duration, isHidden) {
1141     var $$ = this.owner,
1142         transition = duration ? $$.d3.transition().duration(duration) : null;
1143     $$.axes.x.style("opacity", isHidden ? 0 : 1).call($$.xAxis, transition);
1144     $$.axes.y.style("opacity", isHidden ? 0 : 1).call($$.yAxis, transition);
1145     $$.axes.y2.style("opacity", isHidden ? 0 : 1).call($$.y2Axis, transition);
1146     $$.axes.subx.style("opacity", isHidden ? 0 : 1).call($$.subXAxis, transition);
1147   };
1148
1149   var c3 = {
1150     version: "0.6.9",
1151     chart: {
1152       fn: Chart.prototype,
1153       internal: {
1154         fn: ChartInternal.prototype,
1155         axis: {
1156           fn: Axis.prototype,
1157           internal: {
1158             fn: AxisInternal.prototype
1159           }
1160         }
1161       }
1162     },
1163     generate: function generate(config) {
1164       return new Chart(config);
1165     }
1166   };
1167
1168   ChartInternal.prototype.beforeInit = function () {// can do something
1169   };
1170
1171   ChartInternal.prototype.afterInit = function () {// can do something
1172   };
1173
1174   ChartInternal.prototype.init = function () {
1175     var $$ = this,
1176         config = $$.config;
1177     $$.initParams();
1178
1179     if (config.data_url) {
1180       $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_headers, config.data_keys, $$.initWithData);
1181     } else if (config.data_json) {
1182       $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
1183     } else if (config.data_rows) {
1184       $$.initWithData($$.convertRowsToData(config.data_rows));
1185     } else if (config.data_columns) {
1186       $$.initWithData($$.convertColumnsToData(config.data_columns));
1187     } else {
1188       throw Error('url or json or rows or columns is required.');
1189     }
1190   };
1191
1192   ChartInternal.prototype.initParams = function () {
1193     var $$ = this,
1194         d3 = $$.d3,
1195         config = $$.config; // MEMO: clipId needs to be unique because it conflicts when multiple charts exist
1196
1197     $$.clipId = "c3-" + +new Date() + '-clip';
1198     $$.clipIdForXAxis = $$.clipId + '-xaxis';
1199     $$.clipIdForYAxis = $$.clipId + '-yaxis';
1200     $$.clipIdForGrid = $$.clipId + '-grid';
1201     $$.clipIdForSubchart = $$.clipId + '-subchart';
1202     $$.clipPath = $$.getClipPath($$.clipId);
1203     $$.clipPathForXAxis = $$.getClipPath($$.clipIdForXAxis);
1204     $$.clipPathForYAxis = $$.getClipPath($$.clipIdForYAxis);
1205     $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid);
1206     $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart);
1207     $$.dragStart = null;
1208     $$.dragging = false;
1209     $$.flowing = false;
1210     $$.cancelClick = false;
1211     $$.mouseover = false;
1212     $$.transiting = false;
1213     $$.color = $$.generateColor();
1214     $$.levelColor = $$.generateLevelColor();
1215     $$.dataTimeParse = (config.data_xLocaltime ? d3.timeParse : d3.utcParse)($$.config.data_xFormat);
1216     $$.axisTimeFormat = config.axis_x_localtime ? d3.timeFormat : d3.utcFormat;
1217
1218     $$.defaultAxisTimeFormat = function (date) {
1219       if (date.getMilliseconds()) {
1220         return d3.timeFormat(".%L")(date);
1221       }
1222
1223       if (date.getSeconds()) {
1224         return d3.timeFormat(":%S")(date);
1225       }
1226
1227       if (date.getMinutes()) {
1228         return d3.timeFormat("%I:%M")(date);
1229       }
1230
1231       if (date.getHours()) {
1232         return d3.timeFormat("%I %p")(date);
1233       }
1234
1235       if (date.getDay() && date.getDate() !== 1) {
1236         return d3.timeFormat("%-m/%-d")(date);
1237       }
1238
1239       if (date.getDate() !== 1) {
1240         return d3.timeFormat("%-m/%-d")(date);
1241       }
1242
1243       if (date.getMonth()) {
1244         return d3.timeFormat("%-m/%-d")(date);
1245       }
1246
1247       return d3.timeFormat("%Y/%-m/%-d")(date);
1248     };
1249
1250     $$.hiddenTargetIds = [];
1251     $$.hiddenLegendIds = [];
1252     $$.focusedTargetIds = [];
1253     $$.defocusedTargetIds = [];
1254     $$.xOrient = config.axis_rotated ? config.axis_x_inner ? "right" : "left" : config.axis_x_inner ? "top" : "bottom";
1255     $$.yOrient = config.axis_rotated ? config.axis_y_inner ? "top" : "bottom" : config.axis_y_inner ? "right" : "left";
1256     $$.y2Orient = config.axis_rotated ? config.axis_y2_inner ? "bottom" : "top" : config.axis_y2_inner ? "left" : "right";
1257     $$.subXOrient = config.axis_rotated ? "left" : "bottom";
1258     $$.isLegendRight = config.legend_position === 'right';
1259     $$.isLegendInset = config.legend_position === 'inset';
1260     $$.isLegendTop = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'top-right';
1261     $$.isLegendLeft = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'bottom-left';
1262     $$.legendStep = 0;
1263     $$.legendItemWidth = 0;
1264     $$.legendItemHeight = 0;
1265     $$.currentMaxTickWidths = {
1266       x: 0,
1267       y: 0,
1268       y2: 0
1269     };
1270     $$.rotated_padding_left = 30;
1271     $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
1272     $$.rotated_padding_top = 5;
1273     $$.withoutFadeIn = {};
1274     $$.intervalForObserveInserted = undefined;
1275     $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
1276   };
1277
1278   ChartInternal.prototype.initChartElements = function () {
1279     if (this.initBar) {
1280       this.initBar();
1281     }
1282
1283     if (this.initLine) {
1284       this.initLine();
1285     }
1286
1287     if (this.initArc) {
1288       this.initArc();
1289     }
1290
1291     if (this.initGauge) {
1292       this.initGauge();
1293     }
1294
1295     if (this.initText) {
1296       this.initText();
1297     }
1298   };
1299
1300   ChartInternal.prototype.initWithData = function (data) {
1301     var $$ = this,
1302         d3 = $$.d3,
1303         config = $$.config;
1304     var defs,
1305         main,
1306         binding = true;
1307     $$.axis = new Axis($$);
1308
1309     if (!config.bindto) {
1310       $$.selectChart = d3.selectAll([]);
1311     } else if (typeof config.bindto.node === 'function') {
1312       $$.selectChart = config.bindto;
1313     } else {
1314       $$.selectChart = d3.select(config.bindto);
1315     }
1316
1317     if ($$.selectChart.empty()) {
1318       $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
1319       $$.observeInserted($$.selectChart);
1320       binding = false;
1321     }
1322
1323     $$.selectChart.html("").classed("c3", true); // Init data as targets
1324
1325     $$.data.xs = {};
1326     $$.data.targets = $$.convertDataToTargets(data);
1327
1328     if (config.data_filter) {
1329       $$.data.targets = $$.data.targets.filter(config.data_filter);
1330     } // Set targets to hide if needed
1331
1332
1333     if (config.data_hide) {
1334       $$.addHiddenTargetIds(config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide);
1335     }
1336
1337     if (config.legend_hide) {
1338       $$.addHiddenLegendIds(config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide);
1339     } // Init sizes and scales
1340
1341
1342     $$.updateSizes();
1343     $$.updateScales(); // Set domains for each scale
1344
1345     $$.x.domain(d3.extent($$.getXDomain($$.data.targets)));
1346     $$.y.domain($$.getYDomain($$.data.targets, 'y'));
1347     $$.y2.domain($$.getYDomain($$.data.targets, 'y2'));
1348     $$.subX.domain($$.x.domain());
1349     $$.subY.domain($$.y.domain());
1350     $$.subY2.domain($$.y2.domain()); // Save original x domain for zoom update
1351
1352     $$.orgXDomain = $$.x.domain();
1353     /*-- Basic Elements --*/
1354     // Define svgs
1355
1356     $$.svg = $$.selectChart.append("svg").style("overflow", "hidden").on('mouseenter', function () {
1357       return config.onmouseover.call($$);
1358     }).on('mouseleave', function () {
1359       return config.onmouseout.call($$);
1360     });
1361
1362     if ($$.config.svg_classname) {
1363       $$.svg.attr('class', $$.config.svg_classname);
1364     } // Define defs
1365
1366
1367     defs = $$.svg.append("defs");
1368     $$.clipChart = $$.appendClip(defs, $$.clipId);
1369     $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
1370     $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
1371     $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
1372     $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
1373     $$.updateSvgSize(); // Define regions
1374
1375     main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main'));
1376
1377     if ($$.initPie) {
1378       $$.initPie();
1379     }
1380
1381     if ($$.initDragZoom) {
1382       $$.initDragZoom();
1383     }
1384
1385     if ($$.initSubchart) {
1386       $$.initSubchart();
1387     }
1388
1389     if ($$.initTooltip) {
1390       $$.initTooltip();
1391     }
1392
1393     if ($$.initLegend) {
1394       $$.initLegend();
1395     }
1396
1397     if ($$.initTitle) {
1398       $$.initTitle();
1399     }
1400
1401     if ($$.initZoom) {
1402       $$.initZoom();
1403     } // Update selection based on size and scale
1404     // TODO: currently this must be called after initLegend because of update of sizes, but it should be done in initSubchart.
1405
1406
1407     if ($$.initSubchartBrush) {
1408       $$.initSubchartBrush();
1409     }
1410     /*-- Main Region --*/
1411     // text when empty
1412
1413
1414     main.append("text").attr("class", CLASS.text + ' ' + CLASS.empty).attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
1415     .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
1416     // Regions
1417
1418     $$.initRegion(); // Grids
1419
1420     $$.initGrid(); // Define g for chart area
1421
1422     main.append('g').attr("clip-path", $$.clipPath).attr('class', CLASS.chart); // Grid lines
1423
1424     if (config.grid_lines_front) {
1425       $$.initGridLines();
1426     } // Cover whole with rects for events
1427
1428
1429     $$.initEventRect(); // Define g for chart
1430
1431     $$.initChartElements(); // Add Axis
1432
1433     $$.axis.init(); // Set targets
1434
1435     $$.updateTargets($$.data.targets); // Set default extent if defined
1436
1437     if (config.axis_x_selection) {
1438       $$.brush.selectionAsValue($$.getDefaultSelection());
1439     } // Draw with targets
1440
1441
1442     if (binding) {
1443       $$.updateDimension();
1444       $$.config.oninit.call($$);
1445       $$.redraw({
1446         withTransition: false,
1447         withTransform: true,
1448         withUpdateXDomain: true,
1449         withUpdateOrgXDomain: true,
1450         withTransitionForAxis: false
1451       });
1452     } // Bind to resize event
1453
1454
1455     $$.bindResize(); // Bind to window focus event
1456
1457     $$.bindWindowFocus(); // export element of the chart
1458
1459     $$.api.element = $$.selectChart.node();
1460   };
1461
1462   ChartInternal.prototype.smoothLines = function (el, type) {
1463     var $$ = this;
1464
1465     if (type === 'grid') {
1466       el.each(function () {
1467         var g = $$.d3.select(this),
1468             x1 = g.attr('x1'),
1469             x2 = g.attr('x2'),
1470             y1 = g.attr('y1'),
1471             y2 = g.attr('y2');
1472         g.attr({
1473           'x1': Math.ceil(x1),
1474           'x2': Math.ceil(x2),
1475           'y1': Math.ceil(y1),
1476           'y2': Math.ceil(y2)
1477         });
1478       });
1479     }
1480   };
1481
1482   ChartInternal.prototype.updateSizes = function () {
1483     var $$ = this,
1484         config = $$.config;
1485     var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
1486         legendWidth = $$.legend ? $$.getLegendWidth() : 0,
1487         legendHeightForBottom = $$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
1488         hasArc = $$.hasArcType(),
1489         xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
1490         subchartHeight = config.subchart_show && !hasArc ? config.subchart_size_height + xAxisHeight : 0;
1491     $$.currentWidth = $$.getCurrentWidth();
1492     $$.currentHeight = $$.getCurrentHeight(); // for main
1493
1494     $$.margin = config.axis_rotated ? {
1495       top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
1496       right: hasArc ? 0 : $$.getCurrentPaddingRight(),
1497       bottom: $$.getHorizontalAxisHeight('y') + legendHeightForBottom + $$.getCurrentPaddingBottom(),
1498       left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
1499     } : {
1500       top: 4 + $$.getCurrentPaddingTop(),
1501       // for top tick text
1502       right: hasArc ? 0 : $$.getCurrentPaddingRight(),
1503       bottom: xAxisHeight + subchartHeight + legendHeightForBottom + $$.getCurrentPaddingBottom(),
1504       left: hasArc ? 0 : $$.getCurrentPaddingLeft()
1505     }; // for subchart
1506
1507     $$.margin2 = config.axis_rotated ? {
1508       top: $$.margin.top,
1509       right: NaN,
1510       bottom: 20 + legendHeightForBottom,
1511       left: $$.rotated_padding_left
1512     } : {
1513       top: $$.currentHeight - subchartHeight - legendHeightForBottom,
1514       right: NaN,
1515       bottom: xAxisHeight + legendHeightForBottom,
1516       left: $$.margin.left
1517     }; // for legend
1518
1519     $$.margin3 = {
1520       top: 0,
1521       right: NaN,
1522       bottom: 0,
1523       left: 0
1524     };
1525
1526     if ($$.updateSizeForLegend) {
1527       $$.updateSizeForLegend(legendHeight, legendWidth);
1528     }
1529
1530     $$.width = $$.currentWidth - $$.margin.left - $$.margin.right;
1531     $$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom;
1532
1533     if ($$.width < 0) {
1534       $$.width = 0;
1535     }
1536
1537     if ($$.height < 0) {
1538       $$.height = 0;
1539     }
1540
1541     $$.width2 = config.axis_rotated ? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right : $$.width;
1542     $$.height2 = config.axis_rotated ? $$.height : $$.currentHeight - $$.margin2.top - $$.margin2.bottom;
1543
1544     if ($$.width2 < 0) {
1545       $$.width2 = 0;
1546     }
1547
1548     if ($$.height2 < 0) {
1549       $$.height2 = 0;
1550     } // for arc
1551
1552
1553     $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
1554     $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
1555
1556     if ($$.hasType('gauge') && !config.gauge_fullCircle) {
1557       $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
1558     }
1559
1560     if ($$.updateRadius) {
1561       $$.updateRadius();
1562     }
1563
1564     if ($$.isLegendRight && hasArc) {
1565       $$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1;
1566     }
1567   };
1568
1569   ChartInternal.prototype.updateTargets = function (targets) {
1570     var $$ = this;
1571     /*-- Main --*/
1572     //-- Text --//
1573
1574     $$.updateTargetsForText(targets); //-- Bar --//
1575
1576     $$.updateTargetsForBar(targets); //-- Line --//
1577
1578     $$.updateTargetsForLine(targets); //-- Arc --//
1579
1580     if ($$.hasArcType() && $$.updateTargetsForArc) {
1581       $$.updateTargetsForArc(targets);
1582     }
1583     /*-- Sub --*/
1584
1585
1586     if ($$.updateTargetsForSubchart) {
1587       $$.updateTargetsForSubchart(targets);
1588     } // Fade-in each chart
1589
1590
1591     $$.showTargets();
1592   };
1593
1594   ChartInternal.prototype.showTargets = function () {
1595     var $$ = this;
1596     $$.svg.selectAll('.' + CLASS.target).filter(function (d) {
1597       return $$.isTargetToShow(d.id);
1598     }).transition().duration($$.config.transition_duration).style("opacity", 1);
1599   };
1600
1601   ChartInternal.prototype.redraw = function (options, transitions) {
1602     var $$ = this,
1603         main = $$.main,
1604         d3 = $$.d3,
1605         config = $$.config;
1606     var areaIndices = $$.getShapeIndices($$.isAreaType),
1607         barIndices = $$.getShapeIndices($$.isBarType),
1608         lineIndices = $$.getShapeIndices($$.isLineType);
1609     var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis, withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend, withEventRect, withDimension, withUpdateXAxis;
1610     var hideAxis = $$.hasArcType();
1611     var drawArea, drawBar, drawLine, xForText, yForText;
1612     var duration, durationForExit, durationForAxis;
1613     var transitionsToWait, waitForDraw, flow, transition;
1614     var targetsToShow = $$.filterTargetsToShow($$.data.targets),
1615         tickValues,
1616         i,
1617         intervalForCulling,
1618         xDomainForZoom;
1619     var xv = $$.xv.bind($$),
1620         cx,
1621         cy;
1622     options = options || {};
1623     withY = getOption(options, "withY", true);
1624     withSubchart = getOption(options, "withSubchart", true);
1625     withTransition = getOption(options, "withTransition", true);
1626     withTransform = getOption(options, "withTransform", false);
1627     withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
1628     withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
1629     withTrimXDomain = getOption(options, "withTrimXDomain", true);
1630     withUpdateXAxis = getOption(options, "withUpdateXAxis", withUpdateXDomain);
1631     withLegend = getOption(options, "withLegend", false);
1632     withEventRect = getOption(options, "withEventRect", true);
1633     withDimension = getOption(options, "withDimension", true);
1634     withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
1635     withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
1636     duration = withTransition ? config.transition_duration : 0;
1637     durationForExit = withTransitionForExit ? duration : 0;
1638     durationForAxis = withTransitionForAxis ? duration : 0;
1639     transitions = transitions || $$.axis.generateTransitions(durationForAxis); // update legend and transform each g
1640
1641     if (withLegend && config.legend_show) {
1642       $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
1643     } else if (withDimension) {
1644       // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
1645       // no need to update axis in it because they will be updated in redraw()
1646       $$.updateDimension(true);
1647     } // MEMO: needed for grids calculation
1648
1649
1650     if ($$.isCategorized() && targetsToShow.length === 0) {
1651       $$.x.domain([0, $$.axes.x.selectAll('.tick').size()]);
1652     }
1653
1654     if (targetsToShow.length) {
1655       $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
1656
1657       if (!config.axis_x_tick_values) {
1658         tickValues = $$.axis.updateXAxisTickValues(targetsToShow);
1659       }
1660     } else {
1661       $$.xAxis.tickValues([]);
1662       $$.subXAxis.tickValues([]);
1663     }
1664
1665     if (config.zoom_rescale && !options.flow) {
1666       xDomainForZoom = $$.x.orgDomain();
1667     }
1668
1669     $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
1670     $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
1671
1672     if (!config.axis_y_tick_values && config.axis_y_tick_count) {
1673       $$.yAxis.tickValues($$.axis.generateTickValues($$.y.domain(), config.axis_y_tick_count));
1674     }
1675
1676     if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
1677       $$.y2Axis.tickValues($$.axis.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
1678     } // axes
1679
1680
1681     $$.axis.redraw(durationForAxis, hideAxis); // Update axis label
1682
1683     $$.axis.updateLabels(withTransition); // show/hide if manual culling needed
1684
1685     if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
1686       if (config.axis_x_tick_culling && tickValues) {
1687         for (i = 1; i < tickValues.length; i++) {
1688           if (tickValues.length / i < config.axis_x_tick_culling_max) {
1689             intervalForCulling = i;
1690             break;
1691           }
1692         }
1693
1694         $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
1695           var index = tickValues.indexOf(e);
1696
1697           if (index >= 0) {
1698             d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
1699           }
1700         });
1701       } else {
1702         $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
1703       }
1704     } // setup drawer - MEMO: these must be called after axis updated
1705
1706
1707     drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
1708     drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
1709     drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
1710     xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
1711     yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false); // update circleY based on updated parameters
1712
1713     $$.updateCircleY(); // generate circle x/y functions depending on updated params
1714
1715     cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
1716     cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$); // Update sub domain
1717
1718     if (withY) {
1719       $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
1720       $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
1721     } // xgrid focus
1722
1723
1724     $$.updateXgridFocus(); // Data empty label positioning and text.
1725
1726     main.select("text." + CLASS.text + '.' + CLASS.empty).attr("x", $$.width / 2).attr("y", $$.height / 2).text(config.data_empty_label_text).transition().style('opacity', targetsToShow.length ? 0 : 1); // event rect
1727
1728     if (withEventRect) {
1729       $$.redrawEventRect();
1730     } // grid
1731
1732
1733     $$.updateGrid(duration); // rect for regions
1734
1735     $$.updateRegion(duration); // bars
1736
1737     $$.updateBar(durationForExit); // lines, areas and cricles
1738
1739     $$.updateLine(durationForExit);
1740     $$.updateArea(durationForExit);
1741     $$.updateCircle(cx, cy); // text
1742
1743     if ($$.hasDataLabel()) {
1744       $$.updateText(xForText, yForText, durationForExit);
1745     } // title
1746
1747
1748     if ($$.redrawTitle) {
1749       $$.redrawTitle();
1750     } // arc
1751
1752
1753     if ($$.redrawArc) {
1754       $$.redrawArc(duration, durationForExit, withTransform);
1755     } // subchart
1756
1757
1758     if ($$.redrawSubchart) {
1759       $$.redrawSubchart(withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices);
1760     } // circles for select
1761
1762
1763     main.selectAll('.' + CLASS.selectedCircles).filter($$.isBarType.bind($$)).selectAll('circle').remove();
1764
1765     if (options.flow) {
1766       flow = $$.generateFlow({
1767         targets: targetsToShow,
1768         flow: options.flow,
1769         duration: options.flow.duration,
1770         drawBar: drawBar,
1771         drawLine: drawLine,
1772         drawArea: drawArea,
1773         cx: cx,
1774         cy: cy,
1775         xv: xv,
1776         xForText: xForText,
1777         yForText: yForText
1778       });
1779     }
1780
1781     if ($$.isTabVisible()) {
1782       // Only use transition if tab visible. See #938.
1783       if (duration) {
1784         // transition should be derived from one transition
1785         transition = d3.transition().duration(duration);
1786         transitionsToWait = [];
1787         [$$.redrawBar(drawBar, true, transition), $$.redrawLine(drawLine, true, transition), $$.redrawArea(drawArea, true, transition), $$.redrawCircle(cx, cy, true, transition), $$.redrawText(xForText, yForText, options.flow, true, transition), $$.redrawRegion(true, transition), $$.redrawGrid(true, transition)].forEach(function (transitions) {
1788           transitions.forEach(function (transition) {
1789             transitionsToWait.push(transition);
1790           });
1791         }); // Wait for end of transitions to call flow and onrendered callback
1792
1793         waitForDraw = $$.generateWait();
1794         transitionsToWait.forEach(function (t) {
1795           waitForDraw.add(t);
1796         });
1797         waitForDraw(function () {
1798           if (flow) {
1799             flow();
1800           }
1801
1802           if (config.onrendered) {
1803             config.onrendered.call($$);
1804           }
1805         });
1806       } else {
1807         $$.redrawBar(drawBar);
1808         $$.redrawLine(drawLine);
1809         $$.redrawArea(drawArea);
1810         $$.redrawCircle(cx, cy);
1811         $$.redrawText(xForText, yForText, options.flow);
1812         $$.redrawRegion();
1813         $$.redrawGrid();
1814
1815         if (flow) {
1816           flow();
1817         }
1818
1819         if (config.onrendered) {
1820           config.onrendered.call($$);
1821         }
1822       }
1823     } // update fadein condition
1824
1825
1826     $$.mapToIds($$.data.targets).forEach(function (id) {
1827       $$.withoutFadeIn[id] = true;
1828     });
1829   };
1830
1831   ChartInternal.prototype.updateAndRedraw = function (options) {
1832     var $$ = this,
1833         config = $$.config,
1834         transitions;
1835     options = options || {}; // same with redraw
1836
1837     options.withTransition = getOption(options, "withTransition", true);
1838     options.withTransform = getOption(options, "withTransform", false);
1839     options.withLegend = getOption(options, "withLegend", false); // NOT same with redraw
1840
1841     options.withUpdateXDomain = getOption(options, "withUpdateXDomain", true);
1842     options.withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", true);
1843     options.withTransitionForExit = false;
1844     options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition); // MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
1845
1846     $$.updateSizes(); // MEMO: called in updateLegend in redraw if withLegend
1847
1848     if (!(options.withLegend && config.legend_show)) {
1849       transitions = $$.axis.generateTransitions(options.withTransitionForAxis ? config.transition_duration : 0); // Update scales
1850
1851       $$.updateScales();
1852       $$.updateSvgSize(); // Update g positions
1853
1854       $$.transformAll(options.withTransitionForTransform, transitions);
1855     } // Draw with new sizes & scales
1856
1857
1858     $$.redraw(options, transitions);
1859   };
1860
1861   ChartInternal.prototype.redrawWithoutRescale = function () {
1862     this.redraw({
1863       withY: false,
1864       withSubchart: false,
1865       withEventRect: false,
1866       withTransitionForAxis: false
1867     });
1868   };
1869
1870   ChartInternal.prototype.isTimeSeries = function () {
1871     return this.config.axis_x_type === 'timeseries';
1872   };
1873
1874   ChartInternal.prototype.isCategorized = function () {
1875     return this.config.axis_x_type.indexOf('categor') >= 0;
1876   };
1877
1878   ChartInternal.prototype.isCustomX = function () {
1879     var $$ = this,
1880         config = $$.config;
1881     return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
1882   };
1883
1884   ChartInternal.prototype.isTimeSeriesY = function () {
1885     return this.config.axis_y_type === 'timeseries';
1886   };
1887
1888   ChartInternal.prototype.getTranslate = function (target) {
1889     var $$ = this,
1890         config = $$.config,
1891         x,
1892         y;
1893
1894     if (target === 'main') {
1895       x = asHalfPixel($$.margin.left);
1896       y = asHalfPixel($$.margin.top);
1897     } else if (target === 'context') {
1898       x = asHalfPixel($$.margin2.left);
1899       y = asHalfPixel($$.margin2.top);
1900     } else if (target === 'legend') {
1901       x = $$.margin3.left;
1902       y = $$.margin3.top;
1903     } else if (target === 'x') {
1904       x = 0;
1905       y = config.axis_rotated ? 0 : $$.height;
1906     } else if (target === 'y') {
1907       x = 0;
1908       y = config.axis_rotated ? $$.height : 0;
1909     } else if (target === 'y2') {
1910       x = config.axis_rotated ? 0 : $$.width;
1911       y = config.axis_rotated ? 1 : 0;
1912     } else if (target === 'subx') {
1913       x = 0;
1914       y = config.axis_rotated ? 0 : $$.height2;
1915     } else if (target === 'arc') {
1916       x = $$.arcWidth / 2;
1917       y = $$.arcHeight / 2 - ($$.hasType('gauge') ? 6 : 0); // to prevent wrong display of min and max label
1918     }
1919
1920     return "translate(" + x + "," + y + ")";
1921   };
1922
1923   ChartInternal.prototype.initialOpacity = function (d) {
1924     return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
1925   };
1926
1927   ChartInternal.prototype.initialOpacityForCircle = function (d) {
1928     return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
1929   };
1930
1931   ChartInternal.prototype.opacityForCircle = function (d) {
1932     var isPointShouldBeShown = isFunction(this.config.point_show) ? this.config.point_show(d) : this.config.point_show;
1933     var opacity = isPointShouldBeShown ? 1 : 0;
1934     return isValue(d.value) ? this.isScatterType(d) ? 0.5 : opacity : 0;
1935   };
1936
1937   ChartInternal.prototype.opacityForText = function () {
1938     return this.hasDataLabel() ? 1 : 0;
1939   };
1940
1941   ChartInternal.prototype.xx = function (d) {
1942     return d ? this.x(d.x) : null;
1943   };
1944
1945   ChartInternal.prototype.xv = function (d) {
1946     var $$ = this,
1947         value = d.value;
1948
1949     if ($$.isTimeSeries()) {
1950       value = $$.parseDate(d.value);
1951     } else if ($$.isCategorized() && typeof d.value === 'string') {
1952       value = $$.config.axis_x_categories.indexOf(d.value);
1953     }
1954
1955     return Math.ceil($$.x(value));
1956   };
1957
1958   ChartInternal.prototype.yv = function (d) {
1959     var $$ = this,
1960         yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y;
1961     return Math.ceil(yScale(d.value));
1962   };
1963
1964   ChartInternal.prototype.subxx = function (d) {
1965     return d ? this.subX(d.x) : null;
1966   };
1967
1968   ChartInternal.prototype.transformMain = function (withTransition, transitions) {
1969     var $$ = this,
1970         xAxis,
1971         yAxis,
1972         y2Axis;
1973
1974     if (transitions && transitions.axisX) {
1975       xAxis = transitions.axisX;
1976     } else {
1977       xAxis = $$.main.select('.' + CLASS.axisX);
1978
1979       if (withTransition) {
1980         xAxis = xAxis.transition();
1981       }
1982     }
1983
1984     if (transitions && transitions.axisY) {
1985       yAxis = transitions.axisY;
1986     } else {
1987       yAxis = $$.main.select('.' + CLASS.axisY);
1988
1989       if (withTransition) {
1990         yAxis = yAxis.transition();
1991       }
1992     }
1993
1994     if (transitions && transitions.axisY2) {
1995       y2Axis = transitions.axisY2;
1996     } else {
1997       y2Axis = $$.main.select('.' + CLASS.axisY2);
1998
1999       if (withTransition) {
2000         y2Axis = y2Axis.transition();
2001       }
2002     }
2003
2004     (withTransition ? $$.main.transition() : $$.main).attr("transform", $$.getTranslate('main'));
2005     xAxis.attr("transform", $$.getTranslate('x'));
2006     yAxis.attr("transform", $$.getTranslate('y'));
2007     y2Axis.attr("transform", $$.getTranslate('y2'));
2008     $$.main.select('.' + CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
2009   };
2010
2011   ChartInternal.prototype.transformAll = function (withTransition, transitions) {
2012     var $$ = this;
2013     $$.transformMain(withTransition, transitions);
2014
2015     if ($$.config.subchart_show) {
2016       $$.transformContext(withTransition, transitions);
2017     }
2018
2019     if ($$.legend) {
2020       $$.transformLegend(withTransition);
2021     }
2022   };
2023
2024   ChartInternal.prototype.updateSvgSize = function () {
2025     var $$ = this,
2026         brush = $$.svg.select(".c3-brush .overlay");
2027     $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
2028     $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect').attr('width', $$.width).attr('height', $$.height);
2029     $$.svg.select('#' + $$.clipIdForXAxis).select('rect').attr('x', $$.getXAxisClipX.bind($$)).attr('y', $$.getXAxisClipY.bind($$)).attr('width', $$.getXAxisClipWidth.bind($$)).attr('height', $$.getXAxisClipHeight.bind($$));
2030     $$.svg.select('#' + $$.clipIdForYAxis).select('rect').attr('x', $$.getYAxisClipX.bind($$)).attr('y', $$.getYAxisClipY.bind($$)).attr('width', $$.getYAxisClipWidth.bind($$)).attr('height', $$.getYAxisClipHeight.bind($$));
2031     $$.svg.select('#' + $$.clipIdForSubchart).select('rect').attr('width', $$.width).attr('height', brush.size() ? brush.attr('height') : 0); // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
2032
2033     $$.selectChart.style('max-height', $$.currentHeight + "px");
2034   };
2035
2036   ChartInternal.prototype.updateDimension = function (withoutAxis) {
2037     var $$ = this;
2038
2039     if (!withoutAxis) {
2040       if ($$.config.axis_rotated) {
2041         $$.axes.x.call($$.xAxis);
2042         $$.axes.subx.call($$.subXAxis);
2043       } else {
2044         $$.axes.y.call($$.yAxis);
2045         $$.axes.y2.call($$.y2Axis);
2046       }
2047     }
2048
2049     $$.updateSizes();
2050     $$.updateScales();
2051     $$.updateSvgSize();
2052     $$.transformAll(false);
2053   };
2054
2055   ChartInternal.prototype.observeInserted = function (selection) {
2056     var $$ = this,
2057         observer;
2058
2059     if (typeof MutationObserver === 'undefined') {
2060       window.console.error("MutationObserver not defined.");
2061       return;
2062     }
2063
2064     observer = new MutationObserver(function (mutations) {
2065       mutations.forEach(function (mutation) {
2066         if (mutation.type === 'childList' && mutation.previousSibling) {
2067           observer.disconnect(); // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
2068
2069           $$.intervalForObserveInserted = window.setInterval(function () {
2070             // parentNode will NOT be null when completed
2071             if (selection.node().parentNode) {
2072               window.clearInterval($$.intervalForObserveInserted);
2073               $$.updateDimension();
2074
2075               if ($$.brush) {
2076                 $$.brush.update();
2077               }
2078
2079               $$.config.oninit.call($$);
2080               $$.redraw({
2081                 withTransform: true,
2082                 withUpdateXDomain: true,
2083                 withUpdateOrgXDomain: true,
2084                 withTransition: false,
2085                 withTransitionForTransform: false,
2086                 withLegend: true
2087               });
2088               selection.transition().style('opacity', 1);
2089             }
2090           }, 10);
2091         }
2092       });
2093     });
2094     observer.observe(selection.node(), {
2095       attributes: true,
2096       childList: true,
2097       characterData: true
2098     });
2099   };
2100   /**
2101    * Binds handlers to the window resize event.
2102    */
2103
2104
2105   ChartInternal.prototype.bindResize = function () {
2106     var $$ = this,
2107         config = $$.config;
2108     $$.resizeFunction = $$.generateResize(); // need to call .remove
2109
2110     $$.resizeFunction.add(function () {
2111       config.onresize.call($$);
2112     });
2113
2114     if (config.resize_auto) {
2115       $$.resizeFunction.add(function () {
2116         if ($$.resizeTimeout !== undefined) {
2117           window.clearTimeout($$.resizeTimeout);
2118         }
2119
2120         $$.resizeTimeout = window.setTimeout(function () {
2121           delete $$.resizeTimeout;
2122           $$.updateAndRedraw({
2123             withUpdateXDomain: false,
2124             withUpdateOrgXDomain: false,
2125             withTransition: false,
2126             withTransitionForTransform: false,
2127             withLegend: true
2128           });
2129
2130           if ($$.brush) {
2131             $$.brush.update();
2132           }
2133         }, 100);
2134       });
2135     }
2136
2137     $$.resizeFunction.add(function () {
2138       config.onresized.call($$);
2139     });
2140
2141     $$.resizeIfElementDisplayed = function () {
2142       // if element not displayed skip it
2143       if ($$.api == null || !$$.api.element.offsetParent) {
2144         return;
2145       }
2146
2147       $$.resizeFunction();
2148     };
2149
2150     if (window.attachEvent) {
2151       window.attachEvent('onresize', $$.resizeIfElementDisplayed);
2152     } else if (window.addEventListener) {
2153       window.addEventListener('resize', $$.resizeIfElementDisplayed, false);
2154     } else {
2155       // fallback to this, if this is a very old browser
2156       var wrapper = window.onresize;
2157
2158       if (!wrapper) {
2159         // create a wrapper that will call all charts
2160         wrapper = $$.generateResize();
2161       } else if (!wrapper.add || !wrapper.remove) {
2162         // there is already a handler registered, make sure we call it too
2163         wrapper = $$.generateResize();
2164         wrapper.add(window.onresize);
2165       } // add this graph to the wrapper, we will be removed if the user calls destroy
2166
2167
2168       wrapper.add($$.resizeFunction);
2169
2170       window.onresize = function () {
2171         // if element not displayed skip it
2172         if (!$$.api.element.offsetParent) {
2173           return;
2174         }
2175
2176         wrapper();
2177       };
2178     }
2179   };
2180   /**
2181    * Binds handlers to the window focus event.
2182    */
2183
2184
2185   ChartInternal.prototype.bindWindowFocus = function () {
2186     var _this = this;
2187
2188     if (this.windowFocusHandler) {
2189       // The handler is already set
2190       return;
2191     }
2192
2193     this.windowFocusHandler = function () {
2194       _this.redraw();
2195     };
2196
2197     window.addEventListener('focus', this.windowFocusHandler);
2198   };
2199   /**
2200    * Unbinds from the window focus event.
2201    */
2202
2203
2204   ChartInternal.prototype.unbindWindowFocus = function () {
2205     window.removeEventListener('focus', this.windowFocusHandler);
2206     delete this.windowFocusHandler;
2207   };
2208
2209   ChartInternal.prototype.generateResize = function () {
2210     var resizeFunctions = [];
2211
2212     function callResizeFunctions() {
2213       resizeFunctions.forEach(function (f) {
2214         f();
2215       });
2216     }
2217
2218     callResizeFunctions.add = function (f) {
2219       resizeFunctions.push(f);
2220     };
2221
2222     callResizeFunctions.remove = function (f) {
2223       for (var i = 0; i < resizeFunctions.length; i++) {
2224         if (resizeFunctions[i] === f) {
2225           resizeFunctions.splice(i, 1);
2226           break;
2227         }
2228       }
2229     };
2230
2231     return callResizeFunctions;
2232   };
2233
2234   ChartInternal.prototype.endall = function (transition, callback) {
2235     var n = 0;
2236     transition.each(function () {
2237       ++n;
2238     }).on("end", function () {
2239       if (! --n) {
2240         callback.apply(this, arguments);
2241       }
2242     });
2243   };
2244
2245   ChartInternal.prototype.generateWait = function () {
2246     var transitionsToWait = [],
2247         f = function f(callback) {
2248       var timer = setInterval(function () {
2249         var done = 0;
2250         transitionsToWait.forEach(function (t) {
2251           if (t.empty()) {
2252             done += 1;
2253             return;
2254           }
2255
2256           try {
2257             t.transition();
2258           } catch (e) {
2259             done += 1;
2260           }
2261         });
2262
2263         if (done === transitionsToWait.length) {
2264           clearInterval(timer);
2265
2266           if (callback) {
2267             callback();
2268           }
2269         }
2270       }, 50);
2271     };
2272
2273     f.add = function (transition) {
2274       transitionsToWait.push(transition);
2275     };
2276
2277     return f;
2278   };
2279
2280   ChartInternal.prototype.parseDate = function (date) {
2281     var $$ = this,
2282         parsedDate;
2283
2284     if (date instanceof Date) {
2285       parsedDate = date;
2286     } else if (typeof date === 'string') {
2287       parsedDate = $$.dataTimeParse(date);
2288     } else if (_typeof(date) === 'object') {
2289       parsedDate = new Date(+date);
2290     } else if (typeof date === 'number' && !isNaN(date)) {
2291       parsedDate = new Date(+date);
2292     }
2293
2294     if (!parsedDate || isNaN(+parsedDate)) {
2295       window.console.error("Failed to parse x '" + date + "' to Date object");
2296     }
2297
2298     return parsedDate;
2299   };
2300
2301   ChartInternal.prototype.isTabVisible = function () {
2302     return !document.hidden;
2303   };
2304
2305   ChartInternal.prototype.getPathBox = getPathBox;
2306   ChartInternal.prototype.CLASS = CLASS;
2307
2308   /* jshint ignore:start */
2309   // SVGPathSeg API polyfill
2310   // https://github.com/progers/pathseg
2311   //
2312   // This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from
2313   // SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec
2314   // changes which were implemented in Firefox 43 and Chrome 46.
2315   (function () {
2316
2317     if (!("SVGPathSeg" in window)) {
2318       // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
2319       window.SVGPathSeg = function (type, typeAsLetter, owningPathSegList) {
2320         this.pathSegType = type;
2321         this.pathSegTypeAsLetter = typeAsLetter;
2322         this._owningPathSegList = owningPathSegList;
2323       };
2324
2325       window.SVGPathSeg.prototype.classname = "SVGPathSeg";
2326       window.SVGPathSeg.PATHSEG_UNKNOWN = 0;
2327       window.SVGPathSeg.PATHSEG_CLOSEPATH = 1;
2328       window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
2329       window.SVGPathSeg.PATHSEG_MOVETO_REL = 3;
2330       window.SVGPathSeg.PATHSEG_LINETO_ABS = 4;
2331       window.SVGPathSeg.PATHSEG_LINETO_REL = 5;
2332       window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
2333       window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
2334       window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
2335       window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
2336       window.SVGPathSeg.PATHSEG_ARC_ABS = 10;
2337       window.SVGPathSeg.PATHSEG_ARC_REL = 11;
2338       window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
2339       window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
2340       window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
2341       window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
2342       window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
2343       window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
2344       window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
2345       window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; // Notify owning PathSegList on any changes so they can be synchronized back to the path element.
2346
2347       window.SVGPathSeg.prototype._segmentChanged = function () {
2348         if (this._owningPathSegList) this._owningPathSegList.segmentChanged(this);
2349       };
2350
2351       window.SVGPathSegClosePath = function (owningPathSegList) {
2352         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList);
2353       };
2354
2355       window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype);
2356
2357       window.SVGPathSegClosePath.prototype.toString = function () {
2358         return "[object SVGPathSegClosePath]";
2359       };
2360
2361       window.SVGPathSegClosePath.prototype._asPathString = function () {
2362         return this.pathSegTypeAsLetter;
2363       };
2364
2365       window.SVGPathSegClosePath.prototype.clone = function () {
2366         return new window.SVGPathSegClosePath(undefined);
2367       };
2368
2369       window.SVGPathSegMovetoAbs = function (owningPathSegList, x, y) {
2370         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList);
2371         this._x = x;
2372         this._y = y;
2373       };
2374
2375       window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
2376
2377       window.SVGPathSegMovetoAbs.prototype.toString = function () {
2378         return "[object SVGPathSegMovetoAbs]";
2379       };
2380
2381       window.SVGPathSegMovetoAbs.prototype._asPathString = function () {
2382         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
2383       };
2384
2385       window.SVGPathSegMovetoAbs.prototype.clone = function () {
2386         return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y);
2387       };
2388
2389       Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "x", {
2390         get: function get() {
2391           return this._x;
2392         },
2393         set: function set(x) {
2394           this._x = x;
2395
2396           this._segmentChanged();
2397         },
2398         enumerable: true
2399       });
2400       Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "y", {
2401         get: function get() {
2402           return this._y;
2403         },
2404         set: function set(y) {
2405           this._y = y;
2406
2407           this._segmentChanged();
2408         },
2409         enumerable: true
2410       });
2411
2412       window.SVGPathSegMovetoRel = function (owningPathSegList, x, y) {
2413         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList);
2414         this._x = x;
2415         this._y = y;
2416       };
2417
2418       window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
2419
2420       window.SVGPathSegMovetoRel.prototype.toString = function () {
2421         return "[object SVGPathSegMovetoRel]";
2422       };
2423
2424       window.SVGPathSegMovetoRel.prototype._asPathString = function () {
2425         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
2426       };
2427
2428       window.SVGPathSegMovetoRel.prototype.clone = function () {
2429         return new window.SVGPathSegMovetoRel(undefined, this._x, this._y);
2430       };
2431
2432       Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "x", {
2433         get: function get() {
2434           return this._x;
2435         },
2436         set: function set(x) {
2437           this._x = x;
2438
2439           this._segmentChanged();
2440         },
2441         enumerable: true
2442       });
2443       Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "y", {
2444         get: function get() {
2445           return this._y;
2446         },
2447         set: function set(y) {
2448           this._y = y;
2449
2450           this._segmentChanged();
2451         },
2452         enumerable: true
2453       });
2454
2455       window.SVGPathSegLinetoAbs = function (owningPathSegList, x, y) {
2456         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList);
2457         this._x = x;
2458         this._y = y;
2459       };
2460
2461       window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
2462
2463       window.SVGPathSegLinetoAbs.prototype.toString = function () {
2464         return "[object SVGPathSegLinetoAbs]";
2465       };
2466
2467       window.SVGPathSegLinetoAbs.prototype._asPathString = function () {
2468         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
2469       };
2470
2471       window.SVGPathSegLinetoAbs.prototype.clone = function () {
2472         return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y);
2473       };
2474
2475       Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "x", {
2476         get: function get() {
2477           return this._x;
2478         },
2479         set: function set(x) {
2480           this._x = x;
2481
2482           this._segmentChanged();
2483         },
2484         enumerable: true
2485       });
2486       Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "y", {
2487         get: function get() {
2488           return this._y;
2489         },
2490         set: function set(y) {
2491           this._y = y;
2492
2493           this._segmentChanged();
2494         },
2495         enumerable: true
2496       });
2497
2498       window.SVGPathSegLinetoRel = function (owningPathSegList, x, y) {
2499         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList);
2500         this._x = x;
2501         this._y = y;
2502       };
2503
2504       window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
2505
2506       window.SVGPathSegLinetoRel.prototype.toString = function () {
2507         return "[object SVGPathSegLinetoRel]";
2508       };
2509
2510       window.SVGPathSegLinetoRel.prototype._asPathString = function () {
2511         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
2512       };
2513
2514       window.SVGPathSegLinetoRel.prototype.clone = function () {
2515         return new window.SVGPathSegLinetoRel(undefined, this._x, this._y);
2516       };
2517
2518       Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "x", {
2519         get: function get() {
2520           return this._x;
2521         },
2522         set: function set(x) {
2523           this._x = x;
2524
2525           this._segmentChanged();
2526         },
2527         enumerable: true
2528       });
2529       Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "y", {
2530         get: function get() {
2531           return this._y;
2532         },
2533         set: function set(y) {
2534           this._y = y;
2535
2536           this._segmentChanged();
2537         },
2538         enumerable: true
2539       });
2540
2541       window.SVGPathSegCurvetoCubicAbs = function (owningPathSegList, x, y, x1, y1, x2, y2) {
2542         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList);
2543         this._x = x;
2544         this._y = y;
2545         this._x1 = x1;
2546         this._y1 = y1;
2547         this._x2 = x2;
2548         this._y2 = y2;
2549       };
2550
2551       window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype);
2552
2553       window.SVGPathSegCurvetoCubicAbs.prototype.toString = function () {
2554         return "[object SVGPathSegCurvetoCubicAbs]";
2555       };
2556
2557       window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function () {
2558         return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y;
2559       };
2560
2561       window.SVGPathSegCurvetoCubicAbs.prototype.clone = function () {
2562         return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2);
2563       };
2564
2565       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x", {
2566         get: function get() {
2567           return this._x;
2568         },
2569         set: function set(x) {
2570           this._x = x;
2571
2572           this._segmentChanged();
2573         },
2574         enumerable: true
2575       });
2576       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y", {
2577         get: function get() {
2578           return this._y;
2579         },
2580         set: function set(y) {
2581           this._y = y;
2582
2583           this._segmentChanged();
2584         },
2585         enumerable: true
2586       });
2587       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x1", {
2588         get: function get() {
2589           return this._x1;
2590         },
2591         set: function set(x1) {
2592           this._x1 = x1;
2593
2594           this._segmentChanged();
2595         },
2596         enumerable: true
2597       });
2598       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y1", {
2599         get: function get() {
2600           return this._y1;
2601         },
2602         set: function set(y1) {
2603           this._y1 = y1;
2604
2605           this._segmentChanged();
2606         },
2607         enumerable: true
2608       });
2609       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x2", {
2610         get: function get() {
2611           return this._x2;
2612         },
2613         set: function set(x2) {
2614           this._x2 = x2;
2615
2616           this._segmentChanged();
2617         },
2618         enumerable: true
2619       });
2620       Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y2", {
2621         get: function get() {
2622           return this._y2;
2623         },
2624         set: function set(y2) {
2625           this._y2 = y2;
2626
2627           this._segmentChanged();
2628         },
2629         enumerable: true
2630       });
2631
2632       window.SVGPathSegCurvetoCubicRel = function (owningPathSegList, x, y, x1, y1, x2, y2) {
2633         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList);
2634         this._x = x;
2635         this._y = y;
2636         this._x1 = x1;
2637         this._y1 = y1;
2638         this._x2 = x2;
2639         this._y2 = y2;
2640       };
2641
2642       window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype);
2643
2644       window.SVGPathSegCurvetoCubicRel.prototype.toString = function () {
2645         return "[object SVGPathSegCurvetoCubicRel]";
2646       };
2647
2648       window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function () {
2649         return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y;
2650       };
2651
2652       window.SVGPathSegCurvetoCubicRel.prototype.clone = function () {
2653         return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2);
2654       };
2655
2656       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x", {
2657         get: function get() {
2658           return this._x;
2659         },
2660         set: function set(x) {
2661           this._x = x;
2662
2663           this._segmentChanged();
2664         },
2665         enumerable: true
2666       });
2667       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y", {
2668         get: function get() {
2669           return this._y;
2670         },
2671         set: function set(y) {
2672           this._y = y;
2673
2674           this._segmentChanged();
2675         },
2676         enumerable: true
2677       });
2678       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x1", {
2679         get: function get() {
2680           return this._x1;
2681         },
2682         set: function set(x1) {
2683           this._x1 = x1;
2684
2685           this._segmentChanged();
2686         },
2687         enumerable: true
2688       });
2689       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y1", {
2690         get: function get() {
2691           return this._y1;
2692         },
2693         set: function set(y1) {
2694           this._y1 = y1;
2695
2696           this._segmentChanged();
2697         },
2698         enumerable: true
2699       });
2700       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x2", {
2701         get: function get() {
2702           return this._x2;
2703         },
2704         set: function set(x2) {
2705           this._x2 = x2;
2706
2707           this._segmentChanged();
2708         },
2709         enumerable: true
2710       });
2711       Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y2", {
2712         get: function get() {
2713           return this._y2;
2714         },
2715         set: function set(y2) {
2716           this._y2 = y2;
2717
2718           this._segmentChanged();
2719         },
2720         enumerable: true
2721       });
2722
2723       window.SVGPathSegCurvetoQuadraticAbs = function (owningPathSegList, x, y, x1, y1) {
2724         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList);
2725         this._x = x;
2726         this._y = y;
2727         this._x1 = x1;
2728         this._y1 = y1;
2729       };
2730
2731       window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype);
2732
2733       window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function () {
2734         return "[object SVGPathSegCurvetoQuadraticAbs]";
2735       };
2736
2737       window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function () {
2738         return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y;
2739       };
2740
2741       window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function () {
2742         return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1);
2743       };
2744
2745       Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x", {
2746         get: function get() {
2747           return this._x;
2748         },
2749         set: function set(x) {
2750           this._x = x;
2751
2752           this._segmentChanged();
2753         },
2754         enumerable: true
2755       });
2756       Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y", {
2757         get: function get() {
2758           return this._y;
2759         },
2760         set: function set(y) {
2761           this._y = y;
2762
2763           this._segmentChanged();
2764         },
2765         enumerable: true
2766       });
2767       Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x1", {
2768         get: function get() {
2769           return this._x1;
2770         },
2771         set: function set(x1) {
2772           this._x1 = x1;
2773
2774           this._segmentChanged();
2775         },
2776         enumerable: true
2777       });
2778       Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y1", {
2779         get: function get() {
2780           return this._y1;
2781         },
2782         set: function set(y1) {
2783           this._y1 = y1;
2784
2785           this._segmentChanged();
2786         },
2787         enumerable: true
2788       });
2789
2790       window.SVGPathSegCurvetoQuadraticRel = function (owningPathSegList, x, y, x1, y1) {
2791         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList);
2792         this._x = x;
2793         this._y = y;
2794         this._x1 = x1;
2795         this._y1 = y1;
2796       };
2797
2798       window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype);
2799
2800       window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function () {
2801         return "[object SVGPathSegCurvetoQuadraticRel]";
2802       };
2803
2804       window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function () {
2805         return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y;
2806       };
2807
2808       window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function () {
2809         return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1);
2810       };
2811
2812       Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x", {
2813         get: function get() {
2814           return this._x;
2815         },
2816         set: function set(x) {
2817           this._x = x;
2818
2819           this._segmentChanged();
2820         },
2821         enumerable: true
2822       });
2823       Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y", {
2824         get: function get() {
2825           return this._y;
2826         },
2827         set: function set(y) {
2828           this._y = y;
2829
2830           this._segmentChanged();
2831         },
2832         enumerable: true
2833       });
2834       Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x1", {
2835         get: function get() {
2836           return this._x1;
2837         },
2838         set: function set(x1) {
2839           this._x1 = x1;
2840
2841           this._segmentChanged();
2842         },
2843         enumerable: true
2844       });
2845       Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y1", {
2846         get: function get() {
2847           return this._y1;
2848         },
2849         set: function set(y1) {
2850           this._y1 = y1;
2851
2852           this._segmentChanged();
2853         },
2854         enumerable: true
2855       });
2856
2857       window.SVGPathSegArcAbs = function (owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
2858         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList);
2859         this._x = x;
2860         this._y = y;
2861         this._r1 = r1;
2862         this._r2 = r2;
2863         this._angle = angle;
2864         this._largeArcFlag = largeArcFlag;
2865         this._sweepFlag = sweepFlag;
2866       };
2867
2868       window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype);
2869
2870       window.SVGPathSegArcAbs.prototype.toString = function () {
2871         return "[object SVGPathSegArcAbs]";
2872       };
2873
2874       window.SVGPathSegArcAbs.prototype._asPathString = function () {
2875         return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y;
2876       };
2877
2878       window.SVGPathSegArcAbs.prototype.clone = function () {
2879         return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag);
2880       };
2881
2882       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "x", {
2883         get: function get() {
2884           return this._x;
2885         },
2886         set: function set(x) {
2887           this._x = x;
2888
2889           this._segmentChanged();
2890         },
2891         enumerable: true
2892       });
2893       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "y", {
2894         get: function get() {
2895           return this._y;
2896         },
2897         set: function set(y) {
2898           this._y = y;
2899
2900           this._segmentChanged();
2901         },
2902         enumerable: true
2903       });
2904       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r1", {
2905         get: function get() {
2906           return this._r1;
2907         },
2908         set: function set(r1) {
2909           this._r1 = r1;
2910
2911           this._segmentChanged();
2912         },
2913         enumerable: true
2914       });
2915       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r2", {
2916         get: function get() {
2917           return this._r2;
2918         },
2919         set: function set(r2) {
2920           this._r2 = r2;
2921
2922           this._segmentChanged();
2923         },
2924         enumerable: true
2925       });
2926       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "angle", {
2927         get: function get() {
2928           return this._angle;
2929         },
2930         set: function set(angle) {
2931           this._angle = angle;
2932
2933           this._segmentChanged();
2934         },
2935         enumerable: true
2936       });
2937       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "largeArcFlag", {
2938         get: function get() {
2939           return this._largeArcFlag;
2940         },
2941         set: function set(largeArcFlag) {
2942           this._largeArcFlag = largeArcFlag;
2943
2944           this._segmentChanged();
2945         },
2946         enumerable: true
2947       });
2948       Object.defineProperty(window.SVGPathSegArcAbs.prototype, "sweepFlag", {
2949         get: function get() {
2950           return this._sweepFlag;
2951         },
2952         set: function set(sweepFlag) {
2953           this._sweepFlag = sweepFlag;
2954
2955           this._segmentChanged();
2956         },
2957         enumerable: true
2958       });
2959
2960       window.SVGPathSegArcRel = function (owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
2961         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList);
2962         this._x = x;
2963         this._y = y;
2964         this._r1 = r1;
2965         this._r2 = r2;
2966         this._angle = angle;
2967         this._largeArcFlag = largeArcFlag;
2968         this._sweepFlag = sweepFlag;
2969       };
2970
2971       window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype);
2972
2973       window.SVGPathSegArcRel.prototype.toString = function () {
2974         return "[object SVGPathSegArcRel]";
2975       };
2976
2977       window.SVGPathSegArcRel.prototype._asPathString = function () {
2978         return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y;
2979       };
2980
2981       window.SVGPathSegArcRel.prototype.clone = function () {
2982         return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag);
2983       };
2984
2985       Object.defineProperty(window.SVGPathSegArcRel.prototype, "x", {
2986         get: function get() {
2987           return this._x;
2988         },
2989         set: function set(x) {
2990           this._x = x;
2991
2992           this._segmentChanged();
2993         },
2994         enumerable: true
2995       });
2996       Object.defineProperty(window.SVGPathSegArcRel.prototype, "y", {
2997         get: function get() {
2998           return this._y;
2999         },
3000         set: function set(y) {
3001           this._y = y;
3002
3003           this._segmentChanged();
3004         },
3005         enumerable: true
3006       });
3007       Object.defineProperty(window.SVGPathSegArcRel.prototype, "r1", {
3008         get: function get() {
3009           return this._r1;
3010         },
3011         set: function set(r1) {
3012           this._r1 = r1;
3013
3014           this._segmentChanged();
3015         },
3016         enumerable: true
3017       });
3018       Object.defineProperty(window.SVGPathSegArcRel.prototype, "r2", {
3019         get: function get() {
3020           return this._r2;
3021         },
3022         set: function set(r2) {
3023           this._r2 = r2;
3024
3025           this._segmentChanged();
3026         },
3027         enumerable: true
3028       });
3029       Object.defineProperty(window.SVGPathSegArcRel.prototype, "angle", {
3030         get: function get() {
3031           return this._angle;
3032         },
3033         set: function set(angle) {
3034           this._angle = angle;
3035
3036           this._segmentChanged();
3037         },
3038         enumerable: true
3039       });
3040       Object.defineProperty(window.SVGPathSegArcRel.prototype, "largeArcFlag", {
3041         get: function get() {
3042           return this._largeArcFlag;
3043         },
3044         set: function set(largeArcFlag) {
3045           this._largeArcFlag = largeArcFlag;
3046
3047           this._segmentChanged();
3048         },
3049         enumerable: true
3050       });
3051       Object.defineProperty(window.SVGPathSegArcRel.prototype, "sweepFlag", {
3052         get: function get() {
3053           return this._sweepFlag;
3054         },
3055         set: function set(sweepFlag) {
3056           this._sweepFlag = sweepFlag;
3057
3058           this._segmentChanged();
3059         },
3060         enumerable: true
3061       });
3062
3063       window.SVGPathSegLinetoHorizontalAbs = function (owningPathSegList, x) {
3064         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList);
3065         this._x = x;
3066       };
3067
3068       window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
3069
3070       window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function () {
3071         return "[object SVGPathSegLinetoHorizontalAbs]";
3072       };
3073
3074       window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function () {
3075         return this.pathSegTypeAsLetter + " " + this._x;
3076       };
3077
3078       window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function () {
3079         return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x);
3080       };
3081
3082       Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, "x", {
3083         get: function get() {
3084           return this._x;
3085         },
3086         set: function set(x) {
3087           this._x = x;
3088
3089           this._segmentChanged();
3090         },
3091         enumerable: true
3092       });
3093
3094       window.SVGPathSegLinetoHorizontalRel = function (owningPathSegList, x) {
3095         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList);
3096         this._x = x;
3097       };
3098
3099       window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype);
3100
3101       window.SVGPathSegLinetoHorizontalRel.prototype.toString = function () {
3102         return "[object SVGPathSegLinetoHorizontalRel]";
3103       };
3104
3105       window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function () {
3106         return this.pathSegTypeAsLetter + " " + this._x;
3107       };
3108
3109       window.SVGPathSegLinetoHorizontalRel.prototype.clone = function () {
3110         return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x);
3111       };
3112
3113       Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, "x", {
3114         get: function get() {
3115           return this._x;
3116         },
3117         set: function set(x) {
3118           this._x = x;
3119
3120           this._segmentChanged();
3121         },
3122         enumerable: true
3123       });
3124
3125       window.SVGPathSegLinetoVerticalAbs = function (owningPathSegList, y) {
3126         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList);
3127         this._y = y;
3128       };
3129
3130       window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
3131
3132       window.SVGPathSegLinetoVerticalAbs.prototype.toString = function () {
3133         return "[object SVGPathSegLinetoVerticalAbs]";
3134       };
3135
3136       window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function () {
3137         return this.pathSegTypeAsLetter + " " + this._y;
3138       };
3139
3140       window.SVGPathSegLinetoVerticalAbs.prototype.clone = function () {
3141         return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y);
3142       };
3143
3144       Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, "y", {
3145         get: function get() {
3146           return this._y;
3147         },
3148         set: function set(y) {
3149           this._y = y;
3150
3151           this._segmentChanged();
3152         },
3153         enumerable: true
3154       });
3155
3156       window.SVGPathSegLinetoVerticalRel = function (owningPathSegList, y) {
3157         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList);
3158         this._y = y;
3159       };
3160
3161       window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype);
3162
3163       window.SVGPathSegLinetoVerticalRel.prototype.toString = function () {
3164         return "[object SVGPathSegLinetoVerticalRel]";
3165       };
3166
3167       window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function () {
3168         return this.pathSegTypeAsLetter + " " + this._y;
3169       };
3170
3171       window.SVGPathSegLinetoVerticalRel.prototype.clone = function () {
3172         return new window.SVGPathSegLinetoVerticalRel(undefined, this._y);
3173       };
3174
3175       Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, "y", {
3176         get: function get() {
3177           return this._y;
3178         },
3179         set: function set(y) {
3180           this._y = y;
3181
3182           this._segmentChanged();
3183         },
3184         enumerable: true
3185       });
3186
3187       window.SVGPathSegCurvetoCubicSmoothAbs = function (owningPathSegList, x, y, x2, y2) {
3188         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList);
3189         this._x = x;
3190         this._y = y;
3191         this._x2 = x2;
3192         this._y2 = y2;
3193       };
3194
3195       window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
3196
3197       window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function () {
3198         return "[object SVGPathSegCurvetoCubicSmoothAbs]";
3199       };
3200
3201       window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function () {
3202         return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y;
3203       };
3204
3205       window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function () {
3206         return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2);
3207       };
3208
3209       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", {
3210         get: function get() {
3211           return this._x;
3212         },
3213         set: function set(x) {
3214           this._x = x;
3215
3216           this._segmentChanged();
3217         },
3218         enumerable: true
3219       });
3220       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", {
3221         get: function get() {
3222           return this._y;
3223         },
3224         set: function set(y) {
3225           this._y = y;
3226
3227           this._segmentChanged();
3228         },
3229         enumerable: true
3230       });
3231       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", {
3232         get: function get() {
3233           return this._x2;
3234         },
3235         set: function set(x2) {
3236           this._x2 = x2;
3237
3238           this._segmentChanged();
3239         },
3240         enumerable: true
3241       });
3242       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", {
3243         get: function get() {
3244           return this._y2;
3245         },
3246         set: function set(y2) {
3247           this._y2 = y2;
3248
3249           this._segmentChanged();
3250         },
3251         enumerable: true
3252       });
3253
3254       window.SVGPathSegCurvetoCubicSmoothRel = function (owningPathSegList, x, y, x2, y2) {
3255         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList);
3256         this._x = x;
3257         this._y = y;
3258         this._x2 = x2;
3259         this._y2 = y2;
3260       };
3261
3262       window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
3263
3264       window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function () {
3265         return "[object SVGPathSegCurvetoCubicSmoothRel]";
3266       };
3267
3268       window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function () {
3269         return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y;
3270       };
3271
3272       window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function () {
3273         return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2);
3274       };
3275
3276       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x", {
3277         get: function get() {
3278           return this._x;
3279         },
3280         set: function set(x) {
3281           this._x = x;
3282
3283           this._segmentChanged();
3284         },
3285         enumerable: true
3286       });
3287       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y", {
3288         get: function get() {
3289           return this._y;
3290         },
3291         set: function set(y) {
3292           this._y = y;
3293
3294           this._segmentChanged();
3295         },
3296         enumerable: true
3297       });
3298       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", {
3299         get: function get() {
3300           return this._x2;
3301         },
3302         set: function set(x2) {
3303           this._x2 = x2;
3304
3305           this._segmentChanged();
3306         },
3307         enumerable: true
3308       });
3309       Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", {
3310         get: function get() {
3311           return this._y2;
3312         },
3313         set: function set(y2) {
3314           this._y2 = y2;
3315
3316           this._segmentChanged();
3317         },
3318         enumerable: true
3319       });
3320
3321       window.SVGPathSegCurvetoQuadraticSmoothAbs = function (owningPathSegList, x, y) {
3322         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList);
3323         this._x = x;
3324         this._y = y;
3325       };
3326
3327       window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
3328
3329       window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function () {
3330         return "[object SVGPathSegCurvetoQuadraticSmoothAbs]";
3331       };
3332
3333       window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function () {
3334         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
3335       };
3336
3337       window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function () {
3338         return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y);
3339       };
3340
3341       Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", {
3342         get: function get() {
3343           return this._x;
3344         },
3345         set: function set(x) {
3346           this._x = x;
3347
3348           this._segmentChanged();
3349         },
3350         enumerable: true
3351       });
3352       Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", {
3353         get: function get() {
3354           return this._y;
3355         },
3356         set: function set(y) {
3357           this._y = y;
3358
3359           this._segmentChanged();
3360         },
3361         enumerable: true
3362       });
3363
3364       window.SVGPathSegCurvetoQuadraticSmoothRel = function (owningPathSegList, x, y) {
3365         window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList);
3366         this._x = x;
3367         this._y = y;
3368       };
3369
3370       window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
3371
3372       window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function () {
3373         return "[object SVGPathSegCurvetoQuadraticSmoothRel]";
3374       };
3375
3376       window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function () {
3377         return this.pathSegTypeAsLetter + " " + this._x + " " + this._y;
3378       };
3379
3380       window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function () {
3381         return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y);
3382       };
3383
3384       Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", {
3385         get: function get() {
3386           return this._x;
3387         },
3388         set: function set(x) {
3389           this._x = x;
3390
3391           this._segmentChanged();
3392         },
3393         enumerable: true
3394       });
3395       Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", {
3396         get: function get() {
3397           return this._y;
3398         },
3399         set: function set(y) {
3400           this._y = y;
3401
3402           this._segmentChanged();
3403         },
3404         enumerable: true
3405       }); // Add createSVGPathSeg* functions to window.SVGPathElement.
3406       // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement.
3407
3408       window.SVGPathElement.prototype.createSVGPathSegClosePath = function () {
3409         return new window.SVGPathSegClosePath(undefined);
3410       };
3411
3412       window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function (x, y) {
3413         return new window.SVGPathSegMovetoAbs(undefined, x, y);
3414       };
3415
3416       window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function (x, y) {
3417         return new window.SVGPathSegMovetoRel(undefined, x, y);
3418       };
3419
3420       window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function (x, y) {
3421         return new window.SVGPathSegLinetoAbs(undefined, x, y);
3422       };
3423
3424       window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function (x, y) {
3425         return new window.SVGPathSegLinetoRel(undefined, x, y);
3426       };
3427
3428       window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function (x, y, x1, y1, x2, y2) {
3429         return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2);
3430       };
3431
3432       window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function (x, y, x1, y1, x2, y2) {
3433         return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2);
3434       };
3435
3436       window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function (x, y, x1, y1) {
3437         return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1);
3438       };
3439
3440       window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function (x, y, x1, y1) {
3441         return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1);
3442       };
3443
3444       window.SVGPathElement.prototype.createSVGPathSegArcAbs = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
3445         return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
3446       };
3447
3448       window.SVGPathElement.prototype.createSVGPathSegArcRel = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
3449         return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
3450       };
3451
3452       window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function (x) {
3453         return new window.SVGPathSegLinetoHorizontalAbs(undefined, x);
3454       };
3455
3456       window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function (x) {
3457         return new window.SVGPathSegLinetoHorizontalRel(undefined, x);
3458       };
3459
3460       window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function (y) {
3461         return new window.SVGPathSegLinetoVerticalAbs(undefined, y);
3462       };
3463
3464       window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function (y) {
3465         return new window.SVGPathSegLinetoVerticalRel(undefined, y);
3466       };
3467
3468       window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function (x, y, x2, y2) {
3469         return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2);
3470       };
3471
3472       window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function (x, y, x2, y2) {
3473         return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2);
3474       };
3475
3476       window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function (x, y) {
3477         return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y);
3478       };
3479
3480       window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function (x, y) {
3481         return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y);
3482       };
3483
3484       if (!("getPathSegAtLength" in window.SVGPathElement.prototype)) {
3485         // Add getPathSegAtLength to SVGPathElement.
3486         // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength
3487         // This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm.
3488         window.SVGPathElement.prototype.getPathSegAtLength = function (distance) {
3489           if (distance === undefined || !isFinite(distance)) throw "Invalid arguments.";
3490           var measurementElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
3491           measurementElement.setAttribute("d", this.getAttribute("d"));
3492           var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1; // If the path is empty, return 0.
3493
3494           if (lastPathSegment <= 0) return 0;
3495
3496           do {
3497             measurementElement.pathSegList.removeItem(lastPathSegment);
3498             if (distance > measurementElement.getTotalLength()) break;
3499             lastPathSegment--;
3500           } while (lastPathSegment > 0);
3501
3502           return lastPathSegment;
3503         };
3504       }
3505     }
3506
3507     if (!("SVGPathSegList" in window)) {
3508       // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
3509       window.SVGPathSegList = function (pathElement) {
3510         this._pathElement = pathElement;
3511         this._list = this._parsePath(this._pathElement.getAttribute("d")); // Use a MutationObserver to catch changes to the path's "d" attribute.
3512
3513         this._mutationObserverConfig = {
3514           "attributes": true,
3515           "attributeFilter": ["d"]
3516         };
3517         this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this));
3518
3519         this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
3520       };
3521
3522       window.SVGPathSegList.prototype.classname = "SVGPathSegList";
3523       Object.defineProperty(window.SVGPathSegList.prototype, "numberOfItems", {
3524         get: function get() {
3525           this._checkPathSynchronizedToList();
3526
3527           return this._list.length;
3528         },
3529         enumerable: true
3530       }); // Add the pathSegList accessors to window.SVGPathElement.
3531       // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
3532
3533       Object.defineProperty(window.SVGPathElement.prototype, "pathSegList", {
3534         get: function get() {
3535           if (!this._pathSegList) this._pathSegList = new window.SVGPathSegList(this);
3536           return this._pathSegList;
3537         },
3538         enumerable: true
3539       }); // FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList.
3540
3541       Object.defineProperty(window.SVGPathElement.prototype, "normalizedPathSegList", {
3542         get: function get() {
3543           return this.pathSegList;
3544         },
3545         enumerable: true
3546       });
3547       Object.defineProperty(window.SVGPathElement.prototype, "animatedPathSegList", {
3548         get: function get() {
3549           return this.pathSegList;
3550         },
3551         enumerable: true
3552       });
3553       Object.defineProperty(window.SVGPathElement.prototype, "animatedNormalizedPathSegList", {
3554         get: function get() {
3555           return this.pathSegList;
3556         },
3557         enumerable: true
3558       }); // Process any pending mutations to the path element and update the list as needed.
3559       // This should be the first call of all public functions and is needed because
3560       // MutationObservers are not synchronous so we can have pending asynchronous mutations.
3561
3562       window.SVGPathSegList.prototype._checkPathSynchronizedToList = function () {
3563         this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
3564       };
3565
3566       window.SVGPathSegList.prototype._updateListFromPathMutations = function (mutationRecords) {
3567         if (!this._pathElement) return;
3568         var hasPathMutations = false;
3569         mutationRecords.forEach(function (record) {
3570           if (record.attributeName == "d") hasPathMutations = true;
3571         });
3572         if (hasPathMutations) this._list = this._parsePath(this._pathElement.getAttribute("d"));
3573       }; // Serialize the list and update the path's 'd' attribute.
3574
3575
3576       window.SVGPathSegList.prototype._writeListToPath = function () {
3577         this._pathElementMutationObserver.disconnect();
3578
3579         this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list));
3580
3581         this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
3582       }; // When a path segment changes the list needs to be synchronized back to the path element.
3583
3584
3585       window.SVGPathSegList.prototype.segmentChanged = function (pathSeg) {
3586         this._writeListToPath();
3587       };
3588
3589       window.SVGPathSegList.prototype.clear = function () {
3590         this._checkPathSynchronizedToList();
3591
3592         this._list.forEach(function (pathSeg) {
3593           pathSeg._owningPathSegList = null;
3594         });
3595
3596         this._list = [];
3597
3598         this._writeListToPath();
3599       };
3600
3601       window.SVGPathSegList.prototype.initialize = function (newItem) {
3602         this._checkPathSynchronizedToList();
3603
3604         this._list = [newItem];
3605         newItem._owningPathSegList = this;
3606
3607         this._writeListToPath();
3608
3609         return newItem;
3610       };
3611
3612       window.SVGPathSegList.prototype._checkValidIndex = function (index) {
3613         if (isNaN(index) || index < 0 || index >= this.numberOfItems) throw "INDEX_SIZE_ERR";
3614       };
3615
3616       window.SVGPathSegList.prototype.getItem = function (index) {
3617         this._checkPathSynchronizedToList();
3618
3619         this._checkValidIndex(index);
3620
3621         return this._list[index];
3622       };
3623
3624       window.SVGPathSegList.prototype.insertItemBefore = function (newItem, index) {
3625         this._checkPathSynchronizedToList(); // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
3626
3627
3628         if (index > this.numberOfItems) index = this.numberOfItems;
3629
3630         if (newItem._owningPathSegList) {
3631           // SVG2 spec says to make a copy.
3632           newItem = newItem.clone();
3633         }
3634
3635         this._list.splice(index, 0, newItem);
3636
3637         newItem._owningPathSegList = this;
3638
3639         this._writeListToPath();
3640
3641         return newItem;
3642       };
3643
3644       window.SVGPathSegList.prototype.replaceItem = function (newItem, index) {
3645         this._checkPathSynchronizedToList();
3646
3647         if (newItem._owningPathSegList) {
3648           // SVG2 spec says to make a copy.
3649           newItem = newItem.clone();
3650         }
3651
3652         this._checkValidIndex(index);
3653
3654         this._list[index] = newItem;
3655         newItem._owningPathSegList = this;
3656
3657         this._writeListToPath();
3658
3659         return newItem;
3660       };
3661
3662       window.SVGPathSegList.prototype.removeItem = function (index) {
3663         this._checkPathSynchronizedToList();
3664
3665         this._checkValidIndex(index);
3666
3667         var item = this._list[index];
3668
3669         this._list.splice(index, 1);
3670
3671         this._writeListToPath();
3672
3673         return item;
3674       };
3675
3676       window.SVGPathSegList.prototype.appendItem = function (newItem) {
3677         this._checkPathSynchronizedToList();
3678
3679         if (newItem._owningPathSegList) {
3680           // SVG2 spec says to make a copy.
3681           newItem = newItem.clone();
3682         }
3683
3684         this._list.push(newItem);
3685
3686         newItem._owningPathSegList = this; // TODO: Optimize this to just append to the existing attribute.
3687
3688         this._writeListToPath();
3689
3690         return newItem;
3691       };
3692
3693       window.SVGPathSegList._pathSegArrayAsString = function (pathSegArray) {
3694         var string = "";
3695         var first = true;
3696         pathSegArray.forEach(function (pathSeg) {
3697           if (first) {
3698             first = false;
3699             string += pathSeg._asPathString();
3700           } else {
3701             string += " " + pathSeg._asPathString();
3702           }
3703         });
3704         return string;
3705       }; // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
3706
3707
3708       window.SVGPathSegList.prototype._parsePath = function (string) {
3709         if (!string || string.length == 0) return [];
3710         var owningPathSegList = this;
3711
3712         var Builder = function Builder() {
3713           this.pathSegList = [];
3714         };
3715
3716         Builder.prototype.appendSegment = function (pathSeg) {
3717           this.pathSegList.push(pathSeg);
3718         };
3719
3720         var Source = function Source(string) {
3721           this._string = string;
3722           this._currentIndex = 0;
3723           this._endIndex = this._string.length;
3724           this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN;
3725
3726           this._skipOptionalSpaces();
3727         };
3728
3729         Source.prototype._isCurrentSpace = function () {
3730           var character = this._string[this._currentIndex];
3731           return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f");
3732         };
3733
3734         Source.prototype._skipOptionalSpaces = function () {
3735           while (this._currentIndex < this._endIndex && this._isCurrentSpace()) {
3736             this._currentIndex++;
3737           }
3738
3739           return this._currentIndex < this._endIndex;
3740         };
3741
3742         Source.prototype._skipOptionalSpacesOrDelimiter = function () {
3743           if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",") return false;
3744
3745           if (this._skipOptionalSpaces()) {
3746             if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") {
3747               this._currentIndex++;
3748
3749               this._skipOptionalSpaces();
3750             }
3751           }
3752
3753           return this._currentIndex < this._endIndex;
3754         };
3755
3756         Source.prototype.hasMoreData = function () {
3757           return this._currentIndex < this._endIndex;
3758         };
3759
3760         Source.prototype.peekSegmentType = function () {
3761           var lookahead = this._string[this._currentIndex];
3762           return this._pathSegTypeFromChar(lookahead);
3763         };
3764
3765         Source.prototype._pathSegTypeFromChar = function (lookahead) {
3766           switch (lookahead) {
3767             case "Z":
3768             case "z":
3769               return window.SVGPathSeg.PATHSEG_CLOSEPATH;
3770
3771             case "M":
3772               return window.SVGPathSeg.PATHSEG_MOVETO_ABS;
3773
3774             case "m":
3775               return window.SVGPathSeg.PATHSEG_MOVETO_REL;
3776
3777             case "L":
3778               return window.SVGPathSeg.PATHSEG_LINETO_ABS;
3779
3780             case "l":
3781               return window.SVGPathSeg.PATHSEG_LINETO_REL;
3782
3783             case "C":
3784               return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
3785
3786             case "c":
3787               return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
3788
3789             case "Q":
3790               return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
3791
3792             case "q":
3793               return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
3794
3795             case "A":
3796               return window.SVGPathSeg.PATHSEG_ARC_ABS;
3797
3798             case "a":
3799               return window.SVGPathSeg.PATHSEG_ARC_REL;
3800
3801             case "H":
3802               return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
3803
3804             case "h":
3805               return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
3806
3807             case "V":
3808               return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
3809
3810             case "v":
3811               return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
3812
3813             case "S":
3814               return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
3815
3816             case "s":
3817               return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
3818
3819             case "T":
3820               return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
3821
3822             case "t":
3823               return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
3824
3825             default:
3826               return window.SVGPathSeg.PATHSEG_UNKNOWN;
3827           }
3828         };
3829
3830         Source.prototype._nextCommandHelper = function (lookahead, previousCommand) {
3831           // Check for remaining coordinates in the current command.
3832           if ((lookahead == "+" || lookahead == "-" || lookahead == "." || lookahead >= "0" && lookahead <= "9") && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) {
3833             if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS) return window.SVGPathSeg.PATHSEG_LINETO_ABS;
3834             if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL) return window.SVGPathSeg.PATHSEG_LINETO_REL;
3835             return previousCommand;
3836           }
3837
3838           return window.SVGPathSeg.PATHSEG_UNKNOWN;
3839         };
3840
3841         Source.prototype.initialCommandIsMoveTo = function () {
3842           // If the path is empty it is still valid, so return true.
3843           if (!this.hasMoreData()) return true;
3844           var command = this.peekSegmentType(); // Path must start with moveTo.
3845
3846           return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL;
3847         }; // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
3848         // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
3849
3850
3851         Source.prototype._parseNumber = function () {
3852           var exponent = 0;
3853           var integer = 0;
3854           var frac = 1;
3855           var decimal = 0;
3856           var sign = 1;
3857           var expsign = 1;
3858           var startIndex = this._currentIndex;
3859
3860           this._skipOptionalSpaces(); // Read the sign.
3861
3862
3863           if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+") this._currentIndex++;else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") {
3864             this._currentIndex++;
3865             sign = -1;
3866           }
3867           if (this._currentIndex == this._endIndex || (this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != ".") // The first character of a number must be one of [0-9+-.].
3868             return undefined; // Read the integer part, build right-to-left.
3869
3870           var startIntPartIndex = this._currentIndex;
3871
3872           while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
3873             this._currentIndex++;
3874           } // Advance to first non-digit.
3875
3876
3877           if (this._currentIndex != startIntPartIndex) {
3878             var scanIntPartIndex = this._currentIndex - 1;
3879             var multiplier = 1;
3880
3881             while (scanIntPartIndex >= startIntPartIndex) {
3882               integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0");
3883               multiplier *= 10;
3884             }
3885           } // Read the decimals.
3886
3887
3888           if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") {
3889             this._currentIndex++; // There must be a least one digit following the .
3890
3891             if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") return undefined;
3892
3893             while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
3894               frac *= 10;
3895               decimal += (this._string.charAt(this._currentIndex) - "0") / frac;
3896               this._currentIndex += 1;
3897             }
3898           } // Read the exponent part.
3899
3900
3901           if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m") {
3902             this._currentIndex++; // Read the sign of the exponent.
3903
3904             if (this._string.charAt(this._currentIndex) == "+") {
3905               this._currentIndex++;
3906             } else if (this._string.charAt(this._currentIndex) == "-") {
3907               this._currentIndex++;
3908               expsign = -1;
3909             } // There must be an exponent.
3910
3911
3912             if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") return undefined;
3913
3914             while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
3915               exponent *= 10;
3916               exponent += this._string.charAt(this._currentIndex) - "0";
3917               this._currentIndex++;
3918             }
3919           }
3920
3921           var number = integer + decimal;
3922           number *= sign;
3923           if (exponent) number *= Math.pow(10, expsign * exponent);
3924           if (startIndex == this._currentIndex) return undefined;
3925
3926           this._skipOptionalSpacesOrDelimiter();
3927
3928           return number;
3929         };
3930
3931         Source.prototype._parseArcFlag = function () {
3932           if (this._currentIndex >= this._endIndex) return undefined;
3933           var flag = false;
3934
3935           var flagChar = this._string.charAt(this._currentIndex++);
3936
3937           if (flagChar == "0") flag = false;else if (flagChar == "1") flag = true;else return undefined;
3938
3939           this._skipOptionalSpacesOrDelimiter();
3940
3941           return flag;
3942         };
3943
3944         Source.prototype.parseSegment = function () {
3945           var lookahead = this._string[this._currentIndex];
3946
3947           var command = this._pathSegTypeFromChar(lookahead);
3948
3949           if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) {
3950             // Possibly an implicit command. Not allowed if this is the first command.
3951             if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN) return null;
3952             command = this._nextCommandHelper(lookahead, this._previousCommand);
3953             if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) return null;
3954           } else {
3955             this._currentIndex++;
3956           }
3957
3958           this._previousCommand = command;
3959
3960           switch (command) {
3961             case window.SVGPathSeg.PATHSEG_MOVETO_REL:
3962               return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
3963
3964             case window.SVGPathSeg.PATHSEG_MOVETO_ABS:
3965               return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
3966
3967             case window.SVGPathSeg.PATHSEG_LINETO_REL:
3968               return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
3969
3970             case window.SVGPathSeg.PATHSEG_LINETO_ABS:
3971               return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
3972
3973             case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
3974               return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
3975
3976             case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
3977               return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
3978
3979             case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
3980               return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
3981
3982             case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
3983               return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
3984
3985             case window.SVGPathSeg.PATHSEG_CLOSEPATH:
3986               this._skipOptionalSpaces();
3987
3988               return new window.SVGPathSegClosePath(owningPathSegList);
3989
3990             case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
3991               var points = {
3992                 x1: this._parseNumber(),
3993                 y1: this._parseNumber(),
3994                 x2: this._parseNumber(),
3995                 y2: this._parseNumber(),
3996                 x: this._parseNumber(),
3997                 y: this._parseNumber()
3998               };
3999               return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
4000
4001             case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
4002               var points = {
4003                 x1: this._parseNumber(),
4004                 y1: this._parseNumber(),
4005                 x2: this._parseNumber(),
4006                 y2: this._parseNumber(),
4007                 x: this._parseNumber(),
4008                 y: this._parseNumber()
4009               };
4010               return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
4011
4012             case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
4013               var points = {
4014                 x2: this._parseNumber(),
4015                 y2: this._parseNumber(),
4016                 x: this._parseNumber(),
4017                 y: this._parseNumber()
4018               };
4019               return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
4020
4021             case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
4022               var points = {
4023                 x2: this._parseNumber(),
4024                 y2: this._parseNumber(),
4025                 x: this._parseNumber(),
4026                 y: this._parseNumber()
4027               };
4028               return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
4029
4030             case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
4031               var points = {
4032                 x1: this._parseNumber(),
4033                 y1: this._parseNumber(),
4034                 x: this._parseNumber(),
4035                 y: this._parseNumber()
4036               };
4037               return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
4038
4039             case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
4040               var points = {
4041                 x1: this._parseNumber(),
4042                 y1: this._parseNumber(),
4043                 x: this._parseNumber(),
4044                 y: this._parseNumber()
4045               };
4046               return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
4047
4048             case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
4049               return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
4050
4051             case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
4052               return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
4053
4054             case window.SVGPathSeg.PATHSEG_ARC_REL:
4055               var points = {
4056                 x1: this._parseNumber(),
4057                 y1: this._parseNumber(),
4058                 arcAngle: this._parseNumber(),
4059                 arcLarge: this._parseArcFlag(),
4060                 arcSweep: this._parseArcFlag(),
4061                 x: this._parseNumber(),
4062                 y: this._parseNumber()
4063               };
4064               return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
4065
4066             case window.SVGPathSeg.PATHSEG_ARC_ABS:
4067               var points = {
4068                 x1: this._parseNumber(),
4069                 y1: this._parseNumber(),
4070                 arcAngle: this._parseNumber(),
4071                 arcLarge: this._parseArcFlag(),
4072                 arcSweep: this._parseArcFlag(),
4073                 x: this._parseNumber(),
4074                 y: this._parseNumber()
4075               };
4076               return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
4077
4078             default:
4079               throw "Unknown path seg type.";
4080           }
4081         };
4082
4083         var builder = new Builder();
4084         var source = new Source(string);
4085         if (!source.initialCommandIsMoveTo()) return [];
4086
4087         while (source.hasMoreData()) {
4088           var pathSeg = source.parseSegment();
4089           if (!pathSeg) return [];
4090           builder.appendSegment(pathSeg);
4091         }
4092
4093         return builder.pathSegList;
4094       };
4095     }
4096   })(); // String.padEnd polyfill for IE11
4097   //
4098   // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
4099   // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
4100
4101
4102   if (!String.prototype.padEnd) {
4103     String.prototype.padEnd = function padEnd(targetLength, padString) {
4104       targetLength = targetLength >> 0; //floor if number or convert non-number to 0;
4105
4106       padString = String(typeof padString !== 'undefined' ? padString : ' ');
4107
4108       if (this.length > targetLength) {
4109         return String(this);
4110       } else {
4111         targetLength = targetLength - this.length;
4112
4113         if (targetLength > padString.length) {
4114           padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed
4115         }
4116
4117         return String(this) + padString.slice(0, targetLength);
4118       }
4119     };
4120   }
4121   /* jshint ignore:end */
4122
4123   Chart.prototype.axis = function () {};
4124
4125   Chart.prototype.axis.labels = function (labels) {
4126     var $$ = this.internal;
4127
4128     if (arguments.length) {
4129       Object.keys(labels).forEach(function (axisId) {
4130         $$.axis.setLabelText(axisId, labels[axisId]);
4131       });
4132       $$.axis.updateLabels();
4133     } // TODO: return some values?
4134
4135   };
4136
4137   Chart.prototype.axis.max = function (max) {
4138     var $$ = this.internal,
4139         config = $$.config;
4140
4141     if (arguments.length) {
4142       if (_typeof(max) === 'object') {
4143         if (isValue(max.x)) {
4144           config.axis_x_max = max.x;
4145         }
4146
4147         if (isValue(max.y)) {
4148           config.axis_y_max = max.y;
4149         }
4150
4151         if (isValue(max.y2)) {
4152           config.axis_y2_max = max.y2;
4153         }
4154       } else {
4155         config.axis_y_max = config.axis_y2_max = max;
4156       }
4157
4158       $$.redraw({
4159         withUpdateOrgXDomain: true,
4160         withUpdateXDomain: true
4161       });
4162     } else {
4163       return {
4164         x: config.axis_x_max,
4165         y: config.axis_y_max,
4166         y2: config.axis_y2_max
4167       };
4168     }
4169   };
4170
4171   Chart.prototype.axis.min = function (min) {
4172     var $$ = this.internal,
4173         config = $$.config;
4174
4175     if (arguments.length) {
4176       if (_typeof(min) === 'object') {
4177         if (isValue(min.x)) {
4178           config.axis_x_min = min.x;
4179         }
4180
4181         if (isValue(min.y)) {
4182           config.axis_y_min = min.y;
4183         }
4184
4185         if (isValue(min.y2)) {
4186           config.axis_y2_min = min.y2;
4187         }
4188       } else {
4189         config.axis_y_min = config.axis_y2_min = min;
4190       }
4191
4192       $$.redraw({
4193         withUpdateOrgXDomain: true,
4194         withUpdateXDomain: true
4195       });
4196     } else {
4197       return {
4198         x: config.axis_x_min,
4199         y: config.axis_y_min,
4200         y2: config.axis_y2_min
4201       };
4202     }
4203   };
4204
4205   Chart.prototype.axis.range = function (range) {
4206     if (arguments.length) {
4207       if (isDefined(range.max)) {
4208         this.axis.max(range.max);
4209       }
4210
4211       if (isDefined(range.min)) {
4212         this.axis.min(range.min);
4213       }
4214     } else {
4215       return {
4216         max: this.axis.max(),
4217         min: this.axis.min()
4218       };
4219     }
4220   };
4221
4222   Chart.prototype.category = function (i, category) {
4223     var $$ = this.internal,
4224         config = $$.config;
4225
4226     if (arguments.length > 1) {
4227       config.axis_x_categories[i] = category;
4228       $$.redraw();
4229     }
4230
4231     return config.axis_x_categories[i];
4232   };
4233
4234   Chart.prototype.categories = function (categories) {
4235     var $$ = this.internal,
4236         config = $$.config;
4237
4238     if (!arguments.length) {
4239       return config.axis_x_categories;
4240     }
4241
4242     config.axis_x_categories = categories;
4243     $$.redraw();
4244     return config.axis_x_categories;
4245   };
4246
4247   Chart.prototype.resize = function (size) {
4248     var $$ = this.internal,
4249         config = $$.config;
4250     config.size_width = size ? size.width : null;
4251     config.size_height = size ? size.height : null;
4252     this.flush();
4253   };
4254
4255   Chart.prototype.flush = function () {
4256     var $$ = this.internal;
4257     $$.updateAndRedraw({
4258       withLegend: true,
4259       withTransition: false,
4260       withTransitionForTransform: false
4261     });
4262   };
4263
4264   Chart.prototype.destroy = function () {
4265     var $$ = this.internal;
4266     window.clearInterval($$.intervalForObserveInserted);
4267
4268     if ($$.resizeTimeout !== undefined) {
4269       window.clearTimeout($$.resizeTimeout);
4270     }
4271
4272     if (window.detachEvent) {
4273       window.detachEvent('onresize', $$.resizeIfElementDisplayed);
4274     } else if (window.removeEventListener) {
4275       window.removeEventListener('resize', $$.resizeIfElementDisplayed);
4276     } else {
4277       var wrapper = window.onresize; // check if no one else removed our wrapper and remove our resizeFunction from it
4278
4279       if (wrapper && wrapper.add && wrapper.remove) {
4280         wrapper.remove($$.resizeFunction);
4281       }
4282     } // Removes the inner resize functions
4283
4284
4285     $$.resizeFunction.remove(); // Unbinds from the window focus event
4286
4287     $$.unbindWindowFocus();
4288     $$.selectChart.classed('c3', false).html(""); // MEMO: this is needed because the reference of some elements will not be released, then memory leak will happen.
4289
4290     Object.keys($$).forEach(function (key) {
4291       $$[key] = null;
4292     });
4293     return null;
4294   };
4295
4296   Chart.prototype.color = function (id) {
4297     var $$ = this.internal;
4298     return $$.color(id); // more patterns
4299   };
4300
4301   Chart.prototype.data = function (targetIds) {
4302     var targets = this.internal.data.targets;
4303     return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
4304       return [].concat(targetIds).indexOf(t.id) >= 0;
4305     });
4306   };
4307
4308   Chart.prototype.data.shown = function (targetIds) {
4309     return this.internal.filterTargetsToShow(this.data(targetIds));
4310   };
4311
4312   Chart.prototype.data.values = function (targetId) {
4313     var targets,
4314         values = null;
4315
4316     if (targetId) {
4317       targets = this.data(targetId);
4318       values = targets[0] ? targets[0].values.map(function (d) {
4319         return d.value;
4320       }) : null;
4321     }
4322
4323     return values;
4324   };
4325
4326   Chart.prototype.data.names = function (names) {
4327     this.internal.clearLegendItemTextBoxCache();
4328     return this.internal.updateDataAttributes('names', names);
4329   };
4330
4331   Chart.prototype.data.colors = function (colors) {
4332     return this.internal.updateDataAttributes('colors', colors);
4333   };
4334
4335   Chart.prototype.data.axes = function (axes) {
4336     return this.internal.updateDataAttributes('axes', axes);
4337   };
4338
4339   Chart.prototype.flow = function (args) {
4340     var $$ = this.internal,
4341         targets,
4342         data,
4343         notfoundIds = [],
4344         orgDataCount = $$.getMaxDataCount(),
4345         dataCount,
4346         domain,
4347         baseTarget,
4348         baseValue,
4349         length = 0,
4350         tail = 0,
4351         diff,
4352         to;
4353
4354     if (args.json) {
4355       data = $$.convertJsonToData(args.json, args.keys);
4356     } else if (args.rows) {
4357       data = $$.convertRowsToData(args.rows);
4358     } else if (args.columns) {
4359       data = $$.convertColumnsToData(args.columns);
4360     } else {
4361       return;
4362     }
4363
4364     targets = $$.convertDataToTargets(data, true); // Update/Add data
4365
4366     $$.data.targets.forEach(function (t) {
4367       var found = false,
4368           i,
4369           j;
4370
4371       for (i = 0; i < targets.length; i++) {
4372         if (t.id === targets[i].id) {
4373           found = true;
4374
4375           if (t.values[t.values.length - 1]) {
4376             tail = t.values[t.values.length - 1].index + 1;
4377           }
4378
4379           length = targets[i].values.length;
4380
4381           for (j = 0; j < length; j++) {
4382             targets[i].values[j].index = tail + j;
4383
4384             if (!$$.isTimeSeries()) {
4385               targets[i].values[j].x = tail + j;
4386             }
4387           }
4388
4389           t.values = t.values.concat(targets[i].values);
4390           targets.splice(i, 1);
4391           break;
4392         }
4393       }
4394
4395       if (!found) {
4396         notfoundIds.push(t.id);
4397       }
4398     }); // Append null for not found targets
4399
4400     $$.data.targets.forEach(function (t) {
4401       var i, j;
4402
4403       for (i = 0; i < notfoundIds.length; i++) {
4404         if (t.id === notfoundIds[i]) {
4405           tail = t.values[t.values.length - 1].index + 1;
4406
4407           for (j = 0; j < length; j++) {
4408             t.values.push({
4409               id: t.id,
4410               index: tail + j,
4411               x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
4412               value: null
4413             });
4414           }
4415         }
4416       }
4417     }); // Generate null values for new target
4418
4419     if ($$.data.targets.length) {
4420       targets.forEach(function (t) {
4421         var i,
4422             missing = [];
4423
4424         for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
4425           missing.push({
4426             id: t.id,
4427             index: i,
4428             x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
4429             value: null
4430           });
4431         }
4432
4433         t.values.forEach(function (v) {
4434           v.index += tail;
4435
4436           if (!$$.isTimeSeries()) {
4437             v.x += tail;
4438           }
4439         });
4440         t.values = missing.concat(t.values);
4441       });
4442     }
4443
4444     $$.data.targets = $$.data.targets.concat(targets); // add remained
4445     // check data count because behavior needs to change when it's only one
4446
4447     dataCount = $$.getMaxDataCount();
4448     baseTarget = $$.data.targets[0];
4449     baseValue = baseTarget.values[0]; // Update length to flow if needed
4450
4451     if (isDefined(args.to)) {
4452       length = 0;
4453       to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
4454       baseTarget.values.forEach(function (v) {
4455         if (v.x < to) {
4456           length++;
4457         }
4458       });
4459     } else if (isDefined(args.length)) {
4460       length = args.length;
4461     } // If only one data, update the domain to flow from left edge of the chart
4462
4463
4464     if (!orgDataCount) {
4465       if ($$.isTimeSeries()) {
4466         if (baseTarget.values.length > 1) {
4467           diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
4468         } else {
4469           diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
4470         }
4471       } else {
4472         diff = 1;
4473       }
4474
4475       domain = [baseValue.x - diff, baseValue.x];
4476       $$.updateXDomain(null, true, true, false, domain);
4477     } else if (orgDataCount === 1) {
4478       if ($$.isTimeSeries()) {
4479         diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
4480         domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
4481         $$.updateXDomain(null, true, true, false, domain);
4482       }
4483     } // Set targets
4484
4485
4486     $$.updateTargets($$.data.targets); // Redraw with new targets
4487
4488     $$.redraw({
4489       flow: {
4490         index: baseValue.index,
4491         length: length,
4492         duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
4493         done: args.done,
4494         orgDataCount: orgDataCount
4495       },
4496       withLegend: true,
4497       withTransition: orgDataCount > 1,
4498       withTrimXDomain: false,
4499       withUpdateXAxis: true
4500     });
4501   };
4502
4503   ChartInternal.prototype.generateFlow = function (args) {
4504     var $$ = this,
4505         config = $$.config,
4506         d3 = $$.d3;
4507     return function () {
4508       var targets = args.targets,
4509           flow = args.flow,
4510           drawBar = args.drawBar,
4511           drawLine = args.drawLine,
4512           drawArea = args.drawArea,
4513           cx = args.cx,
4514           cy = args.cy,
4515           xv = args.xv,
4516           xForText = args.xForText,
4517           yForText = args.yForText,
4518           duration = args.duration;
4519
4520       var translateX,
4521           scaleX = 1,
4522           transform,
4523           flowIndex = flow.index,
4524           flowLength = flow.length,
4525           flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
4526           flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
4527           orgDomain = $$.x.domain(),
4528           domain,
4529           durationForFlow = flow.duration || duration,
4530           done = flow.done || function () {},
4531           wait = $$.generateWait();
4532
4533       var xgrid, xgridLines, mainRegion, mainText, mainBar, mainLine, mainArea, mainCircle; // set flag
4534
4535       $$.flowing = true; // remove head data after rendered
4536
4537       $$.data.targets.forEach(function (d) {
4538         d.values.splice(0, flowLength);
4539       }); // update x domain to generate axis elements for flow
4540
4541       domain = $$.updateXDomain(targets, true, true); // update elements related to x scale
4542
4543       if ($$.updateXGrid) {
4544         $$.updateXGrid(true);
4545       }
4546
4547       xgrid = $$.xgrid || d3.selectAll([]); // xgrid needs to be obtained after updateXGrid
4548
4549       xgridLines = $$.xgridLines || d3.selectAll([]);
4550       mainRegion = $$.mainRegion || d3.selectAll([]);
4551       mainText = $$.mainText || d3.selectAll([]);
4552       mainBar = $$.mainBar || d3.selectAll([]);
4553       mainLine = $$.mainLine || d3.selectAll([]);
4554       mainArea = $$.mainArea || d3.selectAll([]);
4555       mainCircle = $$.mainCircle || d3.selectAll([]); // generate transform to flow
4556
4557       if (!flow.orgDataCount) {
4558         // if empty
4559         if ($$.data.targets[0].values.length !== 1) {
4560           translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
4561         } else {
4562           if ($$.isTimeSeries()) {
4563             flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
4564             flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
4565             translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
4566           } else {
4567             translateX = diffDomain(domain) / 2;
4568           }
4569         }
4570       } else if (flow.orgDataCount === 1 || (flowStart && flowStart.x) === (flowEnd && flowEnd.x)) {
4571         translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
4572       } else {
4573         if ($$.isTimeSeries()) {
4574           translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
4575         } else {
4576           translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
4577         }
4578       }
4579
4580       scaleX = diffDomain(orgDomain) / diffDomain(domain);
4581       transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
4582       $$.hideXGridFocus();
4583       var flowTransition = d3.transition().ease(d3.easeLinear).duration(durationForFlow);
4584       wait.add($$.xAxis($$.axes.x, flowTransition));
4585       wait.add(mainBar.transition(flowTransition).attr('transform', transform));
4586       wait.add(mainLine.transition(flowTransition).attr('transform', transform));
4587       wait.add(mainArea.transition(flowTransition).attr('transform', transform));
4588       wait.add(mainCircle.transition(flowTransition).attr('transform', transform));
4589       wait.add(mainText.transition(flowTransition).attr('transform', transform));
4590       wait.add(mainRegion.filter($$.isRegionOnX).transition(flowTransition).attr('transform', transform));
4591       wait.add(xgrid.transition(flowTransition).attr('transform', transform));
4592       wait.add(xgridLines.transition(flowTransition).attr('transform', transform));
4593       wait(function () {
4594         var i,
4595             shapes = [],
4596             texts = []; // remove flowed elements
4597
4598         if (flowLength) {
4599           for (i = 0; i < flowLength; i++) {
4600             shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
4601             texts.push('.' + CLASS.text + '-' + (flowIndex + i));
4602           }
4603
4604           $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
4605           $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
4606           $$.svg.select('.' + CLASS.xgrid).remove();
4607         } // draw again for removing flowed elements and reverting attr
4608
4609
4610         xgrid.attr('transform', null).attr('x1', $$.xgridAttr.x1).attr('x2', $$.xgridAttr.x2).attr('y1', $$.xgridAttr.y1).attr('y2', $$.xgridAttr.y2).style("opacity", $$.xgridAttr.opacity);
4611         xgridLines.attr('transform', null);
4612         xgridLines.select('line').attr("x1", config.axis_rotated ? 0 : xv).attr("x2", config.axis_rotated ? $$.width : xv);
4613         xgridLines.select('text').attr("x", config.axis_rotated ? $$.width : 0).attr("y", xv);
4614         mainBar.attr('transform', null).attr("d", drawBar);
4615         mainLine.attr('transform', null).attr("d", drawLine);
4616         mainArea.attr('transform', null).attr("d", drawArea);
4617         mainCircle.attr('transform', null).attr("cx", cx).attr("cy", cy);
4618         mainText.attr('transform', null).attr('x', xForText).attr('y', yForText).style('fill-opacity', $$.opacityForText.bind($$));
4619         mainRegion.attr('transform', null);
4620         mainRegion.filter($$.isRegionOnX).attr("x", $$.regionX.bind($$)).attr("width", $$.regionWidth.bind($$)); // callback for end of flow
4621
4622         done();
4623         $$.flowing = false;
4624       });
4625     };
4626   };
4627
4628   Chart.prototype.focus = function (targetIds) {
4629     var $$ = this.internal,
4630         candidates;
4631     targetIds = $$.mapToTargetIds(targetIds);
4632     candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))), this.revert();
4633     this.defocus();
4634     candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
4635
4636     if ($$.hasArcType()) {
4637       $$.expandArc(targetIds);
4638     }
4639
4640     $$.toggleFocusLegend(targetIds, true);
4641     $$.focusedTargetIds = targetIds;
4642     $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
4643       return targetIds.indexOf(id) < 0;
4644     });
4645   };
4646
4647   Chart.prototype.defocus = function (targetIds) {
4648     var $$ = this.internal,
4649         candidates;
4650     targetIds = $$.mapToTargetIds(targetIds);
4651     candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))), candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
4652
4653     if ($$.hasArcType()) {
4654       $$.unexpandArc(targetIds);
4655     }
4656
4657     $$.toggleFocusLegend(targetIds, false);
4658     $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
4659       return targetIds.indexOf(id) < 0;
4660     });
4661     $$.defocusedTargetIds = targetIds;
4662   };
4663
4664   Chart.prototype.revert = function (targetIds) {
4665     var $$ = this.internal,
4666         candidates;
4667     targetIds = $$.mapToTargetIds(targetIds);
4668     candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
4669
4670     candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
4671
4672     if ($$.hasArcType()) {
4673       $$.unexpandArc(targetIds);
4674     }
4675
4676     if ($$.config.legend_show) {
4677       $$.showLegend(targetIds.filter($$.isLegendToShow.bind($$)));
4678       $$.legend.selectAll($$.selectorLegends(targetIds)).filter(function () {
4679         return $$.d3.select(this).classed(CLASS.legendItemFocused);
4680       }).classed(CLASS.legendItemFocused, false);
4681     }
4682
4683     $$.focusedTargetIds = [];
4684     $$.defocusedTargetIds = [];
4685   };
4686
4687   Chart.prototype.xgrids = function (grids) {
4688     var $$ = this.internal,
4689         config = $$.config;
4690
4691     if (!grids) {
4692       return config.grid_x_lines;
4693     }
4694
4695     config.grid_x_lines = grids;
4696     $$.redrawWithoutRescale();
4697     return config.grid_x_lines;
4698   };
4699
4700   Chart.prototype.xgrids.add = function (grids) {
4701     var $$ = this.internal;
4702     return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
4703   };
4704
4705   Chart.prototype.xgrids.remove = function (params) {
4706     // TODO: multiple
4707     var $$ = this.internal;
4708     $$.removeGridLines(params, true);
4709   };
4710
4711   Chart.prototype.ygrids = function (grids) {
4712     var $$ = this.internal,
4713         config = $$.config;
4714
4715     if (!grids) {
4716       return config.grid_y_lines;
4717     }
4718
4719     config.grid_y_lines = grids;
4720     $$.redrawWithoutRescale();
4721     return config.grid_y_lines;
4722   };
4723
4724   Chart.prototype.ygrids.add = function (grids) {
4725     var $$ = this.internal;
4726     return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
4727   };
4728
4729   Chart.prototype.ygrids.remove = function (params) {
4730     // TODO: multiple
4731     var $$ = this.internal;
4732     $$.removeGridLines(params, false);
4733   };
4734
4735   Chart.prototype.groups = function (groups) {
4736     var $$ = this.internal,
4737         config = $$.config;
4738
4739     if (isUndefined(groups)) {
4740       return config.data_groups;
4741     }
4742
4743     config.data_groups = groups;
4744     $$.redraw();
4745     return config.data_groups;
4746   };
4747
4748   Chart.prototype.legend = function () {};
4749
4750   Chart.prototype.legend.show = function (targetIds) {
4751     var $$ = this.internal;
4752     $$.showLegend($$.mapToTargetIds(targetIds));
4753     $$.updateAndRedraw({
4754       withLegend: true
4755     });
4756   };
4757
4758   Chart.prototype.legend.hide = function (targetIds) {
4759     var $$ = this.internal;
4760     $$.hideLegend($$.mapToTargetIds(targetIds));
4761     $$.updateAndRedraw({
4762       withLegend: false
4763     });
4764   };
4765
4766   Chart.prototype.load = function (args) {
4767     var $$ = this.internal,
4768         config = $$.config; // update xs if specified
4769
4770     if (args.xs) {
4771       $$.addXs(args.xs);
4772     } // update names if exists
4773
4774
4775     if ('names' in args) {
4776       Chart.prototype.data.names.bind(this)(args.names);
4777     } // update classes if exists
4778
4779
4780     if ('classes' in args) {
4781       Object.keys(args.classes).forEach(function (id) {
4782         config.data_classes[id] = args.classes[id];
4783       });
4784     } // update categories if exists
4785
4786
4787     if ('categories' in args && $$.isCategorized()) {
4788       config.axis_x_categories = args.categories;
4789     } // update axes if exists
4790
4791
4792     if ('axes' in args) {
4793       Object.keys(args.axes).forEach(function (id) {
4794         config.data_axes[id] = args.axes[id];
4795       });
4796     } // update colors if exists
4797
4798
4799     if ('colors' in args) {
4800       Object.keys(args.colors).forEach(function (id) {
4801         config.data_colors[id] = args.colors[id];
4802       });
4803     } // use cache if exists
4804
4805
4806     if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
4807       $$.load($$.getCaches(args.cacheIds), args.done);
4808       return;
4809     } // unload if needed
4810
4811
4812     if ('unload' in args) {
4813       // TODO: do not unload if target will load (included in url/rows/columns)
4814       $$.unload($$.mapToTargetIds(typeof args.unload === 'boolean' && args.unload ? null : args.unload), function () {
4815         $$.loadFromArgs(args);
4816       });
4817     } else {
4818       $$.loadFromArgs(args);
4819     }
4820   };
4821
4822   Chart.prototype.unload = function (args) {
4823     var $$ = this.internal;
4824     args = args || {};
4825
4826     if (args instanceof Array) {
4827       args = {
4828         ids: args
4829       };
4830     } else if (typeof args === 'string') {
4831       args = {
4832         ids: [args]
4833       };
4834     }
4835
4836     $$.unload($$.mapToTargetIds(args.ids), function () {
4837       $$.redraw({
4838         withUpdateOrgXDomain: true,
4839         withUpdateXDomain: true,
4840         withLegend: true
4841       });
4842
4843       if (args.done) {
4844         args.done();
4845       }
4846     });
4847   };
4848
4849   Chart.prototype.regions = function (regions) {
4850     var $$ = this.internal,
4851         config = $$.config;
4852
4853     if (!regions) {
4854       return config.regions;
4855     }
4856
4857     config.regions = regions;
4858     $$.redrawWithoutRescale();
4859     return config.regions;
4860   };
4861
4862   Chart.prototype.regions.add = function (regions) {
4863     var $$ = this.internal,
4864         config = $$.config;
4865
4866     if (!regions) {
4867       return config.regions;
4868     }
4869
4870     config.regions = config.regions.concat(regions);
4871     $$.redrawWithoutRescale();
4872     return config.regions;
4873   };
4874
4875   Chart.prototype.regions.remove = function (options) {
4876     var $$ = this.internal,
4877         config = $$.config,
4878         duration,
4879         classes,
4880         regions;
4881     options = options || {};
4882     duration = getOption(options, "duration", config.transition_duration);
4883     classes = getOption(options, "classes", [CLASS.region]);
4884     regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) {
4885       return '.' + c;
4886     }));
4887     (duration ? regions.transition().duration(duration) : regions).style('opacity', 0).remove();
4888     config.regions = config.regions.filter(function (region) {
4889       var found = false;
4890
4891       if (!region['class']) {
4892         return true;
4893       }
4894
4895       region['class'].split(' ').forEach(function (c) {
4896         if (classes.indexOf(c) >= 0) {
4897           found = true;
4898         }
4899       });
4900       return !found;
4901     });
4902     return config.regions;
4903   };
4904
4905   Chart.prototype.selected = function (targetId) {
4906     var $$ = this.internal,
4907         d3 = $$.d3;
4908     return d3.merge($$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape).filter(function () {
4909       return d3.select(this).classed(CLASS.SELECTED);
4910     }).map(function (d) {
4911       return d.map(function (d) {
4912         var data = d.__data__;
4913         return data.data ? data.data : data;
4914       });
4915     }));
4916   };
4917
4918   Chart.prototype.select = function (ids, indices, resetOther) {
4919     var $$ = this.internal,
4920         d3 = $$.d3,
4921         config = $$.config;
4922
4923     if (!config.data_selection_enabled) {
4924       return;
4925     }
4926
4927     $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
4928       var shape = d3.select(this),
4929           id = d.data ? d.data.id : d.id,
4930           toggle = $$.getToggle(this, d).bind($$),
4931           isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
4932           isTargetIndex = !indices || indices.indexOf(i) >= 0,
4933           isSelected = shape.classed(CLASS.SELECTED); // line/area selection not supported yet
4934
4935       if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
4936         return;
4937       }
4938
4939       if (isTargetId && isTargetIndex) {
4940         if (config.data_selection_isselectable(d) && !isSelected) {
4941           toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
4942         }
4943       } else if (isDefined(resetOther) && resetOther) {
4944         if (isSelected) {
4945           toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
4946         }
4947       }
4948     });
4949   };
4950
4951   Chart.prototype.unselect = function (ids, indices) {
4952     var $$ = this.internal,
4953         d3 = $$.d3,
4954         config = $$.config;
4955
4956     if (!config.data_selection_enabled) {
4957       return;
4958     }
4959
4960     $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
4961       var shape = d3.select(this),
4962           id = d.data ? d.data.id : d.id,
4963           toggle = $$.getToggle(this, d).bind($$),
4964           isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
4965           isTargetIndex = !indices || indices.indexOf(i) >= 0,
4966           isSelected = shape.classed(CLASS.SELECTED); // line/area selection not supported yet
4967
4968       if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
4969         return;
4970       }
4971
4972       if (isTargetId && isTargetIndex) {
4973         if (config.data_selection_isselectable(d)) {
4974           if (isSelected) {
4975             toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
4976           }
4977         }
4978       }
4979     });
4980   };
4981
4982   Chart.prototype.show = function (targetIds, options) {
4983     var $$ = this.internal,
4984         targets;
4985     targetIds = $$.mapToTargetIds(targetIds);
4986     options = options || {};
4987     $$.removeHiddenTargetIds(targetIds);
4988     targets = $$.svg.selectAll($$.selectorTargets(targetIds));
4989     targets.transition().style('display', 'initial', 'important').style('opacity', 1, 'important').call($$.endall, function () {
4990       targets.style('opacity', null).style('opacity', 1);
4991     });
4992
4993     if (options.withLegend) {
4994       $$.showLegend(targetIds);
4995     }
4996
4997     $$.redraw({
4998       withUpdateOrgXDomain: true,
4999       withUpdateXDomain: true,
5000       withLegend: true
5001     });
5002   };
5003
5004   Chart.prototype.hide = function (targetIds, options) {
5005     var $$ = this.internal,
5006         targets;
5007     targetIds = $$.mapToTargetIds(targetIds);
5008     options = options || {};
5009     $$.addHiddenTargetIds(targetIds);
5010     targets = $$.svg.selectAll($$.selectorTargets(targetIds));
5011     targets.transition().style('opacity', 0, 'important').call($$.endall, function () {
5012       targets.style('opacity', null).style('opacity', 0);
5013       targets.style('display', 'none');
5014     });
5015
5016     if (options.withLegend) {
5017       $$.hideLegend(targetIds);
5018     }
5019
5020     $$.redraw({
5021       withUpdateOrgXDomain: true,
5022       withUpdateXDomain: true,
5023       withLegend: true
5024     });
5025   };
5026
5027   Chart.prototype.toggle = function (targetIds, options) {
5028     var that = this,
5029         $$ = this.internal;
5030     $$.mapToTargetIds(targetIds).forEach(function (targetId) {
5031       $$.isTargetToShow(targetId) ? that.hide(targetId, options) : that.show(targetId, options);
5032     });
5033   };
5034
5035   Chart.prototype.tooltip = function () {};
5036
5037   Chart.prototype.tooltip.show = function (args) {
5038     var $$ = this.internal,
5039         targets,
5040         data,
5041         mouse = {}; // determine mouse position on the chart
5042
5043     if (args.mouse) {
5044       mouse = args.mouse;
5045     } else {
5046       // determine focus data
5047       if (args.data) {
5048         data = args.data;
5049       } else if (typeof args.x !== 'undefined') {
5050         if (args.id) {
5051           targets = $$.data.targets.filter(function (t) {
5052             return t.id === args.id;
5053           });
5054         } else {
5055           targets = $$.data.targets;
5056         }
5057
5058         data = $$.filterByX(targets, args.x).slice(0, 1)[0];
5059       }
5060
5061       mouse = data ? $$.getMousePosition(data) : null;
5062     } // emulate mouse events to show
5063
5064
5065     $$.dispatchEvent('mousemove', mouse);
5066     $$.config.tooltip_onshow.call($$, data);
5067   };
5068
5069   Chart.prototype.tooltip.hide = function () {
5070     // TODO: get target data by checking the state of focus
5071     this.internal.dispatchEvent('mouseout', 0);
5072     this.internal.config.tooltip_onhide.call(this);
5073   };
5074
5075   Chart.prototype.transform = function (type, targetIds) {
5076     var $$ = this.internal,
5077         options = ['pie', 'donut'].indexOf(type) >= 0 ? {
5078       withTransform: true
5079     } : null;
5080     $$.transformTo(targetIds, type, options);
5081   };
5082
5083   ChartInternal.prototype.transformTo = function (targetIds, type, optionsForRedraw) {
5084     var $$ = this,
5085         withTransitionForAxis = !$$.hasArcType(),
5086         options = optionsForRedraw || {
5087       withTransitionForAxis: withTransitionForAxis
5088     };
5089     options.withTransitionForTransform = false;
5090     $$.transiting = false;
5091     $$.setTargetType(targetIds, type);
5092     $$.updateTargets($$.data.targets); // this is needed when transforming to arc
5093
5094     $$.updateAndRedraw(options);
5095   };
5096
5097   Chart.prototype.x = function (x) {
5098     var $$ = this.internal;
5099
5100     if (arguments.length) {
5101       $$.updateTargetX($$.data.targets, x);
5102       $$.redraw({
5103         withUpdateOrgXDomain: true,
5104         withUpdateXDomain: true
5105       });
5106     }
5107
5108     return $$.data.xs;
5109   };
5110
5111   Chart.prototype.xs = function (xs) {
5112     var $$ = this.internal;
5113
5114     if (arguments.length) {
5115       $$.updateTargetXs($$.data.targets, xs);
5116       $$.redraw({
5117         withUpdateOrgXDomain: true,
5118         withUpdateXDomain: true
5119       });
5120     }
5121
5122     return $$.data.xs;
5123   };
5124
5125   Chart.prototype.zoom = function (domain) {
5126     var $$ = this.internal;
5127
5128     if (domain) {
5129       if ($$.isTimeSeries()) {
5130         domain = domain.map(function (x) {
5131           return $$.parseDate(x);
5132         });
5133       }
5134
5135       if ($$.config.subchart_show) {
5136         $$.brush.selectionAsValue(domain, true);
5137       } else {
5138         $$.updateXDomain(null, true, false, false, domain);
5139         $$.redraw({
5140           withY: $$.config.zoom_rescale,
5141           withSubchart: false
5142         });
5143       }
5144
5145       $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
5146       return domain;
5147     } else {
5148       return $$.x.domain();
5149     }
5150   };
5151
5152   Chart.prototype.zoom.enable = function (enabled) {
5153     var $$ = this.internal;
5154     $$.config.zoom_enabled = enabled;
5155     $$.updateAndRedraw();
5156   };
5157
5158   Chart.prototype.unzoom = function () {
5159     var $$ = this.internal;
5160
5161     if ($$.config.subchart_show) {
5162       $$.brush.clear();
5163     } else {
5164       $$.updateXDomain(null, true, false, false, $$.subX.domain());
5165       $$.redraw({
5166         withY: $$.config.zoom_rescale,
5167         withSubchart: false
5168       });
5169     }
5170   };
5171
5172   Chart.prototype.zoom.max = function (max) {
5173     var $$ = this.internal,
5174         config = $$.config,
5175         d3 = $$.d3;
5176
5177     if (max === 0 || max) {
5178       config.zoom_x_max = d3.max([$$.orgXDomain[1], max]);
5179     } else {
5180       return config.zoom_x_max;
5181     }
5182   };
5183
5184   Chart.prototype.zoom.min = function (min) {
5185     var $$ = this.internal,
5186         config = $$.config,
5187         d3 = $$.d3;
5188
5189     if (min === 0 || min) {
5190       config.zoom_x_min = d3.min([$$.orgXDomain[0], min]);
5191     } else {
5192       return config.zoom_x_min;
5193     }
5194   };
5195
5196   Chart.prototype.zoom.range = function (range) {
5197     if (arguments.length) {
5198       if (isDefined(range.max)) {
5199         this.domain.max(range.max);
5200       }
5201
5202       if (isDefined(range.min)) {
5203         this.domain.min(range.min);
5204       }
5205     } else {
5206       return {
5207         max: this.domain.max(),
5208         min: this.domain.min()
5209       };
5210     }
5211   };
5212
5213   ChartInternal.prototype.initPie = function () {
5214     var $$ = this,
5215         d3 = $$.d3;
5216     $$.pie = d3.pie().value(function (d) {
5217       return d.values.reduce(function (a, b) {
5218         return a + b.value;
5219       }, 0);
5220     });
5221     var orderFct = $$.getOrderFunction(); // we need to reverse the returned order if asc or desc to have the slice in expected order.
5222
5223     if (orderFct && ($$.isOrderAsc() || $$.isOrderDesc())) {
5224       var defaultSort = orderFct;
5225
5226       orderFct = function orderFct(t1, t2) {
5227         return defaultSort(t1, t2) * -1;
5228       };
5229     }
5230
5231     $$.pie.sort(orderFct || null);
5232   };
5233
5234   ChartInternal.prototype.updateRadius = function () {
5235     var $$ = this,
5236         config = $$.config,
5237         w = config.gauge_width || config.donut_width,
5238         gaugeArcWidth = $$.filterTargetsToShow($$.data.targets).length * $$.config.gauge_arcs_minWidth;
5239     $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2 * ($$.hasType('gauge') ? 0.85 : 1);
5240     $$.radius = $$.radiusExpanded * 0.95;
5241     $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
5242     $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
5243     $$.gaugeArcWidth = w ? w : gaugeArcWidth <= $$.radius - $$.innerRadius ? $$.radius - $$.innerRadius : gaugeArcWidth <= $$.radius ? gaugeArcWidth : $$.radius;
5244   };
5245
5246   ChartInternal.prototype.updateArc = function () {
5247     var $$ = this;
5248     $$.svgArc = $$.getSvgArc();
5249     $$.svgArcExpanded = $$.getSvgArcExpanded();
5250     $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
5251   };
5252
5253   ChartInternal.prototype.updateAngle = function (d) {
5254     var $$ = this,
5255         config = $$.config,
5256         found = false,
5257         index = 0,
5258         gMin,
5259         gMax,
5260         gTic,
5261         gValue;
5262
5263     if (!config) {
5264       return null;
5265     }
5266
5267     $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
5268       if (!found && t.data.id === d.data.id) {
5269         found = true;
5270         d = t;
5271         d.index = index;
5272       }
5273
5274       index++;
5275     });
5276
5277     if (isNaN(d.startAngle)) {
5278       d.startAngle = 0;
5279     }
5280
5281     if (isNaN(d.endAngle)) {
5282       d.endAngle = d.startAngle;
5283     }
5284
5285     if ($$.isGaugeType(d.data)) {
5286       gMin = config.gauge_min;
5287       gMax = config.gauge_max;
5288       gTic = Math.PI * (config.gauge_fullCircle ? 2 : 1) / (gMax - gMin);
5289       gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : gMax - gMin;
5290       d.startAngle = config.gauge_startingAngle;
5291       d.endAngle = d.startAngle + gTic * gValue;
5292     }
5293
5294     return found ? d : null;
5295   };
5296
5297   ChartInternal.prototype.getSvgArc = function () {
5298     var $$ = this,
5299         hasGaugeType = $$.hasType('gauge'),
5300         singleArcWidth = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length,
5301         arc = $$.d3.arc().outerRadius(function (d) {
5302       return hasGaugeType ? $$.radius - singleArcWidth * d.index : $$.radius;
5303     }).innerRadius(function (d) {
5304       return hasGaugeType ? $$.radius - singleArcWidth * (d.index + 1) : $$.innerRadius;
5305     }),
5306         newArc = function newArc(d, withoutUpdate) {
5307       var updated;
5308
5309       if (withoutUpdate) {
5310         return arc(d);
5311       } // for interpolate
5312
5313
5314       updated = $$.updateAngle(d);
5315       return updated ? arc(updated) : "M 0 0";
5316     }; // TODO: extends all function
5317
5318
5319     newArc.centroid = arc.centroid;
5320     return newArc;
5321   };
5322
5323   ChartInternal.prototype.getSvgArcExpanded = function (rate) {
5324     rate = rate || 1;
5325     var $$ = this,
5326         hasGaugeType = $$.hasType('gauge'),
5327         singleArcWidth = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length,
5328         expandWidth = Math.min($$.radiusExpanded * rate - $$.radius, singleArcWidth * 0.8 - (1 - rate) * 100),
5329         arc = $$.d3.arc().outerRadius(function (d) {
5330       return hasGaugeType ? $$.radius - singleArcWidth * d.index + expandWidth : $$.radiusExpanded * rate;
5331     }).innerRadius(function (d) {
5332       return hasGaugeType ? $$.radius - singleArcWidth * (d.index + 1) : $$.innerRadius;
5333     });
5334     return function (d) {
5335       var updated = $$.updateAngle(d);
5336       return updated ? arc(updated) : "M 0 0";
5337     };
5338   };
5339
5340   ChartInternal.prototype.getArc = function (d, withoutUpdate, force) {
5341     return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
5342   };
5343
5344   ChartInternal.prototype.transformForArcLabel = function (d) {
5345     var $$ = this,
5346         config = $$.config,
5347         updated = $$.updateAngle(d),
5348         c,
5349         x,
5350         y,
5351         h,
5352         ratio,
5353         translate = "",
5354         hasGauge = $$.hasType('gauge');
5355
5356     if (updated && !hasGauge) {
5357       c = this.svgArc.centroid(updated);
5358       x = isNaN(c[0]) ? 0 : c[0];
5359       y = isNaN(c[1]) ? 0 : c[1];
5360       h = Math.sqrt(x * x + y * y);
5361
5362       if ($$.hasType('donut') && config.donut_label_ratio) {
5363         ratio = isFunction(config.donut_label_ratio) ? config.donut_label_ratio(d, $$.radius, h) : config.donut_label_ratio;
5364       } else if ($$.hasType('pie') && config.pie_label_ratio) {
5365         ratio = isFunction(config.pie_label_ratio) ? config.pie_label_ratio(d, $$.radius, h) : config.pie_label_ratio;
5366       } else {
5367         ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
5368       }
5369
5370       translate = "translate(" + x * ratio + ',' + y * ratio + ")";
5371     } else if (updated && hasGauge && $$.filterTargetsToShow($$.data.targets).length > 1) {
5372       var y1 = Math.sin(updated.endAngle - Math.PI / 2);
5373       x = Math.cos(updated.endAngle - Math.PI / 2) * ($$.radiusExpanded + 25);
5374       y = y1 * ($$.radiusExpanded + 15 - Math.abs(y1 * 10)) + 3;
5375       translate = "translate(" + x + ',' + y + ")";
5376     }
5377
5378     return translate;
5379   };
5380
5381   ChartInternal.prototype.getArcRatio = function (d) {
5382     var $$ = this,
5383         config = $$.config,
5384         whole = Math.PI * ($$.hasType('gauge') && !config.gauge_fullCircle ? 1 : 2);
5385     return d ? (d.endAngle - d.startAngle) / whole : null;
5386   };
5387
5388   ChartInternal.prototype.convertToArcData = function (d) {
5389     return this.addName({
5390       id: d.data.id,
5391       value: d.value,
5392       ratio: this.getArcRatio(d),
5393       index: d.index
5394     });
5395   };
5396
5397   ChartInternal.prototype.textForArcLabel = function (d) {
5398     var $$ = this,
5399         updated,
5400         value,
5401         ratio,
5402         id,
5403         format;
5404
5405     if (!$$.shouldShowArcLabel()) {
5406       return "";
5407     }
5408
5409     updated = $$.updateAngle(d);
5410     value = updated ? updated.value : null;
5411     ratio = $$.getArcRatio(updated);
5412     id = d.data.id;
5413
5414     if (!$$.hasType('gauge') && !$$.meetsArcLabelThreshold(ratio)) {
5415       return "";
5416     }
5417
5418     format = $$.getArcLabelFormat();
5419     return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
5420   };
5421
5422   ChartInternal.prototype.textForGaugeMinMax = function (value, isMax) {
5423     var $$ = this,
5424         format = $$.getGaugeLabelExtents();
5425     return format ? format(value, isMax) : value;
5426   };
5427
5428   ChartInternal.prototype.expandArc = function (targetIds) {
5429     var $$ = this,
5430         interval; // MEMO: avoid to cancel transition
5431
5432     if ($$.transiting) {
5433       interval = window.setInterval(function () {
5434         if (!$$.transiting) {
5435           window.clearInterval(interval);
5436
5437           if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
5438             $$.expandArc(targetIds);
5439           }
5440         }
5441       }, 10);
5442       return;
5443     }
5444
5445     targetIds = $$.mapToTargetIds(targetIds);
5446     $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
5447       if (!$$.shouldExpand(d.data.id)) {
5448         return;
5449       }
5450
5451       $$.d3.select(this).selectAll('path').transition().duration($$.expandDuration(d.data.id)).attr("d", $$.svgArcExpanded).transition().duration($$.expandDuration(d.data.id) * 2).attr("d", $$.svgArcExpandedSub).each(function (d) {
5452         if ($$.isDonutType(d.data)) ;
5453       });
5454     });
5455   };
5456
5457   ChartInternal.prototype.unexpandArc = function (targetIds) {
5458     var $$ = this;
5459
5460     if ($$.transiting) {
5461       return;
5462     }
5463
5464     targetIds = $$.mapToTargetIds(targetIds);
5465     $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path').transition().duration(function (d) {
5466       return $$.expandDuration(d.data.id);
5467     }).attr("d", $$.svgArc);
5468     $$.svg.selectAll('.' + CLASS.arc);
5469   };
5470
5471   ChartInternal.prototype.expandDuration = function (id) {
5472     var $$ = this,
5473         config = $$.config;
5474
5475     if ($$.isDonutType(id)) {
5476       return config.donut_expand_duration;
5477     } else if ($$.isGaugeType(id)) {
5478       return config.gauge_expand_duration;
5479     } else if ($$.isPieType(id)) {
5480       return config.pie_expand_duration;
5481     } else {
5482       return 50;
5483     }
5484   };
5485
5486   ChartInternal.prototype.shouldExpand = function (id) {
5487     var $$ = this,
5488         config = $$.config;
5489     return $$.isDonutType(id) && config.donut_expand || $$.isGaugeType(id) && config.gauge_expand || $$.isPieType(id) && config.pie_expand;
5490   };
5491
5492   ChartInternal.prototype.shouldShowArcLabel = function () {
5493     var $$ = this,
5494         config = $$.config,
5495         shouldShow = true;
5496
5497     if ($$.hasType('donut')) {
5498       shouldShow = config.donut_label_show;
5499     } else if ($$.hasType('pie')) {
5500       shouldShow = config.pie_label_show;
5501     } // when gauge, always true
5502
5503
5504     return shouldShow;
5505   };
5506
5507   ChartInternal.prototype.meetsArcLabelThreshold = function (ratio) {
5508     var $$ = this,
5509         config = $$.config,
5510         threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
5511     return ratio >= threshold;
5512   };
5513
5514   ChartInternal.prototype.getArcLabelFormat = function () {
5515     var $$ = this,
5516         config = $$.config,
5517         format = config.pie_label_format;
5518
5519     if ($$.hasType('gauge')) {
5520       format = config.gauge_label_format;
5521     } else if ($$.hasType('donut')) {
5522       format = config.donut_label_format;
5523     }
5524
5525     return format;
5526   };
5527
5528   ChartInternal.prototype.getGaugeLabelExtents = function () {
5529     var $$ = this,
5530         config = $$.config;
5531     return config.gauge_label_extents;
5532   };
5533
5534   ChartInternal.prototype.getArcTitle = function () {
5535     var $$ = this;
5536     return $$.hasType('donut') ? $$.config.donut_title : "";
5537   };
5538
5539   ChartInternal.prototype.updateTargetsForArc = function (targets) {
5540     var $$ = this,
5541         main = $$.main,
5542         mainPies,
5543         mainPieEnter,
5544         classChartArc = $$.classChartArc.bind($$),
5545         classArcs = $$.classArcs.bind($$),
5546         classFocus = $$.classFocus.bind($$);
5547     mainPies = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc).data($$.pie(targets)).attr("class", function (d) {
5548       return classChartArc(d) + classFocus(d.data);
5549     });
5550     mainPieEnter = mainPies.enter().append("g").attr("class", classChartArc);
5551     mainPieEnter.append('g').attr('class', classArcs);
5552     mainPieEnter.append("text").attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em").style("opacity", 0).style("text-anchor", "middle").style("pointer-events", "none"); // MEMO: can not keep same color..., but not bad to update color in redraw
5553     //mainPieUpdate.exit().remove();
5554   };
5555
5556   ChartInternal.prototype.initArc = function () {
5557     var $$ = this;
5558     $$.arcs = $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
5559     $$.arcs.append('text').attr('class', CLASS.chartArcsTitle).style("text-anchor", "middle").text($$.getArcTitle());
5560   };
5561
5562   ChartInternal.prototype.redrawArc = function (duration, durationForExit, withTransform) {
5563     var $$ = this,
5564         d3 = $$.d3,
5565         config = $$.config,
5566         main = $$.main,
5567         arcs,
5568         mainArc,
5569         arcLabelLines,
5570         mainArcLabelLine,
5571         hasGaugeType = $$.hasType('gauge');
5572     arcs = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc).data($$.arcData.bind($$));
5573     mainArc = arcs.enter().append('path').attr("class", $$.classArc.bind($$)).style("fill", function (d) {
5574       return $$.color(d.data);
5575     }).style("cursor", function (d) {
5576       return config.interaction_enabled && config.data_selection_isselectable(d) ? "pointer" : null;
5577     }).each(function (d) {
5578       if ($$.isGaugeType(d.data)) {
5579         d.startAngle = d.endAngle = config.gauge_startingAngle;
5580       }
5581
5582       this._current = d;
5583     }).merge(arcs);
5584
5585     if (hasGaugeType) {
5586       arcLabelLines = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arcLabelLine).data($$.arcData.bind($$));
5587       mainArcLabelLine = arcLabelLines.enter().append('rect').attr("class", function (d) {
5588         return CLASS.arcLabelLine + ' ' + CLASS.target + ' ' + CLASS.target + '-' + d.data.id;
5589       }).merge(arcLabelLines);
5590
5591       if ($$.filterTargetsToShow($$.data.targets).length === 1) {
5592         mainArcLabelLine.style("display", "none");
5593       } else {
5594         mainArcLabelLine.style("fill", function (d) {
5595           return config.color_pattern.length > 0 ? $$.levelColor(d.data.values[0].value) : $$.color(d.data);
5596         }).style("display", config.gauge_labelLine_show ? "" : "none").each(function (d) {
5597           var lineLength = 0,
5598               lineThickness = 2,
5599               x = 0,
5600               y = 0,
5601               transform = "";
5602
5603           if ($$.hiddenTargetIds.indexOf(d.data.id) < 0) {
5604             var updated = $$.updateAngle(d),
5605                 innerLineLength = $$.gaugeArcWidth / $$.filterTargetsToShow($$.data.targets).length * (updated.index + 1),
5606                 lineAngle = updated.endAngle - Math.PI / 2,
5607                 arcInnerRadius = $$.radius - innerLineLength,
5608                 linePositioningAngle = lineAngle - (arcInnerRadius === 0 ? 0 : 1 / arcInnerRadius);
5609             lineLength = $$.radiusExpanded - $$.radius + innerLineLength;
5610             x = Math.cos(linePositioningAngle) * arcInnerRadius;
5611             y = Math.sin(linePositioningAngle) * arcInnerRadius;
5612             transform = "rotate(" + lineAngle * 180 / Math.PI + ", " + x + ", " + y + ")";
5613           }
5614
5615           d3.select(this).attr('x', x).attr('y', y).attr('width', lineLength).attr('height', lineThickness).attr('transform', transform).style("stroke-dasharray", "0, " + (lineLength + lineThickness) + ", 0");
5616         });
5617       }
5618     }
5619
5620     mainArc.attr("transform", function (d) {
5621       return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : "";
5622     }).on('mouseover', config.interaction_enabled ? function (d) {
5623       var updated, arcData;
5624
5625       if ($$.transiting) {
5626         // skip while transiting
5627         return;
5628       }
5629
5630       updated = $$.updateAngle(d);
5631
5632       if (updated) {
5633         arcData = $$.convertToArcData(updated); // transitions
5634
5635         $$.expandArc(updated.data.id);
5636         $$.api.focus(updated.data.id);
5637         $$.toggleFocusLegend(updated.data.id, true);
5638         $$.config.data_onmouseover(arcData, this);
5639       }
5640     } : null).on('mousemove', config.interaction_enabled ? function (d) {
5641       var updated = $$.updateAngle(d),
5642           arcData,
5643           selectedData;
5644
5645       if (updated) {
5646         arcData = $$.convertToArcData(updated), selectedData = [arcData];
5647         $$.showTooltip(selectedData, this);
5648       }
5649     } : null).on('mouseout', config.interaction_enabled ? function (d) {
5650       var updated, arcData;
5651
5652       if ($$.transiting) {
5653         // skip while transiting
5654         return;
5655       }
5656
5657       updated = $$.updateAngle(d);
5658
5659       if (updated) {
5660         arcData = $$.convertToArcData(updated); // transitions
5661
5662         $$.unexpandArc(updated.data.id);
5663         $$.api.revert();
5664         $$.revertLegend();
5665         $$.hideTooltip();
5666         $$.config.data_onmouseout(arcData, this);
5667       }
5668     } : null).on('click', config.interaction_enabled ? function (d, i) {
5669       var updated = $$.updateAngle(d),
5670           arcData;
5671
5672       if (updated) {
5673         arcData = $$.convertToArcData(updated);
5674
5675         if ($$.toggleShape) {
5676           $$.toggleShape(this, arcData, i);
5677         }
5678
5679         $$.config.data_onclick.call($$.api, arcData, this);
5680       }
5681     } : null).each(function () {
5682       $$.transiting = true;
5683     }).transition().duration(duration).attrTween("d", function (d) {
5684       var updated = $$.updateAngle(d),
5685           interpolate;
5686
5687       if (!updated) {
5688         return function () {
5689           return "M 0 0";
5690         };
5691       } //                if (this._current === d) {
5692       //                    this._current = {
5693       //                        startAngle: Math.PI*2,
5694       //                        endAngle: Math.PI*2,
5695       //                    };
5696       //                }
5697
5698
5699       if (isNaN(this._current.startAngle)) {
5700         this._current.startAngle = 0;
5701       }
5702
5703       if (isNaN(this._current.endAngle)) {
5704         this._current.endAngle = this._current.startAngle;
5705       }
5706
5707       interpolate = d3.interpolate(this._current, updated);
5708       this._current = interpolate(0);
5709       return function (t) {
5710         var interpolated = interpolate(t);
5711         interpolated.data = d.data; // data.id will be updated by interporator
5712
5713         return $$.getArc(interpolated, true);
5714       };
5715     }).attr("transform", withTransform ? "scale(1)" : "").style("fill", function (d) {
5716       return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
5717     }) // Where gauge reading color would receive customization.
5718     .call($$.endall, function () {
5719       $$.transiting = false;
5720     });
5721     arcs.exit().transition().duration(durationForExit).style('opacity', 0).remove();
5722     main.selectAll('.' + CLASS.chartArc).select('text').style("opacity", 0).attr('class', function (d) {
5723       return $$.isGaugeType(d.data) ? CLASS.gaugeValue : '';
5724     }).text($$.textForArcLabel.bind($$)).attr("transform", $$.transformForArcLabel.bind($$)).style('font-size', function (d) {
5725       return $$.isGaugeType(d.data) && $$.filterTargetsToShow($$.data.targets).length === 1 ? Math.round($$.radius / 5) + 'px' : '';
5726     }).transition().duration(duration).style("opacity", function (d) {
5727       return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0;
5728     });
5729     main.select('.' + CLASS.chartArcsTitle).style("opacity", $$.hasType('donut') || hasGaugeType ? 1 : 0);
5730
5731     if (hasGaugeType) {
5732       var index = 0;
5733       var backgroundArc = $$.arcs.select('g.' + CLASS.chartArcsBackground).selectAll('path.' + CLASS.chartArcsBackground).data($$.data.targets);
5734       backgroundArc.enter().append("path").attr("class", function (d, i) {
5735         return CLASS.chartArcsBackground + ' ' + CLASS.chartArcsBackground + '-' + i;
5736       }).merge(backgroundArc).attr("d", function (d1) {
5737         if ($$.hiddenTargetIds.indexOf(d1.id) >= 0) {
5738           return "M 0 0";
5739         }
5740
5741         var d = {
5742           data: [{
5743             value: config.gauge_max
5744           }],
5745           startAngle: config.gauge_startingAngle,
5746           endAngle: -1 * config.gauge_startingAngle * (config.gauge_fullCircle ? Math.PI : 1),
5747           index: index++
5748         };
5749         return $$.getArc(d, true, true);
5750       });
5751       backgroundArc.exit().remove();
5752       $$.arcs.select('.' + CLASS.chartArcsGaugeUnit).attr("dy", ".75em").text(config.gauge_label_show ? config.gauge_units : '');
5753       $$.arcs.select('.' + CLASS.chartArcsGaugeMin).attr("dx", -1 * ($$.innerRadius + ($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2)) + "px").attr("dy", "1.2em").text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_min, false) : '');
5754       $$.arcs.select('.' + CLASS.chartArcsGaugeMax).attr("dx", $$.innerRadius + ($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2) + "px").attr("dy", "1.2em").text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_max, true) : '');
5755     }
5756   };
5757
5758   ChartInternal.prototype.initGauge = function () {
5759     var arcs = this.arcs;
5760
5761     if (this.hasType('gauge')) {
5762       arcs.append('g').attr("class", CLASS.chartArcsBackground);
5763       arcs.append("text").attr("class", CLASS.chartArcsGaugeUnit).style("text-anchor", "middle").style("pointer-events", "none");
5764       arcs.append("text").attr("class", CLASS.chartArcsGaugeMin).style("text-anchor", "middle").style("pointer-events", "none");
5765       arcs.append("text").attr("class", CLASS.chartArcsGaugeMax).style("text-anchor", "middle").style("pointer-events", "none");
5766     }
5767   };
5768
5769   ChartInternal.prototype.getGaugeLabelHeight = function () {
5770     return this.config.gauge_label_show ? 20 : 0;
5771   };
5772
5773   ChartInternal.prototype.hasCaches = function (ids) {
5774     for (var i = 0; i < ids.length; i++) {
5775       if (!(ids[i] in this.cache)) {
5776         return false;
5777       }
5778     }
5779
5780     return true;
5781   };
5782
5783   ChartInternal.prototype.addCache = function (id, target) {
5784     this.cache[id] = this.cloneTarget(target);
5785   };
5786
5787   ChartInternal.prototype.getCaches = function (ids) {
5788     var targets = [],
5789         i;
5790
5791     for (i = 0; i < ids.length; i++) {
5792       if (ids[i] in this.cache) {
5793         targets.push(this.cloneTarget(this.cache[ids[i]]));
5794       }
5795     }
5796
5797     return targets;
5798   };
5799
5800   ChartInternal.prototype.categoryName = function (i) {
5801     var config = this.config;
5802     return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
5803   };
5804
5805   ChartInternal.prototype.generateTargetClass = function (targetId) {
5806     return targetId || targetId === 0 ? ('-' + targetId).replace(/\s/g, '-') : '';
5807   };
5808
5809   ChartInternal.prototype.generateClass = function (prefix, targetId) {
5810     return " " + prefix + " " + prefix + this.generateTargetClass(targetId);
5811   };
5812
5813   ChartInternal.prototype.classText = function (d) {
5814     return this.generateClass(CLASS.text, d.index);
5815   };
5816
5817   ChartInternal.prototype.classTexts = function (d) {
5818     return this.generateClass(CLASS.texts, d.id);
5819   };
5820
5821   ChartInternal.prototype.classShape = function (d) {
5822     return this.generateClass(CLASS.shape, d.index);
5823   };
5824
5825   ChartInternal.prototype.classShapes = function (d) {
5826     return this.generateClass(CLASS.shapes, d.id);
5827   };
5828
5829   ChartInternal.prototype.classLine = function (d) {
5830     return this.classShape(d) + this.generateClass(CLASS.line, d.id);
5831   };
5832
5833   ChartInternal.prototype.classLines = function (d) {
5834     return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
5835   };
5836
5837   ChartInternal.prototype.classCircle = function (d) {
5838     return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
5839   };
5840
5841   ChartInternal.prototype.classCircles = function (d) {
5842     return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
5843   };
5844
5845   ChartInternal.prototype.classBar = function (d) {
5846     return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
5847   };
5848
5849   ChartInternal.prototype.classBars = function (d) {
5850     return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
5851   };
5852
5853   ChartInternal.prototype.classArc = function (d) {
5854     return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
5855   };
5856
5857   ChartInternal.prototype.classArcs = function (d) {
5858     return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
5859   };
5860
5861   ChartInternal.prototype.classArea = function (d) {
5862     return this.classShape(d) + this.generateClass(CLASS.area, d.id);
5863   };
5864
5865   ChartInternal.prototype.classAreas = function (d) {
5866     return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
5867   };
5868
5869   ChartInternal.prototype.classRegion = function (d, i) {
5870     return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
5871   };
5872
5873   ChartInternal.prototype.classEvent = function (d) {
5874     return this.generateClass(CLASS.eventRect, d.index);
5875   };
5876
5877   ChartInternal.prototype.classTarget = function (id) {
5878     var $$ = this;
5879     var additionalClassSuffix = $$.config.data_classes[id],
5880         additionalClass = '';
5881
5882     if (additionalClassSuffix) {
5883       additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
5884     }
5885
5886     return $$.generateClass(CLASS.target, id) + additionalClass;
5887   };
5888
5889   ChartInternal.prototype.classFocus = function (d) {
5890     return this.classFocused(d) + this.classDefocused(d);
5891   };
5892
5893   ChartInternal.prototype.classFocused = function (d) {
5894     return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
5895   };
5896
5897   ChartInternal.prototype.classDefocused = function (d) {
5898     return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
5899   };
5900
5901   ChartInternal.prototype.classChartText = function (d) {
5902     return CLASS.chartText + this.classTarget(d.id);
5903   };
5904
5905   ChartInternal.prototype.classChartLine = function (d) {
5906     return CLASS.chartLine + this.classTarget(d.id);
5907   };
5908
5909   ChartInternal.prototype.classChartBar = function (d) {
5910     return CLASS.chartBar + this.classTarget(d.id);
5911   };
5912
5913   ChartInternal.prototype.classChartArc = function (d) {
5914     return CLASS.chartArc + this.classTarget(d.data.id);
5915   };
5916
5917   ChartInternal.prototype.getTargetSelectorSuffix = function (targetId) {
5918     return this.generateTargetClass(targetId).replace(/([?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\])/g, '\\$1');
5919   };
5920
5921   ChartInternal.prototype.selectorTarget = function (id, prefix) {
5922     return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
5923   };
5924
5925   ChartInternal.prototype.selectorTargets = function (ids, prefix) {
5926     var $$ = this;
5927     ids = ids || [];
5928     return ids.length ? ids.map(function (id) {
5929       return $$.selectorTarget(id, prefix);
5930     }) : null;
5931   };
5932
5933   ChartInternal.prototype.selectorLegend = function (id) {
5934     return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
5935   };
5936
5937   ChartInternal.prototype.selectorLegends = function (ids) {
5938     var $$ = this;
5939     return ids && ids.length ? ids.map(function (id) {
5940       return $$.selectorLegend(id);
5941     }) : null;
5942   };
5943
5944   ChartInternal.prototype.getClipPath = function (id) {
5945     var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
5946     return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
5947   };
5948
5949   ChartInternal.prototype.appendClip = function (parent, id) {
5950     return parent.append("clipPath").attr("id", id).append("rect");
5951   };
5952
5953   ChartInternal.prototype.getAxisClipX = function (forHorizontal) {
5954     // axis line width + padding for left
5955     var left = Math.max(30, this.margin.left);
5956     return forHorizontal ? -(1 + left) : -(left - 1);
5957   };
5958
5959   ChartInternal.prototype.getAxisClipY = function (forHorizontal) {
5960     return forHorizontal ? -20 : -this.margin.top;
5961   };
5962
5963   ChartInternal.prototype.getXAxisClipX = function () {
5964     var $$ = this;
5965     return $$.getAxisClipX(!$$.config.axis_rotated);
5966   };
5967
5968   ChartInternal.prototype.getXAxisClipY = function () {
5969     var $$ = this;
5970     return $$.getAxisClipY(!$$.config.axis_rotated);
5971   };
5972
5973   ChartInternal.prototype.getYAxisClipX = function () {
5974     var $$ = this;
5975     return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
5976   };
5977
5978   ChartInternal.prototype.getYAxisClipY = function () {
5979     var $$ = this;
5980     return $$.getAxisClipY($$.config.axis_rotated);
5981   };
5982
5983   ChartInternal.prototype.getAxisClipWidth = function (forHorizontal) {
5984     var $$ = this,
5985         left = Math.max(30, $$.margin.left),
5986         right = Math.max(30, $$.margin.right); // width + axis line width + padding for left/right
5987
5988     return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
5989   };
5990
5991   ChartInternal.prototype.getAxisClipHeight = function (forHorizontal) {
5992     // less than 20 is not enough to show the axis label 'outer' without legend
5993     return (forHorizontal ? this.margin.bottom : this.margin.top + this.height) + 20;
5994   };
5995
5996   ChartInternal.prototype.getXAxisClipWidth = function () {
5997     var $$ = this;
5998     return $$.getAxisClipWidth(!$$.config.axis_rotated);
5999   };
6000
6001   ChartInternal.prototype.getXAxisClipHeight = function () {
6002     var $$ = this;
6003     return $$.getAxisClipHeight(!$$.config.axis_rotated);
6004   };
6005
6006   ChartInternal.prototype.getYAxisClipWidth = function () {
6007     var $$ = this;
6008     return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
6009   };
6010
6011   ChartInternal.prototype.getYAxisClipHeight = function () {
6012     var $$ = this;
6013     return $$.getAxisClipHeight($$.config.axis_rotated);
6014   };
6015
6016   ChartInternal.prototype.generateColor = function () {
6017     var $$ = this,
6018         config = $$.config,
6019         d3 = $$.d3,
6020         colors = config.data_colors,
6021         pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.schemeCategory10,
6022         callback = config.data_color,
6023         ids = [];
6024     return function (d) {
6025       var id = d.id || d.data && d.data.id || d,
6026           color; // if callback function is provided
6027
6028       if (colors[id] instanceof Function) {
6029         color = colors[id](d);
6030       } // if specified, choose that color
6031       else if (colors[id]) {
6032           color = colors[id];
6033         } // if not specified, choose from pattern
6034         else {
6035             if (ids.indexOf(id) < 0) {
6036               ids.push(id);
6037             }
6038
6039             color = pattern[ids.indexOf(id) % pattern.length];
6040             colors[id] = color;
6041           }
6042
6043       return callback instanceof Function ? callback(color, d) : color;
6044     };
6045   };
6046
6047   ChartInternal.prototype.generateLevelColor = function () {
6048     var $$ = this,
6049         config = $$.config,
6050         colors = config.color_pattern,
6051         threshold = config.color_threshold,
6052         asValue = threshold.unit === 'value',
6053         values = threshold.values && threshold.values.length ? threshold.values : [],
6054         max = threshold.max || 100;
6055     return notEmpty(config.color_threshold) ? function (value) {
6056       var i,
6057           v,
6058           color = colors[colors.length - 1];
6059
6060       for (i = 0; i < values.length; i++) {
6061         v = asValue ? value : value * 100 / max;
6062
6063         if (v < values[i]) {
6064           color = colors[i];
6065           break;
6066         }
6067       }
6068
6069       return color;
6070     } : null;
6071   };
6072
6073   ChartInternal.prototype.getDefaultConfig = function () {
6074     var config = {
6075       bindto: '#chart',
6076       svg_classname: undefined,
6077       size_width: undefined,
6078       size_height: undefined,
6079       padding_left: undefined,
6080       padding_right: undefined,
6081       padding_top: undefined,
6082       padding_bottom: undefined,
6083       resize_auto: true,
6084       zoom_enabled: false,
6085       zoom_initialRange: undefined,
6086       zoom_type: 'scroll',
6087       zoom_disableDefaultBehavior: false,
6088       zoom_privileged: false,
6089       zoom_rescale: false,
6090       zoom_onzoom: function zoom_onzoom() {},
6091       zoom_onzoomstart: function zoom_onzoomstart() {},
6092       zoom_onzoomend: function zoom_onzoomend() {},
6093       zoom_x_min: undefined,
6094       zoom_x_max: undefined,
6095       interaction_brighten: true,
6096       interaction_enabled: true,
6097       onmouseover: function onmouseover() {},
6098       onmouseout: function onmouseout() {},
6099       onresize: function onresize() {},
6100       onresized: function onresized() {},
6101       oninit: function oninit() {},
6102       onrendered: function onrendered() {},
6103       transition_duration: 350,
6104       data_x: undefined,
6105       data_xs: {},
6106       data_xFormat: '%Y-%m-%d',
6107       data_xLocaltime: true,
6108       data_xSort: true,
6109       data_idConverter: function data_idConverter(id) {
6110         return id;
6111       },
6112       data_names: {},
6113       data_classes: {},
6114       data_groups: [],
6115       data_axes: {},
6116       data_type: undefined,
6117       data_types: {},
6118       data_labels: {},
6119       data_order: 'desc',
6120       data_regions: {},
6121       data_color: undefined,
6122       data_colors: {},
6123       data_hide: false,
6124       data_filter: undefined,
6125       data_selection_enabled: false,
6126       data_selection_grouped: false,
6127       data_selection_isselectable: function data_selection_isselectable() {
6128         return true;
6129       },
6130       data_selection_multiple: true,
6131       data_selection_draggable: false,
6132       data_onclick: function data_onclick() {},
6133       data_onmouseover: function data_onmouseover() {},
6134       data_onmouseout: function data_onmouseout() {},
6135       data_onselected: function data_onselected() {},
6136       data_onunselected: function data_onunselected() {},
6137       data_url: undefined,
6138       data_headers: undefined,
6139       data_json: undefined,
6140       data_rows: undefined,
6141       data_columns: undefined,
6142       data_mimeType: undefined,
6143       data_keys: undefined,
6144       // configuration for no plot-able data supplied.
6145       data_empty_label_text: "",
6146       // subchart
6147       subchart_show: false,
6148       subchart_size_height: 60,
6149       subchart_axis_x_show: true,
6150       subchart_onbrush: function subchart_onbrush() {},
6151       // color
6152       color_pattern: [],
6153       color_threshold: {},
6154       // legend
6155       legend_show: true,
6156       legend_hide: false,
6157       legend_position: 'bottom',
6158       legend_inset_anchor: 'top-left',
6159       legend_inset_x: 10,
6160       legend_inset_y: 0,
6161       legend_inset_step: undefined,
6162       legend_item_onclick: undefined,
6163       legend_item_onmouseover: undefined,
6164       legend_item_onmouseout: undefined,
6165       legend_equally: false,
6166       legend_padding: 0,
6167       legend_item_tile_width: 10,
6168       legend_item_tile_height: 10,
6169       // axis
6170       axis_rotated: false,
6171       axis_x_show: true,
6172       axis_x_type: 'indexed',
6173       axis_x_localtime: true,
6174       axis_x_categories: [],
6175       axis_x_tick_centered: false,
6176       axis_x_tick_format: undefined,
6177       axis_x_tick_culling: {},
6178       axis_x_tick_culling_max: 10,
6179       axis_x_tick_count: undefined,
6180       axis_x_tick_fit: true,
6181       axis_x_tick_values: null,
6182       axis_x_tick_rotate: 0,
6183       axis_x_tick_outer: true,
6184       axis_x_tick_multiline: true,
6185       axis_x_tick_multilineMax: 0,
6186       axis_x_tick_width: null,
6187       axis_x_max: undefined,
6188       axis_x_min: undefined,
6189       axis_x_padding: {},
6190       axis_x_height: undefined,
6191       axis_x_selection: undefined,
6192       axis_x_label: {},
6193       axis_x_inner: undefined,
6194       axis_y_show: true,
6195       axis_y_type: undefined,
6196       axis_y_max: undefined,
6197       axis_y_min: undefined,
6198       axis_y_inverted: false,
6199       axis_y_center: undefined,
6200       axis_y_inner: undefined,
6201       axis_y_label: {},
6202       axis_y_tick_format: undefined,
6203       axis_y_tick_outer: true,
6204       axis_y_tick_values: null,
6205       axis_y_tick_rotate: 0,
6206       axis_y_tick_count: undefined,
6207       axis_y_tick_time_type: undefined,
6208       axis_y_tick_time_interval: undefined,
6209       axis_y_padding: {},
6210       axis_y_default: undefined,
6211       axis_y2_show: false,
6212       axis_y2_max: undefined,
6213       axis_y2_min: undefined,
6214       axis_y2_inverted: false,
6215       axis_y2_center: undefined,
6216       axis_y2_inner: undefined,
6217       axis_y2_label: {},
6218       axis_y2_tick_format: undefined,
6219       axis_y2_tick_outer: true,
6220       axis_y2_tick_values: null,
6221       axis_y2_tick_count: undefined,
6222       axis_y2_padding: {},
6223       axis_y2_default: undefined,
6224       // grid
6225       grid_x_show: false,
6226       grid_x_type: 'tick',
6227       grid_x_lines: [],
6228       grid_y_show: false,
6229       // not used
6230       // grid_y_type: 'tick',
6231       grid_y_lines: [],
6232       grid_y_ticks: 10,
6233       grid_focus_show: true,
6234       grid_lines_front: true,
6235       // point - point of each data
6236       point_show: true,
6237       point_r: 2.5,
6238       point_sensitivity: 10,
6239       point_focus_expand_enabled: true,
6240       point_focus_expand_r: undefined,
6241       point_select_r: undefined,
6242       // line
6243       line_connectNull: false,
6244       line_step_type: 'step',
6245       // bar
6246       bar_width: undefined,
6247       bar_width_ratio: 0.6,
6248       bar_width_max: undefined,
6249       bar_zerobased: true,
6250       bar_space: 0,
6251       // area
6252       area_zerobased: true,
6253       area_above: false,
6254       // pie
6255       pie_label_show: true,
6256       pie_label_format: undefined,
6257       pie_label_threshold: 0.05,
6258       pie_label_ratio: undefined,
6259       pie_expand: {},
6260       pie_expand_duration: 50,
6261       // gauge
6262       gauge_fullCircle: false,
6263       gauge_label_show: true,
6264       gauge_labelLine_show: true,
6265       gauge_label_format: undefined,
6266       gauge_min: 0,
6267       gauge_max: 100,
6268       gauge_startingAngle: -1 * Math.PI / 2,
6269       gauge_label_extents: undefined,
6270       gauge_units: undefined,
6271       gauge_width: undefined,
6272       gauge_arcs_minWidth: 5,
6273       gauge_expand: {},
6274       gauge_expand_duration: 50,
6275       // donut
6276       donut_label_show: true,
6277       donut_label_format: undefined,
6278       donut_label_threshold: 0.05,
6279       donut_label_ratio: undefined,
6280       donut_width: undefined,
6281       donut_title: "",
6282       donut_expand: {},
6283       donut_expand_duration: 50,
6284       // spline
6285       spline_interpolation_type: 'cardinal',
6286       // region - region to change style
6287       regions: [],
6288       // tooltip - show when mouseover on each data
6289       tooltip_show: true,
6290       tooltip_grouped: true,
6291       tooltip_order: undefined,
6292       tooltip_format_title: undefined,
6293       tooltip_format_name: undefined,
6294       tooltip_format_value: undefined,
6295       tooltip_position: undefined,
6296       tooltip_contents: function tooltip_contents(d, defaultTitleFormat, defaultValueFormat, color) {
6297         return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
6298       },
6299       tooltip_init_show: false,
6300       tooltip_init_x: 0,
6301       tooltip_init_position: {
6302         top: '0px',
6303         left: '50px'
6304       },
6305       tooltip_onshow: function tooltip_onshow() {},
6306       tooltip_onhide: function tooltip_onhide() {},
6307       // title
6308       title_text: undefined,
6309       title_padding: {
6310         top: 0,
6311         right: 0,
6312         bottom: 0,
6313         left: 0
6314       },
6315       title_position: 'top-center'
6316     };
6317     Object.keys(this.additionalConfig).forEach(function (key) {
6318       config[key] = this.additionalConfig[key];
6319     }, this);
6320     return config;
6321   };
6322
6323   ChartInternal.prototype.additionalConfig = {};
6324
6325   ChartInternal.prototype.loadConfig = function (config) {
6326     var this_config = this.config,
6327         target,
6328         keys,
6329         read;
6330
6331     function find() {
6332       var key = keys.shift(); //        console.log("key =>", key, ", target =>", target);
6333
6334       if (key && target && _typeof(target) === 'object' && key in target) {
6335         target = target[key];
6336         return find();
6337       } else if (!key) {
6338         return target;
6339       } else {
6340         return undefined;
6341       }
6342     }
6343
6344     Object.keys(this_config).forEach(function (key) {
6345       target = config;
6346       keys = key.split('_');
6347       read = find(); //        console.log("CONFIG : ", key, read);
6348
6349       if (isDefined(read)) {
6350         this_config[key] = read;
6351       }
6352     });
6353   };
6354
6355   ChartInternal.prototype.convertUrlToData = function (url, mimeType, headers, keys, done) {
6356     var $$ = this,
6357         type = mimeType ? mimeType : 'csv',
6358         f,
6359         converter;
6360
6361     if (type === 'json') {
6362       f = $$.d3.json;
6363       converter = $$.convertJsonToData;
6364     } else if (type === 'tsv') {
6365       f = $$.d3.tsv;
6366       converter = $$.convertXsvToData;
6367     } else {
6368       f = $$.d3.csv;
6369       converter = $$.convertXsvToData;
6370     }
6371
6372     f(url, headers).then(function (data) {
6373       done.call($$, converter.call($$, data, keys));
6374     }).catch(function (error) {
6375       throw error;
6376     });
6377   };
6378
6379   ChartInternal.prototype.convertXsvToData = function (xsv) {
6380     var keys = xsv.columns,
6381         rows = xsv;
6382
6383     if (rows.length === 0) {
6384       return {
6385         keys: keys,
6386         rows: [keys.reduce(function (row, key) {
6387           return Object.assign(row, _defineProperty({}, key, null));
6388         }, {})]
6389       };
6390     } else {
6391       // [].concat() is to convert result into a plain array otherwise
6392       // test is not happy because rows have properties.
6393       return {
6394         keys: keys,
6395         rows: [].concat(xsv)
6396       };
6397     }
6398   };
6399
6400   ChartInternal.prototype.convertJsonToData = function (json, keys) {
6401     var $$ = this,
6402         new_rows = [],
6403         targetKeys,
6404         data;
6405
6406     if (keys) {
6407       // when keys specified, json would be an array that includes objects
6408       if (keys.x) {
6409         targetKeys = keys.value.concat(keys.x);
6410         $$.config.data_x = keys.x;
6411       } else {
6412         targetKeys = keys.value;
6413       }
6414
6415       new_rows.push(targetKeys);
6416       json.forEach(function (o) {
6417         var new_row = [];
6418         targetKeys.forEach(function (key) {
6419           // convert undefined to null because undefined data will be removed in convertDataToTargets()
6420           var v = $$.findValueInJson(o, key);
6421
6422           if (isUndefined(v)) {
6423             v = null;
6424           }
6425
6426           new_row.push(v);
6427         });
6428         new_rows.push(new_row);
6429       });
6430       data = $$.convertRowsToData(new_rows);
6431     } else {
6432       Object.keys(json).forEach(function (key) {
6433         new_rows.push([key].concat(json[key]));
6434       });
6435       data = $$.convertColumnsToData(new_rows);
6436     }
6437
6438     return data;
6439   };
6440
6441   ChartInternal.prototype.findValueInJson = function (object, path) {
6442     path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties (replace [] with .)
6443
6444     path = path.replace(/^\./, ''); // strip a leading dot
6445
6446     var pathArray = path.split('.');
6447
6448     for (var i = 0; i < pathArray.length; ++i) {
6449       var k = pathArray[i];
6450
6451       if (k in object) {
6452         object = object[k];
6453       } else {
6454         return;
6455       }
6456     }
6457
6458     return object;
6459   };
6460   /**
6461    * Converts the rows to normalized data.
6462    * @param {any[][]} rows The row data
6463    * @return {Object}
6464    */
6465
6466
6467   ChartInternal.prototype.convertRowsToData = function (rows) {
6468     var newRows = [];
6469     var keys = rows[0];
6470
6471     for (var i = 1; i < rows.length; i++) {
6472       var newRow = {};
6473
6474       for (var j = 0; j < rows[i].length; j++) {
6475         if (isUndefined(rows[i][j])) {
6476           throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
6477         }
6478
6479         newRow[keys[j]] = rows[i][j];
6480       }
6481
6482       newRows.push(newRow);
6483     }
6484
6485     return {
6486       keys: keys,
6487       rows: newRows
6488     };
6489   };
6490   /**
6491    * Converts the columns to normalized data.
6492    * @param {any[][]} columns The column data
6493    * @return {Object}
6494    */
6495
6496
6497   ChartInternal.prototype.convertColumnsToData = function (columns) {
6498     var newRows = [];
6499     var keys = [];
6500
6501     for (var i = 0; i < columns.length; i++) {
6502       var key = columns[i][0];
6503
6504       for (var j = 1; j < columns[i].length; j++) {
6505         if (isUndefined(newRows[j - 1])) {
6506           newRows[j - 1] = {};
6507         }
6508
6509         if (isUndefined(columns[i][j])) {
6510           throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
6511         }
6512
6513         newRows[j - 1][key] = columns[i][j];
6514       }
6515
6516       keys.push(key);
6517     }
6518
6519     return {
6520       keys: keys,
6521       rows: newRows
6522     };
6523   };
6524   /**
6525    * Converts the data format into the target format.
6526    * @param {!Object} data
6527    * @param {!Array} data.keys Ordered list of target IDs.
6528    * @param {!Array} data.rows Rows of data to convert.
6529    * @param {boolean} appendXs True to append to $$.data.xs, False to replace.
6530    * @return {!Array}
6531    */
6532
6533
6534   ChartInternal.prototype.convertDataToTargets = function (data, appendXs) {
6535     var $$ = this,
6536         config = $$.config,
6537         targets,
6538         ids,
6539         xs,
6540         keys; // handles format where keys are not orderly provided
6541
6542     if (isArray(data)) {
6543       keys = Object.keys(data[0]);
6544     } else {
6545       keys = data.keys;
6546       data = data.rows;
6547     }
6548
6549     ids = keys.filter($$.isNotX, $$);
6550     xs = keys.filter($$.isX, $$); // save x for update data by load when custom x and c3.x API
6551
6552     ids.forEach(function (id) {
6553       var xKey = $$.getXKey(id);
6554
6555       if ($$.isCustomX() || $$.isTimeSeries()) {
6556         // if included in input data
6557         if (xs.indexOf(xKey) >= 0) {
6558           $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(data.map(function (d) {
6559             return d[xKey];
6560           }).filter(isValue).map(function (rawX, i) {
6561             return $$.generateTargetX(rawX, id, i);
6562           }));
6563         } // if not included in input data, find from preloaded data of other id's x
6564         else if (config.data_x) {
6565             $$.data.xs[id] = $$.getOtherTargetXs();
6566           } // if not included in input data, find from preloaded data
6567           else if (notEmpty(config.data_xs)) {
6568               $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
6569             } // MEMO: if no x included, use same x of current will be used
6570
6571       } else {
6572         $$.data.xs[id] = data.map(function (d, i) {
6573           return i;
6574         });
6575       }
6576     }); // check x is defined
6577
6578     ids.forEach(function (id) {
6579       if (!$$.data.xs[id]) {
6580         throw new Error('x is not defined for id = "' + id + '".');
6581       }
6582     }); // convert to target
6583
6584     targets = ids.map(function (id, index) {
6585       var convertedId = config.data_idConverter(id);
6586       return {
6587         id: convertedId,
6588         id_org: id,
6589         values: data.map(function (d, i) {
6590           var xKey = $$.getXKey(id),
6591               rawX = d[xKey],
6592               value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null,
6593               x; // use x as categories if custom x and categorized
6594
6595           if ($$.isCustomX() && $$.isCategorized() && !isUndefined(rawX)) {
6596             if (index === 0 && i === 0) {
6597               config.axis_x_categories = [];
6598             }
6599
6600             x = config.axis_x_categories.indexOf(rawX);
6601
6602             if (x === -1) {
6603               x = config.axis_x_categories.length;
6604               config.axis_x_categories.push(rawX);
6605             }
6606           } else {
6607             x = $$.generateTargetX(rawX, id, i);
6608           } // mark as x = undefined if value is undefined and filter to remove after mapped
6609
6610
6611           if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
6612             x = undefined;
6613           }
6614
6615           return {
6616             x: x,
6617             value: value,
6618             id: convertedId
6619           };
6620         }).filter(function (v) {
6621           return isDefined(v.x);
6622         })
6623       };
6624     }); // finish targets
6625
6626     targets.forEach(function (t) {
6627       var i; // sort values by its x
6628
6629       if (config.data_xSort) {
6630         t.values = t.values.sort(function (v1, v2) {
6631           var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
6632               x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
6633           return x1 - x2;
6634         });
6635       } // indexing each value
6636
6637
6638       i = 0;
6639       t.values.forEach(function (v) {
6640         v.index = i++;
6641       }); // this needs to be sorted because its index and value.index is identical
6642
6643       $$.data.xs[t.id].sort(function (v1, v2) {
6644         return v1 - v2;
6645       });
6646     }); // cache information about values
6647
6648     $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets);
6649     $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets); // set target types
6650
6651     if (config.data_type) {
6652       $$.setTargetType($$.mapToIds(targets).filter(function (id) {
6653         return !(id in config.data_types);
6654       }), config.data_type);
6655     } // cache as original id keyed
6656
6657
6658     targets.forEach(function (d) {
6659       $$.addCache(d.id_org, d);
6660     });
6661     return targets;
6662   };
6663
6664   ChartInternal.prototype.isX = function (key) {
6665     var $$ = this,
6666         config = $$.config;
6667     return config.data_x && key === config.data_x || notEmpty(config.data_xs) && hasValue(config.data_xs, key);
6668   };
6669
6670   ChartInternal.prototype.isNotX = function (key) {
6671     return !this.isX(key);
6672   };
6673
6674   ChartInternal.prototype.getXKey = function (id) {
6675     var $$ = this,
6676         config = $$.config;
6677     return config.data_x ? config.data_x : notEmpty(config.data_xs) ? config.data_xs[id] : null;
6678   };
6679
6680   ChartInternal.prototype.getXValuesOfXKey = function (key, targets) {
6681     var $$ = this,
6682         xValues,
6683         ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : [];
6684     ids.forEach(function (id) {
6685       if ($$.getXKey(id) === key) {
6686         xValues = $$.data.xs[id];
6687       }
6688     });
6689     return xValues;
6690   };
6691
6692   ChartInternal.prototype.getXValue = function (id, i) {
6693     var $$ = this;
6694     return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
6695   };
6696
6697   ChartInternal.prototype.getOtherTargetXs = function () {
6698     var $$ = this,
6699         idsForX = Object.keys($$.data.xs);
6700     return idsForX.length ? $$.data.xs[idsForX[0]] : null;
6701   };
6702
6703   ChartInternal.prototype.getOtherTargetX = function (index) {
6704     var xs = this.getOtherTargetXs();
6705     return xs && index < xs.length ? xs[index] : null;
6706   };
6707
6708   ChartInternal.prototype.addXs = function (xs) {
6709     var $$ = this;
6710     Object.keys(xs).forEach(function (id) {
6711       $$.config.data_xs[id] = xs[id];
6712     });
6713   };
6714
6715   ChartInternal.prototype.addName = function (data) {
6716     var $$ = this,
6717         name;
6718
6719     if (data) {
6720       name = $$.config.data_names[data.id];
6721       data.name = name !== undefined ? name : data.id;
6722     }
6723
6724     return data;
6725   };
6726
6727   ChartInternal.prototype.getValueOnIndex = function (values, index) {
6728     var valueOnIndex = values.filter(function (v) {
6729       return v.index === index;
6730     });
6731     return valueOnIndex.length ? valueOnIndex[0] : null;
6732   };
6733
6734   ChartInternal.prototype.updateTargetX = function (targets, x) {
6735     var $$ = this;
6736     targets.forEach(function (t) {
6737       t.values.forEach(function (v, i) {
6738         v.x = $$.generateTargetX(x[i], t.id, i);
6739       });
6740       $$.data.xs[t.id] = x;
6741     });
6742   };
6743
6744   ChartInternal.prototype.updateTargetXs = function (targets, xs) {
6745     var $$ = this;
6746     targets.forEach(function (t) {
6747       if (xs[t.id]) {
6748         $$.updateTargetX([t], xs[t.id]);
6749       }
6750     });
6751   };
6752
6753   ChartInternal.prototype.generateTargetX = function (rawX, id, index) {
6754     var $$ = this,
6755         x;
6756
6757     if ($$.isTimeSeries()) {
6758       x = rawX ? $$.parseDate(rawX) : $$.parseDate($$.getXValue(id, index));
6759     } else if ($$.isCustomX() && !$$.isCategorized()) {
6760       x = isValue(rawX) ? +rawX : $$.getXValue(id, index);
6761     } else {
6762       x = index;
6763     }
6764
6765     return x;
6766   };
6767
6768   ChartInternal.prototype.cloneTarget = function (target) {
6769     return {
6770       id: target.id,
6771       id_org: target.id_org,
6772       values: target.values.map(function (d) {
6773         return {
6774           x: d.x,
6775           value: d.value,
6776           id: d.id
6777         };
6778       })
6779     };
6780   };
6781
6782   ChartInternal.prototype.getMaxDataCount = function () {
6783     var $$ = this;
6784     return $$.d3.max($$.data.targets, function (t) {
6785       return t.values.length;
6786     });
6787   };
6788
6789   ChartInternal.prototype.mapToIds = function (targets) {
6790     return targets.map(function (d) {
6791       return d.id;
6792     });
6793   };
6794
6795   ChartInternal.prototype.mapToTargetIds = function (ids) {
6796     var $$ = this;
6797     return ids ? [].concat(ids) : $$.mapToIds($$.data.targets);
6798   };
6799
6800   ChartInternal.prototype.hasTarget = function (targets, id) {
6801     var ids = this.mapToIds(targets),
6802         i;
6803
6804     for (i = 0; i < ids.length; i++) {
6805       if (ids[i] === id) {
6806         return true;
6807       }
6808     }
6809
6810     return false;
6811   };
6812
6813   ChartInternal.prototype.isTargetToShow = function (targetId) {
6814     return this.hiddenTargetIds.indexOf(targetId) < 0;
6815   };
6816
6817   ChartInternal.prototype.isLegendToShow = function (targetId) {
6818     return this.hiddenLegendIds.indexOf(targetId) < 0;
6819   };
6820
6821   ChartInternal.prototype.filterTargetsToShow = function (targets) {
6822     var $$ = this;
6823     return targets.filter(function (t) {
6824       return $$.isTargetToShow(t.id);
6825     });
6826   };
6827
6828   ChartInternal.prototype.mapTargetsToUniqueXs = function (targets) {
6829     var $$ = this;
6830     var xs = $$.d3.set($$.d3.merge(targets.map(function (t) {
6831       return t.values.map(function (v) {
6832         return +v.x;
6833       });
6834     }))).values();
6835     xs = $$.isTimeSeries() ? xs.map(function (x) {
6836       return new Date(+x);
6837     }) : xs.map(function (x) {
6838       return +x;
6839     });
6840     return xs.sort(function (a, b) {
6841       return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
6842     });
6843   };
6844
6845   ChartInternal.prototype.addHiddenTargetIds = function (targetIds) {
6846     targetIds = targetIds instanceof Array ? targetIds : new Array(targetIds);
6847
6848     for (var i = 0; i < targetIds.length; i++) {
6849       if (this.hiddenTargetIds.indexOf(targetIds[i]) < 0) {
6850         this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds[i]);
6851       }
6852     }
6853   };
6854
6855   ChartInternal.prototype.removeHiddenTargetIds = function (targetIds) {
6856     this.hiddenTargetIds = this.hiddenTargetIds.filter(function (id) {
6857       return targetIds.indexOf(id) < 0;
6858     });
6859   };
6860
6861   ChartInternal.prototype.addHiddenLegendIds = function (targetIds) {
6862     targetIds = targetIds instanceof Array ? targetIds : new Array(targetIds);
6863
6864     for (var i = 0; i < targetIds.length; i++) {
6865       if (this.hiddenLegendIds.indexOf(targetIds[i]) < 0) {
6866         this.hiddenLegendIds = this.hiddenLegendIds.concat(targetIds[i]);
6867       }
6868     }
6869   };
6870
6871   ChartInternal.prototype.removeHiddenLegendIds = function (targetIds) {
6872     this.hiddenLegendIds = this.hiddenLegendIds.filter(function (id) {
6873       return targetIds.indexOf(id) < 0;
6874     });
6875   };
6876
6877   ChartInternal.prototype.getValuesAsIdKeyed = function (targets) {
6878     var ys = {};
6879     targets.forEach(function (t) {
6880       ys[t.id] = [];
6881       t.values.forEach(function (v) {
6882         ys[t.id].push(v.value);
6883       });
6884     });
6885     return ys;
6886   };
6887
6888   ChartInternal.prototype.checkValueInTargets = function (targets, checker) {
6889     var ids = Object.keys(targets),
6890         i,
6891         j,
6892         values;
6893
6894     for (i = 0; i < ids.length; i++) {
6895       values = targets[ids[i]].values;
6896
6897       for (j = 0; j < values.length; j++) {
6898         if (checker(values[j].value)) {
6899           return true;
6900         }
6901       }
6902     }
6903
6904     return false;
6905   };
6906
6907   ChartInternal.prototype.hasNegativeValueInTargets = function (targets) {
6908     return this.checkValueInTargets(targets, function (v) {
6909       return v < 0;
6910     });
6911   };
6912
6913   ChartInternal.prototype.hasPositiveValueInTargets = function (targets) {
6914     return this.checkValueInTargets(targets, function (v) {
6915       return v > 0;
6916     });
6917   };
6918
6919   ChartInternal.prototype.isOrderDesc = function () {
6920     var config = this.config;
6921     return typeof config.data_order === 'string' && config.data_order.toLowerCase() === 'desc';
6922   };
6923
6924   ChartInternal.prototype.isOrderAsc = function () {
6925     var config = this.config;
6926     return typeof config.data_order === 'string' && config.data_order.toLowerCase() === 'asc';
6927   };
6928
6929   ChartInternal.prototype.getOrderFunction = function () {
6930     var $$ = this,
6931         config = $$.config,
6932         orderAsc = $$.isOrderAsc(),
6933         orderDesc = $$.isOrderDesc();
6934
6935     if (orderAsc || orderDesc) {
6936       var reducer = function reducer(p, c) {
6937         return p + Math.abs(c.value);
6938       };
6939
6940       return function (t1, t2) {
6941         var t1Sum = t1.values.reduce(reducer, 0),
6942             t2Sum = t2.values.reduce(reducer, 0);
6943         return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
6944       };
6945     } else if (isFunction(config.data_order)) {
6946       return config.data_order;
6947     } else if (isArray(config.data_order)) {
6948       var order = config.data_order;
6949       return function (t1, t2) {
6950         return order.indexOf(t1.id) - order.indexOf(t2.id);
6951       };
6952     }
6953   };
6954
6955   ChartInternal.prototype.orderTargets = function (targets) {
6956     var fct = this.getOrderFunction();
6957
6958     if (fct) {
6959       targets.sort(fct);
6960     }
6961
6962     return targets;
6963   };
6964
6965   ChartInternal.prototype.filterByX = function (targets, x) {
6966     return this.d3.merge(targets.map(function (t) {
6967       return t.values;
6968     })).filter(function (v) {
6969       return v.x - x === 0;
6970     });
6971   };
6972
6973   ChartInternal.prototype.filterRemoveNull = function (data) {
6974     return data.filter(function (d) {
6975       return isValue(d.value);
6976     });
6977   };
6978
6979   ChartInternal.prototype.filterByXDomain = function (targets, xDomain) {
6980     return targets.map(function (t) {
6981       return {
6982         id: t.id,
6983         id_org: t.id_org,
6984         values: t.values.filter(function (v) {
6985           return xDomain[0] <= v.x && v.x <= xDomain[1];
6986         })
6987       };
6988     });
6989   };
6990
6991   ChartInternal.prototype.hasDataLabel = function () {
6992     var config = this.config;
6993
6994     if (typeof config.data_labels === 'boolean' && config.data_labels) {
6995       return true;
6996     } else if (_typeof(config.data_labels) === 'object' && notEmpty(config.data_labels)) {
6997       return true;
6998     }
6999
7000     return false;
7001   };
7002
7003   ChartInternal.prototype.getDataLabelLength = function (min, max, key) {
7004     var $$ = this,
7005         lengths = [0, 0],
7006         paddingCoef = 1.3;
7007     $$.selectChart.select('svg').selectAll('.dummy').data([min, max]).enter().append('text').text(function (d) {
7008       return $$.dataLabelFormat(d.id)(d);
7009     }).each(function (d, i) {
7010       lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
7011     }).remove();
7012     return lengths;
7013   };
7014   /**
7015    * Returns true if the given data point is not arc type, otherwise false.
7016    * @param {Object} d The data point
7017    * @return {boolean}
7018    */
7019
7020
7021   ChartInternal.prototype.isNoneArc = function (d) {
7022     return this.hasTarget(this.data.targets, d.id);
7023   };
7024   /**
7025    * Returns true if the given data point is arc type, otherwise false.
7026    * @param {Object} d The data point
7027    * @return {boolean}
7028    */
7029
7030
7031   ChartInternal.prototype.isArc = function (d) {
7032     return 'data' in d && this.hasTarget(this.data.targets, d.data.id);
7033   };
7034
7035   ChartInternal.prototype.findClosestFromTargets = function (targets, pos) {
7036     var $$ = this,
7037         candidates; // map to array of closest points of each target
7038
7039     candidates = targets.map(function (target) {
7040       return $$.findClosest(target.values, pos);
7041     }); // decide closest point and return
7042
7043     return $$.findClosest(candidates, pos);
7044   };
7045
7046   ChartInternal.prototype.findClosest = function (values, pos) {
7047     var $$ = this,
7048         minDist = $$.config.point_sensitivity,
7049         closest; // find mouseovering bar
7050
7051     values.filter(function (v) {
7052       return v && $$.isBarType(v.id);
7053     }).forEach(function (v) {
7054       var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
7055
7056       if (!closest && $$.isWithinBar($$.d3.mouse(shape), shape)) {
7057         closest = v;
7058       }
7059     }); // find closest point from non-bar
7060
7061     values.filter(function (v) {
7062       return v && !$$.isBarType(v.id);
7063     }).forEach(function (v) {
7064       var d = $$.dist(v, pos);
7065
7066       if (d < minDist) {
7067         minDist = d;
7068         closest = v;
7069       }
7070     });
7071     return closest;
7072   };
7073
7074   ChartInternal.prototype.dist = function (data, pos) {
7075     var $$ = this,
7076         config = $$.config,
7077         xIndex = config.axis_rotated ? 1 : 0,
7078         yIndex = config.axis_rotated ? 0 : 1,
7079         y = $$.circleY(data, data.index),
7080         x = $$.x(data.x);
7081     return Math.sqrt(Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2));
7082   };
7083
7084   ChartInternal.prototype.convertValuesToStep = function (values) {
7085     var converted = [].concat(values),
7086         i;
7087
7088     if (!this.isCategorized()) {
7089       return values;
7090     }
7091
7092     for (i = values.length + 1; 0 < i; i--) {
7093       converted[i] = converted[i - 1];
7094     }
7095
7096     converted[0] = {
7097       x: converted[0].x - 1,
7098       value: converted[0].value,
7099       id: converted[0].id
7100     };
7101     converted[values.length + 1] = {
7102       x: converted[values.length].x + 1,
7103       value: converted[values.length].value,
7104       id: converted[values.length].id
7105     };
7106     return converted;
7107   };
7108
7109   ChartInternal.prototype.updateDataAttributes = function (name, attrs) {
7110     var $$ = this,
7111         config = $$.config,
7112         current = config['data_' + name];
7113
7114     if (typeof attrs === 'undefined') {
7115       return current;
7116     }
7117
7118     Object.keys(attrs).forEach(function (id) {
7119       current[id] = attrs[id];
7120     });
7121     $$.redraw({
7122       withLegend: true
7123     });
7124     return current;
7125   };
7126
7127   ChartInternal.prototype.load = function (targets, args) {
7128     var $$ = this;
7129
7130     if (targets) {
7131       // filter loading targets if needed
7132       if (args.filter) {
7133         targets = targets.filter(args.filter);
7134       } // set type if args.types || args.type specified
7135
7136
7137       if (args.type || args.types) {
7138         targets.forEach(function (t) {
7139           var type = args.types && args.types[t.id] ? args.types[t.id] : args.type;
7140           $$.setTargetType(t.id, type);
7141         });
7142       } // Update/Add data
7143
7144
7145       $$.data.targets.forEach(function (d) {
7146         for (var i = 0; i < targets.length; i++) {
7147           if (d.id === targets[i].id) {
7148             d.values = targets[i].values;
7149             targets.splice(i, 1);
7150             break;
7151           }
7152         }
7153       });
7154       $$.data.targets = $$.data.targets.concat(targets); // add remained
7155     } // Set targets
7156
7157
7158     $$.updateTargets($$.data.targets); // Redraw with new targets
7159
7160     $$.redraw({
7161       withUpdateOrgXDomain: true,
7162       withUpdateXDomain: true,
7163       withLegend: true
7164     });
7165
7166     if (args.done) {
7167       args.done();
7168     }
7169   };
7170
7171   ChartInternal.prototype.loadFromArgs = function (args) {
7172     var $$ = this;
7173
7174     if (args.data) {
7175       $$.load($$.convertDataToTargets(args.data), args);
7176     } else if (args.url) {
7177       $$.convertUrlToData(args.url, args.mimeType, args.headers, args.keys, function (data) {
7178         $$.load($$.convertDataToTargets(data), args);
7179       });
7180     } else if (args.json) {
7181       $$.load($$.convertDataToTargets($$.convertJsonToData(args.json, args.keys)), args);
7182     } else if (args.rows) {
7183       $$.load($$.convertDataToTargets($$.convertRowsToData(args.rows)), args);
7184     } else if (args.columns) {
7185       $$.load($$.convertDataToTargets($$.convertColumnsToData(args.columns)), args);
7186     } else {
7187       $$.load(null, args);
7188     }
7189   };
7190
7191   ChartInternal.prototype.unload = function (targetIds, done) {
7192     var $$ = this;
7193
7194     if (!done) {
7195       done = function done() {};
7196     } // filter existing target
7197
7198
7199     targetIds = targetIds.filter(function (id) {
7200       return $$.hasTarget($$.data.targets, id);
7201     }); // If no target, call done and return
7202
7203     if (!targetIds || targetIds.length === 0) {
7204       done();
7205       return;
7206     }
7207
7208     $$.svg.selectAll(targetIds.map(function (id) {
7209       return $$.selectorTarget(id);
7210     })).transition().style('opacity', 0).remove().call($$.endall, done);
7211     targetIds.forEach(function (id) {
7212       // Reset fadein for future load
7213       $$.withoutFadeIn[id] = false; // Remove target's elements
7214
7215       if ($$.legend) {
7216         $$.legend.selectAll('.' + CLASS.legendItem + $$.getTargetSelectorSuffix(id)).remove();
7217       } // Remove target
7218
7219
7220       $$.data.targets = $$.data.targets.filter(function (t) {
7221         return t.id !== id;
7222       });
7223     });
7224   };
7225
7226   ChartInternal.prototype.getYDomainMin = function (targets) {
7227     var $$ = this,
7228         config = $$.config,
7229         ids = $$.mapToIds(targets),
7230         ys = $$.getValuesAsIdKeyed(targets),
7231         j,
7232         k,
7233         baseId,
7234         idsInGroup,
7235         id,
7236         hasNegativeValue;
7237
7238     if (config.data_groups.length > 0) {
7239       hasNegativeValue = $$.hasNegativeValueInTargets(targets);
7240
7241       for (j = 0; j < config.data_groups.length; j++) {
7242         // Determine baseId
7243         idsInGroup = config.data_groups[j].filter(function (id) {
7244           return ids.indexOf(id) >= 0;
7245         });
7246
7247         if (idsInGroup.length === 0) {
7248           continue;
7249         }
7250
7251         baseId = idsInGroup[0]; // Consider negative values
7252
7253         if (hasNegativeValue && ys[baseId]) {
7254           ys[baseId].forEach(function (v, i) {
7255             ys[baseId][i] = v < 0 ? v : 0;
7256           });
7257         } // Compute min
7258
7259
7260         for (k = 1; k < idsInGroup.length; k++) {
7261           id = idsInGroup[k];
7262
7263           if (!ys[id]) {
7264             continue;
7265           }
7266
7267           ys[id].forEach(function (v, i) {
7268             if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
7269               ys[baseId][i] += +v;
7270             }
7271           });
7272         }
7273       }
7274     }
7275
7276     return $$.d3.min(Object.keys(ys).map(function (key) {
7277       return $$.d3.min(ys[key]);
7278     }));
7279   };
7280
7281   ChartInternal.prototype.getYDomainMax = function (targets) {
7282     var $$ = this,
7283         config = $$.config,
7284         ids = $$.mapToIds(targets),
7285         ys = $$.getValuesAsIdKeyed(targets),
7286         j,
7287         k,
7288         baseId,
7289         idsInGroup,
7290         id,
7291         hasPositiveValue;
7292
7293     if (config.data_groups.length > 0) {
7294       hasPositiveValue = $$.hasPositiveValueInTargets(targets);
7295
7296       for (j = 0; j < config.data_groups.length; j++) {
7297         // Determine baseId
7298         idsInGroup = config.data_groups[j].filter(function (id) {
7299           return ids.indexOf(id) >= 0;
7300         });
7301
7302         if (idsInGroup.length === 0) {
7303           continue;
7304         }
7305
7306         baseId = idsInGroup[0]; // Consider positive values
7307
7308         if (hasPositiveValue && ys[baseId]) {
7309           ys[baseId].forEach(function (v, i) {
7310             ys[baseId][i] = v > 0 ? v : 0;
7311           });
7312         } // Compute max
7313
7314
7315         for (k = 1; k < idsInGroup.length; k++) {
7316           id = idsInGroup[k];
7317
7318           if (!ys[id]) {
7319             continue;
7320           }
7321
7322           ys[id].forEach(function (v, i) {
7323             if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
7324               ys[baseId][i] += +v;
7325             }
7326           });
7327         }
7328       }
7329     }
7330
7331     return $$.d3.max(Object.keys(ys).map(function (key) {
7332       return $$.d3.max(ys[key]);
7333     }));
7334   };
7335
7336   ChartInternal.prototype.getYDomain = function (targets, axisId, xDomain) {
7337     var $$ = this,
7338         config = $$.config,
7339         targetsByAxisId = targets.filter(function (t) {
7340       return $$.axis.getId(t.id) === axisId;
7341     }),
7342         yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
7343         yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
7344         yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
7345         yDomainMin = $$.getYDomainMin(yTargets),
7346         yDomainMax = $$.getYDomainMax(yTargets),
7347         domain,
7348         domainLength,
7349         padding,
7350         padding_top,
7351         padding_bottom,
7352         center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
7353         yDomainAbs,
7354         lengths,
7355         diff,
7356         ratio,
7357         isAllPositive,
7358         isAllNegative,
7359         isZeroBased = $$.hasType('bar', yTargets) && config.bar_zerobased || $$.hasType('area', yTargets) && config.area_zerobased,
7360         isInverted = axisId === 'y2' ? config.axis_y2_inverted : config.axis_y_inverted,
7361         showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
7362         showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated; // MEMO: avoid inverting domain unexpectedly
7363
7364     yDomainMin = isValue(yMin) ? yMin : isValue(yMax) ? yDomainMin < yMax ? yDomainMin : yMax - 10 : yDomainMin;
7365     yDomainMax = isValue(yMax) ? yMax : isValue(yMin) ? yMin < yDomainMax ? yDomainMax : yMin + 10 : yDomainMax;
7366
7367     if (yTargets.length === 0) {
7368       // use current domain if target of axisId is none
7369       return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
7370     }
7371
7372     if (isNaN(yDomainMin)) {
7373       // set minimum to zero when not number
7374       yDomainMin = 0;
7375     }
7376
7377     if (isNaN(yDomainMax)) {
7378       // set maximum to have same value as yDomainMin
7379       yDomainMax = yDomainMin;
7380     }
7381
7382     if (yDomainMin === yDomainMax) {
7383       yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
7384     }
7385
7386     isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
7387     isAllNegative = yDomainMin <= 0 && yDomainMax <= 0; // Cancel zerobased if axis_*_min / axis_*_max specified
7388
7389     if (isValue(yMin) && isAllPositive || isValue(yMax) && isAllNegative) {
7390       isZeroBased = false;
7391     } // Bar/Area chart should be 0-based if all positive|negative
7392
7393
7394     if (isZeroBased) {
7395       if (isAllPositive) {
7396         yDomainMin = 0;
7397       }
7398
7399       if (isAllNegative) {
7400         yDomainMax = 0;
7401       }
7402     }
7403
7404     domainLength = Math.abs(yDomainMax - yDomainMin);
7405     padding = padding_top = padding_bottom = domainLength * 0.1;
7406
7407     if (typeof center !== 'undefined') {
7408       yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
7409       yDomainMax = center + yDomainAbs;
7410       yDomainMin = center - yDomainAbs;
7411     } // add padding for data label
7412
7413
7414     if (showHorizontalDataLabel) {
7415       lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'width');
7416       diff = diffDomain($$.y.range());
7417       ratio = [lengths[0] / diff, lengths[1] / diff];
7418       padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
7419       padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
7420     } else if (showVerticalDataLabel) {
7421       lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'height');
7422       padding_top += $$.axis.convertPixelsToAxisPadding(lengths[1], domainLength);
7423       padding_bottom += $$.axis.convertPixelsToAxisPadding(lengths[0], domainLength);
7424     }
7425
7426     if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
7427       padding_top = $$.axis.getPadding(config.axis_y_padding, 'top', padding_top, domainLength);
7428       padding_bottom = $$.axis.getPadding(config.axis_y_padding, 'bottom', padding_bottom, domainLength);
7429     }
7430
7431     if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
7432       padding_top = $$.axis.getPadding(config.axis_y2_padding, 'top', padding_top, domainLength);
7433       padding_bottom = $$.axis.getPadding(config.axis_y2_padding, 'bottom', padding_bottom, domainLength);
7434     } // Bar/Area chart should be 0-based if all positive|negative
7435
7436
7437     if (isZeroBased) {
7438       if (isAllPositive) {
7439         padding_bottom = yDomainMin;
7440       }
7441
7442       if (isAllNegative) {
7443         padding_top = -yDomainMax;
7444       }
7445     }
7446
7447     domain = [yDomainMin - padding_bottom, yDomainMax + padding_top];
7448     return isInverted ? domain.reverse() : domain;
7449   };
7450
7451   ChartInternal.prototype.getXDomainMin = function (targets) {
7452     var $$ = this,
7453         config = $$.config;
7454     return isDefined(config.axis_x_min) ? $$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min : $$.d3.min(targets, function (t) {
7455       return $$.d3.min(t.values, function (v) {
7456         return v.x;
7457       });
7458     });
7459   };
7460
7461   ChartInternal.prototype.getXDomainMax = function (targets) {
7462     var $$ = this,
7463         config = $$.config;
7464     return isDefined(config.axis_x_max) ? $$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max : $$.d3.max(targets, function (t) {
7465       return $$.d3.max(t.values, function (v) {
7466         return v.x;
7467       });
7468     });
7469   };
7470
7471   ChartInternal.prototype.getXDomainPadding = function (domain) {
7472     var $$ = this,
7473         config = $$.config,
7474         diff = domain[1] - domain[0],
7475         maxDataCount,
7476         padding,
7477         paddingLeft,
7478         paddingRight;
7479
7480     if ($$.isCategorized()) {
7481       padding = 0;
7482     } else if ($$.hasType('bar')) {
7483       maxDataCount = $$.getMaxDataCount();
7484       padding = maxDataCount > 1 ? diff / (maxDataCount - 1) / 2 : 0.5;
7485     } else {
7486       padding = diff * 0.01;
7487     }
7488
7489     if (_typeof(config.axis_x_padding) === 'object' && notEmpty(config.axis_x_padding)) {
7490       paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding;
7491       paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding;
7492     } else if (typeof config.axis_x_padding === 'number') {
7493       paddingLeft = paddingRight = config.axis_x_padding;
7494     } else {
7495       paddingLeft = paddingRight = padding;
7496     }
7497
7498     return {
7499       left: paddingLeft,
7500       right: paddingRight
7501     };
7502   };
7503
7504   ChartInternal.prototype.getXDomain = function (targets) {
7505     var $$ = this,
7506         xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
7507         firstX = xDomain[0],
7508         lastX = xDomain[1],
7509         padding = $$.getXDomainPadding(xDomain),
7510         min = 0,
7511         max = 0; // show center of x domain if min and max are the same
7512
7513     if (firstX - lastX === 0 && !$$.isCategorized()) {
7514       if ($$.isTimeSeries()) {
7515         firstX = new Date(firstX.getTime() * 0.5);
7516         lastX = new Date(lastX.getTime() * 1.5);
7517       } else {
7518         firstX = firstX === 0 ? 1 : firstX * 0.5;
7519         lastX = lastX === 0 ? -1 : lastX * 1.5;
7520       }
7521     }
7522
7523     if (firstX || firstX === 0) {
7524       min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
7525     }
7526
7527     if (lastX || lastX === 0) {
7528       max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
7529     }
7530
7531     return [min, max];
7532   };
7533
7534   ChartInternal.prototype.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
7535     var $$ = this,
7536         config = $$.config;
7537
7538     if (withUpdateOrgXDomain) {
7539       $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
7540       $$.orgXDomain = $$.x.domain();
7541
7542       if (config.zoom_enabled) {
7543         $$.zoom.update();
7544       }
7545
7546       $$.subX.domain($$.x.domain());
7547
7548       if ($$.brush) {
7549         $$.brush.updateScale($$.subX);
7550       }
7551     }
7552
7553     if (withUpdateXDomain) {
7554       $$.x.domain(domain ? domain : !$$.brush || $$.brush.empty() ? $$.orgXDomain : $$.brush.selectionAsValue());
7555     } // Trim domain when too big by zoom mousemove event
7556
7557
7558     if (withTrim) {
7559       $$.x.domain($$.trimXDomain($$.x.orgDomain()));
7560     }
7561
7562     return $$.x.domain();
7563   };
7564
7565   ChartInternal.prototype.trimXDomain = function (domain) {
7566     var zoomDomain = this.getZoomDomain(),
7567         min = zoomDomain[0],
7568         max = zoomDomain[1];
7569
7570     if (domain[0] <= min) {
7571       domain[1] = +domain[1] + (min - domain[0]);
7572       domain[0] = min;
7573     }
7574
7575     if (max <= domain[1]) {
7576       domain[0] = +domain[0] - (domain[1] - max);
7577       domain[1] = max;
7578     }
7579
7580     return domain;
7581   };
7582
7583   ChartInternal.prototype.drag = function (mouse) {
7584     var $$ = this,
7585         config = $$.config,
7586         main = $$.main,
7587         d3 = $$.d3;
7588     var sx, sy, mx, my, minX, maxX, minY, maxY;
7589
7590     if ($$.hasArcType()) {
7591       return;
7592     }
7593
7594     if (!config.data_selection_enabled) {
7595       return;
7596     } // do nothing if not selectable
7597
7598
7599     if (!config.data_selection_multiple) {
7600       return;
7601     } // skip when single selection because drag is used for multiple selection
7602
7603
7604     sx = $$.dragStart[0];
7605     sy = $$.dragStart[1];
7606     mx = mouse[0];
7607     my = mouse[1];
7608     minX = Math.min(sx, mx);
7609     maxX = Math.max(sx, mx);
7610     minY = config.data_selection_grouped ? $$.margin.top : Math.min(sy, my);
7611     maxY = config.data_selection_grouped ? $$.height : Math.max(sy, my);
7612     main.select('.' + CLASS.dragarea).attr('x', minX).attr('y', minY).attr('width', maxX - minX).attr('height', maxY - minY); // TODO: binary search when multiple xs
7613
7614     main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).filter(function (d) {
7615       return config.data_selection_isselectable(d);
7616     }).each(function (d, i) {
7617       var shape = d3.select(this),
7618           isSelected = shape.classed(CLASS.SELECTED),
7619           isIncluded = shape.classed(CLASS.INCLUDED),
7620           _x,
7621           _y,
7622           _w,
7623           _h,
7624           toggle,
7625           isWithin = false,
7626           box;
7627
7628       if (shape.classed(CLASS.circle)) {
7629         _x = shape.attr("cx") * 1;
7630         _y = shape.attr("cy") * 1;
7631         toggle = $$.togglePoint;
7632         isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
7633       } else if (shape.classed(CLASS.bar)) {
7634         box = getPathBox(this);
7635         _x = box.x;
7636         _y = box.y;
7637         _w = box.width;
7638         _h = box.height;
7639         toggle = $$.togglePath;
7640         isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
7641       } else {
7642         // line/area selection not supported yet
7643         return;
7644       }
7645
7646       if (isWithin ^ isIncluded) {
7647         shape.classed(CLASS.INCLUDED, !isIncluded); // TODO: included/unincluded callback here
7648
7649         shape.classed(CLASS.SELECTED, !isSelected);
7650         toggle.call($$, !isSelected, shape, d, i);
7651       }
7652     });
7653   };
7654
7655   ChartInternal.prototype.dragstart = function (mouse) {
7656     var $$ = this,
7657         config = $$.config;
7658
7659     if ($$.hasArcType()) {
7660       return;
7661     }
7662
7663     if (!config.data_selection_enabled) {
7664       return;
7665     } // do nothing if not selectable
7666
7667
7668     $$.dragStart = mouse;
7669     $$.main.select('.' + CLASS.chart).append('rect').attr('class', CLASS.dragarea).style('opacity', 0.1);
7670     $$.dragging = true;
7671   };
7672
7673   ChartInternal.prototype.dragend = function () {
7674     var $$ = this,
7675         config = $$.config;
7676
7677     if ($$.hasArcType()) {
7678       return;
7679     }
7680
7681     if (!config.data_selection_enabled) {
7682       return;
7683     } // do nothing if not selectable
7684
7685
7686     $$.main.select('.' + CLASS.dragarea).transition().duration(100).style('opacity', 0).remove();
7687     $$.main.selectAll('.' + CLASS.shape).classed(CLASS.INCLUDED, false);
7688     $$.dragging = false;
7689   };
7690
7691   ChartInternal.prototype.getYFormat = function (forArc) {
7692     var $$ = this,
7693         formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
7694         formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
7695     return function (v, ratio, id) {
7696       var format = $$.axis.getId(id) === 'y2' ? formatForY2 : formatForY;
7697       return format.call($$, v, ratio);
7698     };
7699   };
7700
7701   ChartInternal.prototype.yFormat = function (v) {
7702     var $$ = this,
7703         config = $$.config,
7704         format = config.axis_y_tick_format ? config.axis_y_tick_format : $$.defaultValueFormat;
7705     return format(v);
7706   };
7707
7708   ChartInternal.prototype.y2Format = function (v) {
7709     var $$ = this,
7710         config = $$.config,
7711         format = config.axis_y2_tick_format ? config.axis_y2_tick_format : $$.defaultValueFormat;
7712     return format(v);
7713   };
7714
7715   ChartInternal.prototype.defaultValueFormat = function (v) {
7716     return isValue(v) ? +v : "";
7717   };
7718
7719   ChartInternal.prototype.defaultArcValueFormat = function (v, ratio) {
7720     return (ratio * 100).toFixed(1) + '%';
7721   };
7722
7723   ChartInternal.prototype.dataLabelFormat = function (targetId) {
7724     var $$ = this,
7725         data_labels = $$.config.data_labels,
7726         format,
7727         defaultFormat = function defaultFormat(v) {
7728       return isValue(v) ? +v : "";
7729     }; // find format according to axis id
7730
7731
7732     if (typeof data_labels.format === 'function') {
7733       format = data_labels.format;
7734     } else if (_typeof(data_labels.format) === 'object') {
7735       if (data_labels.format[targetId]) {
7736         format = data_labels.format[targetId] === true ? defaultFormat : data_labels.format[targetId];
7737       } else {
7738         format = function format() {
7739           return '';
7740         };
7741       }
7742     } else {
7743       format = defaultFormat;
7744     }
7745
7746     return format;
7747   };
7748
7749   ChartInternal.prototype.initGrid = function () {
7750     var $$ = this,
7751         config = $$.config,
7752         d3 = $$.d3;
7753     $$.grid = $$.main.append('g').attr("clip-path", $$.clipPathForGrid).attr('class', CLASS.grid);
7754
7755     if (config.grid_x_show) {
7756       $$.grid.append("g").attr("class", CLASS.xgrids);
7757     }
7758
7759     if (config.grid_y_show) {
7760       $$.grid.append('g').attr('class', CLASS.ygrids);
7761     }
7762
7763     if (config.grid_focus_show) {
7764       $$.grid.append('g').attr("class", CLASS.xgridFocus).append('line').attr('class', CLASS.xgridFocus);
7765     }
7766
7767     $$.xgrid = d3.selectAll([]);
7768
7769     if (!config.grid_lines_front) {
7770       $$.initGridLines();
7771     }
7772   };
7773
7774   ChartInternal.prototype.initGridLines = function () {
7775     var $$ = this,
7776         d3 = $$.d3;
7777     $$.gridLines = $$.main.append('g').attr("clip-path", $$.clipPathForGrid).attr('class', CLASS.grid + ' ' + CLASS.gridLines);
7778     $$.gridLines.append('g').attr("class", CLASS.xgridLines);
7779     $$.gridLines.append('g').attr('class', CLASS.ygridLines);
7780     $$.xgridLines = d3.selectAll([]);
7781   };
7782
7783   ChartInternal.prototype.updateXGrid = function (withoutUpdate) {
7784     var $$ = this,
7785         config = $$.config,
7786         d3 = $$.d3,
7787         xgridData = $$.generateGridData(config.grid_x_type, $$.x),
7788         tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0;
7789     $$.xgridAttr = config.axis_rotated ? {
7790       'x1': 0,
7791       'x2': $$.width,
7792       'y1': function y1(d) {
7793         return $$.x(d) - tickOffset;
7794       },
7795       'y2': function y2(d) {
7796         return $$.x(d) - tickOffset;
7797       }
7798     } : {
7799       'x1': function x1(d) {
7800         return $$.x(d) + tickOffset;
7801       },
7802       'x2': function x2(d) {
7803         return $$.x(d) + tickOffset;
7804       },
7805       'y1': 0,
7806       'y2': $$.height
7807     };
7808
7809     $$.xgridAttr.opacity = function () {
7810       var pos = +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1');
7811       return pos === (config.axis_rotated ? $$.height : 0) ? 0 : 1;
7812     };
7813
7814     var xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid).data(xgridData);
7815     var xgridEnter = xgrid.enter().append('line').attr("class", CLASS.xgrid).attr('x1', $$.xgridAttr.x1).attr('x2', $$.xgridAttr.x2).attr('y1', $$.xgridAttr.y1).attr('y2', $$.xgridAttr.y2).style("opacity", 0);
7816     $$.xgrid = xgridEnter.merge(xgrid);
7817
7818     if (!withoutUpdate) {
7819       $$.xgrid.attr('x1', $$.xgridAttr.x1).attr('x2', $$.xgridAttr.x2).attr('y1', $$.xgridAttr.y1).attr('y2', $$.xgridAttr.y2).style("opacity", $$.xgridAttr.opacity);
7820     }
7821
7822     xgrid.exit().remove();
7823   };
7824
7825   ChartInternal.prototype.updateYGrid = function () {
7826     var $$ = this,
7827         config = $$.config,
7828         gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
7829     var ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid).data(gridValues);
7830     var ygridEnter = ygrid.enter().append('line') // TODO: x1, x2, y1, y2, opacity need to be set here maybe
7831     .attr('class', CLASS.ygrid);
7832     $$.ygrid = ygridEnter.merge(ygrid);
7833     $$.ygrid.attr("x1", config.axis_rotated ? $$.y : 0).attr("x2", config.axis_rotated ? $$.y : $$.width).attr("y1", config.axis_rotated ? 0 : $$.y).attr("y2", config.axis_rotated ? $$.height : $$.y);
7834     ygrid.exit().remove();
7835     $$.smoothLines($$.ygrid, 'grid');
7836   };
7837
7838   ChartInternal.prototype.gridTextAnchor = function (d) {
7839     return d.position ? d.position : "end";
7840   };
7841
7842   ChartInternal.prototype.gridTextDx = function (d) {
7843     return d.position === 'start' ? 4 : d.position === 'middle' ? 0 : -4;
7844   };
7845
7846   ChartInternal.prototype.xGridTextX = function (d) {
7847     return d.position === 'start' ? -this.height : d.position === 'middle' ? -this.height / 2 : 0;
7848   };
7849
7850   ChartInternal.prototype.yGridTextX = function (d) {
7851     return d.position === 'start' ? 0 : d.position === 'middle' ? this.width / 2 : this.width;
7852   };
7853
7854   ChartInternal.prototype.updateGrid = function (duration) {
7855     var $$ = this,
7856         main = $$.main,
7857         config = $$.config,
7858         xgridLine,
7859         xgridLineEnter,
7860         ygridLine,
7861         ygridLineEnter,
7862         xv = $$.xv.bind($$),
7863         yv = $$.yv.bind($$),
7864         xGridTextX = $$.xGridTextX.bind($$),
7865         yGridTextX = $$.yGridTextX.bind($$); // hide if arc type
7866
7867     $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
7868     main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
7869
7870     if (config.grid_x_show) {
7871       $$.updateXGrid();
7872     }
7873
7874     xgridLine = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine).data(config.grid_x_lines); // enter
7875
7876     xgridLineEnter = xgridLine.enter().append('g').attr("class", function (d) {
7877       return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : '');
7878     });
7879     xgridLineEnter.append('line').attr("x1", config.axis_rotated ? 0 : xv).attr("x2", config.axis_rotated ? $$.width : xv).attr("y1", config.axis_rotated ? xv : 0).attr("y2", config.axis_rotated ? xv : $$.height).style("opacity", 0);
7880     xgridLineEnter.append('text').attr("text-anchor", $$.gridTextAnchor).attr("transform", config.axis_rotated ? "" : "rotate(-90)").attr("x", config.axis_rotated ? yGridTextX : xGridTextX).attr("y", xv).attr('dx', $$.gridTextDx).attr('dy', -5).style("opacity", 0); // udpate
7881
7882     $$.xgridLines = xgridLineEnter.merge(xgridLine); // done in d3.transition() of the end of this function
7883     // exit
7884
7885     xgridLine.exit().transition().duration(duration).style("opacity", 0).remove(); // Y-Grid
7886
7887     if (config.grid_y_show) {
7888       $$.updateYGrid();
7889     }
7890
7891     ygridLine = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine).data(config.grid_y_lines); // enter
7892
7893     ygridLineEnter = ygridLine.enter().append('g').attr("class", function (d) {
7894       return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : '');
7895     });
7896     ygridLineEnter.append('line').attr("x1", config.axis_rotated ? yv : 0).attr("x2", config.axis_rotated ? yv : $$.width).attr("y1", config.axis_rotated ? 0 : yv).attr("y2", config.axis_rotated ? $$.height : yv).style("opacity", 0);
7897     ygridLineEnter.append('text').attr("text-anchor", $$.gridTextAnchor).attr("transform", config.axis_rotated ? "rotate(-90)" : "").attr("x", config.axis_rotated ? xGridTextX : yGridTextX).attr("y", yv).attr('dx', $$.gridTextDx).attr('dy', -5).style("opacity", 0); // update
7898
7899     $$.ygridLines = ygridLineEnter.merge(ygridLine);
7900     $$.ygridLines.select('line').transition().duration(duration).attr("x1", config.axis_rotated ? yv : 0).attr("x2", config.axis_rotated ? yv : $$.width).attr("y1", config.axis_rotated ? 0 : yv).attr("y2", config.axis_rotated ? $$.height : yv).style("opacity", 1);
7901     $$.ygridLines.select('text').transition().duration(duration).attr("x", config.axis_rotated ? $$.xGridTextX.bind($$) : $$.yGridTextX.bind($$)).attr("y", yv).text(function (d) {
7902       return d.text;
7903     }).style("opacity", 1); // exit
7904
7905     ygridLine.exit().transition().duration(duration).style("opacity", 0).remove();
7906   };
7907
7908   ChartInternal.prototype.redrawGrid = function (withTransition, transition) {
7909     var $$ = this,
7910         config = $$.config,
7911         xv = $$.xv.bind($$),
7912         lines = $$.xgridLines.select('line'),
7913         texts = $$.xgridLines.select('text');
7914     return [(withTransition ? lines.transition(transition) : lines).attr("x1", config.axis_rotated ? 0 : xv).attr("x2", config.axis_rotated ? $$.width : xv).attr("y1", config.axis_rotated ? xv : 0).attr("y2", config.axis_rotated ? xv : $$.height).style("opacity", 1), (withTransition ? texts.transition(transition) : texts).attr("x", config.axis_rotated ? $$.yGridTextX.bind($$) : $$.xGridTextX.bind($$)).attr("y", xv).text(function (d) {
7915       return d.text;
7916     }).style("opacity", 1)];
7917   };
7918
7919   ChartInternal.prototype.showXGridFocus = function (selectedData) {
7920     var $$ = this,
7921         config = $$.config,
7922         dataToShow = selectedData.filter(function (d) {
7923       return d && isValue(d.value);
7924     }),
7925         focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
7926         xx = $$.xx.bind($$);
7927
7928     if (!config.tooltip_show) {
7929       return;
7930     } // Hide when scatter plot exists
7931
7932
7933     if ($$.hasType('scatter') || $$.hasArcType()) {
7934       return;
7935     }
7936
7937     focusEl.style("visibility", "visible").data([dataToShow[0]]).attr(config.axis_rotated ? 'y1' : 'x1', xx).attr(config.axis_rotated ? 'y2' : 'x2', xx);
7938     $$.smoothLines(focusEl, 'grid');
7939   };
7940
7941   ChartInternal.prototype.hideXGridFocus = function () {
7942     this.main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
7943   };
7944
7945   ChartInternal.prototype.updateXgridFocus = function () {
7946     var $$ = this,
7947         config = $$.config;
7948     $$.main.select('line.' + CLASS.xgridFocus).attr("x1", config.axis_rotated ? 0 : -10).attr("x2", config.axis_rotated ? $$.width : -10).attr("y1", config.axis_rotated ? -10 : 0).attr("y2", config.axis_rotated ? -10 : $$.height);
7949   };
7950
7951   ChartInternal.prototype.generateGridData = function (type, scale) {
7952     var $$ = this,
7953         gridData = [],
7954         xDomain,
7955         firstYear,
7956         lastYear,
7957         i,
7958         tickNum = $$.main.select("." + CLASS.axisX).selectAll('.tick').size();
7959
7960     if (type === 'year') {
7961       xDomain = $$.getXDomain();
7962       firstYear = xDomain[0].getFullYear();
7963       lastYear = xDomain[1].getFullYear();
7964
7965       for (i = firstYear; i <= lastYear; i++) {
7966         gridData.push(new Date(i + '-01-01 00:00:00'));
7967       }
7968     } else {
7969       gridData = scale.ticks(10);
7970
7971       if (gridData.length > tickNum) {
7972         // use only int
7973         gridData = gridData.filter(function (d) {
7974           return ("" + d).indexOf('.') < 0;
7975         });
7976       }
7977     }
7978
7979     return gridData;
7980   };
7981
7982   ChartInternal.prototype.getGridFilterToRemove = function (params) {
7983     return params ? function (line) {
7984       var found = false;
7985       [].concat(params).forEach(function (param) {
7986         if ('value' in param && line.value === param.value || 'class' in param && line['class'] === param['class']) {
7987           found = true;
7988         }
7989       });
7990       return found;
7991     } : function () {
7992       return true;
7993     };
7994   };
7995
7996   ChartInternal.prototype.removeGridLines = function (params, forX) {
7997     var $$ = this,
7998         config = $$.config,
7999         toRemove = $$.getGridFilterToRemove(params),
8000         toShow = function toShow(line) {
8001       return !toRemove(line);
8002     },
8003         classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
8004         classLine = forX ? CLASS.xgridLine : CLASS.ygridLine;
8005
8006     $$.main.select('.' + classLines).selectAll('.' + classLine).filter(toRemove).transition().duration(config.transition_duration).style('opacity', 0).remove();
8007
8008     if (forX) {
8009       config.grid_x_lines = config.grid_x_lines.filter(toShow);
8010     } else {
8011       config.grid_y_lines = config.grid_y_lines.filter(toShow);
8012     }
8013   };
8014
8015   ChartInternal.prototype.initEventRect = function () {
8016     var $$ = this,
8017         config = $$.config;
8018     $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.eventRects).style('fill-opacity', 0);
8019     $$.eventRect = $$.main.select('.' + CLASS.eventRects).append('rect').attr('class', CLASS.eventRect); // event rect handle zoom event as well
8020
8021     if (config.zoom_enabled && $$.zoom) {
8022       $$.eventRect.call($$.zoom).on("dblclick.zoom", null);
8023
8024       if (config.zoom_initialRange) {
8025         // WORKAROUND: Add transition to apply transform immediately when no subchart
8026         $$.eventRect.transition().duration(0).call($$.zoom.transform, $$.zoomTransform(config.zoom_initialRange));
8027       }
8028     }
8029   };
8030
8031   ChartInternal.prototype.redrawEventRect = function () {
8032     var $$ = this,
8033         d3 = $$.d3,
8034         config = $$.config,
8035         x,
8036         y,
8037         w,
8038         h; // TODO: rotated not supported yet
8039
8040     x = 0;
8041     y = 0;
8042     w = $$.width;
8043     h = $$.height;
8044
8045     function mouseout() {
8046       $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
8047       $$.hideXGridFocus();
8048       $$.hideTooltip();
8049       $$.unexpandCircles();
8050       $$.unexpandBars();
8051     } // rects for mouseover
8052
8053
8054     $$.main.select('.' + CLASS.eventRects).style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null);
8055     $$.eventRect.attr('x', x).attr('y', y).attr('width', w).attr('height', h).on('mouseout', config.interaction_enabled ? function () {
8056       if (!config) {
8057         return;
8058       } // chart is destroyed
8059
8060
8061       if ($$.hasArcType()) {
8062         return;
8063       }
8064
8065       mouseout();
8066     } : null).on('mousemove', config.interaction_enabled ? function () {
8067       var targetsToShow, mouse, closest, sameXData, selectedData;
8068
8069       if ($$.dragging) {
8070         return;
8071       } // do nothing when dragging
8072
8073
8074       if ($$.hasArcType(targetsToShow)) {
8075         return;
8076       }
8077
8078       targetsToShow = $$.filterTargetsToShow($$.data.targets);
8079       mouse = d3.mouse(this);
8080       closest = $$.findClosestFromTargets(targetsToShow, mouse);
8081
8082       if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
8083         config.data_onmouseout.call($$.api, $$.mouseover);
8084         $$.mouseover = undefined;
8085       }
8086
8087       if (!closest) {
8088         mouseout();
8089         return;
8090       }
8091
8092       if ($$.isScatterType(closest) || !config.tooltip_grouped) {
8093         sameXData = [closest];
8094       } else {
8095         sameXData = $$.filterByX(targetsToShow, closest.x);
8096       } // show tooltip when cursor is close to some point
8097
8098
8099       selectedData = sameXData.map(function (d) {
8100         return $$.addName(d);
8101       });
8102       $$.showTooltip(selectedData, this); // expand points
8103
8104       if (config.point_focus_expand_enabled) {
8105         $$.unexpandCircles();
8106         selectedData.forEach(function (d) {
8107           $$.expandCircles(d.index, d.id, false);
8108         });
8109       }
8110
8111       $$.expandBars(closest.index, closest.id, true); // Show xgrid focus line
8112
8113       $$.showXGridFocus(selectedData); // Show cursor as pointer if point is close to mouse position
8114
8115       if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
8116         $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
8117
8118         if (!$$.mouseover) {
8119           config.data_onmouseover.call($$.api, closest);
8120           $$.mouseover = closest;
8121         }
8122       }
8123     } : null).on('click', config.interaction_enabled ? function () {
8124       var targetsToShow, mouse, closest, sameXData;
8125
8126       if ($$.hasArcType(targetsToShow)) {
8127         return;
8128       }
8129
8130       targetsToShow = $$.filterTargetsToShow($$.data.targets);
8131       mouse = d3.mouse(this);
8132       closest = $$.findClosestFromTargets(targetsToShow, mouse);
8133
8134       if (!closest) {
8135         return;
8136       } // select if selection enabled
8137
8138
8139       if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
8140         if ($$.isScatterType(closest) || !config.data_selection_grouped) {
8141           sameXData = [closest];
8142         } else {
8143           sameXData = $$.filterByX(targetsToShow, closest.x);
8144         }
8145
8146         sameXData.forEach(function (d) {
8147           $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.shape + '-' + d.index).each(function () {
8148             if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
8149               $$.toggleShape(this, d, d.index);
8150               config.data_onclick.call($$.api, d, this);
8151             }
8152           });
8153         });
8154       }
8155     } : null).call(config.interaction_enabled && config.data_selection_draggable && $$.drag ? d3.drag().on('drag', function () {
8156       $$.drag(d3.mouse(this));
8157     }).on('start', function () {
8158       $$.dragstart(d3.mouse(this));
8159     }).on('end', function () {
8160       $$.dragend();
8161     }) : function () {});
8162   };
8163
8164   ChartInternal.prototype.getMousePosition = function (data) {
8165     var $$ = this;
8166     return [$$.x(data.x), $$.getYScale(data.id)(data.value)];
8167   };
8168
8169   ChartInternal.prototype.dispatchEvent = function (type, mouse) {
8170     var $$ = this,
8171         selector = '.' + CLASS.eventRect,
8172         eventRect = $$.main.select(selector).node(),
8173         box = eventRect.getBoundingClientRect(),
8174         x = box.left + (mouse ? mouse[0] : 0),
8175         y = box.top + (mouse ? mouse[1] : 0),
8176         event = document.createEvent("MouseEvents");
8177     event.initMouseEvent(type, true, true, window, 0, x, y, x, y, false, false, false, false, 0, null);
8178     eventRect.dispatchEvent(event);
8179   };
8180
8181   ChartInternal.prototype.initLegend = function () {
8182     var $$ = this;
8183     $$.legendItemTextBox = {};
8184     $$.legendHasRendered = false;
8185     $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
8186
8187     if (!$$.config.legend_show) {
8188       $$.legend.style('visibility', 'hidden');
8189       $$.hiddenLegendIds = $$.mapToIds($$.data.targets);
8190       return;
8191     } // MEMO: call here to update legend box and tranlate for all
8192     // MEMO: translate will be upated by this, so transform not needed in updateLegend()
8193
8194
8195     $$.updateLegendWithDefaults();
8196   };
8197
8198   ChartInternal.prototype.updateLegendWithDefaults = function () {
8199     var $$ = this;
8200     $$.updateLegend($$.mapToIds($$.data.targets), {
8201       withTransform: false,
8202       withTransitionForTransform: false,
8203       withTransition: false
8204     });
8205   };
8206
8207   ChartInternal.prototype.updateSizeForLegend = function (legendHeight, legendWidth) {
8208     var $$ = this,
8209         config = $$.config,
8210         insetLegendPosition = {
8211       top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
8212       left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
8213     };
8214     $$.margin3 = {
8215       top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
8216       right: NaN,
8217       bottom: 0,
8218       left: $$.isLegendRight ? $$.currentWidth - legendWidth : $$.isLegendInset ? insetLegendPosition.left : 0
8219     };
8220   };
8221
8222   ChartInternal.prototype.transformLegend = function (withTransition) {
8223     var $$ = this;
8224     (withTransition ? $$.legend.transition() : $$.legend).attr("transform", $$.getTranslate('legend'));
8225   };
8226
8227   ChartInternal.prototype.updateLegendStep = function (step) {
8228     this.legendStep = step;
8229   };
8230
8231   ChartInternal.prototype.updateLegendItemWidth = function (w) {
8232     this.legendItemWidth = w;
8233   };
8234
8235   ChartInternal.prototype.updateLegendItemHeight = function (h) {
8236     this.legendItemHeight = h;
8237   };
8238
8239   ChartInternal.prototype.getLegendWidth = function () {
8240     var $$ = this;
8241     return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
8242   };
8243
8244   ChartInternal.prototype.getLegendHeight = function () {
8245     var $$ = this,
8246         h = 0;
8247
8248     if ($$.config.legend_show) {
8249       if ($$.isLegendRight) {
8250         h = $$.currentHeight;
8251       } else {
8252         h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
8253       }
8254     }
8255
8256     return h;
8257   };
8258
8259   ChartInternal.prototype.opacityForLegend = function (legendItem) {
8260     return legendItem.classed(CLASS.legendItemHidden) ? null : 1;
8261   };
8262
8263   ChartInternal.prototype.opacityForUnfocusedLegend = function (legendItem) {
8264     return legendItem.classed(CLASS.legendItemHidden) ? null : 0.3;
8265   };
8266
8267   ChartInternal.prototype.toggleFocusLegend = function (targetIds, focus) {
8268     var $$ = this;
8269     targetIds = $$.mapToTargetIds(targetIds);
8270     $$.legend.selectAll('.' + CLASS.legendItem).filter(function (id) {
8271       return targetIds.indexOf(id) >= 0;
8272     }).classed(CLASS.legendItemFocused, focus).transition().duration(100).style('opacity', function () {
8273       var opacity = focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
8274       return opacity.call($$, $$.d3.select(this));
8275     });
8276   };
8277
8278   ChartInternal.prototype.revertLegend = function () {
8279     var $$ = this,
8280         d3 = $$.d3;
8281     $$.legend.selectAll('.' + CLASS.legendItem).classed(CLASS.legendItemFocused, false).transition().duration(100).style('opacity', function () {
8282       return $$.opacityForLegend(d3.select(this));
8283     });
8284   };
8285
8286   ChartInternal.prototype.showLegend = function (targetIds) {
8287     var $$ = this,
8288         config = $$.config;
8289
8290     if (!config.legend_show) {
8291       config.legend_show = true;
8292       $$.legend.style('visibility', 'visible');
8293
8294       if (!$$.legendHasRendered) {
8295         $$.updateLegendWithDefaults();
8296       }
8297     }
8298
8299     $$.removeHiddenLegendIds(targetIds);
8300     $$.legend.selectAll($$.selectorLegends(targetIds)).style('visibility', 'visible').transition().style('opacity', function () {
8301       return $$.opacityForLegend($$.d3.select(this));
8302     });
8303   };
8304
8305   ChartInternal.prototype.hideLegend = function (targetIds) {
8306     var $$ = this,
8307         config = $$.config;
8308
8309     if (config.legend_show && isEmpty(targetIds)) {
8310       config.legend_show = false;
8311       $$.legend.style('visibility', 'hidden');
8312     }
8313
8314     $$.addHiddenLegendIds(targetIds);
8315     $$.legend.selectAll($$.selectorLegends(targetIds)).style('opacity', 0).style('visibility', 'hidden');
8316   };
8317
8318   ChartInternal.prototype.clearLegendItemTextBoxCache = function () {
8319     this.legendItemTextBox = {};
8320   };
8321
8322   ChartInternal.prototype.updateLegend = function (targetIds, options, transitions) {
8323     var $$ = this,
8324         config = $$.config;
8325     var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect, x1ForLegendTile, x2ForLegendTile, yForLegendTile;
8326     var paddingTop = 4,
8327         paddingRight = 10,
8328         maxWidth = 0,
8329         maxHeight = 0,
8330         posMin = 10,
8331         tileWidth = config.legend_item_tile_width + 5;
8332     var l,
8333         totalLength = 0,
8334         offsets = {},
8335         widths = {},
8336         heights = {},
8337         margins = [0],
8338         steps = {},
8339         step = 0;
8340     var withTransition, withTransitionForTransform;
8341     var texts, rects, tiles, background; // Skip elements when their name is set to null
8342
8343     targetIds = targetIds.filter(function (id) {
8344       return !isDefined(config.data_names[id]) || config.data_names[id] !== null;
8345     });
8346     options = options || {};
8347     withTransition = getOption(options, "withTransition", true);
8348     withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
8349
8350     function getTextBox(textElement, id) {
8351       if (!$$.legendItemTextBox[id]) {
8352         $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem, textElement);
8353       }
8354
8355       return $$.legendItemTextBox[id];
8356     }
8357
8358     function updatePositions(textElement, id, index) {
8359       var reset = index === 0,
8360           isLast = index === targetIds.length - 1,
8361           box = getTextBox(textElement, id),
8362           itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight) + config.legend_padding,
8363           itemHeight = box.height + paddingTop,
8364           itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
8365           areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
8366           margin,
8367           maxLength; // MEMO: care about condifion of step, totalLength
8368
8369       function updateValues(id, withoutStep) {
8370         if (!withoutStep) {
8371           margin = (areaLength - totalLength - itemLength) / 2;
8372
8373           if (margin < posMin) {
8374             margin = (areaLength - itemLength) / 2;
8375             totalLength = 0;
8376             step++;
8377           }
8378         }
8379
8380         steps[id] = step;
8381         margins[step] = $$.isLegendInset ? 10 : margin;
8382         offsets[id] = totalLength;
8383         totalLength += itemLength;
8384       }
8385
8386       if (reset) {
8387         totalLength = 0;
8388         step = 0;
8389         maxWidth = 0;
8390         maxHeight = 0;
8391       }
8392
8393       if (config.legend_show && !$$.isLegendToShow(id)) {
8394         widths[id] = heights[id] = steps[id] = offsets[id] = 0;
8395         return;
8396       }
8397
8398       widths[id] = itemWidth;
8399       heights[id] = itemHeight;
8400
8401       if (!maxWidth || itemWidth >= maxWidth) {
8402         maxWidth = itemWidth;
8403       }
8404
8405       if (!maxHeight || itemHeight >= maxHeight) {
8406         maxHeight = itemHeight;
8407       }
8408
8409       maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth;
8410
8411       if (config.legend_equally) {
8412         Object.keys(widths).forEach(function (id) {
8413           widths[id] = maxWidth;
8414         });
8415         Object.keys(heights).forEach(function (id) {
8416           heights[id] = maxHeight;
8417         });
8418         margin = (areaLength - maxLength * targetIds.length) / 2;
8419
8420         if (margin < posMin) {
8421           totalLength = 0;
8422           step = 0;
8423           targetIds.forEach(function (id) {
8424             updateValues(id);
8425           });
8426         } else {
8427           updateValues(id, true);
8428         }
8429       } else {
8430         updateValues(id);
8431       }
8432     }
8433
8434     if ($$.isLegendInset) {
8435       step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
8436       $$.updateLegendStep(step);
8437     }
8438
8439     if ($$.isLegendRight) {
8440       xForLegend = function xForLegend(id) {
8441         return maxWidth * steps[id];
8442       };
8443
8444       yForLegend = function yForLegend(id) {
8445         return margins[steps[id]] + offsets[id];
8446       };
8447     } else if ($$.isLegendInset) {
8448       xForLegend = function xForLegend(id) {
8449         return maxWidth * steps[id] + 10;
8450       };
8451
8452       yForLegend = function yForLegend(id) {
8453         return margins[steps[id]] + offsets[id];
8454       };
8455     } else {
8456       xForLegend = function xForLegend(id) {
8457         return margins[steps[id]] + offsets[id];
8458       };
8459
8460       yForLegend = function yForLegend(id) {
8461         return maxHeight * steps[id];
8462       };
8463     }
8464
8465     xForLegendText = function xForLegendText(id, i) {
8466       return xForLegend(id, i) + 4 + config.legend_item_tile_width;
8467     };
8468
8469     yForLegendText = function yForLegendText(id, i) {
8470       return yForLegend(id, i) + 9;
8471     };
8472
8473     xForLegendRect = function xForLegendRect(id, i) {
8474       return xForLegend(id, i);
8475     };
8476
8477     yForLegendRect = function yForLegendRect(id, i) {
8478       return yForLegend(id, i) - 5;
8479     };
8480
8481     x1ForLegendTile = function x1ForLegendTile(id, i) {
8482       return xForLegend(id, i) - 2;
8483     };
8484
8485     x2ForLegendTile = function x2ForLegendTile(id, i) {
8486       return xForLegend(id, i) - 2 + config.legend_item_tile_width;
8487     };
8488
8489     yForLegendTile = function yForLegendTile(id, i) {
8490       return yForLegend(id, i) + 4;
8491     }; // Define g for legend area
8492
8493
8494     l = $$.legend.selectAll('.' + CLASS.legendItem).data(targetIds).enter().append('g').attr('class', function (id) {
8495       return $$.generateClass(CLASS.legendItem, id);
8496     }).style('visibility', function (id) {
8497       return $$.isLegendToShow(id) ? 'visible' : 'hidden';
8498     }).style('cursor', 'pointer').on('click', function (id) {
8499       if (config.legend_item_onclick) {
8500         config.legend_item_onclick.call($$, id);
8501       } else {
8502         if ($$.d3.event.altKey) {
8503           $$.api.hide();
8504           $$.api.show(id);
8505         } else {
8506           $$.api.toggle(id);
8507           $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
8508         }
8509       }
8510     }).on('mouseover', function (id) {
8511       if (config.legend_item_onmouseover) {
8512         config.legend_item_onmouseover.call($$, id);
8513       } else {
8514         $$.d3.select(this).classed(CLASS.legendItemFocused, true);
8515
8516         if (!$$.transiting && $$.isTargetToShow(id)) {
8517           $$.api.focus(id);
8518         }
8519       }
8520     }).on('mouseout', function (id) {
8521       if (config.legend_item_onmouseout) {
8522         config.legend_item_onmouseout.call($$, id);
8523       } else {
8524         $$.d3.select(this).classed(CLASS.legendItemFocused, false);
8525         $$.api.revert();
8526       }
8527     });
8528     l.append('text').text(function (id) {
8529       return isDefined(config.data_names[id]) ? config.data_names[id] : id;
8530     }).each(function (id, i) {
8531       updatePositions(this, id, i);
8532     }).style("pointer-events", "none").attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200).attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
8533     l.append('rect').attr("class", CLASS.legendItemEvent).style('fill-opacity', 0).attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200).attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
8534     l.append('line').attr('class', CLASS.legendItemTile).style('stroke', $$.color).style("pointer-events", "none").attr('x1', $$.isLegendRight || $$.isLegendInset ? x1ForLegendTile : -200).attr('y1', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile).attr('x2', $$.isLegendRight || $$.isLegendInset ? x2ForLegendTile : -200).attr('y2', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile).attr('stroke-width', config.legend_item_tile_height); // Set background for inset legend
8535
8536     background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
8537
8538     if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
8539       background = $$.legend.insert('g', '.' + CLASS.legendItem).attr("class", CLASS.legendBackground).append('rect');
8540     }
8541
8542     texts = $$.legend.selectAll('text').data(targetIds).text(function (id) {
8543       return isDefined(config.data_names[id]) ? config.data_names[id] : id;
8544     }) // MEMO: needed for update
8545     .each(function (id, i) {
8546       updatePositions(this, id, i);
8547     });
8548     (withTransition ? texts.transition() : texts).attr('x', xForLegendText).attr('y', yForLegendText);
8549     rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent).data(targetIds);
8550     (withTransition ? rects.transition() : rects).attr('width', function (id) {
8551       return widths[id];
8552     }).attr('height', function (id) {
8553       return heights[id];
8554     }).attr('x', xForLegendRect).attr('y', yForLegendRect);
8555     tiles = $$.legend.selectAll('line.' + CLASS.legendItemTile).data(targetIds);
8556     (withTransition ? tiles.transition() : tiles).style('stroke', $$.levelColor ? function (id) {
8557       return $$.levelColor($$.cache[id].values[0].value);
8558     } : $$.color).attr('x1', x1ForLegendTile).attr('y1', yForLegendTile).attr('x2', x2ForLegendTile).attr('y2', yForLegendTile);
8559
8560     if (background) {
8561       (withTransition ? background.transition() : background).attr('height', $$.getLegendHeight() - 12).attr('width', maxWidth * (step + 1) + 10);
8562     } // toggle legend state
8563
8564
8565     $$.legend.selectAll('.' + CLASS.legendItem).classed(CLASS.legendItemHidden, function (id) {
8566       return !$$.isTargetToShow(id);
8567     }); // Update all to reflect change of legend
8568
8569     $$.updateLegendItemWidth(maxWidth);
8570     $$.updateLegendItemHeight(maxHeight);
8571     $$.updateLegendStep(step); // Update size and scale
8572
8573     $$.updateSizes();
8574     $$.updateScales();
8575     $$.updateSvgSize(); // Update g positions
8576
8577     $$.transformAll(withTransitionForTransform, transitions);
8578     $$.legendHasRendered = true;
8579   };
8580
8581   ChartInternal.prototype.initRegion = function () {
8582     var $$ = this;
8583     $$.region = $$.main.append('g').attr("clip-path", $$.clipPath).attr("class", CLASS.regions);
8584   };
8585
8586   ChartInternal.prototype.updateRegion = function (duration) {
8587     var $$ = this,
8588         config = $$.config; // hide if arc type
8589
8590     $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
8591     var mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region).data(config.regions);
8592     var mainRegionEnter = mainRegion.enter().append('rect').attr("x", $$.regionX.bind($$)).attr("y", $$.regionY.bind($$)).attr("width", $$.regionWidth.bind($$)).attr("height", $$.regionHeight.bind($$)).style("fill-opacity", 0);
8593     $$.mainRegion = mainRegionEnter.merge(mainRegion).attr('class', $$.classRegion.bind($$));
8594     mainRegion.exit().transition().duration(duration).style("opacity", 0).remove();
8595   };
8596
8597   ChartInternal.prototype.redrawRegion = function (withTransition, transition) {
8598     var $$ = this,
8599         regions = $$.mainRegion;
8600     return [(withTransition ? regions.transition(transition) : regions).attr("x", $$.regionX.bind($$)).attr("y", $$.regionY.bind($$)).attr("width", $$.regionWidth.bind($$)).attr("height", $$.regionHeight.bind($$)).style("fill-opacity", function (d) {
8601       return isValue(d.opacity) ? d.opacity : 0.1;
8602     })];
8603   };
8604
8605   ChartInternal.prototype.regionX = function (d) {
8606     var $$ = this,
8607         config = $$.config,
8608         xPos,
8609         yScale = d.axis === 'y' ? $$.y : $$.y2;
8610
8611     if (d.axis === 'y' || d.axis === 'y2') {
8612       xPos = config.axis_rotated ? 'start' in d ? yScale(d.start) : 0 : 0;
8613     } else {
8614       xPos = config.axis_rotated ? 0 : 'start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0;
8615     }
8616
8617     return xPos;
8618   };
8619
8620   ChartInternal.prototype.regionY = function (d) {
8621     var $$ = this,
8622         config = $$.config,
8623         yPos,
8624         yScale = d.axis === 'y' ? $$.y : $$.y2;
8625
8626     if (d.axis === 'y' || d.axis === 'y2') {
8627       yPos = config.axis_rotated ? 0 : 'end' in d ? yScale(d.end) : 0;
8628     } else {
8629       yPos = config.axis_rotated ? 'start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0 : 0;
8630     }
8631
8632     return yPos;
8633   };
8634
8635   ChartInternal.prototype.regionWidth = function (d) {
8636     var $$ = this,
8637         config = $$.config,
8638         start = $$.regionX(d),
8639         end,
8640         yScale = d.axis === 'y' ? $$.y : $$.y2;
8641
8642     if (d.axis === 'y' || d.axis === 'y2') {
8643       end = config.axis_rotated ? 'end' in d ? yScale(d.end) : $$.width : $$.width;
8644     } else {
8645       end = config.axis_rotated ? $$.width : 'end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.width;
8646     }
8647
8648     return end < start ? 0 : end - start;
8649   };
8650
8651   ChartInternal.prototype.regionHeight = function (d) {
8652     var $$ = this,
8653         config = $$.config,
8654         start = this.regionY(d),
8655         end,
8656         yScale = d.axis === 'y' ? $$.y : $$.y2;
8657
8658     if (d.axis === 'y' || d.axis === 'y2') {
8659       end = config.axis_rotated ? $$.height : 'start' in d ? yScale(d.start) : $$.height;
8660     } else {
8661       end = config.axis_rotated ? 'end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.height : $$.height;
8662     }
8663
8664     return end < start ? 0 : end - start;
8665   };
8666
8667   ChartInternal.prototype.isRegionOnX = function (d) {
8668     return !d.axis || d.axis === 'x';
8669   };
8670
8671   ChartInternal.prototype.getScale = function (min, max, forTimeseries) {
8672     return (forTimeseries ? this.d3.scaleTime() : this.d3.scaleLinear()).range([min, max]);
8673   };
8674
8675   ChartInternal.prototype.getX = function (min, max, domain, offset) {
8676     var $$ = this,
8677         scale = $$.getScale(min, max, $$.isTimeSeries()),
8678         _scale = domain ? scale.domain(domain) : scale,
8679         key; // Define customized scale if categorized axis
8680
8681
8682     if ($$.isCategorized()) {
8683       offset = offset || function () {
8684         return 0;
8685       };
8686
8687       scale = function scale(d, raw) {
8688         var v = _scale(d) + offset(d);
8689         return raw ? v : Math.ceil(v);
8690       };
8691     } else {
8692       scale = function scale(d, raw) {
8693         var v = _scale(d);
8694
8695         return raw ? v : Math.ceil(v);
8696       };
8697     } // define functions
8698
8699
8700     for (key in _scale) {
8701       scale[key] = _scale[key];
8702     }
8703
8704     scale.orgDomain = function () {
8705       return _scale.domain();
8706     }; // define custom domain() for categorized axis
8707
8708
8709     if ($$.isCategorized()) {
8710       scale.domain = function (domain) {
8711         if (!arguments.length) {
8712           domain = this.orgDomain();
8713           return [domain[0], domain[1] + 1];
8714         }
8715
8716         _scale.domain(domain);
8717
8718         return scale;
8719       };
8720     }
8721
8722     return scale;
8723   };
8724
8725   ChartInternal.prototype.getY = function (min, max, domain) {
8726     var scale = this.getScale(min, max, this.isTimeSeriesY());
8727
8728     if (domain) {
8729       scale.domain(domain);
8730     }
8731
8732     return scale;
8733   };
8734
8735   ChartInternal.prototype.getYScale = function (id) {
8736     return this.axis.getId(id) === 'y2' ? this.y2 : this.y;
8737   };
8738
8739   ChartInternal.prototype.getSubYScale = function (id) {
8740     return this.axis.getId(id) === 'y2' ? this.subY2 : this.subY;
8741   };
8742
8743   ChartInternal.prototype.updateScales = function () {
8744     var $$ = this,
8745         config = $$.config,
8746         forInit = !$$.x; // update edges
8747
8748     $$.xMin = config.axis_rotated ? 1 : 0;
8749     $$.xMax = config.axis_rotated ? $$.height : $$.width;
8750     $$.yMin = config.axis_rotated ? 0 : $$.height;
8751     $$.yMax = config.axis_rotated ? $$.width : 1;
8752     $$.subXMin = $$.xMin;
8753     $$.subXMax = $$.xMax;
8754     $$.subYMin = config.axis_rotated ? 0 : $$.height2;
8755     $$.subYMax = config.axis_rotated ? $$.width2 : 1; // update scales
8756
8757     $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () {
8758       return $$.xAxis.tickOffset();
8759     });
8760     $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
8761     $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
8762     $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) {
8763       return d % 1 ? 0 : $$.subXAxis.tickOffset();
8764     });
8765     $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
8766     $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain()); // update axes
8767
8768     $$.xAxisTickFormat = $$.axis.getXAxisTickFormat();
8769     $$.xAxisTickValues = $$.axis.getXAxisTickValues();
8770     $$.yAxisTickValues = $$.axis.getYAxisTickValues();
8771     $$.y2AxisTickValues = $$.axis.getY2AxisTickValues();
8772     $$.xAxis = $$.axis.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
8773     $$.subXAxis = $$.axis.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
8774     $$.yAxis = $$.axis.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
8775     $$.y2Axis = $$.axis.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer); // Set initialized scales to brush and zoom
8776
8777     if (!forInit) {
8778       if ($$.brush) {
8779         $$.brush.updateScale($$.subX);
8780       }
8781     } // update for arc
8782
8783
8784     if ($$.updateArc) {
8785       $$.updateArc();
8786     }
8787   };
8788
8789   ChartInternal.prototype.selectPoint = function (target, d, i) {
8790     var $$ = this,
8791         config = $$.config,
8792         cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
8793         cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
8794         r = $$.pointSelectR.bind($$);
8795     config.data_onselected.call($$.api, d, target.node()); // add selected-circle on low layer g
8796
8797     $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i).data([d]).enter().append('circle').attr("class", function () {
8798       return $$.generateClass(CLASS.selectedCircle, i);
8799     }).attr("cx", cx).attr("cy", cy).attr("stroke", function () {
8800       return $$.color(d);
8801     }).attr("r", function (d) {
8802       return $$.pointSelectR(d) * 1.4;
8803     }).transition().duration(100).attr("r", r);
8804   };
8805
8806   ChartInternal.prototype.unselectPoint = function (target, d, i) {
8807     var $$ = this;
8808     $$.config.data_onunselected.call($$.api, d, target.node()); // remove selected-circle from low layer g
8809
8810     $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i).transition().duration(100).attr('r', 0).remove();
8811   };
8812
8813   ChartInternal.prototype.togglePoint = function (selected, target, d, i) {
8814     selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
8815   };
8816
8817   ChartInternal.prototype.selectPath = function (target, d) {
8818     var $$ = this;
8819     $$.config.data_onselected.call($$, d, target.node());
8820
8821     if ($$.config.interaction_brighten) {
8822       target.transition().duration(100).style("fill", function () {
8823         return $$.d3.rgb($$.color(d)).brighter(0.75);
8824       });
8825     }
8826   };
8827
8828   ChartInternal.prototype.unselectPath = function (target, d) {
8829     var $$ = this;
8830     $$.config.data_onunselected.call($$, d, target.node());
8831
8832     if ($$.config.interaction_brighten) {
8833       target.transition().duration(100).style("fill", function () {
8834         return $$.color(d);
8835       });
8836     }
8837   };
8838
8839   ChartInternal.prototype.togglePath = function (selected, target, d, i) {
8840     selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
8841   };
8842
8843   ChartInternal.prototype.getToggle = function (that, d) {
8844     var $$ = this,
8845         toggle;
8846
8847     if (that.nodeName === 'circle') {
8848       if ($$.isStepType(d)) {
8849         // circle is hidden in step chart, so treat as within the click area
8850         toggle = function toggle() {}; // TODO: how to select step chart?
8851
8852       } else {
8853         toggle = $$.togglePoint;
8854       }
8855     } else if (that.nodeName === 'path') {
8856       toggle = $$.togglePath;
8857     }
8858
8859     return toggle;
8860   };
8861
8862   ChartInternal.prototype.toggleShape = function (that, d, i) {
8863     var $$ = this,
8864         d3 = $$.d3,
8865         config = $$.config,
8866         shape = d3.select(that),
8867         isSelected = shape.classed(CLASS.SELECTED),
8868         toggle = $$.getToggle(that, d).bind($$);
8869
8870     if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
8871       if (!config.data_selection_multiple) {
8872         $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
8873           var shape = d3.select(this);
8874
8875           if (shape.classed(CLASS.SELECTED)) {
8876             toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
8877           }
8878         });
8879       }
8880
8881       shape.classed(CLASS.SELECTED, !isSelected);
8882       toggle(!isSelected, shape, d, i);
8883     }
8884   };
8885
8886   ChartInternal.prototype.initBar = function () {
8887     var $$ = this;
8888     $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartBars);
8889   };
8890
8891   ChartInternal.prototype.updateTargetsForBar = function (targets) {
8892     var $$ = this,
8893         config = $$.config,
8894         mainBars,
8895         mainBarEnter,
8896         classChartBar = $$.classChartBar.bind($$),
8897         classBars = $$.classBars.bind($$),
8898         classFocus = $$.classFocus.bind($$);
8899     mainBars = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar).data(targets).attr('class', function (d) {
8900       return classChartBar(d) + classFocus(d);
8901     });
8902     mainBarEnter = mainBars.enter().append('g').attr('class', classChartBar).style("pointer-events", "none"); // Bars for each data
8903
8904     mainBarEnter.append('g').attr("class", classBars).style("cursor", function (d) {
8905       return config.data_selection_isselectable(d) ? "pointer" : null;
8906     });
8907   };
8908
8909   ChartInternal.prototype.updateBar = function (durationForExit) {
8910     var $$ = this,
8911         barData = $$.barData.bind($$),
8912         classBar = $$.classBar.bind($$),
8913         initialOpacity = $$.initialOpacity.bind($$),
8914         color = function color(d) {
8915       return $$.color(d.id);
8916     };
8917
8918     var mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar).data(barData);
8919     var mainBarEnter = mainBar.enter().append('path').attr("class", classBar).style("stroke", color).style("fill", color);
8920     $$.mainBar = mainBarEnter.merge(mainBar).style("opacity", initialOpacity);
8921     mainBar.exit().transition().duration(durationForExit).style("opacity", 0);
8922   };
8923
8924   ChartInternal.prototype.redrawBar = function (drawBar, withTransition, transition) {
8925     return [(withTransition ? this.mainBar.transition(transition) : this.mainBar).attr('d', drawBar).style("stroke", this.color).style("fill", this.color).style("opacity", 1)];
8926   };
8927
8928   ChartInternal.prototype.getBarW = function (axis, barTargetsNum) {
8929     var $$ = this,
8930         config = $$.config,
8931         w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? axis.tickInterval() * config.bar_width_ratio / barTargetsNum : 0;
8932     return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
8933   };
8934
8935   ChartInternal.prototype.getBars = function (i, id) {
8936     var $$ = this;
8937     return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
8938   };
8939
8940   ChartInternal.prototype.expandBars = function (i, id, reset) {
8941     var $$ = this;
8942
8943     if (reset) {
8944       $$.unexpandBars();
8945     }
8946
8947     $$.getBars(i, id).classed(CLASS.EXPANDED, true);
8948   };
8949
8950   ChartInternal.prototype.unexpandBars = function (i) {
8951     var $$ = this;
8952     $$.getBars(i).classed(CLASS.EXPANDED, false);
8953   };
8954
8955   ChartInternal.prototype.generateDrawBar = function (barIndices, isSub) {
8956     var $$ = this,
8957         config = $$.config,
8958         getPoints = $$.generateGetBarPoints(barIndices, isSub);
8959     return function (d, i) {
8960       // 4 points that make a bar
8961       var points = getPoints(d, i); // switch points if axis is rotated, not applicable for sub chart
8962
8963       var indexX = config.axis_rotated ? 1 : 0;
8964       var indexY = config.axis_rotated ? 0 : 1;
8965       var path = 'M ' + points[0][indexX] + ',' + points[0][indexY] + ' ' + 'L' + points[1][indexX] + ',' + points[1][indexY] + ' ' + 'L' + points[2][indexX] + ',' + points[2][indexY] + ' ' + 'L' + points[3][indexX] + ',' + points[3][indexY] + ' ' + 'z';
8966       return path;
8967     };
8968   };
8969
8970   ChartInternal.prototype.generateGetBarPoints = function (barIndices, isSub) {
8971     var $$ = this,
8972         axis = isSub ? $$.subXAxis : $$.xAxis,
8973         barTargetsNum = barIndices.__max__ + 1,
8974         barW = $$.getBarW(axis, barTargetsNum),
8975         barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
8976         barY = $$.getShapeY(!!isSub),
8977         barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
8978         barSpaceOffset = barW * ($$.config.bar_space / 2),
8979         yScale = isSub ? $$.getSubYScale : $$.getYScale;
8980     return function (d, i) {
8981       var y0 = yScale.call($$, d.id)(0),
8982           offset = barOffset(d, i) || y0,
8983           // offset is for stacked bar chart
8984       posX = barX(d),
8985           posY = barY(d); // fix posY not to overflow opposite quadrant
8986
8987       if ($$.config.axis_rotated) {
8988         if (0 < d.value && posY < y0 || d.value < 0 && y0 < posY) {
8989           posY = y0;
8990         }
8991       } // 4 points that make a bar
8992
8993
8994       return [[posX + barSpaceOffset, offset], [posX + barSpaceOffset, posY - (y0 - offset)], [posX + barW - barSpaceOffset, posY - (y0 - offset)], [posX + barW - barSpaceOffset, offset]];
8995     };
8996   };
8997
8998   ChartInternal.prototype.isWithinBar = function (mouse, that) {
8999     var box = that.getBoundingClientRect(),
9000         seg0 = that.pathSegList.getItem(0),
9001         seg1 = that.pathSegList.getItem(1),
9002         x = Math.min(seg0.x, seg1.x),
9003         y = Math.min(seg0.y, seg1.y),
9004         w = box.width,
9005         h = box.height,
9006         offset = 2,
9007         sx = x - offset,
9008         ex = x + w + offset,
9009         sy = y + h + offset,
9010         ey = y - offset;
9011     return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
9012   };
9013
9014   ChartInternal.prototype.getShapeIndices = function (typeFilter) {
9015     var $$ = this,
9016         config = $$.config,
9017         indices = {},
9018         i = 0,
9019         j,
9020         k;
9021     $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)).forEach(function (d) {
9022       for (j = 0; j < config.data_groups.length; j++) {
9023         if (config.data_groups[j].indexOf(d.id) < 0) {
9024           continue;
9025         }
9026
9027         for (k = 0; k < config.data_groups[j].length; k++) {
9028           if (config.data_groups[j][k] in indices) {
9029             indices[d.id] = indices[config.data_groups[j][k]];
9030             break;
9031           }
9032         }
9033       }
9034
9035       if (isUndefined(indices[d.id])) {
9036         indices[d.id] = i++;
9037       }
9038     });
9039     indices.__max__ = i - 1;
9040     return indices;
9041   };
9042
9043   ChartInternal.prototype.getShapeX = function (offset, targetsNum, indices, isSub) {
9044     var $$ = this,
9045         scale = isSub ? $$.subX : $$.x;
9046     return function (d) {
9047       var index = d.id in indices ? indices[d.id] : 0;
9048       return d.x || d.x === 0 ? scale(d.x) - offset * (targetsNum / 2 - index) : 0;
9049     };
9050   };
9051
9052   ChartInternal.prototype.getShapeY = function (isSub) {
9053     var $$ = this;
9054     return function (d) {
9055       var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id);
9056       return scale(d.value);
9057     };
9058   };
9059
9060   ChartInternal.prototype.getShapeOffset = function (typeFilter, indices, isSub) {
9061     var $$ = this,
9062         targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))),
9063         targetIds = targets.map(function (t) {
9064       return t.id;
9065     });
9066     return function (d, i) {
9067       var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
9068           y0 = scale(0),
9069           offset = y0;
9070       targets.forEach(function (t) {
9071         var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
9072
9073         if (t.id === d.id || indices[t.id] !== indices[d.id]) {
9074           return;
9075         }
9076
9077         if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
9078           // check if the x values line up
9079           if (typeof values[i] === 'undefined' || +values[i].x !== +d.x) {
9080             // "+" for timeseries
9081             // if not, try to find the value that does line up
9082             i = -1;
9083             values.forEach(function (v, j) {
9084               if (v.x === d.x) {
9085                 i = j;
9086               }
9087             });
9088           }
9089
9090           if (i in values && values[i].value * d.value >= 0) {
9091             offset += scale(values[i].value) - y0;
9092           }
9093         }
9094       });
9095       return offset;
9096     };
9097   };
9098
9099   ChartInternal.prototype.isWithinShape = function (that, d) {
9100     var $$ = this,
9101         shape = $$.d3.select(that),
9102         isWithin;
9103
9104     if (!$$.isTargetToShow(d.id)) {
9105       isWithin = false;
9106     } else if (that.nodeName === 'circle') {
9107       isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
9108     } else if (that.nodeName === 'path') {
9109       isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar($$.d3.mouse(that), that) : true;
9110     }
9111
9112     return isWithin;
9113   };
9114
9115   ChartInternal.prototype.getInterpolate = function (d) {
9116     var $$ = this,
9117         d3 = $$.d3,
9118         types = {
9119       'linear': d3.curveLinear,
9120       'linear-closed': d3.curveLinearClosed,
9121       'basis': d3.curveBasis,
9122       'basis-open': d3.curveBasisOpen,
9123       'basis-closed': d3.curveBasisClosed,
9124       'bundle': d3.curveBundle,
9125       'cardinal': d3.curveCardinal,
9126       'cardinal-open': d3.curveCardinalOpen,
9127       'cardinal-closed': d3.curveCardinalClosed,
9128       'monotone': d3.curveMonotoneX,
9129       'step': d3.curveStep,
9130       'step-before': d3.curveStepBefore,
9131       'step-after': d3.curveStepAfter
9132     },
9133         type;
9134
9135     if ($$.isSplineType(d)) {
9136       type = types[$$.config.spline_interpolation_type] || types.cardinal;
9137     } else if ($$.isStepType(d)) {
9138       type = types[$$.config.line_step_type];
9139     } else {
9140       type = types.linear;
9141     }
9142
9143     return type;
9144   };
9145
9146   ChartInternal.prototype.initLine = function () {
9147     var $$ = this;
9148     $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartLines);
9149   };
9150
9151   ChartInternal.prototype.updateTargetsForLine = function (targets) {
9152     var $$ = this,
9153         config = $$.config,
9154         mainLines,
9155         mainLineEnter,
9156         classChartLine = $$.classChartLine.bind($$),
9157         classLines = $$.classLines.bind($$),
9158         classAreas = $$.classAreas.bind($$),
9159         classCircles = $$.classCircles.bind($$),
9160         classFocus = $$.classFocus.bind($$);
9161     mainLines = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine).data(targets).attr('class', function (d) {
9162       return classChartLine(d) + classFocus(d);
9163     });
9164     mainLineEnter = mainLines.enter().append('g').attr('class', classChartLine).style('opacity', 0).style("pointer-events", "none"); // Lines for each data
9165
9166     mainLineEnter.append('g').attr("class", classLines); // Areas
9167
9168     mainLineEnter.append('g').attr('class', classAreas); // Circles for each data point on lines
9169
9170     mainLineEnter.append('g').attr("class", function (d) {
9171       return $$.generateClass(CLASS.selectedCircles, d.id);
9172     });
9173     mainLineEnter.append('g').attr("class", classCircles).style("cursor", function (d) {
9174       return config.data_selection_isselectable(d) ? "pointer" : null;
9175     }); // Update date for selected circles
9176
9177     targets.forEach(function (t) {
9178       $$.main.selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d) {
9179         d.value = t.values[d.index].value;
9180       });
9181     }); // MEMO: can not keep same color...
9182     //mainLineUpdate.exit().remove();
9183   };
9184
9185   ChartInternal.prototype.updateLine = function (durationForExit) {
9186     var $$ = this;
9187     var mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line).data($$.lineData.bind($$));
9188     var mainLineEnter = mainLine.enter().append('path').attr('class', $$.classLine.bind($$)).style("stroke", $$.color);
9189     $$.mainLine = mainLineEnter.merge(mainLine).style("opacity", $$.initialOpacity.bind($$)).style('shape-rendering', function (d) {
9190       return $$.isStepType(d) ? 'crispEdges' : '';
9191     }).attr('transform', null);
9192     mainLine.exit().transition().duration(durationForExit).style('opacity', 0);
9193   };
9194
9195   ChartInternal.prototype.redrawLine = function (drawLine, withTransition, transition) {
9196     return [(withTransition ? this.mainLine.transition(transition) : this.mainLine).attr("d", drawLine).style("stroke", this.color).style("opacity", 1)];
9197   };
9198
9199   ChartInternal.prototype.generateDrawLine = function (lineIndices, isSub) {
9200     var $$ = this,
9201         config = $$.config,
9202         line = $$.d3.line(),
9203         getPoints = $$.generateGetLinePoints(lineIndices, isSub),
9204         yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
9205         xValue = function xValue(d) {
9206       return (isSub ? $$.subxx : $$.xx).call($$, d);
9207     },
9208         yValue = function yValue(d, i) {
9209       return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
9210     };
9211
9212     line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
9213
9214     if (!config.line_connectNull) {
9215       line = line.defined(function (d) {
9216         return d.value != null;
9217       });
9218     }
9219
9220     return function (d) {
9221       var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
9222           x = isSub ? $$.subX : $$.x,
9223           y = yScaleGetter.call($$, d.id),
9224           x0 = 0,
9225           y0 = 0,
9226           path;
9227
9228       if ($$.isLineType(d)) {
9229         if (config.data_regions[d.id]) {
9230           path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
9231         } else {
9232           if ($$.isStepType(d)) {
9233             values = $$.convertValuesToStep(values);
9234           }
9235
9236           path = line.curve($$.getInterpolate(d))(values);
9237         }
9238       } else {
9239         if (values[0]) {
9240           x0 = x(values[0].x);
9241           y0 = y(values[0].value);
9242         }
9243
9244         path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
9245       }
9246
9247       return path ? path : "M 0 0";
9248     };
9249   };
9250
9251   ChartInternal.prototype.generateGetLinePoints = function (lineIndices, isSub) {
9252     // partial duplication of generateGetBarPoints
9253     var $$ = this,
9254         config = $$.config,
9255         lineTargetsNum = lineIndices.__max__ + 1,
9256         x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
9257         y = $$.getShapeY(!!isSub),
9258         lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
9259         yScale = isSub ? $$.getSubYScale : $$.getYScale;
9260     return function (d, i) {
9261       var y0 = yScale.call($$, d.id)(0),
9262           offset = lineOffset(d, i) || y0,
9263           // offset is for stacked area chart
9264       posX = x(d),
9265           posY = y(d); // fix posY not to overflow opposite quadrant
9266
9267       if (config.axis_rotated) {
9268         if (0 < d.value && posY < y0 || d.value < 0 && y0 < posY) {
9269           posY = y0;
9270         }
9271       } // 1 point that marks the line position
9272
9273
9274       return [[posX, posY - (y0 - offset)], [posX, posY - (y0 - offset)], // needed for compatibility
9275       [posX, posY - (y0 - offset)], // needed for compatibility
9276       [posX, posY - (y0 - offset)] // needed for compatibility
9277       ];
9278     };
9279   };
9280
9281   ChartInternal.prototype.lineWithRegions = function (d, x, y, _regions) {
9282     var $$ = this,
9283         config = $$.config,
9284         prev = -1,
9285         i,
9286         j,
9287         s = "M",
9288         sWithRegion,
9289         xp,
9290         yp,
9291         dx,
9292         dy,
9293         dd,
9294         diff,
9295         diffx2,
9296         xOffset = $$.isCategorized() ? 0.5 : 0,
9297         xValue,
9298         yValue,
9299         regions = [];
9300
9301     function isWithinRegions(x, regions) {
9302       var i;
9303
9304       for (i = 0; i < regions.length; i++) {
9305         if (regions[i].start < x && x <= regions[i].end) {
9306           return true;
9307         }
9308       }
9309
9310       return false;
9311     } // Check start/end of regions
9312
9313
9314     if (isDefined(_regions)) {
9315       for (i = 0; i < _regions.length; i++) {
9316         regions[i] = {};
9317
9318         if (isUndefined(_regions[i].start)) {
9319           regions[i].start = d[0].x;
9320         } else {
9321           regions[i].start = $$.isTimeSeries() ? $$.parseDate(_regions[i].start) : _regions[i].start;
9322         }
9323
9324         if (isUndefined(_regions[i].end)) {
9325           regions[i].end = d[d.length - 1].x;
9326         } else {
9327           regions[i].end = $$.isTimeSeries() ? $$.parseDate(_regions[i].end) : _regions[i].end;
9328         }
9329       }
9330     } // Set scales
9331
9332
9333     xValue = config.axis_rotated ? function (d) {
9334       return y(d.value);
9335     } : function (d) {
9336       return x(d.x);
9337     };
9338     yValue = config.axis_rotated ? function (d) {
9339       return x(d.x);
9340     } : function (d) {
9341       return y(d.value);
9342     }; // Define svg generator function for region
9343
9344     function generateM(points) {
9345       return 'M' + points[0][0] + ' ' + points[0][1] + ' ' + points[1][0] + ' ' + points[1][1];
9346     }
9347
9348     if ($$.isTimeSeries()) {
9349       sWithRegion = function sWithRegion(d0, d1, j, diff) {
9350         var x0 = d0.x.getTime(),
9351             x_diff = d1.x - d0.x,
9352             xv0 = new Date(x0 + x_diff * j),
9353             xv1 = new Date(x0 + x_diff * (j + diff)),
9354             points;
9355
9356         if (config.axis_rotated) {
9357           points = [[y(yp(j)), x(xv0)], [y(yp(j + diff)), x(xv1)]];
9358         } else {
9359           points = [[x(xv0), y(yp(j))], [x(xv1), y(yp(j + diff))]];
9360         }
9361
9362         return generateM(points);
9363       };
9364     } else {
9365       sWithRegion = function sWithRegion(d0, d1, j, diff) {
9366         var points;
9367
9368         if (config.axis_rotated) {
9369           points = [[y(yp(j), true), x(xp(j))], [y(yp(j + diff), true), x(xp(j + diff))]];
9370         } else {
9371           points = [[x(xp(j), true), y(yp(j))], [x(xp(j + diff), true), y(yp(j + diff))]];
9372         }
9373
9374         return generateM(points);
9375       };
9376     } // Generate
9377
9378
9379     for (i = 0; i < d.length; i++) {
9380       // Draw as normal
9381       if (isUndefined(regions) || !isWithinRegions(d[i].x, regions)) {
9382         s += " " + xValue(d[i]) + " " + yValue(d[i]);
9383       } // Draw with region // TODO: Fix for horizotal charts
9384       else {
9385           xp = $$.getScale(d[i - 1].x + xOffset, d[i].x + xOffset, $$.isTimeSeries());
9386           yp = $$.getScale(d[i - 1].value, d[i].value);
9387           dx = x(d[i].x) - x(d[i - 1].x);
9388           dy = y(d[i].value) - y(d[i - 1].value);
9389           dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
9390           diff = 2 / dd;
9391           diffx2 = diff * 2;
9392
9393           for (j = diff; j <= 1; j += diffx2) {
9394             s += sWithRegion(d[i - 1], d[i], j, diff);
9395           }
9396         }
9397
9398       prev = d[i].x;
9399     }
9400
9401     return s;
9402   };
9403
9404   ChartInternal.prototype.updateArea = function (durationForExit) {
9405     var $$ = this,
9406         d3 = $$.d3;
9407     var mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area).data($$.lineData.bind($$));
9408     var mainAreaEnter = mainArea.enter().append('path').attr("class", $$.classArea.bind($$)).style("fill", $$.color).style("opacity", function () {
9409       $$.orgAreaOpacity = +d3.select(this).style('opacity');
9410       return 0;
9411     });
9412     $$.mainArea = mainAreaEnter.merge(mainArea).style("opacity", $$.orgAreaOpacity);
9413     mainArea.exit().transition().duration(durationForExit).style('opacity', 0);
9414   };
9415
9416   ChartInternal.prototype.redrawArea = function (drawArea, withTransition, transition) {
9417     return [(withTransition ? this.mainArea.transition(transition) : this.mainArea).attr("d", drawArea).style("fill", this.color).style("opacity", this.orgAreaOpacity)];
9418   };
9419
9420   ChartInternal.prototype.generateDrawArea = function (areaIndices, isSub) {
9421     var $$ = this,
9422         config = $$.config,
9423         area = $$.d3.area(),
9424         getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
9425         yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
9426         xValue = function xValue(d) {
9427       return (isSub ? $$.subxx : $$.xx).call($$, d);
9428     },
9429         value0 = function value0(d, i) {
9430       return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)($$.getAreaBaseValue(d.id));
9431     },
9432         value1 = function value1(d, i) {
9433       return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
9434     };
9435
9436     area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(config.area_above ? 0 : value0).y1(value1);
9437
9438     if (!config.line_connectNull) {
9439       area = area.defined(function (d) {
9440         return d.value !== null;
9441       });
9442     }
9443
9444     return function (d) {
9445       var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
9446           x0 = 0,
9447           y0 = 0,
9448           path;
9449
9450       if ($$.isAreaType(d)) {
9451         if ($$.isStepType(d)) {
9452           values = $$.convertValuesToStep(values);
9453         }
9454
9455         path = area.curve($$.getInterpolate(d))(values);
9456       } else {
9457         if (values[0]) {
9458           x0 = $$.x(values[0].x);
9459           y0 = $$.getYScale(d.id)(values[0].value);
9460         }
9461
9462         path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
9463       }
9464
9465       return path ? path : "M 0 0";
9466     };
9467   };
9468
9469   ChartInternal.prototype.getAreaBaseValue = function () {
9470     return 0;
9471   };
9472
9473   ChartInternal.prototype.generateGetAreaPoints = function (areaIndices, isSub) {
9474     // partial duplication of generateGetBarPoints
9475     var $$ = this,
9476         config = $$.config,
9477         areaTargetsNum = areaIndices.__max__ + 1,
9478         x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
9479         y = $$.getShapeY(!!isSub),
9480         areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
9481         yScale = isSub ? $$.getSubYScale : $$.getYScale;
9482     return function (d, i) {
9483       var y0 = yScale.call($$, d.id)(0),
9484           offset = areaOffset(d, i) || y0,
9485           // offset is for stacked area chart
9486       posX = x(d),
9487           posY = y(d); // fix posY not to overflow opposite quadrant
9488
9489       if (config.axis_rotated) {
9490         if (0 < d.value && posY < y0 || d.value < 0 && y0 < posY) {
9491           posY = y0;
9492         }
9493       } // 1 point that marks the area position
9494
9495
9496       return [[posX, offset], [posX, posY - (y0 - offset)], [posX, posY - (y0 - offset)], // needed for compatibility
9497       [posX, offset] // needed for compatibility
9498       ];
9499     };
9500   };
9501
9502   ChartInternal.prototype.updateCircle = function (cx, cy) {
9503     var $$ = this;
9504     var mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle).data($$.lineOrScatterData.bind($$));
9505     var mainCircleEnter = mainCircle.enter().append("circle").attr("class", $$.classCircle.bind($$)).attr("cx", cx).attr("cy", cy).attr("r", $$.pointR.bind($$)).style("fill", $$.color);
9506     $$.mainCircle = mainCircleEnter.merge(mainCircle).style("opacity", $$.initialOpacityForCircle.bind($$));
9507     mainCircle.exit().style("opacity", 0);
9508   };
9509
9510   ChartInternal.prototype.redrawCircle = function (cx, cy, withTransition, transition) {
9511     var $$ = this,
9512         selectedCircles = $$.main.selectAll('.' + CLASS.selectedCircle);
9513     return [(withTransition ? $$.mainCircle.transition(transition) : $$.mainCircle).style('opacity', this.opacityForCircle.bind($$)).style("fill", $$.color).attr("cx", cx).attr("cy", cy), (withTransition ? selectedCircles.transition(transition) : selectedCircles).attr("cx", cx).attr("cy", cy)];
9514   };
9515
9516   ChartInternal.prototype.circleX = function (d) {
9517     return d.x || d.x === 0 ? this.x(d.x) : null;
9518   };
9519
9520   ChartInternal.prototype.updateCircleY = function () {
9521     var $$ = this,
9522         lineIndices,
9523         getPoints;
9524
9525     if ($$.config.data_groups.length > 0) {
9526       lineIndices = $$.getShapeIndices($$.isLineType), getPoints = $$.generateGetLinePoints(lineIndices);
9527
9528       $$.circleY = function (d, i) {
9529         return getPoints(d, i)[0][1];
9530       };
9531     } else {
9532       $$.circleY = function (d) {
9533         return $$.getYScale(d.id)(d.value);
9534       };
9535     }
9536   };
9537
9538   ChartInternal.prototype.getCircles = function (i, id) {
9539     var $$ = this;
9540     return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
9541   };
9542
9543   ChartInternal.prototype.expandCircles = function (i, id, reset) {
9544     var $$ = this,
9545         r = $$.pointExpandedR.bind($$);
9546
9547     if (reset) {
9548       $$.unexpandCircles();
9549     }
9550
9551     $$.getCircles(i, id).classed(CLASS.EXPANDED, true).attr('r', r);
9552   };
9553
9554   ChartInternal.prototype.unexpandCircles = function (i) {
9555     var $$ = this,
9556         r = $$.pointR.bind($$);
9557     $$.getCircles(i).filter(function () {
9558       return $$.d3.select(this).classed(CLASS.EXPANDED);
9559     }).classed(CLASS.EXPANDED, false).attr('r', r);
9560   };
9561
9562   ChartInternal.prototype.pointR = function (d) {
9563     var $$ = this,
9564         config = $$.config;
9565     return $$.isStepType(d) ? 0 : isFunction(config.point_r) ? config.point_r(d) : config.point_r;
9566   };
9567
9568   ChartInternal.prototype.pointExpandedR = function (d) {
9569     var $$ = this,
9570         config = $$.config;
9571
9572     if (config.point_focus_expand_enabled) {
9573       return isFunction(config.point_focus_expand_r) ? config.point_focus_expand_r(d) : config.point_focus_expand_r ? config.point_focus_expand_r : $$.pointR(d) * 1.75;
9574     } else {
9575       return $$.pointR(d);
9576     }
9577   };
9578
9579   ChartInternal.prototype.pointSelectR = function (d) {
9580     var $$ = this,
9581         config = $$.config;
9582     return isFunction(config.point_select_r) ? config.point_select_r(d) : config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
9583   };
9584
9585   ChartInternal.prototype.isWithinCircle = function (that, r) {
9586     var d3 = this.d3,
9587         mouse = d3.mouse(that),
9588         d3_this = d3.select(that),
9589         cx = +d3_this.attr("cx"),
9590         cy = +d3_this.attr("cy");
9591     return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
9592   };
9593
9594   ChartInternal.prototype.isWithinStep = function (that, y) {
9595     return Math.abs(y - this.d3.mouse(that)[1]) < 30;
9596   };
9597
9598   ChartInternal.prototype.getCurrentWidth = function () {
9599     var $$ = this,
9600         config = $$.config;
9601     return config.size_width ? config.size_width : $$.getParentWidth();
9602   };
9603
9604   ChartInternal.prototype.getCurrentHeight = function () {
9605     var $$ = this,
9606         config = $$.config,
9607         h = config.size_height ? config.size_height : $$.getParentHeight();
9608     return h > 0 ? h : 320 / ($$.hasType('gauge') && !config.gauge_fullCircle ? 2 : 1);
9609   };
9610
9611   ChartInternal.prototype.getCurrentPaddingTop = function () {
9612     var $$ = this,
9613         config = $$.config,
9614         padding = isValue(config.padding_top) ? config.padding_top : 0;
9615
9616     if ($$.title && $$.title.node()) {
9617       padding += $$.getTitlePadding();
9618     }
9619
9620     return padding;
9621   };
9622
9623   ChartInternal.prototype.getCurrentPaddingBottom = function () {
9624     var config = this.config;
9625     return isValue(config.padding_bottom) ? config.padding_bottom : 0;
9626   };
9627
9628   ChartInternal.prototype.getCurrentPaddingLeft = function (withoutRecompute) {
9629     var $$ = this,
9630         config = $$.config;
9631
9632     if (isValue(config.padding_left)) {
9633       return config.padding_left;
9634     } else if (config.axis_rotated) {
9635       return !config.axis_x_show || config.axis_x_inner ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
9636     } else if (!config.axis_y_show || config.axis_y_inner) {
9637       // && !config.axis_rotated
9638       return $$.axis.getYAxisLabelPosition().isOuter ? 30 : 1;
9639     } else {
9640       return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
9641     }
9642   };
9643
9644   ChartInternal.prototype.getCurrentPaddingRight = function () {
9645     var $$ = this,
9646         config = $$.config,
9647         defaultPadding = 10,
9648         legendWidthOnRight = $$.isLegendRight ? $$.getLegendWidth() + 20 : 0;
9649
9650     if (isValue(config.padding_right)) {
9651       return config.padding_right + 1; // 1 is needed not to hide tick line
9652     } else if (config.axis_rotated) {
9653       return defaultPadding + legendWidthOnRight;
9654     } else if (!config.axis_y2_show || config.axis_y2_inner) {
9655       // && !config.axis_rotated
9656       return 2 + legendWidthOnRight + ($$.axis.getY2AxisLabelPosition().isOuter ? 20 : 0);
9657     } else {
9658       return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
9659     }
9660   };
9661
9662   ChartInternal.prototype.getParentRectValue = function (key) {
9663     var parent = this.selectChart.node(),
9664         v;
9665
9666     while (parent && parent.tagName !== 'BODY') {
9667       try {
9668         v = parent.getBoundingClientRect()[key];
9669       } catch (e) {
9670         if (key === 'width') {
9671           // In IE in certain cases getBoundingClientRect
9672           // will cause an "unspecified error"
9673           v = parent.offsetWidth;
9674         }
9675       }
9676
9677       if (v) {
9678         break;
9679       }
9680
9681       parent = parent.parentNode;
9682     }
9683
9684     return v;
9685   };
9686
9687   ChartInternal.prototype.getParentWidth = function () {
9688     return this.getParentRectValue('width');
9689   };
9690
9691   ChartInternal.prototype.getParentHeight = function () {
9692     var h = this.selectChart.style('height');
9693     return h.indexOf('px') > 0 ? +h.replace('px', '') : 0;
9694   };
9695
9696   ChartInternal.prototype.getSvgLeft = function (withoutRecompute) {
9697     var $$ = this,
9698         config = $$.config,
9699         hasLeftAxisRect = config.axis_rotated || !config.axis_rotated && !config.axis_y_inner,
9700         leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
9701         leftAxis = $$.main.select('.' + leftAxisClass).node(),
9702         svgRect = leftAxis && hasLeftAxisRect ? leftAxis.getBoundingClientRect() : {
9703       right: 0
9704     },
9705         chartRect = $$.selectChart.node().getBoundingClientRect(),
9706         hasArc = $$.hasArcType(),
9707         svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
9708     return svgLeft > 0 ? svgLeft : 0;
9709   };
9710
9711   ChartInternal.prototype.getAxisWidthByAxisId = function (id, withoutRecompute) {
9712     var $$ = this,
9713         position = $$.axis.getLabelPositionById(id);
9714     return $$.axis.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
9715   };
9716
9717   ChartInternal.prototype.getHorizontalAxisHeight = function (axisId) {
9718     var $$ = this,
9719         config = $$.config,
9720         h = 30;
9721
9722     if (axisId === 'x' && !config.axis_x_show) {
9723       return 8;
9724     }
9725
9726     if (axisId === 'x' && config.axis_x_height) {
9727       return config.axis_x_height;
9728     }
9729
9730     if (axisId === 'y' && !config.axis_y_show) {
9731       return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1;
9732     }
9733
9734     if (axisId === 'y2' && !config.axis_y2_show) {
9735       return $$.rotated_padding_top;
9736     } // Calculate x axis height when tick rotated
9737
9738
9739     if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
9740       h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - Math.abs(config.axis_x_tick_rotate)) / 180);
9741     } // Calculate y axis height when tick rotated
9742
9743
9744     if (axisId === 'y' && config.axis_rotated && config.axis_y_tick_rotate) {
9745       h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - Math.abs(config.axis_y_tick_rotate)) / 180);
9746     }
9747
9748     return h + ($$.axis.getLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
9749   };
9750
9751   ChartInternal.prototype.initBrush = function (scale) {
9752     var $$ = this,
9753         d3 = $$.d3; // TODO: dynamically change brushY/brushX according to axis_rotated.
9754
9755     $$.brush = ($$.config.axis_rotated ? d3.brushY() : d3.brushX()).on("brush", function () {
9756       var event = d3.event.sourceEvent;
9757
9758       if (event && event.type === "zoom") {
9759         return;
9760       }
9761
9762       $$.redrawForBrush();
9763     }).on("end", function () {
9764       var event = d3.event.sourceEvent;
9765
9766       if (event && event.type === "zoom") {
9767         return;
9768       }
9769
9770       if ($$.brush.empty() && event && event.type !== 'end') {
9771         $$.brush.clear();
9772       }
9773     });
9774
9775     $$.brush.updateExtent = function () {
9776       var range = this.scale.range(),
9777           extent;
9778
9779       if ($$.config.axis_rotated) {
9780         extent = [[0, range[0]], [$$.width2, range[1]]];
9781       } else {
9782         extent = [[range[0], 0], [range[1], $$.height2]];
9783       }
9784
9785       this.extent(extent);
9786       return this;
9787     };
9788
9789     $$.brush.updateScale = function (scale) {
9790       this.scale = scale;
9791       return this;
9792     };
9793
9794     $$.brush.update = function (scale) {
9795       this.updateScale(scale || $$.subX).updateExtent();
9796       $$.context.select('.' + CLASS.brush).call(this);
9797     };
9798
9799     $$.brush.clear = function () {
9800       $$.context.select('.' + CLASS.brush).call($$.brush.move, null);
9801     };
9802
9803     $$.brush.selection = function () {
9804       return d3.brushSelection($$.context.select('.' + CLASS.brush).node());
9805     };
9806
9807     $$.brush.selectionAsValue = function (selectionAsValue, withTransition) {
9808       var selection, brush;
9809
9810       if (selectionAsValue) {
9811         if ($$.context) {
9812           selection = [this.scale(selectionAsValue[0]), this.scale(selectionAsValue[1])];
9813           brush = $$.context.select('.' + CLASS.brush);
9814
9815           if (withTransition) {
9816             brush = brush.transition();
9817           }
9818
9819           $$.brush.move(brush, selection);
9820         }
9821
9822         return [];
9823       }
9824
9825       selection = $$.brush.selection() || [0, 0];
9826       return [this.scale.invert(selection[0]), this.scale.invert(selection[1])];
9827     };
9828
9829     $$.brush.empty = function () {
9830       var selection = $$.brush.selection();
9831       return !selection || selection[0] === selection[1];
9832     };
9833
9834     return $$.brush.updateScale(scale);
9835   };
9836
9837   ChartInternal.prototype.initSubchart = function () {
9838     var $$ = this,
9839         config = $$.config,
9840         context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context')),
9841         visibility = config.subchart_show ? 'visible' : 'hidden'; // set style
9842
9843     context.style('visibility', visibility); // Define g for chart area
9844
9845     context.append('g').attr("clip-path", $$.clipPathForSubchart).attr('class', CLASS.chart); // Define g for bar chart area
9846
9847     context.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartBars); // Define g for line chart area
9848
9849     context.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartLines); // Add extent rect for Brush
9850
9851     context.append("g").attr("clip-path", $$.clipPath).attr("class", CLASS.brush); // ATTENTION: This must be called AFTER chart added
9852     // Add Axis
9853
9854     $$.axes.subx = context.append("g").attr("class", CLASS.axisX).attr("transform", $$.getTranslate('subx')).attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis);
9855   };
9856
9857   ChartInternal.prototype.initSubchartBrush = function () {
9858     var $$ = this; // Add extent rect for Brush
9859
9860     $$.initBrush($$.subX).updateExtent();
9861     $$.context.select('.' + CLASS.brush).call($$.brush);
9862   };
9863
9864   ChartInternal.prototype.updateTargetsForSubchart = function (targets) {
9865     var $$ = this,
9866         context = $$.context,
9867         config = $$.config,
9868         contextLineEnter,
9869         contextLine,
9870         contextBarEnter,
9871         contextBar,
9872         classChartBar = $$.classChartBar.bind($$),
9873         classBars = $$.classBars.bind($$),
9874         classChartLine = $$.classChartLine.bind($$),
9875         classLines = $$.classLines.bind($$),
9876         classAreas = $$.classAreas.bind($$);
9877
9878     if (config.subchart_show) {
9879       //-- Bar --//
9880       contextBar = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar).data(targets);
9881       contextBarEnter = contextBar.enter().append('g').style('opacity', 0);
9882       contextBarEnter.merge(contextBar).attr('class', classChartBar); // Bars for each data
9883
9884       contextBarEnter.append('g').attr("class", classBars); //-- Line --//
9885
9886       contextLine = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine).data(targets);
9887       contextLineEnter = contextLine.enter().append('g').style('opacity', 0);
9888       contextLineEnter.merge(contextLine).attr('class', classChartLine); // Lines for each data
9889
9890       contextLineEnter.append("g").attr("class", classLines); // Area
9891
9892       contextLineEnter.append("g").attr("class", classAreas); //-- Brush --//
9893
9894       context.selectAll('.' + CLASS.brush + ' rect').attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
9895     }
9896   };
9897
9898   ChartInternal.prototype.updateBarForSubchart = function (durationForExit) {
9899     var $$ = this;
9900     var contextBar = $$.context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar).data($$.barData.bind($$));
9901     var contextBarEnter = contextBar.enter().append('path').attr("class", $$.classBar.bind($$)).style("stroke", 'none').style("fill", $$.color);
9902     contextBar.exit().transition().duration(durationForExit).style('opacity', 0).remove();
9903     $$.contextBar = contextBarEnter.merge(contextBar).style("opacity", $$.initialOpacity.bind($$));
9904   };
9905
9906   ChartInternal.prototype.redrawBarForSubchart = function (drawBarOnSub, withTransition, duration) {
9907     (withTransition ? this.contextBar.transition(Math.random().toString()).duration(duration) : this.contextBar).attr('d', drawBarOnSub).style('opacity', 1);
9908   };
9909
9910   ChartInternal.prototype.updateLineForSubchart = function (durationForExit) {
9911     var $$ = this;
9912     var contextLine = $$.context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line).data($$.lineData.bind($$));
9913     var contextLineEnter = contextLine.enter().append('path').attr('class', $$.classLine.bind($$)).style('stroke', $$.color);
9914     contextLine.exit().transition().duration(durationForExit).style('opacity', 0).remove();
9915     $$.contextLine = contextLineEnter.merge(contextLine).style("opacity", $$.initialOpacity.bind($$));
9916   };
9917
9918   ChartInternal.prototype.redrawLineForSubchart = function (drawLineOnSub, withTransition, duration) {
9919     (withTransition ? this.contextLine.transition(Math.random().toString()).duration(duration) : this.contextLine).attr("d", drawLineOnSub).style('opacity', 1);
9920   };
9921
9922   ChartInternal.prototype.updateAreaForSubchart = function (durationForExit) {
9923     var $$ = this,
9924         d3 = $$.d3;
9925     var contextArea = $$.context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area).data($$.lineData.bind($$));
9926     var contextAreaEnter = contextArea.enter().append('path').attr("class", $$.classArea.bind($$)).style("fill", $$.color).style("opacity", function () {
9927       $$.orgAreaOpacity = +d3.select(this).style('opacity');
9928       return 0;
9929     });
9930     contextArea.exit().transition().duration(durationForExit).style('opacity', 0).remove();
9931     $$.contextArea = contextAreaEnter.merge(contextArea).style("opacity", 0);
9932   };
9933
9934   ChartInternal.prototype.redrawAreaForSubchart = function (drawAreaOnSub, withTransition, duration) {
9935     (withTransition ? this.contextArea.transition(Math.random().toString()).duration(duration) : this.contextArea).attr("d", drawAreaOnSub).style("fill", this.color).style("opacity", this.orgAreaOpacity);
9936   };
9937
9938   ChartInternal.prototype.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
9939     var $$ = this,
9940         d3 = $$.d3,
9941         config = $$.config,
9942         drawAreaOnSub,
9943         drawBarOnSub,
9944         drawLineOnSub;
9945     $$.context.style('visibility', config.subchart_show ? 'visible' : 'hidden'); // subchart
9946
9947     if (config.subchart_show) {
9948       // reflect main chart to extent on subchart if zoomed
9949       if (d3.event && d3.event.type === 'zoom') {
9950         $$.brush.selectionAsValue($$.x.orgDomain());
9951       } // update subchart elements if needed
9952
9953
9954       if (withSubchart) {
9955         // extent rect
9956         if (!$$.brush.empty()) {
9957           $$.brush.selectionAsValue($$.x.orgDomain());
9958         } // setup drawer - MEMO: this must be called after axis updated
9959
9960
9961         drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
9962         drawBarOnSub = $$.generateDrawBar(barIndices, true);
9963         drawLineOnSub = $$.generateDrawLine(lineIndices, true);
9964         $$.updateBarForSubchart(duration);
9965         $$.updateLineForSubchart(duration);
9966         $$.updateAreaForSubchart(duration);
9967         $$.redrawBarForSubchart(drawBarOnSub, duration, duration);
9968         $$.redrawLineForSubchart(drawLineOnSub, duration, duration);
9969         $$.redrawAreaForSubchart(drawAreaOnSub, duration, duration);
9970       }
9971     }
9972   };
9973
9974   ChartInternal.prototype.redrawForBrush = function () {
9975     var $$ = this,
9976         x = $$.x,
9977         d3 = $$.d3,
9978         s;
9979     $$.redraw({
9980       withTransition: false,
9981       withY: $$.config.zoom_rescale,
9982       withSubchart: false,
9983       withUpdateXDomain: true,
9984       withEventRect: false,
9985       withDimension: false
9986     }); // update zoom transation binded to event rect
9987
9988     s = d3.event.selection || $$.brush.scale.range();
9989     $$.main.select('.' + CLASS.eventRect).call($$.zoom.transform, d3.zoomIdentity.scale($$.width / (s[1] - s[0])).translate(-s[0], 0));
9990     $$.config.subchart_onbrush.call($$.api, x.orgDomain());
9991   };
9992
9993   ChartInternal.prototype.transformContext = function (withTransition, transitions) {
9994     var $$ = this,
9995         subXAxis;
9996
9997     if (transitions && transitions.axisSubX) {
9998       subXAxis = transitions.axisSubX;
9999     } else {
10000       subXAxis = $$.context.select('.' + CLASS.axisX);
10001
10002       if (withTransition) {
10003         subXAxis = subXAxis.transition();
10004       }
10005     }
10006
10007     $$.context.attr("transform", $$.getTranslate('context'));
10008     subXAxis.attr("transform", $$.getTranslate('subx'));
10009   };
10010
10011   ChartInternal.prototype.getDefaultSelection = function () {
10012     var $$ = this,
10013         config = $$.config,
10014         selection = isFunction(config.axis_x_selection) ? config.axis_x_selection($$.getXDomain($$.data.targets)) : config.axis_x_selection;
10015
10016     if ($$.isTimeSeries()) {
10017       selection = [$$.parseDate(selection[0]), $$.parseDate(selection[1])];
10018     }
10019
10020     return selection;
10021   };
10022
10023   ChartInternal.prototype.initText = function () {
10024     var $$ = this;
10025     $$.main.select('.' + CLASS.chart).append("g").attr("class", CLASS.chartTexts);
10026     $$.mainText = $$.d3.selectAll([]);
10027   };
10028
10029   ChartInternal.prototype.updateTargetsForText = function (targets) {
10030     var $$ = this,
10031         classChartText = $$.classChartText.bind($$),
10032         classTexts = $$.classTexts.bind($$),
10033         classFocus = $$.classFocus.bind($$);
10034     var mainText = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText).data(targets);
10035     var mainTextEnter = mainText.enter().append('g').attr('class', classChartText).style('opacity', 0).style("pointer-events", "none");
10036     mainTextEnter.append('g').attr('class', classTexts);
10037     mainTextEnter.merge(mainText).attr('class', function (d) {
10038       return classChartText(d) + classFocus(d);
10039     });
10040   };
10041
10042   ChartInternal.prototype.updateText = function (xForText, yForText, durationForExit) {
10043     var $$ = this,
10044         config = $$.config,
10045         barOrLineData = $$.barOrLineData.bind($$),
10046         classText = $$.classText.bind($$);
10047     var mainText = $$.main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text).data(barOrLineData);
10048     var mainTextEnter = mainText.enter().append('text').attr("class", classText).attr('text-anchor', function (d) {
10049       return config.axis_rotated ? d.value < 0 ? 'end' : 'start' : 'middle';
10050     }).style("stroke", 'none').attr('x', xForText).attr('y', yForText).style("fill", function (d) {
10051       return $$.color(d);
10052     }).style("fill-opacity", 0);
10053     $$.mainText = mainTextEnter.merge(mainText).text(function (d, i, j) {
10054       return $$.dataLabelFormat(d.id)(d.value, d.id, i, j);
10055     });
10056     mainText.exit().transition().duration(durationForExit).style('fill-opacity', 0).remove();
10057   };
10058
10059   ChartInternal.prototype.redrawText = function (xForText, yForText, forFlow, withTransition, transition) {
10060     return [(withTransition ? this.mainText.transition(transition) : this.mainText).attr('x', xForText).attr('y', yForText).style("fill", this.color).style("fill-opacity", forFlow ? 0 : this.opacityForText.bind(this))];
10061   };
10062
10063   ChartInternal.prototype.getTextRect = function (text, cls, element) {
10064     var dummy = this.d3.select('body').append('div').classed('c3', true),
10065         svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
10066         font = this.d3.select(element).style('font'),
10067         rect;
10068     svg.selectAll('.dummy').data([text]).enter().append('text').classed(cls ? cls : "", true).style('font', font).text(text).each(function () {
10069       rect = this.getBoundingClientRect();
10070     });
10071     dummy.remove();
10072     return rect;
10073   };
10074
10075   ChartInternal.prototype.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
10076     var $$ = this,
10077         getAreaPoints = $$.generateGetAreaPoints(areaIndices, false),
10078         getBarPoints = $$.generateGetBarPoints(barIndices, false),
10079         getLinePoints = $$.generateGetLinePoints(lineIndices, false),
10080         getter = forX ? $$.getXForText : $$.getYForText;
10081     return function (d, i) {
10082       var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
10083       return getter.call($$, getPoints(d, i), d, this);
10084     };
10085   };
10086
10087   ChartInternal.prototype.getXForText = function (points, d, textElement) {
10088     var $$ = this,
10089         box = textElement.getBoundingClientRect(),
10090         xPos,
10091         padding;
10092
10093     if ($$.config.axis_rotated) {
10094       padding = $$.isBarType(d) ? 4 : 6;
10095       xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
10096     } else {
10097       xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
10098     } // show labels regardless of the domain if value is null
10099
10100
10101     if (d.value === null) {
10102       if (xPos > $$.width) {
10103         xPos = $$.width - box.width;
10104       } else if (xPos < 0) {
10105         xPos = 4;
10106       }
10107     }
10108
10109     return xPos;
10110   };
10111
10112   ChartInternal.prototype.getYForText = function (points, d, textElement) {
10113     var $$ = this,
10114         box = textElement.getBoundingClientRect(),
10115         yPos;
10116
10117     if ($$.config.axis_rotated) {
10118       yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
10119     } else {
10120       yPos = points[2][1];
10121
10122       if (d.value < 0 || d.value === 0 && !$$.hasPositiveValue) {
10123         yPos += box.height;
10124
10125         if ($$.isBarType(d) && $$.isSafari()) {
10126           yPos -= 3;
10127         } else if (!$$.isBarType(d) && $$.isChrome()) {
10128           yPos += 3;
10129         }
10130       } else {
10131         yPos += $$.isBarType(d) ? -3 : -6;
10132       }
10133     } // show labels regardless of the domain if value is null
10134
10135
10136     if (d.value === null && !$$.config.axis_rotated) {
10137       if (yPos < box.height) {
10138         yPos = box.height;
10139       } else if (yPos > this.height) {
10140         yPos = this.height - 4;
10141       }
10142     }
10143
10144     return yPos;
10145   };
10146
10147   ChartInternal.prototype.initTitle = function () {
10148     var $$ = this;
10149     $$.title = $$.svg.append("text").text($$.config.title_text).attr("class", $$.CLASS.title);
10150   };
10151
10152   ChartInternal.prototype.redrawTitle = function () {
10153     var $$ = this;
10154     $$.title.attr("x", $$.xForTitle.bind($$)).attr("y", $$.yForTitle.bind($$));
10155   };
10156
10157   ChartInternal.prototype.xForTitle = function () {
10158     var $$ = this,
10159         config = $$.config,
10160         position = config.title_position || 'left',
10161         x;
10162
10163     if (position.indexOf('right') >= 0) {
10164       x = $$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width - config.title_padding.right;
10165     } else if (position.indexOf('center') >= 0) {
10166       x = ($$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width) / 2;
10167     } else {
10168       // left
10169       x = config.title_padding.left;
10170     }
10171
10172     return x;
10173   };
10174
10175   ChartInternal.prototype.yForTitle = function () {
10176     var $$ = this;
10177     return $$.config.title_padding.top + $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).height;
10178   };
10179
10180   ChartInternal.prototype.getTitlePadding = function () {
10181     var $$ = this;
10182     return $$.yForTitle() + $$.config.title_padding.bottom;
10183   };
10184
10185   ChartInternal.prototype.initTooltip = function () {
10186     var $$ = this,
10187         config = $$.config,
10188         i;
10189     $$.tooltip = $$.selectChart.style("position", "relative").append("div").attr('class', CLASS.tooltipContainer).style("position", "absolute").style("pointer-events", "none").style("display", "none"); // Show tooltip if needed
10190
10191     if (config.tooltip_init_show) {
10192       if ($$.isTimeSeries() && isString(config.tooltip_init_x)) {
10193         config.tooltip_init_x = $$.parseDate(config.tooltip_init_x);
10194
10195         for (i = 0; i < $$.data.targets[0].values.length; i++) {
10196           if ($$.data.targets[0].values[i].x - config.tooltip_init_x === 0) {
10197             break;
10198           }
10199         }
10200
10201         config.tooltip_init_x = i;
10202       }
10203
10204       $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
10205         return $$.addName(d.values[config.tooltip_init_x]);
10206       }), $$.axis.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
10207       $$.tooltip.style("top", config.tooltip_init_position.top).style("left", config.tooltip_init_position.left).style("display", "block");
10208     }
10209   };
10210
10211   ChartInternal.prototype.getTooltipSortFunction = function () {
10212     var $$ = this,
10213         config = $$.config;
10214
10215     if (config.data_groups.length === 0 || config.tooltip_order !== undefined) {
10216       // if data are not grouped or if an order is specified
10217       // for the tooltip values we sort them by their values
10218       var order = config.tooltip_order;
10219
10220       if (order === undefined) {
10221         order = config.data_order;
10222       }
10223
10224       var valueOf = function valueOf(obj) {
10225         return obj ? obj.value : null;
10226       }; // if data are not grouped, we sort them by their value
10227
10228
10229       if (isString(order) && order.toLowerCase() === 'asc') {
10230         return function (a, b) {
10231           return valueOf(a) - valueOf(b);
10232         };
10233       } else if (isString(order) && order.toLowerCase() === 'desc') {
10234         return function (a, b) {
10235           return valueOf(b) - valueOf(a);
10236         };
10237       } else if (isFunction(order)) {
10238         // if the function is from data_order we need
10239         // to wrap the returned function in order to format
10240         // the sorted value to the expected format
10241         var sortFunction = order;
10242
10243         if (config.tooltip_order === undefined) {
10244           sortFunction = function sortFunction(a, b) {
10245             return order(a ? {
10246               id: a.id,
10247               values: [a]
10248             } : null, b ? {
10249               id: b.id,
10250               values: [b]
10251             } : null);
10252           };
10253         }
10254
10255         return sortFunction;
10256       } else if (isArray(order)) {
10257         return function (a, b) {
10258           return order.indexOf(a.id) - order.indexOf(b.id);
10259         };
10260       }
10261     } else {
10262       // if data are grouped, we follow the order of grouped targets
10263       var ids = $$.orderTargets($$.data.targets).map(function (i) {
10264         return i.id;
10265       }); // if it was either asc or desc we need to invert the order
10266       // returned by orderTargets
10267
10268       if ($$.isOrderAsc() || $$.isOrderDesc()) {
10269         ids = ids.reverse();
10270       }
10271
10272       return function (a, b) {
10273         return ids.indexOf(a.id) - ids.indexOf(b.id);
10274       };
10275     }
10276   };
10277
10278   ChartInternal.prototype.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
10279     var $$ = this,
10280         config = $$.config,
10281         titleFormat = config.tooltip_format_title || defaultTitleFormat,
10282         nameFormat = config.tooltip_format_name || function (name) {
10283       return name;
10284     },
10285         valueFormat = config.tooltip_format_value || defaultValueFormat,
10286         text,
10287         i,
10288         title,
10289         value,
10290         name,
10291         bgcolor;
10292
10293     var tooltipSortFunction = this.getTooltipSortFunction();
10294
10295     if (tooltipSortFunction) {
10296       d.sort(tooltipSortFunction);
10297     }
10298
10299     for (i = 0; i < d.length; i++) {
10300       if (!(d[i] && (d[i].value || d[i].value === 0))) {
10301         continue;
10302       }
10303
10304       if (!text) {
10305         title = sanitise(titleFormat ? titleFormat(d[i].x) : d[i].x);
10306         text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
10307       }
10308
10309       value = sanitise(valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index, d));
10310
10311       if (value !== undefined) {
10312         // Skip elements when their name is set to null
10313         if (d[i].name === null) {
10314           continue;
10315         }
10316
10317         name = sanitise(nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index));
10318         bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
10319         text += "<tr class='" + $$.CLASS.tooltipName + "-" + $$.getTargetSelectorSuffix(d[i].id) + "'>";
10320         text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
10321         text += "<td class='value'>" + value + "</td>";
10322         text += "</tr>";
10323       }
10324     }
10325
10326     return text + "</table>";
10327   };
10328
10329   ChartInternal.prototype.tooltipPosition = function (dataToShow, tWidth, tHeight, element) {
10330     var $$ = this,
10331         config = $$.config,
10332         d3 = $$.d3;
10333     var svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
10334     var forArc = $$.hasArcType(),
10335         mouse = d3.mouse(element); // Determin tooltip position
10336
10337     if (forArc) {
10338       tooltipLeft = ($$.width - ($$.isLegendRight ? $$.getLegendWidth() : 0)) / 2 + mouse[0];
10339       tooltipTop = ($$.hasType('gauge') ? $$.height : $$.height / 2) + mouse[1] + 20;
10340     } else {
10341       svgLeft = $$.getSvgLeft(true);
10342
10343       if (config.axis_rotated) {
10344         tooltipLeft = svgLeft + mouse[0] + 100;
10345         tooltipRight = tooltipLeft + tWidth;
10346         chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
10347         tooltipTop = $$.x(dataToShow[0].x) + 20;
10348       } else {
10349         tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
10350         tooltipRight = tooltipLeft + tWidth;
10351         chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
10352         tooltipTop = mouse[1] + 15;
10353       }
10354
10355       if (tooltipRight > chartRight) {
10356         // 20 is needed for Firefox to keep tooltip width
10357         tooltipLeft -= tooltipRight - chartRight + 20;
10358       }
10359
10360       if (tooltipTop + tHeight > $$.currentHeight) {
10361         tooltipTop -= tHeight + 30;
10362       }
10363     }
10364
10365     if (tooltipTop < 0) {
10366       tooltipTop = 0;
10367     }
10368
10369     return {
10370       top: tooltipTop,
10371       left: tooltipLeft
10372     };
10373   };
10374
10375   ChartInternal.prototype.showTooltip = function (selectedData, element) {
10376     var $$ = this,
10377         config = $$.config;
10378     var tWidth, tHeight, position;
10379     var forArc = $$.hasArcType(),
10380         dataToShow = selectedData.filter(function (d) {
10381       return d && isValue(d.value);
10382     }),
10383         positionFunction = config.tooltip_position || ChartInternal.prototype.tooltipPosition;
10384
10385     if (dataToShow.length === 0 || !config.tooltip_show) {
10386       return;
10387     }
10388
10389     $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.axis.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block"); // Get tooltip dimensions
10390
10391     tWidth = $$.tooltip.property('offsetWidth');
10392     tHeight = $$.tooltip.property('offsetHeight');
10393     position = positionFunction.call(this, dataToShow, tWidth, tHeight, element); // Set tooltip
10394
10395     $$.tooltip.style("top", position.top + "px").style("left", position.left + 'px');
10396   };
10397
10398   ChartInternal.prototype.hideTooltip = function () {
10399     this.tooltip.style("display", "none");
10400   };
10401
10402   ChartInternal.prototype.setTargetType = function (targetIds, type) {
10403     var $$ = this,
10404         config = $$.config;
10405     $$.mapToTargetIds(targetIds).forEach(function (id) {
10406       $$.withoutFadeIn[id] = type === config.data_types[id];
10407       config.data_types[id] = type;
10408     });
10409
10410     if (!targetIds) {
10411       config.data_type = type;
10412     }
10413   };
10414
10415   ChartInternal.prototype.hasType = function (type, targets) {
10416     var $$ = this,
10417         types = $$.config.data_types,
10418         has = false;
10419     targets = targets || $$.data.targets;
10420
10421     if (targets && targets.length) {
10422       targets.forEach(function (target) {
10423         var t = types[target.id];
10424
10425         if (t && t.indexOf(type) >= 0 || !t && type === 'line') {
10426           has = true;
10427         }
10428       });
10429     } else if (Object.keys(types).length) {
10430       Object.keys(types).forEach(function (id) {
10431         if (types[id] === type) {
10432           has = true;
10433         }
10434       });
10435     } else {
10436       has = $$.config.data_type === type;
10437     }
10438
10439     return has;
10440   };
10441
10442   ChartInternal.prototype.hasArcType = function (targets) {
10443     return this.hasType('pie', targets) || this.hasType('donut', targets) || this.hasType('gauge', targets);
10444   };
10445
10446   ChartInternal.prototype.isLineType = function (d) {
10447     var config = this.config,
10448         id = isString(d) ? d : d.id;
10449     return !config.data_types[id] || ['line', 'spline', 'area', 'area-spline', 'step', 'area-step'].indexOf(config.data_types[id]) >= 0;
10450   };
10451
10452   ChartInternal.prototype.isStepType = function (d) {
10453     var id = isString(d) ? d : d.id;
10454     return ['step', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
10455   };
10456
10457   ChartInternal.prototype.isSplineType = function (d) {
10458     var id = isString(d) ? d : d.id;
10459     return ['spline', 'area-spline'].indexOf(this.config.data_types[id]) >= 0;
10460   };
10461
10462   ChartInternal.prototype.isAreaType = function (d) {
10463     var id = isString(d) ? d : d.id;
10464     return ['area', 'area-spline', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
10465   };
10466
10467   ChartInternal.prototype.isBarType = function (d) {
10468     var id = isString(d) ? d : d.id;
10469     return this.config.data_types[id] === 'bar';
10470   };
10471
10472   ChartInternal.prototype.isScatterType = function (d) {
10473     var id = isString(d) ? d : d.id;
10474     return this.config.data_types[id] === 'scatter';
10475   };
10476
10477   ChartInternal.prototype.isPieType = function (d) {
10478     var id = isString(d) ? d : d.id;
10479     return this.config.data_types[id] === 'pie';
10480   };
10481
10482   ChartInternal.prototype.isGaugeType = function (d) {
10483     var id = isString(d) ? d : d.id;
10484     return this.config.data_types[id] === 'gauge';
10485   };
10486
10487   ChartInternal.prototype.isDonutType = function (d) {
10488     var id = isString(d) ? d : d.id;
10489     return this.config.data_types[id] === 'donut';
10490   };
10491
10492   ChartInternal.prototype.isArcType = function (d) {
10493     return this.isPieType(d) || this.isDonutType(d) || this.isGaugeType(d);
10494   };
10495
10496   ChartInternal.prototype.lineData = function (d) {
10497     return this.isLineType(d) ? [d] : [];
10498   };
10499
10500   ChartInternal.prototype.arcData = function (d) {
10501     return this.isArcType(d.data) ? [d] : [];
10502   };
10503   /* not used
10504    function scatterData(d) {
10505    return isScatterType(d) ? d.values : [];
10506    }
10507    */
10508
10509
10510   ChartInternal.prototype.barData = function (d) {
10511     return this.isBarType(d) ? d.values : [];
10512   };
10513
10514   ChartInternal.prototype.lineOrScatterData = function (d) {
10515     return this.isLineType(d) || this.isScatterType(d) ? d.values : [];
10516   };
10517
10518   ChartInternal.prototype.barOrLineData = function (d) {
10519     return this.isBarType(d) || this.isLineType(d) ? d.values : [];
10520   };
10521
10522   ChartInternal.prototype.isSafari = function () {
10523     var ua = window.navigator.userAgent;
10524     return ua.indexOf('Safari') >= 0 && ua.indexOf('Chrome') < 0;
10525   };
10526
10527   ChartInternal.prototype.isChrome = function () {
10528     var ua = window.navigator.userAgent;
10529     return ua.indexOf('Chrome') >= 0;
10530   };
10531
10532   ChartInternal.prototype.initZoom = function () {
10533     var $$ = this,
10534         d3 = $$.d3,
10535         config = $$.config,
10536         startEvent;
10537     $$.zoom = d3.zoom().on("start", function () {
10538       if (config.zoom_type !== 'scroll') {
10539         return;
10540       }
10541
10542       var e = d3.event.sourceEvent;
10543
10544       if (e && e.type === "brush") {
10545         return;
10546       }
10547
10548       startEvent = e;
10549       config.zoom_onzoomstart.call($$.api, e);
10550     }).on("zoom", function () {
10551       if (config.zoom_type !== 'scroll') {
10552         return;
10553       }
10554
10555       var e = d3.event.sourceEvent;
10556
10557       if (e && e.type === "brush") {
10558         return;
10559       }
10560
10561       $$.redrawForZoom();
10562       config.zoom_onzoom.call($$.api, $$.x.orgDomain());
10563     }).on('end', function () {
10564       if (config.zoom_type !== 'scroll') {
10565         return;
10566       }
10567
10568       var e = d3.event.sourceEvent;
10569
10570       if (e && e.type === "brush") {
10571         return;
10572       } // if click, do nothing. otherwise, click interaction will be canceled.
10573
10574
10575       if (e && startEvent.clientX === e.clientX && startEvent.clientY === e.clientY) {
10576         return;
10577       }
10578
10579       config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
10580     });
10581
10582     $$.zoom.updateDomain = function () {
10583       if (d3.event && d3.event.transform) {
10584         $$.x.domain(d3.event.transform.rescaleX($$.subX).domain());
10585       }
10586
10587       return this;
10588     };
10589
10590     $$.zoom.updateExtent = function () {
10591       this.scaleExtent([1, Infinity]).translateExtent([[0, 0], [$$.width, $$.height]]).extent([[0, 0], [$$.width, $$.height]]);
10592       return this;
10593     };
10594
10595     $$.zoom.update = function () {
10596       return this.updateExtent().updateDomain();
10597     };
10598
10599     return $$.zoom.updateExtent();
10600   };
10601
10602   ChartInternal.prototype.zoomTransform = function (range) {
10603     var $$ = this,
10604         s = [$$.x(range[0]), $$.x(range[1])];
10605     return $$.d3.zoomIdentity.scale($$.width / (s[1] - s[0])).translate(-s[0], 0);
10606   };
10607
10608   ChartInternal.prototype.initDragZoom = function () {
10609     var $$ = this;
10610     var d3 = $$.d3;
10611     var config = $$.config;
10612     var context = $$.context = $$.svg;
10613     var brushXPos = $$.margin.left + 20.5;
10614     var brushYPos = $$.margin.top + 0.5;
10615
10616     if (!(config.zoom_type === 'drag' && config.zoom_enabled)) {
10617       return;
10618     }
10619
10620     var getZoomedDomain = function getZoomedDomain(selection) {
10621       return selection && selection.map(function (x) {
10622         return $$.x.invert(x);
10623       });
10624     };
10625
10626     var brush = $$.dragZoomBrush = d3.brushX().on("start", function () {
10627       $$.api.unzoom();
10628       $$.svg.select("." + CLASS.dragZoom).classed("disabled", false);
10629       config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
10630     }).on("brush", function () {
10631       config.zoom_onzoom.call($$.api, getZoomedDomain(d3.event.selection));
10632     }).on("end", function () {
10633       if (d3.event.selection == null) {
10634         return;
10635       }
10636
10637       var zoomedDomain = getZoomedDomain(d3.event.selection);
10638
10639       if (!config.zoom_disableDefaultBehavior) {
10640         $$.api.zoom(zoomedDomain);
10641       }
10642
10643       $$.svg.select("." + CLASS.dragZoom).classed("disabled", true);
10644       config.zoom_onzoomend.call($$.api, zoomedDomain);
10645     });
10646     context.append("g").classed(CLASS.dragZoom, true).attr("clip-path", $$.clipPath).attr("transform", "translate(" + brushXPos + "," + brushYPos + ")").call(brush);
10647   };
10648
10649   ChartInternal.prototype.getZoomDomain = function () {
10650     var $$ = this,
10651         config = $$.config,
10652         d3 = $$.d3,
10653         min = d3.min([$$.orgXDomain[0], config.zoom_x_min]),
10654         max = d3.max([$$.orgXDomain[1], config.zoom_x_max]);
10655     return [min, max];
10656   };
10657
10658   ChartInternal.prototype.redrawForZoom = function () {
10659     var $$ = this,
10660         d3 = $$.d3,
10661         config = $$.config,
10662         zoom = $$.zoom,
10663         x = $$.x;
10664
10665     if (!config.zoom_enabled) {
10666       return;
10667     }
10668
10669     if ($$.filterTargetsToShow($$.data.targets).length === 0) {
10670       return;
10671     }
10672
10673     zoom.update();
10674
10675     if (config.zoom_disableDefaultBehavior) {
10676       return;
10677     }
10678
10679     if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
10680       x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
10681     }
10682
10683     $$.redraw({
10684       withTransition: false,
10685       withY: config.zoom_rescale,
10686       withSubchart: false,
10687       withEventRect: false,
10688       withDimension: false
10689     });
10690
10691     if (d3.event.sourceEvent && d3.event.sourceEvent.type === 'mousemove') {
10692       $$.cancelClick = true;
10693     }
10694   };
10695
10696   return c3;
10697
10698 })));