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