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