diff --git a/.gitignore b/.gitignore
index 501448a..6650258 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
 node_modules
 bower_components
 d3.js
-d3.min.js
\ No newline at end of file
+d3.min.js
+components
+build
diff --git a/Gruntfile.coffee b/Gruntfile.coffee
index 7d387bc..4ee8f3b 100644
--- a/Gruntfile.coffee
+++ b/Gruntfile.coffee
@@ -2,6 +2,77 @@ module.exports = (grunt) ->
     require('load-grunt-tasks') grunt, pattern: 'grunt-contrib-*'
 
     grunt.initConfig
+        watch:
+          concat:
+            tasks: 'concat'
+            files: ['src/*.js']
+
+        concat:
+          dist:
+            options:
+              process: (src, filepath) ->
+                if filepath != 'src/head.js' && filepath != 'src/tail.js'
+                  lines = []
+                  src.split('\n').forEach (line) ->
+                    lines.push( (if line.length > 0 then '    ' else '') + line)
+                  src = lines.join('\n')
+                return src
+            src: [
+              'src/head.js',
+              'src/core.js',
+              'src/config.js',
+              'src/scale.js',
+              'src/domain.js',
+              'src/data.js',
+              'src/data.convert.js',
+              'src/data.load.js',
+              'src/category.js',
+              'src/interaction.js',
+              'src/size.js',
+              'src/shape.js',
+              'src/shape.line.js',
+              'src/shape.bar.js',
+              'src/text.js',
+              'src/type.js',
+              'src/grid.js',
+              'src/tooltip.js',
+              'src/legend.js',
+              'src/axis.js',
+              'src/clip.js',
+              'src/arc.js',
+              'src/region.js',
+              'src/drag.js',
+              'src/selection.js',
+              'src/subchart.js',
+              'src/zoom.js',
+              'src/color.js',
+              'src/format.js',
+              'src/cache.js',
+              'src/class.js',
+              'src/util.js',
+              'src/api.focus.js',
+              'src/api.show.js',
+              'src/api.zoom.js',
+              'src/api.load.js',
+              'src/api.flow.js',
+              'src/api.selection.js',
+              'src/api.transform.js',
+              'src/api.group.js',
+              'src/api.grid.js',
+              'src/api.region.js',
+              'src/api.data.js',
+              'src/api.category.js',
+              'src/api.color.js',
+              'src/api.x.js',
+              'src/api.axis.js',
+              'src/api.legend.js',
+              'src/api.chart.js',
+              'src/api.tooltip.js',
+              'src/c3.axis.js',
+              'src/tail.js'
+            ]
+            dest: 'c3.js'
+
         jshint:
           c3: 'c3.js'
           spec: 'spec/*.js'
@@ -12,11 +83,19 @@ module.exports = (grunt) ->
           c3:
             src: 'c3.js'
             options:
-              specs: 'spec/*.js'
+              specs: 'spec/*-spec.js'
+              helpers: 'spec/*-helper.js'
+              styles: 'c3.css'
+              vendor: 'http://d3js.org/d3.v3.min.js'
 
         uglify:
           c3:
             files:
               'c3.min.js': 'c3.js'
 
-    grunt.registerTask 'default', ['jshint', 'jasmine', 'uglify']
+        cssmin:
+          c3:
+            src: 'c3.css'
+            dest: 'c3.min.css'
+
+    grunt.registerTask 'default', ['concat', 'jshint', 'jasmine', 'cssmin', 'uglify']
diff --git a/README.md b/README.md
index 8e5dc33..a1b207a 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,48 @@
-c3 [![Build Status](https://travis-ci.org/masayuki0812/c3.png?branch=master)](https://travis-ci.org/masayuki0812/c3)
+c3 [![Build Status](https://travis-ci.org/masayuki0812/c3.svg?branch=master)](https://travis-ci.org/masayuki0812/c3)
 ==
 
-c3 is a D3-based chart library that allows you to integrate charts into web applications more deeply.
+c3 is a D3-based reusable chart library that enables deeper integration of charts into web applications.
 
-More information in [the wiki](https://github.com/masayuki0812/c3/wiki).
+Follow the link for more information: [http://c3js.org](http://c3js.org/)
 
-Samples in [c3js.org](http://c3js.org/#basic)
+## Tutorial and Examples
+
++ [Getting Started](http://c3js.org/gettingstarted.html)
++ [Examples](http://c3js.org/examples.html)
+
+Additional samples can be found in this repository:
++ [https://github.com/masayuki0812/c3/tree/master/htdocs/samples](https://github.com/masayuki0812/c3/tree/master/htdocs/samples)
+
+You can run these samples as:
+```
+$ cd c3/htdocs
+$ python -m SimpleHTTPServer 8080
+```
+
+## Google Group
+For general C3.js-related discussion, please visit our [Google Group at https://groups.google.com/forum/#!forum/c3js](https://groups.google.com/forum/#!forum/c3js).
+
+## Using the issue queue
+The [issue queue](https://github.com/masayuki0812/c3/issues) is to be used for reporting defects and problems with C3.js, in addition to feature requests and ideas. It is **not** a catch-all support forum. **For general support enquiries, please use the [Google Group](https://groups.google.com/forum/#!forum/c3js) at https://groups.google.com/forum/#!forum/c3js.** All questions involving the interplay between C3.js and any other library (such as AngularJS) should be posted there first!
+
+Before reporting an issue, please do the following:
+1. [Search for existing issues](https://github.com/masayuki0812/c3/issues) to ensure you're not posting a duplicate.
+
+1.  [Search the Google Group](https://groups.google.com/forum/#!forum/c3js) to ensure it hasn't been addressed there already.
+
+1. Create a JSFiddle or Plunkr highlighting the issue. Please don't include any unnecessary dependencies so we can isolate that the issue is in fact with C3. *Please be advised that custom CSS can modify C3.js output!*
+
+1. When posting the issue, please use a descriptive title and include the version of C3 (or, if cloning from Git, the commit hash — C3 is under active development and the master branch contains the latest dev commits!), along with any platform/browser/OS information that may be relevant.
+
+## Pull requests
+Pull requests are welcome, though please post an issue first to see whether such a change is desirable.
+If you choose to submit a pull request, please do not bump the version number unless asked to, and please include test cases for any new features!
+
+## Playground
+Please fork this fiddle:
++ [http://jsfiddle.net/masayuki0812/7kYJu/](http://jsfiddle.net/masayuki0812/7kYJu/)
+
+## License
+MIT
+
+[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=masayuki0812&url=https://github.com/masayuki0812/c3&title=c3&language=javascript&tags=github&category=software)
diff --git a/bower.json b/bower.json
index f500698..775888b 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,10 @@
 {
   "name": "c3",
-  "main": "c3.min.js",
-  "version": "0.1.34",
+  "main": [
+    "c3.css",
+    "c3.js"
+  ],
+  "version": "0.4.6",
   "homepage": "https://github.com/masayuki0812/c3",
   "authors": [
     "Masayuki Tanaka <masayuki0812@mac.com>"
diff --git a/c3.css b/c3.css
index 737e783..4250778 100644
--- a/c3.css
+++ b/c3.css
@@ -13,6 +13,14 @@
           user-select: none;
 }
 
+.c3-legend-item-tile,
+.c3-xgrid-focus,
+.c3-ygrid,
+.c3-event-rect,
+.c3-bars path {
+  shape-rendering: crispEdges;
+}
+
 .c3-chart-arc path {
   stroke: #fff;
 
@@ -58,6 +66,11 @@
 .c3-text {
 }
 
+.c3-text.c3-empty {
+  fill: #808080;
+  font-size: 2em;
+}
+
 /*-- Line --*/
 
 .c3-line {
@@ -76,6 +89,9 @@
 
 /*-- Bar --*/
 
+.c3-bar {
+  stroke-width: 0;
+}
 .c3-bar._expanded_ {
   fill-opacity: 0.75;
 }
@@ -88,9 +104,16 @@
 
 /*-- Focus --*/
 
-.c3-target.c3-focused path.c3-line {
+.c3-target.c3-focused {
+  opacity: 1;
+}
+.c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step {
   stroke-width: 2px;
 }
+.c3-target.c3-defocused {
+  opacity: 0.3 !important;
+}
+
 
 /*-- Region --*/
 
@@ -115,9 +138,22 @@
 .c3-legend-item {
   font-size: 12px;
 }
+.c3-legend-item-hidden {
+  opacity: 0.15;
+}
+
+.c3-legend-background {
+  opacity: 0.75;
+  fill: white;
+  stroke: lightgray;
+  stroke-width: 1
+}
 
 /*-- Tooltip --*/
 
+.c3-tooltip-container {
+  z-index: 10;
+}
 .c3-tooltip {
   border-collapse:collapse;
   border-spacing:0;
@@ -158,3 +194,23 @@
   stroke-width: 0;
   opacity: 0.2;
 }
+
+.c3-chart-arcs .c3-chart-arcs-background {
+  fill: #e0e0e0;
+  stroke: none;
+}
+.c3-chart-arcs .c3-chart-arcs-gauge-unit {
+  fill: #000;
+  font-size: 16px;
+}
+.c3-chart-arcs .c3-chart-arcs-gauge-max {
+  fill: #777;
+}
+.c3-chart-arcs .c3-chart-arcs-gauge-min {
+  fill: #777;
+}
+
+.c3-chart-arc .c3-gauge-value {
+  fill: #000;
+/*  font-size: 28px !important;*/
+}
diff --git a/c3.js b/c3.js
index 21bba66..69fa1b8 100644
--- a/c3.js
+++ b/c3.js
@@ -1,4620 +1,6763 @@
 (function (window) {
     'use strict';
 
-    var c3 = {
-        version: "0.1.34"
-    };
-
-    var CLASS = {
-        target: 'c3-target',
-        chart : 'c3-chart',
-        chartLine: 'c3-chart-line',
-        chartLines: 'c3-chart-lines',
-        chartBar: 'c3-chart-bar',
-        chartBars: 'c3-chart-bars',
-        chartText: 'c3-chart-text',
-        chartTexts: 'c3-chart-texts',
-        chartArc: 'c3-chart-arc',
-        chartArcs: 'c3-chart-arcs',
-        chartArcsTitle: 'c3-chart-arcs-title',
-        selectedCircle: 'c3-selected-circle',
-        selectedCircles: 'c3-selected-circles',
-        eventRect: 'c3-event-rect',
-        eventRects: 'c3-event-rects',
-        eventRectsSingle: 'c3-event-rects-single',
-        eventRectsMultiple: 'c3-event-rects-multiple',
-        zoomRect: 'c3-zoom-rect',
-        brush: 'c3-brush',
-        focused: 'c3-focused',
-        region: 'c3-region',
-        regions: 'c3-regions',
-        tooltip: 'c3-tooltip',
-        tooltipName: 'c3-tooltip-name',
-        shape: 'c3-shape',
-        shapes: 'c3-shapes',
-        line: 'c3-line',
-        lines: 'c3-lines',
-        bar: 'c3-bar',
-        bars: 'c3-bars',
-        circle: 'c3-circle',
-        circles: 'c3-circles',
-        arc: 'c3-arc',
-        arcs: 'c3-arcs',
-        area: 'c3-area',
-        areas: 'c3-areas',
-        text: 'c3-text',
-        texts: 'c3-texts',
-        grid: 'c3-grid',
-        xgrid: 'c3-xgrid',
-        xgrids: 'c3-xgrids',
-        xgridLine: 'c3-xgrid-line',
-        xgridLines: 'c3-xgrid-lines',
-        xgridFocus: 'c3-xgrid-focus',
-        ygrid: 'c3-ygrid',
-        ygrids: 'c3-ygrids',
-        ygridLine: 'c3-ygrid-line',
-        ygridLines: 'c3-ygrid-lines',
-        axisX: 'c3-axis-x',
-        axisXLabel: 'c3-axis-x-label',
-        axisY: 'c3-axis-y',
-        axisYLabel: 'c3-axis-y-label',
-        axisY2: 'c3-axis-y2',
-        axisY2Label: 'c3-axis-y2-label',
-        legendItem: 'c3-legend-item',
-        legendItemEvent: 'c3-legend-item-event',
-        legendItemTile: 'c3-legend-item-tile',
-        legendItemHidden: 'c3-legend-item-hidden',
-        legendItemFocused: 'c3-legend-item-focused',
-        dragarea: 'c3-dragarea',
-        EXPANDED: '_expanded_',
-        SELECTED: '_selected_',
-        INCLUDED: '_included_',
-    };
+    /*global define, module, exports, require */
 
-    /*
-     * Generate chart according to config
-     */
-    c3.generate = function (config) {
-
-        var d3 = window.d3 ? window.d3 : window.require ? window.require("d3") : undefined;
-
-        var c3 = { data : {}, axis: {}, legend: {} },
-            cache = {};
+    var c3 = { version: "0.4.6" };
 
-        /*-- Handle Config --*/
+    var c3_chart_fn, c3_chart_internal_fn;
 
-        function checkConfig(key, message) {
-            if (! (key in config)) { throw Error(message); }
-        }
+    function Chart(config) {
+        var $$ = this.internal = new ChartInternal(this);
+        $$.loadConfig(config);
+        $$.init();
 
-        function getConfig(keys, defaultValue) {
-            var target = config, i, isLast, nextTarget;
-            for (i = 0; i < keys.length; i++) {
-                // return default if key not found
-                if (typeof target === 'object' && !(keys[i] in target)) { return defaultValue; }
-                // Check next key's value
-                isLast = (i === keys.length - 1);
-                nextTarget = target[keys[i]];
-                if (!isLast && typeof nextTarget !== 'object') {
-                    return defaultValue;
+        // bind "this" to nested API
+        (function bindThis(fn, target, argThis) {
+            Object.keys(fn).forEach(function (key) {
+                target[key] = fn[key].bind(argThis);
+                if (Object.keys(fn[key]).length > 0) {
+                    bindThis(fn[key], target[key], argThis);
                 }
-                target = nextTarget;
-            }
-            return target;
-        }
-
-        // bindto - id to bind the chart
-        var __bindto = getConfig(['bindto'], '#chart');
-
-        var __size_width = getConfig(['size', 'width']),
-            __size_height = getConfig(['size', 'height']);
-
-        var __padding_left = getConfig(['padding', 'left'], 50),
-            __padding_right = getConfig(['padding', 'right']);
-
-        var __zoom_enabled = getConfig(['zoom', 'enabled'], false),
-            __zoom_extent = getConfig(['zoom', 'extent']),
-            __zoom_privileged = getConfig(['zoom', 'privileged'], false);
-
-        var __onenter = getConfig(['onenter'], function () {}),
-            __onleave = getConfig(['onleave'], function () {}),
-            __onresize = getConfig(['onresize'], function () {}),
-            __onresized = getConfig(['onresized'], function () {});
-
-        var __transition_duration = getConfig(['transition', 'duration'], 350);
-
-        // data - data configuration
-        checkConfig('data', 'data is required in config');
-
-        var __data_x = getConfig(['data', 'x']),
-            __data_xs = getConfig(['data', 'xs'], {}),
-            __data_x_format = getConfig(['data', 'x_format']),
-            __data_id_converter = getConfig(['data', 'id_converter'], function (id) { return id; }),
-            __data_names = getConfig(['data', 'names'], {}),
-            __data_classes = getConfig(['data', 'classes'], {}),
-            __data_groups = getConfig(['data', 'groups'], []),
-            __data_axes = getConfig(['data', 'axes'], {}),
-            __data_type = getConfig(['data', 'type']),
-            __data_types = getConfig(['data', 'types'], {}),
-            __data_labels = getConfig(['data', 'labels'], {}),
-            __data_order = getConfig(['data', 'order']),
-            __data_regions = getConfig(['data', 'regions'], {}),
-            __data_color = getConfig(['data', 'color']),
-            __data_colors = getConfig(['data', 'colors'], {}),
-            __data_hide = getConfig(['data', 'hide'], false),
-            __data_selection_enabled = getConfig(['data', 'selection', 'enabled'], false),
-            __data_selection_grouped = getConfig(['data', 'selection', 'grouped'], false),
-            __data_selection_isselectable = getConfig(['data', 'selection', 'isselectable'], function () { return true; }),
-            __data_selection_multiple = getConfig(['data', 'selection', 'multiple'], true),
-            __data_onclick = getConfig(['data', 'onclick'], function () {}),
-            __data_onenter = getConfig(['data', 'onenter'], function () {}),
-            __data_onleave = getConfig(['data', 'onleave'], function () {}),
-            __data_onselected = getConfig(['data', 'onselected'], function () {}),
-            __data_onunselected = getConfig(['data', 'onunselected'], function () {}),
-            __data_ondragstart = getConfig(['data', 'ondragstart'], function () {}),
-            __data_ondragend = getConfig(['data', 'ondragend'], function () {});
+            });
+        })(c3_chart_fn, this, this);
+    }
 
-        // subchart
-        var __subchart_show = getConfig(['subchart', 'show'], false),
-            __subchart_size_height = getConfig(['subchart', 'size', 'height'], 60);
-
-        // color
-        var __color_pattern = getConfig(['color', 'pattern'], []);
-
-        // legend
-        var __legend_show = getConfig(['legend', 'show'], true),
-            __legend_position = getConfig(['legend', 'position'], 'bottom'),
-            __legend_item_onclick = getConfig(['legend', 'item', 'onclick']),
-            __legend_item_onmouseover = getConfig(['legend', 'item', 'onmouseover']),
-            __legend_item_onmouseout = getConfig(['legend', 'item', 'onmouseout']),
-            __legend_equally = getConfig(['legend', 'equally'], false);
-
-        // axis
-        var __axis_rotated = getConfig(['axis', 'rotated'], false),
-            __axis_x_show = getConfig(['axis', 'x', 'show'], true),
-            __axis_x_type = getConfig(['axis', 'x', 'type'], 'indexed'),
-            __axis_x_localtime = getConfig(['axis', 'x', 'localtime'], true),
-            __axis_x_categories = getConfig(['axis', 'x', 'categories'], []),
-            __axis_x_tick_centered = getConfig(['axis', 'x', 'tick', 'centered'], false),
-            __axis_x_tick_format = getConfig(['axis', 'x', 'tick', 'format']),
-            __axis_x_tick_culling = getConfig(['axis', 'x', 'tick', 'culling'], {}),
-            __axis_x_tick_culling_max = getConfig(['axis', 'x', 'tick', 'culling', 'max'], 10),
-            __axis_x_tick_count = getConfig(['axis', 'x', 'tick', 'count']),
-            __axis_x_tick_fit = getConfig(['axis', 'x', 'tick', 'fit'], true),
-            __axis_x_tick_values = getConfig(['axis', 'x', 'tick', 'values'], null),
-            __axis_x_tick_rotate = getConfig(['axis', 'x', 'tick', 'rotate']),
-            __axis_x_max = getConfig(['axis', 'x', 'max'], null),
-            __axis_x_min = getConfig(['axis', 'x', 'min'], null),
-            __axis_x_padding = getConfig(['axis', 'x', 'padding'], {}),
-            __axis_x_height = getConfig(['axis', 'x', 'height']),
-            __axis_x_default = getConfig(['axis', 'x', 'default']),
-            __axis_x_label = getConfig(['axis', 'x', 'label'], {}),
-            __axis_y_show = getConfig(['axis', 'y', 'show'], true),
-            __axis_y_max = getConfig(['axis', 'y', 'max']),
-            __axis_y_min = getConfig(['axis', 'y', 'min']),
-            __axis_y_center = getConfig(['axis', 'y', 'center']),
-            __axis_y_label = getConfig(['axis', 'y', 'label'], {}),
-            __axis_y_inner = getConfig(['axis', 'y', 'inner'], false),
-            __axis_y_tick_format = getConfig(['axis', 'y', 'tick', 'format']),
-            __axis_y_padding = getConfig(['axis', 'y', 'padding']),
-            __axis_y_ticks = getConfig(['axis', 'y', 'ticks'], 10),
-            __axis_y2_show = getConfig(['axis', 'y2', 'show'], false),
-            __axis_y2_max = getConfig(['axis', 'y2', 'max']),
-            __axis_y2_min = getConfig(['axis', 'y2', 'min']),
-            __axis_y2_center = getConfig(['axis', 'y2', 'center']),
-            __axis_y2_label = getConfig(['axis', 'y2', 'label'], {}),
-            __axis_y2_inner = getConfig(['axis', 'y2', 'inner'], false),
-            __axis_y2_tick_format = getConfig(['axis', 'y2', 'tick', 'format']),
-            __axis_y2_padding = getConfig(['axis', 'y2', 'padding']),
-            __axis_y2_ticks = getConfig(['axis', 'y2', 'ticks'], 10);
+    function ChartInternal(api) {
+        var $$ = this;
+        $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
+        $$.api = api;
+        $$.config = $$.getDefaultConfig();
+        $$.data = {};
+        $$.cache = {};
+        $$.axes = {};
+    }
 
-        // grid
-        var __grid_x_show = getConfig(['grid', 'x', 'show'], false),
-            __grid_x_type = getConfig(['grid', 'x', 'type'], 'tick'),
-            __grid_x_lines = getConfig(['grid', 'x', 'lines'], []),
-            __grid_y_show = getConfig(['grid', 'y', 'show'], false),
-            // not used
-            // __grid_y_type = getConfig(['grid', 'y', 'type'], 'tick'),
-            __grid_y_lines = getConfig(['grid', 'y', 'lines'], []),
-            __grid_y_ticks = getConfig(['grid', 'y', 'ticks'], 10);
-
-        // point - point of each data
-        var __point_show = getConfig(['point', 'show'], true),
-            __point_r = getConfig(['point', 'r'], 2.5),
-            __point_focus_line_enabled = getConfig(['point', 'focus', 'line', 'enabled'], true),
-            __point_focus_expand_enabled = getConfig(['point', 'focus', 'expand', 'enabled'], true),
-            __point_focus_expand_r = getConfig(['point', 'focus', 'expand', 'r']),
-            __point_select_r = getConfig(['point', 'focus', 'select', 'r']);
-
-        var __line_connect_null = getConfig(['line', 'connect_null'], false);
-
-        // bar
-        var __bar_width = getConfig(['bar', 'width']),
-            __bar_width_ratio = getConfig(['bar', 'width', 'ratio'], 0.6);
-
-        // pie
-        var __pie_label_show = getConfig(['pie', 'label', 'show'], true),
-            __pie_label_format = getConfig(['pie', 'label', 'format']),
-            __pie_expand = getConfig(['pie', 'expand'], true),
-            __pie_onclick = getConfig(['pie', 'onclick'], function () {}),
-            __pie_onmouseover = getConfig(['pie', 'onmouseover'], function () {}),
-            __pie_onmouseout = getConfig(['pie', 'onmouseout'], function () {});
-
-        // donut
-        var __donut_label_show = getConfig(['donut', 'label', 'show'], true),
-            __donut_label_format = getConfig(['donut', 'label', 'format']),
-            __donut_expand = getConfig(['donut', 'expand'], true),
-            __donut_title = getConfig(['donut', 'title'], ""),
-            __donut_onclick = getConfig(['donut', 'onclick'], function () {}),
-            __donut_onmouseover = getConfig(['donut', 'onmouseover'], function () {}),
-            __donut_onmouseout = getConfig(['donut', 'onmouseout'], function () {});
-
-        // region - region to change style
-        var __regions = getConfig(['regions'], []);
-
-        // tooltip - show when mouseover on each data
-        var __tooltip_show = getConfig(['tooltip', 'show'], true),
-            __tooltip_format_title = getConfig(['tooltip', 'format', 'title']),
-            __tooltip_format_value = getConfig(['tooltip', 'format', 'value']),
-            __tooltip_contents = getConfig(['tooltip', 'contents'], function (d, defaultTitleFormat, defaultValueFormat, color) {
-            var titleFormat = __tooltip_format_title ? __tooltip_format_title : defaultTitleFormat,
-                valueFormat = __tooltip_format_value ? __tooltip_format_value : defaultValueFormat,
-                text, i, title, value, name;
-            for (i = 0; i < d.length; i++) {
-                if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
-
-                if (! text) {
-                    title = titleFormat ? titleFormat(d[i].x) : d[i].x;
-                    text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
-                }
+    c3.generate = function (config) {
+        return new Chart(config);
+    };
 
-                name = d[i].name;
-                value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
+    c3.chart = {
+        fn: Chart.prototype,
+        internal: {
+            fn: ChartInternal.prototype
+        }
+    };
+    c3_chart_fn = c3.chart.fn;
+    c3_chart_internal_fn = c3.chart.internal.fn;
 
-                text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
-                text += "<td class='name'><span style='background-color:" + color(d[i].id) + "'></span>" + name + "</td>";
-                text += "<td class='value'>" + value + "</td>";
-                text += "</tr>";
-            }
-            return text + "</table>";
-        }),
-            __tooltip_init_show = getConfig(['tooltip', 'init', 'show'], false),
-            __tooltip_init_x = getConfig(['tooltip', 'init', 'x'], 0),
-            __tooltip_init_position = getConfig(['tooltip', 'init', 'position'], {top: '0px', left: '50px'});
-
-        /*-- Set Variables --*/
-
-        var clipId = (typeof __bindto === "string" ? __bindto.replace('#', '') : __bindto.id)  + '-clip',
-            clipIdForXAxis = clipId + '-xaxis',
-            clipIdForYAxis = clipId + '-yaxis',
-            clipPath = getClipPath(clipId),
-            clipPathForXAxis = getClipPath(clipIdForXAxis),
-            clipPathForYAxis = getClipPath(clipIdForYAxis);
-
-        var isTimeSeries = (__axis_x_type === 'timeseries'),
-            isCategorized = (__axis_x_type === 'categorized'),
-            isCustomX = !isTimeSeries && (__data_x || notEmpty(__data_xs));
-
-        var dragStart = null, dragging = false, cancelClick = false, mouseover = false, transiting = false;
-
-        var defaultColorPattern = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'], //same as d3.scale.category10()
-            color = generateColor(__data_colors, notEmpty(__color_pattern) ? __color_pattern : defaultColorPattern, __data_color);
-
-        var xTimeFormat = __axis_x_localtime ? d3.time.format : d3.time.format.utc,
-            defaultTimeFormat = (function () {
-            var formats = [
-                [xTimeFormat("%Y/%-m/%-d"), function () { return true; }],
-                [xTimeFormat("%-m/%-d"), function (d) { return d.getMonth(); }],
-                [xTimeFormat("%-m/%-d"), function (d) { return d.getDate() !== 1; }],
-                [xTimeFormat("%-m/%-d"), function (d) { return d.getDay() && d.getDate() !== 1; }],
-                [xTimeFormat("%I %p"), function (d) { return d.getHours(); }],
-                [xTimeFormat("%I:%M"), function (d) { return d.getMinutes(); }],
-                [xTimeFormat(":%S"), function (d) { return d.getSeconds(); }],
-                [xTimeFormat(".%L"), function (d) { return d.getMilliseconds(); }]
-            ];
-            return function (date) {
-                var i = formats.length - 1, f = formats[i];
-                while (!f[1](date)) { f = formats[--i]; }
-                return f[0](date);
-            };
-        })();
-
-        var hiddenTargetIds = [], hiddenLegendIds = [];
-
-        /*-- Set Chart Params --*/
-
-        var margin, margin2, margin3, width, width2, height, height2, currentWidth, currentHeight;
-        var radius, radiusExpanded, innerRadius, svgArc, svgArcExpanded, svgArcExpandedSub, pie;
-        var xMin, xMax, yMin, yMax, subXMin, subXMax, subYMin, subYMax;
-        var x, y, y2, subX, subY, subY2, xAxis, yAxis, y2Axis, subXAxis;
-
-        var xOrient = __axis_rotated ? "left" : "bottom",
-            yOrient = __axis_rotated ? (__axis_y_inner ? "top" : "bottom") : (__axis_y_inner ? "right" : "left"),
-            y2Orient = __axis_rotated ? (__axis_y2_inner ? "bottom" : "top") : (__axis_y2_inner ? "left" : "right"),
-            subXOrient = __axis_rotated ? "left" : "bottom";
-
-        var translate = {
-            main : function () { return "translate(" + margin.left + "," + margin.top + ")"; },
-            context : function () { return "translate(" + margin2.left + "," + margin2.top + ")"; },
-            legend : function () { return "translate(" + margin3.left + "," + margin3.top + ")"; },
-            x : function () {
-              if (__legend_show === true) {
-                return "translate(0," + (__axis_rotated ? 0 : height) + ")";
-              }
-              return "translate(0," + (__axis_rotated ? 0 : height + margin3.top) + ")";
-            },
-            y : function () { return "translate(0," + (__axis_rotated ? height : 0) + ")"; },
-            y2 : function () { return "translate(" + (__axis_rotated ? 0 : width) + "," + (__axis_rotated ? 1 : 0) + ")"; },
-            subx : function () { return "translate(0," + (__axis_rotated ? 0 : height2) + ")"; },
-            arc: function () { return "translate(" + width / 2 + "," + height / 2 + ")"; }
-        };
 
-        var isLegendRight = __legend_position === 'right';
-        var legendStep = 0, legendItemWidth = 0, legendItemHeight = 0, legendOpacityForHidden = 0.15;
+    c3_chart_internal_fn.init = function () {
+        var $$ = this, config = $$.config;
 
-        /*-- Define Functions --*/
+        $$.initParams();
 
-        function getClipPath(id) {
-            return "url(" + document.URL.split('#')[0] + "#" + id + ")";
+        if (config.data_url) {
+            $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_keys, $$.initWithData);
         }
-
-        function transformMain(withTransition, transitions) {
-            var xAxis, yAxis, y2Axis;
-            if (transitions && transitions.axisX) {
-                xAxis = transitions.axisX;
-            } else {
-                xAxis  = main.select('.' + CLASS.axisX);
-                if (withTransition) { xAxis = xAxis.transition(); }
-            }
-            if (transitions && transitions.axisY) {
-                yAxis = transitions.axisY;
-            } else {
-                yAxis = main.select('.' + CLASS.axisY);
-                if (withTransition) { yAxis = yAxis.transition(); }
-            }
-            if (transitions && transitions.axisY2) {
-                y2Axis = transitions.axisY2;
-            } else {
-                y2Axis = main.select('.' + CLASS.axisY2);
-                if (withTransition) { y2Axis = y2Axis.transition(); }
-            }
-            main.attr("transform", translate.main);
-            xAxis.attr("transform", translate.x);
-            yAxis.attr("transform", translate.y);
-            y2Axis.attr("transform", translate.y2);
-            main.select('.' + CLASS.chartArcs).attr("transform", translate.arc);
-        }
-        function transformContext(withTransition, transitions) {
-            var subXAxis;
-            if (transitions && transitions.axisSubX) {
-                subXAxis = transitions.axisSubX;
-            } else {
-                subXAxis = context.select('.' + CLASS.axisX);
-                if (withTransition) { subXAxis = subXAxis.transition(); }
-            }
-            context.attr("transform", translate.context);
-            subXAxis.attr("transform", translate.subx);
+        else if (config.data_json) {
+            $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
+        }
+        else if (config.data_rows) {
+            $$.initWithData($$.convertRowsToData(config.data_rows));
         }
-        function transformLegend(withTransition) {
-            (withTransition ? legend.transition() : legend).attr("transform", translate.legend);
+        else if (config.data_columns) {
+            $$.initWithData($$.convertColumnsToData(config.data_columns));
         }
-        function transformAll(withTransition, transitions) {
-            transformMain(withTransition, transitions);
-            if (__subchart_show) { transformContext(withTransition, transitions); }
-            transformLegend(withTransition);
+        else {
+            throw Error('url or json or rows or columns is required.');
         }
+    };
 
-        //-- Sizes --//
+    c3_chart_internal_fn.initParams = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+
+        // MEMO: clipId needs to be unique because it conflicts when multiple charts exist
+        $$.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);
+        $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid),
+        $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart),
+
+        $$.dragStart = null;
+        $$.dragging = false;
+        $$.flowing = false;
+        $$.cancelClick = false;
+        $$.mouseover = false;
+        $$.transiting = false;
+
+        $$.color = $$.generateColor();
+        $$.levelColor = $$.generateLevelColor();
+
+        $$.dataTimeFormat = config.data_xLocaltime ? d3.time.format : d3.time.format.utc;
+        $$.axisTimeFormat = config.axis_x_localtime ? d3.time.format : d3.time.format.utc;
+        $$.defaultAxisTimeFormat = $$.axisTimeFormat.multi([
+            [".%L", function (d) { return d.getMilliseconds(); }],
+            [":%S", function (d) { return d.getSeconds(); }],
+            ["%I:%M", function (d) { return d.getMinutes(); }],
+            ["%I %p", function (d) { return d.getHours(); }],
+            ["%-m/%-d", function (d) { return d.getDay() && d.getDate() !== 1; }],
+            ["%-m/%-d", function (d) { return d.getDate() !== 1; }],
+            ["%-m/%-d", function (d) { return d.getMonth(); }],
+            ["%Y/%-m/%-d", function () { return true; }]
+        ]);
+
+        $$.hiddenTargetIds = [];
+        $$.hiddenLegendIds = [];
+        $$.focusedTargetIds = [];
+        $$.defocusedTargetIds = [];
+
+        $$.xOrient = config.axis_rotated ? "left" : "bottom";
+        $$.yOrient = config.axis_rotated ? (config.axis_y_inner ? "top" : "bottom") : (config.axis_y_inner ? "right" : "left");
+        $$.y2Orient = config.axis_rotated ? (config.axis_y_inner ? "bottom" : "top") : (config.axis_y_inner ? "left" : "right");
+        $$.subXOrient = config.axis_rotated ? "left" : "bottom";
+
+        $$.isLegendRight = config.legend_position === 'right';
+        $$.isLegendInset = config.legend_position === 'inset';
+        $$.isLegendTop = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'top-right';
+        $$.isLegendLeft = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'bottom-left';
+        $$.legendStep = 0;
+        $$.legendItemWidth = 0;
+        $$.legendItemHeight = 0;
+
+        $$.currentMaxTickWidths = {
+            x: 0,
+            y: 0,
+            y2: 0
+        };
 
-        // TODO: configurabale
-        var rotated_padding_left = 30, rotated_padding_right = __axis_rotated && !__axis_x_show ? 0 : 30, rotated_padding_top = 5;
+        $$.rotated_padding_left = 30;
+        $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
+        $$.rotated_padding_top = 5;
 
-        function updateSizes() {
-            var legendHeight = getLegendHeight(), legendWidth = getLegendWidth(),
-                legendHeightForBottom = isLegendRight ? 0 : legendHeight,
-                xAxisHeight = __axis_rotated ? 0 : getHorizontalAxisHeight('x'),
-                subchartHeight = __subchart_show ? (__subchart_size_height + xAxisHeight) : 0;
+        $$.withoutFadeIn = {};
 
-            currentWidth = getCurrentWidth();
-            currentHeight = getCurrentHeight();
+        $$.intervalForObserveInserted = undefined;
 
-            // for main, context
-            if (__axis_rotated) {
-                margin = {
-                    top: getHorizontalAxisHeight('y2'),
-                    right: getCurrentPaddingRight(),
-                    bottom: getHorizontalAxisHeight('y') + legendHeightForBottom,
-                    left: subchartHeight + getCurrentPaddingLeft()
-                };
-                margin2 = {
-                    top: margin.top,
-                    right: NaN,
-                    bottom: 20 + legendHeightForBottom,
-                    left: rotated_padding_left
-                };
-            } else {
-                margin = {
-                    top: 4, // for top tick text
-                    right: getCurrentPaddingRight(),
-                    bottom: xAxisHeight + subchartHeight + legendHeightForBottom,
-                    left: getCurrentPaddingLeft()
-                };
-                margin2 = {
-                    top: currentHeight - subchartHeight - legendHeightForBottom,
-                    right: NaN,
-                    bottom: xAxisHeight + legendHeightForBottom,
-                    left: margin.left
-                };
-            }
-            // for legend
-            margin3 = {
-                top: isLegendRight ? 0 : currentHeight - legendHeight,
-                right: NaN,
-                bottom: 0,
-                left: isLegendRight ? currentWidth - legendWidth : 0
-            };
+        $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
+    };
 
-            width = currentWidth - margin.left - margin.right;
-            height = currentHeight - margin.top - margin.bottom;
-            if (width < 0) { width = 0; }
-            if (height < 0) { height = 0; }
+    c3_chart_internal_fn.initChartElements = function () {
+        if (this.initBar) { this.initBar(); }
+        if (this.initLine) { this.initLine(); }
+        if (this.initArc) { this.initArc(); }
+        if (this.initGauge) { this.initGauge(); }
+        if (this.initText) { this.initText(); }
+    };
 
-            width2 = __axis_rotated ? margin.left - rotated_padding_left - rotated_padding_right : width;
-            height2 = __axis_rotated ? height : currentHeight - margin2.top - margin2.bottom;
-            if (width2 < 0) { width2 = 0; }
-            if (height2 < 0) { height2 = 0; }
+    c3_chart_internal_fn.initWithData = function (data) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        var defs, main, binding = true;
 
-            // for arc
-            updateRadius();
+        if ($$.initPie) { $$.initPie(); }
+        if ($$.initBrush) { $$.initBrush(); }
+        if ($$.initZoom) { $$.initZoom(); }
 
-            if (isLegendRight && hasArcType(c3.data.targets)) {
-                margin3.left = width / 2 + radiusExpanded;
-            }
-        }
-        function updateXgridFocus() {
-            main.select('line.' + CLASS.xgridFocus)
-                .attr("x1", __axis_rotated ? 0 : -10)
-                .attr("x2", __axis_rotated ? width : -10)
-                .attr("y1", __axis_rotated ? -10 : margin.top)
-                .attr("y2", __axis_rotated ? -10 : height);
-        }
-        function updateRadius() {
-            radiusExpanded = height / 2;
-            radius = radiusExpanded * 0.95;
-            innerRadius = hasDonutType(c3.data.targets) ? radius * 0.6 : 0;
-        }
-        function getSvgLeft() {
-            var leftAxisClass = __axis_rotated ? CLASS.axisX : CLASS.axisY,
-                leftAxis = main.select('.' + leftAxisClass).node(),
-                svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
-                chartRect = d3.select(__bindto).node().getBoundingClientRect(),
-                svgLeft = svgRect.right - chartRect.left - getCurrentPaddingLeft();
-            return svgLeft > 0 ? svgLeft : 0;
-        }
-        function getCurrentWidth() {
-            var result = __size_width ? __size_width : getParentWidth();
-            if (isNaN(result)) {
-                return 0;
-            }
-            return result;
-        }
-        function getCurrentHeight() {
-            var h = __size_height ? __size_height : getParentHeight();
-            return h > 0 ? h : 320;
-        }
-        function getCurrentPaddingLeft() {
-            if (hasArcType(c3.data.targets)) {
-                return 0;
-            } else if (__padding_left) {
-                return __padding_left;
-            } else if (__axis_rotated) {
-                return !__axis_x_show ? 1 : getAxisWidthByAxisId('x');
-            } else {
-                return !__axis_y_show || __axis_y_inner ? 1 : getAxisWidthByAxisId('y');
-            }
-        }
-        function getCurrentPaddingRight() {
-            var defaultPadding = 1;
-            if (hasArcType(c3.data.targets)) {
-                return 0;
-            } else if (__padding_right) {
-                return __padding_right;
-            } else if (isLegendRight) {
-                return getLegendWidth() + (__axis_y2_show && !__axis_rotated ? getAxisWidthByAxisId('y2') : defaultPadding);
-            } else if (__axis_y2_show) {
-                return __axis_y2_inner || __axis_rotated ? defaultPadding : getAxisWidthByAxisId('y2');
-            } else {
-                return defaultPadding;
-            }
-        }
-        function getAxisWidthByAxisId(id) {
-            var position = getAxisLabelPositionById(id);
-            return position.isInner ? 20 + getMaxTickWidth(id) : 40 + getMaxTickWidth(id);
-        }
-        function getHorizontalAxisHeight(axisId) {
-            if (axisId === 'x' && !__axis_x_show) { return 0; }
-            if (axisId === 'x' && __axis_x_height) { return __axis_x_height; }
-            if (axisId === 'y' && !__axis_y_show) { return __legend_show && !isLegendRight ? 10 : 1; }
-            if (axisId === 'y2' && !__axis_y2_show) { return rotated_padding_top; }
-            return (getAxisLabelPositionById(axisId).isInner ? 30 : 40) + (axisId === 'y2' ? -10 : 0);
-        }
-        function getParentWidth() {
-            return +d3.select(__bindto).style("width").replace('px', ''); // TODO: if rotated, use height
-        }
-        function getParentHeight() {
-            return +d3.select(__bindto).style('height').replace('px', ''); // TODO: if rotated, use width
+        $$.selectChart = typeof config.bindto.node === 'function' ? config.bindto : d3.select(config.bindto);
+        if ($$.selectChart.empty()) {
+            $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
+            $$.observeInserted($$.selectChart);
+            binding = false;
         }
-        function getAxisClipX(forHorizontal) {
-            return forHorizontal ? -(1 + 4) : -(margin.left - 1);
-        }
-        function getAxisClipY(forHorizontal) {
-            return forHorizontal ? -20 : -4;
-        }
-        function getXAxisClipX() {
-            return getAxisClipX(!__axis_rotated);
+        $$.selectChart.html("").classed("c3", true);
+
+        // Init data as targets
+        $$.data.xs = {};
+        $$.data.targets = $$.convertDataToTargets(data);
+
+        if (config.data_filter) {
+            $$.data.targets = $$.data.targets.filter(config.data_filter);
         }
-        function getXAxisClipY() {
-            return getAxisClipY(!__axis_rotated);
+
+        // Set targets to hide if needed
+        if (config.data_hide) {
+            $$.addHiddenTargetIds(config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide);
         }
-        function getYAxisClipX() {
-            return getAxisClipX(__axis_rotated);
+        if (config.legend_hide) {
+            $$.addHiddenLegendIds(config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide);
         }
-        function getYAxisClipY() {
-            return getAxisClipY(__axis_rotated);
+
+        // when gauge, hide legend // TODO: fix
+        if ($$.hasType('gauge')) {
+            config.legend_show = false;
         }
-        function getAxisClipWidth(forHorizontal) {
-            return forHorizontal ? width + 2 + 4 : margin.left + 20;
+
+        // Init sizes and scales
+        $$.updateSizes();
+        $$.updateScales();
+
+        // Set domains for each scale
+        $$.x.domain(d3.extent($$.getXDomain($$.data.targets)));
+        $$.y.domain($$.getYDomain($$.data.targets, 'y'));
+        $$.y2.domain($$.getYDomain($$.data.targets, 'y2'));
+        $$.subX.domain($$.x.domain());
+        $$.subY.domain($$.y.domain());
+        $$.subY2.domain($$.y2.domain());
+
+        // Save original x domain for zoom update
+        $$.orgXDomain = $$.x.domain();
+
+        // Set initialized scales to brush and zoom
+        if ($$.brush) { $$.brush.scale($$.subX); }
+        if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+
+        /*-- Basic Elements --*/
+
+        // Define svgs
+        $$.svg = $$.selectChart.append("svg")
+            .style("overflow", "hidden")
+            .on('mouseenter', function () { return config.onmouseover.call($$); })
+            .on('mouseleave', function () { return config.onmouseout.call($$); });
+
+        // Define defs
+        defs = $$.svg.append("defs");
+        $$.clipChart = $$.appendClip(defs, $$.clipId);
+        $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
+        $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
+        $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
+        $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
+        $$.updateSvgSize();
+
+        // Define regions
+        main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main'));
+
+        if ($$.initSubchart) { $$.initSubchart(); }
+        if ($$.initTooltip) { $$.initTooltip(); }
+        if ($$.initLegend) { $$.initLegend(); }
+
+        /*-- Main Region --*/
+
+        // text when empty
+        main.append("text")
+            .attr("class", CLASS.text + ' ' + CLASS.empty)
+            .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
+            .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
+
+        // Regions
+        $$.initRegion();
+
+        // Grids
+        $$.initGrid();
+
+        // Define g for chart area
+        main.append('g')
+            .attr("clip-path", $$.clipPath)
+            .attr('class', CLASS.chart);
+
+        // Grid lines
+        if (config.grid_lines_front) { $$.initGridLines(); }
+
+        // Cover whole with rects for events
+        $$.initEventRect();
+
+        // Define g for chart
+        $$.initChartElements();
+
+        // if zoom privileged, insert rect to forefront
+        // TODO: is this needed?
+        main.insert('rect', config.zoom_privileged ? null : 'g.' + CLASS.regions)
+            .attr('class', CLASS.zoomRect)
+            .attr('width', $$.width)
+            .attr('height', $$.height)
+            .style('opacity', 0)
+            .on("dblclick.zoom", null);
+
+        // Set default extent if defined
+        if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
+
+        // Add Axis
+        $$.initAxis();
+
+        // Set targets
+        $$.updateTargets($$.data.targets);
+
+        // Draw with targets
+        if (binding) {
+            $$.updateDimension();
+            $$.config.oninit.call($$);
+            $$.redraw({
+                withTransform: true,
+                withUpdateXDomain: true,
+                withUpdateOrgXDomain: true,
+                withTransitionForAxis: false
+            });
         }
-        function getAxisClipHeight(forHorizontal) {
-            return forHorizontal ? (__axis_x_height ? __axis_x_height : 0) + 80 : height + 8;
+
+        // Bind resize event
+        if (window.onresize == null) {
+            window.onresize = $$.generateResize();
         }
-        function getXAxisClipWidth() {
-            return getAxisClipWidth(!__axis_rotated);
+        if (window.onresize.add) {
+            window.onresize.add(function () {
+                config.onresize.call($$);
+            });
+            window.onresize.add(function () {
+                $$.api.flush();
+            });
+            window.onresize.add(function () {
+                config.onresized.call($$);
+            });
         }
-        function getXAxisClipHeight() {
-            return getAxisClipHeight(!__axis_rotated);
+
+        // export element of the chart
+        $$.api.element = $$.selectChart.node();
+    };
+
+    c3_chart_internal_fn.smoothLines = function (el, type) {
+        var $$ = this;
+        if (type === 'grid') {
+            el.each(function () {
+                var g = $$.d3.select(this),
+                    x1 = g.attr('x1'),
+                    x2 = g.attr('x2'),
+                    y1 = g.attr('y1'),
+                    y2 = g.attr('y2');
+                g.attr({
+                    'x1': Math.ceil(x1),
+                    'x2': Math.ceil(x2),
+                    'y1': Math.ceil(y1),
+                    'y2': Math.ceil(y2)
+                });
+            });
         }
-        function getYAxisClipWidth() {
-            return getAxisClipWidth(__axis_rotated);
+    };
+
+
+    c3_chart_internal_fn.updateSizes = function () {
+        var $$ = this, config = $$.config;
+        var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
+            legendWidth = $$.legend ? $$.getLegendWidth() : 0,
+            legendHeightForBottom = $$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
+            hasArc = $$.hasArcType(),
+            xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
+            subchartHeight = config.subchart_show && !hasArc ? (config.subchart_size_height + xAxisHeight) : 0;
+
+        $$.currentWidth = $$.getCurrentWidth();
+        $$.currentHeight = $$.getCurrentHeight();
+
+        // for main
+        $$.margin = config.axis_rotated ? {
+            top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
+            right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+            bottom: $$.getHorizontalAxisHeight('y') + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+            left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
+        } : {
+            top: 4 + $$.getCurrentPaddingTop(), // for top tick text
+            right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+            bottom: xAxisHeight + subchartHeight + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+            left: hasArc ? 0 : $$.getCurrentPaddingLeft()
+        };
+
+        // for subchart
+        $$.margin2 = config.axis_rotated ? {
+            top: $$.margin.top,
+            right: NaN,
+            bottom: 20 + legendHeightForBottom,
+            left: $$.rotated_padding_left
+        } : {
+            top: $$.currentHeight - subchartHeight - legendHeightForBottom,
+            right: NaN,
+            bottom: xAxisHeight + legendHeightForBottom,
+            left: $$.margin.left
+        };
+
+        // for legend
+        $$.margin3 = {
+            top: 0,
+            right: NaN,
+            bottom: 0,
+            left: 0
+        };
+        if ($$.updateSizeForLegend) { $$.updateSizeForLegend(legendHeight, legendWidth); }
+
+        $$.width = $$.currentWidth - $$.margin.left - $$.margin.right;
+        $$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom;
+        if ($$.width < 0) { $$.width = 0; }
+        if ($$.height < 0) { $$.height = 0; }
+
+        $$.width2 = config.axis_rotated ? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right : $$.width;
+        $$.height2 = config.axis_rotated ? $$.height : $$.currentHeight - $$.margin2.top - $$.margin2.bottom;
+        if ($$.width2 < 0) { $$.width2 = 0; }
+        if ($$.height2 < 0) { $$.height2 = 0; }
+
+        // for arc
+        $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
+        $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
+        if ($$.hasType('gauge')) {
+            $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
         }
-        function getYAxisClipHeight() {
-            return getAxisClipHeight(__axis_rotated);
+        if ($$.updateRadius) { $$.updateRadius(); }
+
+        if ($$.isLegendRight && hasArc) {
+            $$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1;
         }
-        function getEventRectWidth() {
-            var target = getMaxDataCountTarget(c3.data.targets),
-                firstData, lastData, base, maxDataCount, ratio;
-            if (!target) {
-                return 0;
-            }
-            firstData = target.values[0], lastData = target.values[target.values.length - 1];
-            base = x(lastData.x) - x(firstData.x);
-            if (base === 0) {
-                return __axis_rotated ? height : width;
-            }
-            maxDataCount = getMaxDataCount();
-            ratio = (hasBarType(c3.data.targets) ? (maxDataCount - (isCategorized ? 0.25 : 1)) / maxDataCount : 1);
-            return maxDataCount > 1 ? (base * ratio) / (maxDataCount - 1) : base;
-        }
-        function updateLegendStep(step) {
-            legendStep = step;
-        }
-        function updateLegendItemWidth(w) {
-            legendItemWidth = w;
-        }
-        function updateLegendItemHeight(h) {
-            legendItemHeight = h;
-        }
-        function getLegendWidth() {
-            return __legend_show ? isLegendRight ? legendItemWidth * (legendStep + 1) : currentWidth : 0;
-        }
-        function getLegendHeight() {
-            return __legend_show ? isLegendRight ? currentHeight : legendItemHeight * (legendStep + 1) : 0;
-        }
-
-        //-- Scales --//
-
-        function updateScales() {
-            var xAxisTickFormat, xAxisTickValues, forInit = !x;
-            // update edges
-            xMin = __axis_rotated ? 1 : 0;
-            xMax = __axis_rotated ? height : width;
-            yMin = __axis_rotated ? 0 : height;
-            yMax = __axis_rotated ? width : 1;
-            subXMin = xMin;
-            subXMax = xMax;
-            subYMin = __axis_rotated ? 0 : height2;
-            subYMax = __axis_rotated ? width2 : 1;
-            // update scales
-            x = getX(xMin, xMax, forInit ? undefined : x.domain(), function () { return xAxis.tickOffset(); });
-            y = getY(yMin, yMax, forInit ? undefined : y.domain());
-            y2 = getY(yMin, yMax, forInit ? undefined : y2.domain());
-            subX = getX(xMin, xMax, orgXDomain, function (d) { return d % 1 ? 0 : subXAxis.tickOffset(); });
-            subY = getY(subYMin, subYMax, forInit ? undefined : subY.domain());
-            subY2 = getY(subYMin, subYMax, forInit ? undefined : subY2.domain());
-            // update axes
-            xAxisTickFormat = getXAxisTickFormat();
-            xAxisTickValues = __axis_x_tick_values ? __axis_x_tick_values : (forInit ? undefined : xAxis.tickValues());
-            xAxis = getXAxis(x, xOrient, xAxisTickFormat, xAxisTickValues);
-            subXAxis = getXAxis(subX, subXOrient, xAxisTickFormat, xAxisTickValues);
-            yAxis = getYAxis(y, yOrient, __axis_y_tick_format, __axis_y_ticks);
-            y2Axis = getYAxis(y2, y2Orient, __axis_y2_tick_format, __axis_y2_ticks);
-            // Set initialized scales to brush and zoom
-            if (!forInit) {
-                brush.scale(subX);
-                if (__zoom_enabled) { zoom.scale(x); }
-            }
-            // update for arc
-            updateArc();
-        }
-        function updateArc() {
-            svgArc = getSvgArc();
-            svgArcExpanded = getSvgArcExpanded();
-            svgArcExpandedSub = getSvgArcExpanded(0.98);
-        }
-        function getX(min, max, domain, offset) {
-            var scale = ((isTimeSeries) ? d3.time.scale() : d3.scale.linear()).range([min, max]);
-            // Set function and values for c3
-            scale.orgDomain = function () { return scale.domain(); };
-            if (domain) { scale.domain(domain); }
-            if (isUndefined(offset)) { offset = function () { return 0; }; }
-            // Define customized scale if categorized axis
-            if (isCategorized) {
-                var _scale = scale, key;
-                scale = function (d) { return _scale(d) + offset(d); };
-                for (key in _scale) {
-                    scale[key] = _scale[key];
+    };
+
+    c3_chart_internal_fn.updateTargets = function (targets) {
+        var $$ = this, config = $$.config;
+
+        /*-- Main --*/
+
+        //-- Text --//
+        $$.updateTargetsForText(targets);
+
+        //-- Bar --//
+        $$.updateTargetsForBar(targets);
+
+        //-- Line --//
+        $$.updateTargetsForLine(targets);
+
+        //-- Arc --//
+        if ($$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
+        if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
+
+        /*-- Show --*/
+
+        // Fade-in each chart
+        $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); })
+          .transition().duration(config.transition_duration)
+            .style("opacity", 1);
+    };
+
+    c3_chart_internal_fn.redraw = function (options, transitions) {
+        var $$ = this, main = $$.main, d3 = $$.d3, config = $$.config;
+        var areaIndices = $$.getShapeIndices($$.isAreaType), barIndices = $$.getShapeIndices($$.isBarType), lineIndices = $$.getShapeIndices($$.isLineType);
+        var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis,
+            withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend,
+            withEventRect, withDimension, withUpdateXAxis;
+        var hideAxis = $$.hasArcType();
+        var drawArea, drawBar, drawLine, xForText, yForText;
+        var duration, durationForExit, durationForAxis;
+        var waitForDraw, flow;
+        var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling, xDomainForZoom;
+        var xv = $$.xv.bind($$), cx, cy;
+
+        options = options || {};
+        withY = getOption(options, "withY", true);
+        withSubchart = getOption(options, "withSubchart", true);
+        withTransition = getOption(options, "withTransition", true);
+        withTransform = getOption(options, "withTransform", false);
+        withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
+        withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
+        withTrimXDomain = getOption(options, "withTrimXDomain", true);
+        withUpdateXAxis = getOption(options, "withUpdateXAxis", withUpdateXDomain);
+        withLegend = getOption(options, "withLegend", false);
+        withEventRect = getOption(options, "withEventRect", true);
+        withDimension = getOption(options, "withDimension", true);
+        withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
+        withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
+
+        duration = withTransition ? config.transition_duration : 0;
+        durationForExit = withTransitionForExit ? duration : 0;
+        durationForAxis = withTransitionForAxis ? duration : 0;
+
+        transitions = transitions || $$.generateAxisTransitions(durationForAxis);
+
+        // update legend and transform each g
+        if (withLegend && config.legend_show) {
+            $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
+        } else if (withDimension) {
+            // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
+            // no need to update axis in it because they will be updated in redraw()
+            $$.updateDimension(true);
+        }
+
+        // MEMO: needed for grids calculation
+        if ($$.isCategorized() && targetsToShow.length === 0) {
+            $$.x.domain([0, $$.axes.x.selectAll('.tick').size()]);
+        }
+
+        if (targetsToShow.length) {
+            $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
+            if (!config.axis_x_tick_values) {
+                if (config.axis_x_tick_fit || config.axis_x_tick_count) {
+                    tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count, $$.isTimeSeries());
+                } else {
+                    tickValues = undefined;
                 }
-                scale.orgDomain = function () {
-                    return _scale.domain();
-                };
-                scale.domain = function (domain) {
-                    if (!arguments.length) {
-                        domain = _scale.domain();
-                        return [domain[0], domain[1] + 1];
-                    }
-                    _scale.domain(domain);
-                    return scale;
-                };
+                $$.xAxis.tickValues(tickValues);
+                $$.subXAxis.tickValues(tickValues);
             }
-            return scale;
+        } else {
+            $$.xAxis.tickValues([]);
+            $$.subXAxis.tickValues([]);
         }
-        function getY(min, max, domain) {
-            var scale = d3.scale.linear().range([min, max]);
-            if (domain) { scale.domain(domain); }
-            return scale;
+
+        if (config.zoom_rescale && !options.flow) {
+            xDomainForZoom = $$.x.orgDomain();
         }
-        function getYScale(id) {
-            return getAxisId(id) === 'y2' ? y2 : y;
+
+        $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
+        $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
+
+        if (!config.axis_y_tick_values && config.axis_y_tick_count) {
+            $$.yAxis.tickValues($$.generateTickValues($$.y.domain(), config.axis_y_tick_count));
         }
-        function getSubYScale(id) {
-            return getAxisId(id) === 'y2' ? subY2 : subY;
+        if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
+            $$.y2Axis.tickValues($$.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
         }
 
-        //-- Axes --//
+        // axes
+        $$.redrawAxis(transitions, hideAxis);
 
-        function getXAxis(scale, orient, tickFormat, tickValues) {
-            var axis = (isCategorized ? categoryAxis() : d3.svg.axis()).scale(scale).orient(orient);
+        // Update axis label
+        $$.updateAxisLabels(withTransition);
 
-            // Set tick
-            axis.tickFormat(tickFormat).tickValues(tickValues);
-            if (isCategorized) {
-                axis.tickCentered(__axis_x_tick_centered);
-                if (isEmpty(__axis_x_tick_culling)) {
-                    __axis_x_tick_culling = false;
+        // show/hide if manual culling needed
+        if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
+            if (config.axis_x_tick_culling && tickValues) {
+                for (i = 1; i < tickValues.length; i++) {
+                    if (tickValues.length / i < config.axis_x_tick_culling_max) {
+                        intervalForCulling = i;
+                        break;
+                    }
                 }
+                $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
+                    var index = tickValues.indexOf(e);
+                    if (index >= 0) {
+                        d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
+                    }
+                });
             } else {
-                axis.tickOffset = function () {
-                    var edgeX = getEdgeX(c3.data.targets), diff = x(edgeX[1]) - x(edgeX[0]),
-                        base = diff ? diff : (__axis_rotated ? height : width);
-                    return (base / getMaxDataCount()) / 2;
-                };
+                $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
             }
+        }
 
-            // Set categories
-            if (isCategorized) {
-                axis.categories(__axis_x_categories);
-            }
+        // setup drawer - MEMO: these must be called after axis updated
+        drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
+        drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
+        drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
+        xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
+        yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false);
 
-            return axis;
+        // Update sub domain
+        if (withY) {
+            $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
+            $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
         }
-        function getYAxis(scale, orient, tickFormat, ticks) {
-            return d3.svg.axis().scale(scale).orient(orient).tickFormat(tickFormat).ticks(ticks).outerTickSize(0);
-        }
-        function getAxisId(id) {
-            return id in __data_axes ? __data_axes[id] : 'y';
+
+        // tooltip
+        $$.tooltip.style("display", "none");
+
+        // xgrid focus
+        $$.updateXgridFocus();
+
+        // Data empty label positioning and text.
+        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);
+
+        // grid
+        $$.redrawGrid(duration);
+
+        // rect for regions
+        $$.redrawRegion(duration);
+
+        // bars
+        $$.redrawBar(durationForExit);
+
+        // lines, areas and cricles
+        $$.redrawLine(durationForExit);
+        $$.redrawArea(durationForExit);
+        $$.redrawCircle();
+
+        // text
+        if ($$.hasDataLabel()) {
+            $$.redrawText(durationForExit);
         }
-        function getXAxisTickFormat() {
-            var format = isTimeSeries ? defaultTimeFormat : isCategorized ? categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
-            if (__axis_x_tick_format) {
-                if (typeof __axis_x_tick_format === 'function') {
-                    format = __axis_x_tick_format;
-                } else if (isTimeSeries) {
-                    format = function (date) {
-                        return date ? xTimeFormat(__axis_x_tick_format)(date) : "";
-                    };
-                }
+
+        // arc
+        if ($$.redrawArc) { $$.redrawArc(duration, durationForExit, withTransform); }
+
+        // subchart
+        if ($$.redrawSubchart) {
+            $$.redrawSubchart(withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices);
+        }
+
+        // circles for select
+        main.selectAll('.' + CLASS.selectedCircles)
+            .filter($$.isBarType.bind($$))
+            .selectAll('circle')
+            .remove();
+
+        // event rects will redrawn when flow called
+        if (config.interaction_enabled && !options.flow && withEventRect) {
+            $$.redrawEventRect();
+            if ($$.updateZoom) { $$.updateZoom(); }
+        }
+
+        // update circleY based on updated parameters
+        $$.updateCircleY();
+
+        // generate circle x/y functions depending on updated params
+        cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
+        cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
+
+        // transition should be derived from one transition
+        d3.transition().duration(duration).each(function () {
+            var transitions = [];
+
+            $$.addTransitionForBar(transitions, drawBar);
+            $$.addTransitionForLine(transitions, drawLine);
+            $$.addTransitionForArea(transitions, drawArea);
+            $$.addTransitionForCircle(transitions, cx, cy);
+            $$.addTransitionForText(transitions, xForText, yForText, options.flow);
+            $$.addTransitionForRegion(transitions);
+            $$.addTransitionForGrid(transitions);
+
+            // Wait for end of transitions if called from flow API
+            if (options.flow) {
+                waitForDraw = $$.generateWait();
+                transitions.forEach(function (t) {
+                    waitForDraw.add(t);
+                });
+                flow = $$.generateFlow({
+                    targets: targetsToShow,
+                    flow: options.flow,
+                    duration: duration,
+                    drawBar: drawBar,
+                    drawLine: drawLine,
+                    drawArea: drawArea,
+                    cx: cx,
+                    cy: cy,
+                    xv: xv,
+                    xForText: xForText,
+                    yForText: yForText
+                });
             }
-            return format;
+        })
+        .call(waitForDraw || function () {}, flow || function () {});
+
+        // update fadein condition
+        $$.mapToIds($$.data.targets).forEach(function (id) {
+            $$.withoutFadeIn[id] = true;
+        });
+    };
+
+    c3_chart_internal_fn.updateAndRedraw = function (options) {
+        var $$ = this, config = $$.config, transitions;
+        options = options || {};
+        // same with redraw
+        options.withTransition = getOption(options, "withTransition", true);
+        options.withTransform = getOption(options, "withTransform", false);
+        options.withLegend = getOption(options, "withLegend", false);
+        // NOT same with redraw
+        options.withUpdateXDomain = true;
+        options.withUpdateOrgXDomain = true;
+        options.withTransitionForExit = false;
+        options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
+        // MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
+        $$.updateSizes();
+        // MEMO: called in updateLegend in redraw if withLegend
+        if (!(options.withLegend && config.legend_show)) {
+            transitions = $$.generateAxisTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
+            // Update scales
+            $$.updateScales();
+            $$.updateSvgSize();
+            // Update g positions
+            $$.transformAll(options.withTransitionForTransform, transitions);
         }
-        function getAxisLabelOptionByAxisId(axisId) {
-            var option;
-            if (axisId === 'y') {
-                option = __axis_y_label;
-            } else if (axisId === 'y2') {
-                option = __axis_y2_label;
-            } else if (axisId === 'x') {
-                option = __axis_x_label;
-            }
-            return option;
-        }
-        function getAxisLabelText(axisId) {
-            var option = getAxisLabelOptionByAxisId(axisId);
-            return typeof option === 'string' ? option : option ? option.text : null;
-        }
-        function setAxisLabelText(axisId, text) {
-            var option = getAxisLabelOptionByAxisId(axisId);
-            if (typeof option === 'string') {
-                if (axisId === 'y') {
-                    __axis_y_label = text;
-                } else if (axisId === 'y2') {
-                    __axis_y2_label = text;
-                } else if (axisId === 'x') {
-                    __axis_x_label = text;
-                }
-            } else if (option) {
-                option.text = text;
+        // Draw with new sizes & scales
+        $$.redraw(options, transitions);
+    };
+    c3_chart_internal_fn.redrawWithoutRescale = function () {
+        this.redraw({
+            withY: false,
+            withSubchart: false,
+            withEventRect: false,
+            withTransitionForAxis: false
+        });
+    };
+
+    c3_chart_internal_fn.isTimeSeries = function () {
+        return this.config.axis_x_type === 'timeseries';
+    };
+    c3_chart_internal_fn.isCategorized = function () {
+        return this.config.axis_x_type.indexOf('categor') >= 0;
+    };
+    c3_chart_internal_fn.isCustomX = function () {
+        var $$ = this, config = $$.config;
+        return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
+    };
+
+    c3_chart_internal_fn.isTimeSeriesY = function () {
+        return this.config.axis_y_type === 'timeseries';
+    };
+
+    c3_chart_internal_fn.getTranslate = function (target) {
+        var $$ = this, config = $$.config, x, y;
+        if (target === 'main') {
+            x = asHalfPixel($$.margin.left);
+            y = asHalfPixel($$.margin.top);
+        } else if (target === 'context') {
+            x = asHalfPixel($$.margin2.left);
+            y = asHalfPixel($$.margin2.top);
+        } else if (target === 'legend') {
+            x = $$.margin3.left;
+            y = $$.margin3.top;
+        } else if (target === 'x') {
+            x = 0;
+            y = config.axis_rotated ? 0 : $$.height;
+        } else if (target === 'y') {
+            x = 0;
+            y = config.axis_rotated ? $$.height : 0;
+        } else if (target === 'y2') {
+            x = config.axis_rotated ? 0 : $$.width;
+            y = config.axis_rotated ? 1 : 0;
+        } else if (target === 'subx') {
+            x = 0;
+            y = config.axis_rotated ? 0 : $$.height2;
+        } else if (target === 'arc') {
+            x = $$.arcWidth / 2;
+            y = $$.arcHeight / 2;
+        }
+        return "translate(" + x + "," + y + ")";
+    };
+    c3_chart_internal_fn.initialOpacity = function (d) {
+        return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
+    };
+    c3_chart_internal_fn.initialOpacityForCircle = function (d) {
+        return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
+    };
+    c3_chart_internal_fn.opacityForCircle = function (d) {
+        var opacity = this.config.point_show ? 1 : 0;
+        return isValue(d.value) ? (this.isScatterType(d) ? 0.5 : opacity) : 0;
+    };
+    c3_chart_internal_fn.opacityForText = function () {
+        return this.hasDataLabel() ? 1 : 0;
+    };
+    c3_chart_internal_fn.xx = function (d) {
+        return d ? this.x(d.x) : null;
+    };
+    c3_chart_internal_fn.xv = function (d) {
+        var $$ = this;
+        return Math.ceil($$.x($$.isTimeSeries() ? $$.parseDate(d.value) : d.value));
+    };
+    c3_chart_internal_fn.yv = function (d) {
+        var $$ = this,
+            yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y;
+        return Math.ceil(yScale(d.value));
+    };
+    c3_chart_internal_fn.subxx = function (d) {
+        return d ? this.subX(d.x) : null;
+    };
+
+    c3_chart_internal_fn.transformMain = function (withTransition, transitions) {
+        var $$ = this,
+            xAxis, yAxis, y2Axis;
+        if (transitions && transitions.axisX) {
+            xAxis = transitions.axisX;
+        } else {
+            xAxis  = $$.main.select('.' + CLASS.axisX);
+            if (withTransition) { xAxis = xAxis.transition(); }
+        }
+        if (transitions && transitions.axisY) {
+            yAxis = transitions.axisY;
+        } else {
+            yAxis = $$.main.select('.' + CLASS.axisY);
+            if (withTransition) { yAxis = yAxis.transition(); }
+        }
+        if (transitions && transitions.axisY2) {
+            y2Axis = transitions.axisY2;
+        } else {
+            y2Axis = $$.main.select('.' + CLASS.axisY2);
+            if (withTransition) { y2Axis = y2Axis.transition(); }
+        }
+        (withTransition ? $$.main.transition() : $$.main).attr("transform", $$.getTranslate('main'));
+        xAxis.attr("transform", $$.getTranslate('x'));
+        yAxis.attr("transform", $$.getTranslate('y'));
+        y2Axis.attr("transform", $$.getTranslate('y2'));
+        $$.main.select('.' + CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
+    };
+    c3_chart_internal_fn.transformAll = function (withTransition, transitions) {
+        var $$ = this;
+        $$.transformMain(withTransition, transitions);
+        if ($$.config.subchart_show) { $$.transformContext(withTransition, transitions); }
+        if ($$.legend) { $$.transformLegend(withTransition); }
+    };
+
+    c3_chart_internal_fn.updateSvgSize = function () {
+        var $$ = this,
+            brush = $$.svg.select(".c3-brush .background");
+        $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
+        $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect')
+            .attr('width', $$.width)
+            .attr('height', $$.height);
+        $$.svg.select('#' + $$.clipIdForXAxis).select('rect')
+            .attr('x', $$.getXAxisClipX.bind($$))
+            .attr('y', $$.getXAxisClipY.bind($$))
+            .attr('width', $$.getXAxisClipWidth.bind($$))
+            .attr('height', $$.getXAxisClipHeight.bind($$));
+        $$.svg.select('#' + $$.clipIdForYAxis).select('rect')
+            .attr('x', $$.getYAxisClipX.bind($$))
+            .attr('y', $$.getYAxisClipY.bind($$))
+            .attr('width', $$.getYAxisClipWidth.bind($$))
+            .attr('height', $$.getYAxisClipHeight.bind($$));
+        $$.svg.select('#' + $$.clipIdForSubchart).select('rect')
+            .attr('width', $$.width)
+            .attr('height', brush.size() ? brush.attr('height') : 0);
+        $$.svg.select('.' + CLASS.zoomRect)
+            .attr('width', $$.width)
+            .attr('height', $$.height);
+        // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
+        $$.selectChart.style('max-height', $$.currentHeight + "px");
+    };
+
+
+    c3_chart_internal_fn.updateDimension = function (withoutAxis) {
+        var $$ = this;
+        if (!withoutAxis) {
+            if ($$.config.axis_rotated) {
+                $$.axes.x.call($$.xAxis);
+                $$.axes.subx.call($$.subXAxis);
+            } else {
+                $$.axes.y.call($$.yAxis);
+                $$.axes.y2.call($$.y2Axis);
             }
         }
-        function xForRotatedTickText(r) {
-            return 10 * Math.sin(Math.PI * (r / 180));
-        }
-        function yForRotatedTickText(r) {
-            return 11.5 - 2.5 * (r / 15);
-        }
-        function rotateTickText(axis, transition, rotate) {
-            axis.selectAll('.tick text')
-                .style("text-anchor", "start");
-            transition.selectAll('.tick text')
-                .attr("y", yForRotatedTickText(rotate))
-                .attr("x", xForRotatedTickText(rotate))
-                .attr("transform", "rotate(" + rotate + ")");
-        }
-        function getAxisLabelPosition(axisId, defaultPosition) {
-            var option = getAxisLabelOptionByAxisId(axisId),
-                position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
-            return {
-                isInner: position.indexOf('inner') >= 0,
-                isOuter: position.indexOf('outer') >= 0,
-                isLeft: position.indexOf('left') >= 0,
-                isCenter: position.indexOf('center') >= 0,
-                isRight: position.indexOf('right') >= 0,
-                isTop: position.indexOf('top') >= 0,
-                isMiddle: position.indexOf('middle') >= 0,
-                isBottom: position.indexOf('bottom') >= 0
-            };
-        }
-        function getXAxisLabelPosition() {
-            return getAxisLabelPosition('x', __axis_rotated ? 'inner-top' : 'inner-right');
-        }
-        function getYAxisLabelPosition() {
-            return getAxisLabelPosition('y', __axis_rotated ? 'inner-right' : 'inner-top');
-        }
-        function getY2AxisLabelPosition() {
-            return getAxisLabelPosition('y2', __axis_rotated ? 'inner-right' : 'inner-top');
-        }
-        function getAxisLabelPositionById(id) {
-            return id === 'y2' ? getY2AxisLabelPosition() : id === 'y' ? getYAxisLabelPosition() : getXAxisLabelPosition();
-        }
-        function textForXAxisLabel() {
-            return getAxisLabelText('x');
-        }
-        function textForYAxisLabel() {
-            return getAxisLabelText('y');
-        }
-        function textForY2AxisLabel() {
-            return getAxisLabelText('y2');
-        }
-        function xForAxisLabel(forHorizontal, position) {
-            if (forHorizontal) {
-                return position.isLeft ? 0 : position.isCenter ? width / 2 : width;
-            } else {
-                return position.isBottom ? -height : position.isMiddle ? -height / 2 : 0;
-            }
-        }
-        function dxForAxisLabel(forHorizontal, position) {
-            if (forHorizontal) {
-                return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
-            } else {
-                return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
-            }
-        }
-        function textAnchorForAxisLabel(forHorizontal, position) {
-            if (forHorizontal) {
-                return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
-            } else {
-                return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
-            }
-        }
-        function xForXAxisLabel() {
-            return xForAxisLabel(!__axis_rotated, getXAxisLabelPosition());
-        }
-        function xForYAxisLabel() {
-            return xForAxisLabel(__axis_rotated, getYAxisLabelPosition());
-        }
-        function xForY2AxisLabel() {
-            return xForAxisLabel(__axis_rotated, getY2AxisLabelPosition());
-        }
-        function dxForXAxisLabel() {
-            return dxForAxisLabel(!__axis_rotated, getXAxisLabelPosition());
-        }
-        function dxForYAxisLabel() {
-            return dxForAxisLabel(__axis_rotated, getYAxisLabelPosition());
-        }
-        function dxForY2AxisLabel() {
-            return dxForAxisLabel(__axis_rotated, getY2AxisLabelPosition());
-        }
-        function dyForXAxisLabel() {
-            var position = getXAxisLabelPosition();
-            if (__axis_rotated) {
-                return position.isInner ? "1.2em" : -25 - getMaxTickWidth('x');
-            } else {
-                return position.isInner ? "-0.5em" : __axis_x_height ? __axis_x_height - 10 : "3em";
-            }
-        }
-        function dyForYAxisLabel() {
-            var position = getYAxisLabelPosition();
-            if (__axis_rotated) {
-                return position.isInner ? "-0.5em" : "3em";
-            } else {
-                return position.isInner ? "1.2em" : -20 - getMaxTickWidth('y');
-            }
-        }
-        function dyForY2AxisLabel() {
-            var position = getY2AxisLabelPosition();
-            if (__axis_rotated) {
-                return position.isInner ? "1.2em" : "-2.2em";
-            } else {
-                return position.isInner ? "-0.5em" : 30 + getMaxTickWidth('y2');
-            }
-        }
-        function textAnchorForXAxisLabel() {
-            return textAnchorForAxisLabel(!__axis_rotated, getXAxisLabelPosition());
-        }
-        function textAnchorForYAxisLabel() {
-            return textAnchorForAxisLabel(__axis_rotated, getYAxisLabelPosition());
-        }
-        function textAnchorForY2AxisLabel() {
-            return textAnchorForAxisLabel(__axis_rotated, getY2AxisLabelPosition());
-        }
-        function getMaxTickWidth(id) {
-            var maxWidth = 0, axisClass = id === 'x' ? CLASS.axisX : id === 'y' ? CLASS.axisY : CLASS.axisY2;
-            d3.selectAll('.' + axisClass + ' .tick text').each(function () {
-                var box = this.getBoundingClientRect();
-                if (maxWidth < box.width) { maxWidth = box.width; }
-            });
-            return maxWidth < 0 ? 0 : maxWidth;
-        }
-        function updateAxisLabels() {
-            main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel)
-              .transition()
-                .attr("x", xForXAxisLabel)
-                .attr("dx", dxForXAxisLabel)
-                .attr("dy", dyForXAxisLabel)
-                .text(textForXAxisLabel);
-            main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel)
-              .transition()
-                .attr("x", xForYAxisLabel)
-                .attr("dx", dxForYAxisLabel)
-                .attr("dy", dyForYAxisLabel)
-                .attr("dy", dyForYAxisLabel)
-                .text(textForYAxisLabel);
-            main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label)
-              .transition()
-                .attr("x", xForY2AxisLabel)
-                .attr("dx", dxForY2AxisLabel)
-                .attr("dy", dyForY2AxisLabel)
-                .text(textForY2AxisLabel);
-        }
-
-        function categoryAxis() {
-            var scale = d3.scale.linear(), orient = "bottom";
-            var tickMajorSize = 6, /*tickMinorSize = 6,*/ tickEndSize = 6, tickPadding = 3, tickCentered = false, tickTextNum = 10, tickOffset = 0, tickFormat = null, tickCulling = true;
-            var categories = [];
-            function axisX(selection, x) {
-                selection.attr("transform", function (d) {
-                    return "translate(" + (x(d) + tickOffset) + ", 0)";
-                });
-            }
-            function axisY(selection, y) {
-                selection.attr("transform", function (d) {
-                    return "translate(0," + y(d) + ")";
-                });
-            }
-            function scaleExtent(domain) {
-                var start = domain[0], stop = domain[domain.length - 1];
-                return start < stop ? [ start, stop ] : [ stop, start ];
-            }
-            function generateTicks(domain) {
-                var ticks = [];
-                for (var i = Math.ceil(domain[0]); i < domain[1]; i++) {
-                    ticks.push(i);
-                }
-                if (ticks.length > 0 && ticks[0] > 0) {
-                    ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
+        $$.updateSizes();
+        $$.updateScales();
+        $$.updateSvgSize();
+        $$.transformAll(false);
+    };
+
+    c3_chart_internal_fn.observeInserted = function (selection) {
+        var $$ = this, observer = new MutationObserver(function (mutations) {
+            mutations.forEach(function (mutation) {
+                if (mutation.type === 'childList' && mutation.previousSibling) {
+                    observer.disconnect();
+                    // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
+                    $$.intervalForObserveInserted = window.setInterval(function () {
+                        // parentNode will NOT be null when completed
+                        if (selection.node().parentNode) {
+                            window.clearInterval($$.intervalForObserveInserted);
+                            $$.updateDimension();
+                            $$.config.oninit.call($$);
+                            $$.redraw({
+                                withTransform: true,
+                                withUpdateXDomain: true,
+                                withUpdateOrgXDomain: true,
+                                withTransition: false,
+                                withTransitionForTransform: false,
+                                withLegend: true
+                            });
+                            selection.transition().style('opacity', 1);
+                        }
+                    }, 10);
                 }
-                return ticks;
-            }
-            function category(i) {
-                return i < categories.length ? categories[i] : i;
-            }
-            function formattedCategory(i) {
-                var c = category(i);
-                return tickFormat ? tickFormat(c) : c;
-            }
-            function copyScale() {
-                var newScale = scale.copy(), domain = scale.domain();
-                newScale.domain([domain[0], domain[1] - 1]);
-                return newScale;
-            }
-            function axis(g) {
-                g.each(function () {
-                    var g = d3.select(this);
-                    var scale1 = copyScale(), scale0 = this.__chart__ || scale1;
-                    var tick = g.selectAll(".tick.major").data(generateTicks(scale1.domain()), String),
-                        tickEnter = tick.enter().insert("g", "path").attr("class", "tick major").style("opacity", 1e-6),
-                        tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(),
-                        tickUpdate = d3.transition(tick).style("opacity", 1),
-                        tickTransform,
-                        tickX;
-                    var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range());
-                    var path = g.selectAll(".domain").data([ 0 ]), pathUpdate;
-                    var lineEnter, lineUpdate, text, textEnter, textUpdate;
-
-                    path.enter().append("path").attr("class", "domain");
-                    pathUpdate = d3.transition(path);
-
-                    tickEnter.append("line");
-                    tickEnter.append("text");
-
-                    lineEnter = tickEnter.select("line");
-                    lineUpdate = tickUpdate.select("line");
-                    text = tick.select("text");
-                    textEnter = tickEnter.select("text");
-                    textUpdate = tickUpdate.select("text");
+            });
+        });
+        observer.observe(selection.node(), {attributes: true, childList: true, characterData: true});
+    };
 
-                    tickOffset = (scale1(1) - scale1(0)) / 2;
-                    tickX = tickCentered ? 0 : tickOffset;
 
-                    this.__chart__ = scale1;
-
-                    switch (orient) {
-                    case "bottom":
-                        {
-                            tickTransform = axisX;
-                            lineEnter.attr("y2", tickMajorSize);
-                            textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
-                            lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickMajorSize);
-                            textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding);
-                            text.attr("dy", ".71em").style("text-anchor", "middle");
-                            text.text(formattedCategory);
-                            pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
-                            break;
-                        }
-/* TODO: implement
-                    case "top":
-                        {
-                        tickTransform = axisX
-                        lineEnter.attr("y2", -tickMajorSize)
-                        textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding))
-                        lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize)
-                        textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding))
-                        text.attr("dy", "0em").style("text-anchor", "middle")
-                        pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize)
-                        break
+    c3_chart_internal_fn.generateResize = function () {
+        var resizeFunctions = [];
+        function callResizeFunctions() {
+            resizeFunctions.forEach(function (f) {
+                f();
+            });
+        }
+        callResizeFunctions.add = function (f) {
+            resizeFunctions.push(f);
+        };
+        return callResizeFunctions;
+    };
+
+    c3_chart_internal_fn.endall = function (transition, callback) {
+        var n = 0;
+        transition
+            .each(function () { ++n; })
+            .each("end", function () {
+                if (!--n) { callback.apply(this, arguments); }
+            });
+    };
+    c3_chart_internal_fn.generateWait = function () {
+        var transitionsToWait = [],
+            f = function (transition, callback) {
+                var timer = setInterval(function () {
+                    var done = 0;
+                    transitionsToWait.forEach(function (t) {
+                        if (t.empty()) {
+                            done += 1;
+                            return;
                         }
-*/
-                    case "left":
-                        {
-                            tickTransform = axisY;
-                            lineEnter.attr("x2", -tickMajorSize);
-                            textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
-                            lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
-                            textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", tickOffset);
-                            text.attr("dy", ".32em").style("text-anchor", "end");
-                            text.text(formattedCategory);
-                            pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
-                            break;
+                        try {
+                            t.transition();
+                        } catch (e) {
+                            done += 1;
                         }
-/*
-                case "right":
-                    {
-                        tickTransform = axisY
-                        lineEnter.attr("x2", tickMajorSize)
-                        textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding)
-                        lineUpdate.attr("x2", tickMajorSize).attr("y2", 0)
-                        textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0)
-                        text.attr("dy", ".32em").style("text-anchor", "start")
-                        pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize)
-                        break
-                    }
-*/
-                    }
-                    if (scale.ticks) {
-                        tickEnter.call(tickTransform, scale0);
-                        tickUpdate.call(tickTransform, scale1);
-                        tickExit.call(tickTransform, scale1);
-                    } else {
-                        var dx = scale1.rangeBand() / 2, x = function (d) {
-                            return scale1(d) + dx;
-                        };
-                        tickEnter.call(tickTransform, x);
-                        tickUpdate.call(tickTransform, x);
+                    });
+                    if (done === transitionsToWait.length) {
+                        clearInterval(timer);
+                        if (callback) { callback(); }
                     }
-                });
-            }
-            axis.scale = function (x) {
-                if (!arguments.length) { return scale; }
-                scale = x;
-                return axis;
-            };
-            axis.orient = function (x) {
-                if (!arguments.length) { return orient; }
-                orient = x in {top: 1, right: 1, bottom: 1, left: 1} ? x + "" : "bottom";
-                return axis;
-            };
-            axis.categories = function (x) {
-                if (!arguments.length) { return categories; }
-                categories = x;
-                return axis;
-            };
-            axis.tickCentered = function (x) {
-                if (!arguments.length) { return tickCentered; }
-                tickCentered = x;
-                return axis;
-            };
-            axis.tickFormat = function (format) {
-                if (!arguments.length) { return tickFormat; }
-                tickFormat = format;
-                return axis;
+                }, 10);
             };
-            axis.tickOffset = function () {
-                return tickOffset;
-            };
-            axis.ticks = function (n) {
-                if (!arguments.length) { return tickTextNum; }
-                tickTextNum = n;
-                return axis;
-            };
-            axis.tickCulling = function (culling) {
-                if (!arguments.length) { return tickCulling; }
-                tickCulling = culling;
-                return axis;
-            };
-            axis.tickValues = function () {
-                // TODO: do something
-            };
-            return axis;
+        f.add = function (transition) {
+            transitionsToWait.push(transition);
+        };
+        return f;
+    };
+
+    c3_chart_internal_fn.parseDate = function (date) {
+        var $$ = this, parsedDate;
+        if (date instanceof Date) {
+            parsedDate = date;
+        } else if (typeof date === 'number') {
+            parsedDate = new Date(date);
+        } else {
+            parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
+        }
+        if (!parsedDate || isNaN(+parsedDate)) {
+            window.console.error("Failed to parse x '" + date + "' to Date object");
         }
+        return parsedDate;
+    };
 
-        //-- Arc --//
+    c3_chart_internal_fn.getDefaultConfig = function () {
+        var config = {
+            bindto: '#chart',
+            size_width: undefined,
+            size_height: undefined,
+            padding_left: undefined,
+            padding_right: undefined,
+            padding_top: undefined,
+            padding_bottom: undefined,
+            zoom_enabled: false,
+            zoom_extent: undefined,
+            zoom_privileged: false,
+            zoom_rescale: false,
+            zoom_onzoom: function () {},
+            zoom_onzoomstart: function () {},
+            zoom_onzoomend: function () {},
+            interaction_enabled: true,
+            onmouseover: function () {},
+            onmouseout: function () {},
+            onresize: function () {},
+            onresized: function () {},
+            oninit: function () {},
+            transition_duration: 350,
+            data_x: undefined,
+            data_xs: {},
+            data_xFormat: '%Y-%m-%d',
+            data_xLocaltime: true,
+            data_xSort: true,
+            data_idConverter: function (id) { return id; },
+            data_names: {},
+            data_classes: {},
+            data_groups: [],
+            data_axes: {},
+            data_type: undefined,
+            data_types: {},
+            data_labels: {},
+            data_order: 'desc',
+            data_regions: {},
+            data_color: undefined,
+            data_colors: {},
+            data_hide: false,
+            data_filter: undefined,
+            data_selection_enabled: false,
+            data_selection_grouped: false,
+            data_selection_isselectable: function () { return true; },
+            data_selection_multiple: true,
+            data_onclick: function () {},
+            data_onmouseover: function () {},
+            data_onmouseout: function () {},
+            data_onselected: function () {},
+            data_onunselected: function () {},
+            data_ondragstart: function () {},
+            data_ondragend: function () {},
+            data_url: undefined,
+            data_json: undefined,
+            data_rows: undefined,
+            data_columns: undefined,
+            data_mimeType: undefined,
+            data_keys: undefined,
+            // configuration for no plot-able data supplied.
+            data_empty_label_text: "",
+            // subchart
+            subchart_show: false,
+            subchart_size_height: 60,
+            subchart_onbrush: function () {},
+            // color
+            color_pattern: [],
+            color_threshold: {},
+            // legend
+            legend_show: true,
+            legend_hide: false,
+            legend_position: 'bottom',
+            legend_inset_anchor: 'top-left',
+            legend_inset_x: 10,
+            legend_inset_y: 0,
+            legend_inset_step: undefined,
+            legend_item_onclick: undefined,
+            legend_item_onmouseover: undefined,
+            legend_item_onmouseout: undefined,
+            legend_equally: false,
+            // axis
+            axis_rotated: false,
+            axis_x_show: true,
+            axis_x_type: 'indexed',
+            axis_x_localtime: true,
+            axis_x_categories: [],
+            axis_x_tick_centered: false,
+            axis_x_tick_format: undefined,
+            axis_x_tick_culling: {},
+            axis_x_tick_culling_max: 10,
+            axis_x_tick_count: undefined,
+            axis_x_tick_fit: true,
+            axis_x_tick_values: null,
+            axis_x_tick_rotate: 0,
+            axis_x_tick_outer: true,
+            axis_x_tick_multiline: true,
+            axis_x_tick_width: null,
+            axis_x_max: undefined,
+            axis_x_min: undefined,
+            axis_x_padding: {},
+            axis_x_height: undefined,
+            axis_x_extent: undefined,
+            axis_x_label: {},
+            axis_y_show: true,
+            axis_y_type: undefined,
+            axis_y_max: undefined,
+            axis_y_min: undefined,
+            axis_y_center: undefined,
+            axis_y_inner: undefined,
+            axis_y_label: {},
+            axis_y_tick_format: undefined,
+            axis_y_tick_outer: true,
+            axis_y_tick_values: null,
+            axis_y_tick_count: undefined,
+            axis_y_tick_time_value: undefined,
+            axis_y_tick_time_interval: undefined,
+            axis_y_padding: {},
+            axis_y_default: undefined,
+            axis_y2_show: false,
+            axis_y2_max: undefined,
+            axis_y2_min: undefined,
+            axis_y2_center: undefined,
+            axis_y2_inner: undefined,
+            axis_y2_label: {},
+            axis_y2_tick_format: undefined,
+            axis_y2_tick_outer: true,
+            axis_y2_tick_values: null,
+            axis_y2_tick_count: undefined,
+            axis_y2_padding: {},
+            axis_y2_default: undefined,
+            // grid
+            grid_x_show: false,
+            grid_x_type: 'tick',
+            grid_x_lines: [],
+            grid_y_show: false,
+            // not used
+            // grid_y_type: 'tick',
+            grid_y_lines: [],
+            grid_y_ticks: 10,
+            grid_focus_show: true,
+            grid_lines_front: true,
+            // point - point of each data
+            point_show: true,
+            point_r: 2.5,
+            point_focus_expand_enabled: true,
+            point_focus_expand_r: undefined,
+            point_select_r: undefined,
+            // line
+            line_connectNull: false,
+            line_step_type: 'step',
+            // bar
+            bar_width: undefined,
+            bar_width_ratio: 0.6,
+            bar_width_max: undefined,
+            bar_zerobased: true,
+            // area
+            area_zerobased: true,
+            // pie
+            pie_label_show: true,
+            pie_label_format: undefined,
+            pie_label_threshold: 0.05,
+            pie_expand: true,
+            // gauge
+            gauge_label_show: true,
+            gauge_label_format: undefined,
+            gauge_expand: true,
+            gauge_min: 0,
+            gauge_max: 100,
+            gauge_units: undefined,
+            gauge_width: undefined,
+            // donut
+            donut_label_show: true,
+            donut_label_format: undefined,
+            donut_label_threshold: 0.05,
+            donut_width: undefined,
+            donut_expand: true,
+            donut_title: "",
+            // region - region to change style
+            regions: [],
+            // tooltip - show when mouseover on each data
+            tooltip_show: true,
+            tooltip_grouped: true,
+            tooltip_format_title: undefined,
+            tooltip_format_name: undefined,
+            tooltip_format_value: undefined,
+            tooltip_contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
+                return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
+            },
+            tooltip_init_show: false,
+            tooltip_init_x: 0,
+            tooltip_init_position: {top: '0px', left: '50px'}
+        };
 
-        pie = d3.layout.pie().value(function (d) {
-            return d.values.reduce(function (a, b) { return a + b.value; }, 0);
-        });
+        Object.keys(this.additionalConfig).forEach(function (key) {
+            config[key] = this.additionalConfig[key];
+        }, this);
 
-        function updateAngle(d) {
-            var found = false;
+        return config;
+    };
+    c3_chart_internal_fn.additionalConfig = {};
 
-            if (isNaN(d)) {
-                return null;
+    c3_chart_internal_fn.loadConfig = function (config) {
+        var this_config = this.config, target, keys, read;
+        function find() {
+            var key = keys.shift();
+    //        console.log("key =>", key, ", target =>", target);
+            if (key && target && typeof target === 'object' && key in target) {
+                target = target[key];
+                return find();
+            }
+            else if (!key) {
+                return target;
+            }
+            else {
+                return undefined;
             }
-
-            pie(filterTargetsToShow(c3.data.targets)).forEach(function (t) {
-                if (! found && t.data.id === d.data.id) {
-                    found = true;
-                    d = t;
-                    return;
-                }
-            });
-            return found ? d : null;
         }
+        Object.keys(this_config).forEach(function (key) {
+            target = config;
+            keys = key.split('_');
+            read = find();
+    //        console.log("CONFIG : ", key, read);
+            if (isDefined(read)) {
+                this_config[key] = read;
+            }
+        });
+    };
 
-        function getSvgArc() {
-            var arc = d3.svg.arc().outerRadius(radius).innerRadius(innerRadius),
-                newArc = function (d, withoutUpdate) {
-                    var updated;
-                    if (withoutUpdate) { return arc(d); } // for interpolate
-                    updated = updateAngle(d);
-                    return updated ? arc(updated) : "M 0 0";
-                };
-            // TODO: extends all function
-            newArc.centroid = arc.centroid;
-            return newArc;
-        }
-        function getSvgArcExpanded(rate) {
-            var arc = d3.svg.arc().outerRadius(radiusExpanded * (rate ? rate : 1)).innerRadius(innerRadius);
-            return function (d) {
-                var updated = updateAngle(d);
-                return updated ? arc(updated) : "M 0 0";
+    c3_chart_internal_fn.getScale = function (min, max, forTimeseries) {
+        return (forTimeseries ? this.d3.time.scale() : this.d3.scale.linear()).range([min, max]);
+    };
+    c3_chart_internal_fn.getX = function (min, max, domain, offset) {
+        var $$ = this,
+            scale = $$.getScale(min, max, $$.isTimeSeries()),
+            _scale = domain ? scale.domain(domain) : scale, key;
+        // Define customized scale if categorized axis
+        if ($$.isCategorized()) {
+            offset = offset || function () { return 0; };
+            scale = function (d, raw) {
+                var v = _scale(d) + offset(d);
+                return raw ? v : Math.ceil(v);
+            };
+        } else {
+            scale = function (d, raw) {
+                var v = _scale(d);
+                return raw ? v : Math.ceil(v);
             };
         }
-        function getArc(d, withoutUpdate) {
-            return isArcType(d.data) ? svgArc(d, withoutUpdate) : "M 0 0";
-        }
-        function transformForArcLabel(d) {
-            var updated = updateAngle(d), c, x, y, h, translate = "";
-            if (updated) {
-                c = svgArc.centroid(updated);
-                x = c[0], y = c[1], h = Math.sqrt(x * x + y * y);
-                translate = "translate(" + ((x / h) * radius * 0.8) +  ',' + ((y / h) * radius * 0.8) +  ")";
-            }
-            return translate;
-        }
-        function getArcRatio(d) {
-            return d ? (d.endAngle - d.startAngle) / (Math.PI * 2) : null;
+        // define functions
+        for (key in _scale) {
+            scale[key] = _scale[key];
         }
-        function convertToArcData(d) {
-            return addName({
-                id: d.data.id,
-                value: d.value,
-                ratio: getArcRatio(d)
-            });
+        scale.orgDomain = function () {
+            return _scale.domain();
+        };
+        // define custom domain() for categorized axis
+        if ($$.isCategorized()) {
+            scale.domain = function (domain) {
+                if (!arguments.length) {
+                    domain = this.orgDomain();
+                    return [domain[0], domain[1] + 1];
+                }
+                _scale.domain(domain);
+                return scale;
+            };
         }
-        function textForArcLabel(d) {
-            var updated, value, ratio, format;
-            if (! shouldShowArcLable()) { return ""; }
-            updated = updateAngle(d);
-            value = updated ? updated.value : null;
-            ratio = getArcRatio(updated);
-            format = getArcLabelFormat();
-            return format ? format(value, ratio) : defaultArcValueFormat(value, ratio);
-        }
-        function expandArc(id, withoutFadeOut) {
-            var target = svg.selectAll('.' + CLASS.chartArc + selectorTarget(id)),
-                noneTargets = svg.selectAll('.' + CLASS.arc).filter(function (data) { return data.data.id !== id; });
-
-            if (shouldExpand(id)) {
-                target.selectAll('path')
-                  .transition().duration(50)
-                    .attr("d", svgArcExpanded)
-                  .transition().duration(100)
-                    .attr("d", svgArcExpandedSub)
-                    .each(function (d) {
-                        if (isDonutType(d.data)) {
-                            // callback here
+        return scale;
+    };
+    c3_chart_internal_fn.getY = function (min, max, domain) {
+        var scale = this.getScale(min, max, this.isTimeSeriesY());
+        if (domain) { scale.domain(domain); }
+        return scale;
+    };
+    c3_chart_internal_fn.getYScale = function (id) {
+        return this.getAxisId(id) === 'y2' ? this.y2 : this.y;
+    };
+    c3_chart_internal_fn.getSubYScale = function (id) {
+        return this.getAxisId(id) === 'y2' ? this.subY2 : this.subY;
+    };
+    c3_chart_internal_fn.updateScales = function () {
+        var $$ = this, config = $$.config,
+            forInit = !$$.x;
+        // update edges
+        $$.xMin = config.axis_rotated ? 1 : 0;
+        $$.xMax = config.axis_rotated ? $$.height : $$.width;
+        $$.yMin = config.axis_rotated ? 0 : $$.height;
+        $$.yMax = config.axis_rotated ? $$.width : 1;
+        $$.subXMin = $$.xMin;
+        $$.subXMax = $$.xMax;
+        $$.subYMin = config.axis_rotated ? 0 : $$.height2;
+        $$.subYMax = config.axis_rotated ? $$.width2 : 1;
+        // update scales
+        $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () { return $$.xAxis.tickOffset(); });
+        $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
+        $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
+        $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) { return d % 1 ? 0 : $$.subXAxis.tickOffset(); });
+        $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
+        $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
+        // update axes
+        $$.xAxisTickFormat = $$.getXAxisTickFormat();
+        $$.xAxisTickValues = $$.getXAxisTickValues();
+        $$.yAxisTickValues = $$.getYAxisTickValues();
+        $$.y2AxisTickValues = $$.getY2AxisTickValues();
+
+        $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+        $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+        $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
+        $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
+
+        // Set initialized scales to brush and zoom
+        if (!forInit) {
+            if ($$.brush) { $$.brush.scale($$.subX); }
+            if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+        }
+        // update for arc
+        if ($$.updateArc) { $$.updateArc(); }
+    };
+
+    c3_chart_internal_fn.getYDomainMin = function (targets) {
+        var $$ = this, config = $$.config,
+            ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+            j, k, baseId, idsInGroup, id, hasNegativeValue;
+        if (config.data_groups.length > 0) {
+            hasNegativeValue = $$.hasNegativeValueInTargets(targets);
+            for (j = 0; j < config.data_groups.length; j++) {
+                // Determine baseId
+                idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+                if (idsInGroup.length === 0) { continue; }
+                baseId = idsInGroup[0];
+                // Consider negative values
+                if (hasNegativeValue && ys[baseId]) {
+                    ys[baseId].forEach(function (v, i) {
+                        ys[baseId][i] = v < 0 ? v : 0;
+                    });
+                }
+                // Compute min
+                for (k = 1; k < idsInGroup.length; k++) {
+                    id = idsInGroup[k];
+                    if (! ys[id]) { continue; }
+                    ys[id].forEach(function (v, i) {
+                        if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
+                            ys[baseId][i] += +v;
                         }
                     });
-            }
-            if (!withoutFadeOut) {
-                noneTargets.style("opacity", 0.3);
+                }
             }
         }
-        function unexpandArc(id) {
-            var target = svg.selectAll('.' + CLASS.chartArc + selectorTarget(id));
-            target.selectAll('path')
-              .transition().duration(50)
-                .attr("d", svgArc);
-            svg.selectAll('.' + CLASS.arc)
-                .style("opacity", 1);
-        }
-        function shouldShowArcLable() {
-            return hasDonutType(c3.data.targets) ? __donut_label_show : __pie_label_show;
-        }
-        function getArcLabelFormat() {
-            return hasDonutType(c3.data.targets) ? __donut_label_format : __pie_label_format;
-        }
-        function getArcTitle() {
-            return hasDonutType(c3.data.targets) ? __donut_title : "";
-        }
-        function getArcOnClick() {
-            var callback = hasDonutType(c3.data.targets) ? __donut_onclick : __pie_onclick;
-            return typeof callback === 'function' ? callback : function () {};
-        }
-        function getArcOnMouseOver() {
-            var callback = hasDonutType(c3.data.targets) ? __donut_onmouseover : __pie_onmouseover;
-            return typeof callback === 'function' ? callback : function () {};
-        }
-        function getArcOnMouseOut() {
-            var callback = hasDonutType(c3.data.targets) ? __donut_onmouseout : __pie_onmouseout;
-            return typeof callback === 'function' ? callback : function () {};
-        }
-
-        //-- Domain --//
-
-        function getYDomainMin(targets) {
-            var ids = mapToIds(targets), ys = getValuesAsIdKeyed(targets), j, k, baseId, idsInGroup, id, hasNegativeValue;
-            if (__data_groups.length > 0) {
-                hasNegativeValue = hasNegativeValueInTargets(targets);
-                for (j = 0; j < __data_groups.length; j++) {
-                    // Determine baseId
-                    idsInGroup = __data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
-                    if (idsInGroup.length === 0) { continue; }
-                    baseId = idsInGroup[0];
-                    // Consider negative values
-                    if (hasNegativeValue && ys[baseId]) {
-                        ys[baseId].forEach(function (v, i) {
-                            ys[baseId][i] = v < 0 ? v : 0;
-                        });
-                    }
-                    // Compute min
-                    for (k = 1; k < idsInGroup.length; k++) {
-                        id = idsInGroup[k];
-                        if (! ys[id]) { continue; }
-                        ys[id].forEach(function (v, i) {
-                            if (getAxisId(id) === getAxisId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
-                                ys[baseId][i] += +v;
-                            }
-                        });
-                    }
+        return $$.d3.min(Object.keys(ys).map(function (key) { return $$.d3.min(ys[key]); }));
+    };
+    c3_chart_internal_fn.getYDomainMax = function (targets) {
+        var $$ = this, config = $$.config,
+            ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+            j, k, baseId, idsInGroup, id, hasPositiveValue;
+        if (config.data_groups.length > 0) {
+            hasPositiveValue = $$.hasPositiveValueInTargets(targets);
+            for (j = 0; j < config.data_groups.length; j++) {
+                // Determine baseId
+                idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+                if (idsInGroup.length === 0) { continue; }
+                baseId = idsInGroup[0];
+                // Consider positive values
+                if (hasPositiveValue && ys[baseId]) {
+                    ys[baseId].forEach(function (v, i) {
+                        ys[baseId][i] = v > 0 ? v : 0;
+                    });
                 }
-            }
-            return d3.min(Object.keys(ys).map(function (key) { return d3.min(ys[key]); }));
-        }
-        function getYDomainMax(targets) {
-            var ids = mapToIds(targets), ys = getValuesAsIdKeyed(targets), j, k, baseId, idsInGroup, id, hasPositiveValue;
-            if (__data_groups.length > 0) {
-                hasPositiveValue = hasPositiveValueInTargets(targets);
-                for (j = 0; j < __data_groups.length; j++) {
-                    // Determine baseId
-                    idsInGroup = __data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
-                    if (idsInGroup.length === 0) { continue; }
-                    baseId = idsInGroup[0];
-                    // Consider positive values
-                    if (hasPositiveValue && ys[baseId]) {
-                        ys[baseId].forEach(function (v, i) {
-                            ys[baseId][i] = v > 0 ? v : 0;
-                        });
-                    }
-                    // Compute max
-                    for (k = 1; k < idsInGroup.length; k++) {
-                        id = idsInGroup[k];
-                        if (! ys[id]) { continue; }
-                        ys[id].forEach(function (v, i) {
-                            if (getAxisId(id) === getAxisId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
-                                ys[baseId][i] += +v;
-                            }
-                        });
-                    }
+                // Compute max
+                for (k = 1; k < idsInGroup.length; k++) {
+                    id = idsInGroup[k];
+                    if (! ys[id]) { continue; }
+                    ys[id].forEach(function (v, i) {
+                        if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
+                            ys[baseId][i] += +v;
+                        }
+                    });
                 }
             }
-            return d3.max(Object.keys(ys).map(function (key) { return d3.max(ys[key]); }));
-        }
-        function getYDomain(targets, axisId) {
-            var yTargets = targets.filter(function (d) { return getAxisId(d.id) === axisId; }),
-                yMin = axisId === 'y2' ? __axis_y2_min : __axis_y_min,
-                yMax = axisId === 'y2' ? __axis_y2_max : __axis_y_max,
-                yDomainMin = isValue(yMin) ? yMin : getYDomainMin(yTargets),
-                yDomainMax = isValue(yMax) ? yMax : getYDomainMax(yTargets),
-                domainLength, padding, padding_top, padding_bottom,
-                center = axisId === 'y2' ? __axis_y2_center : __axis_y_center,
-                yDomainAbs, widths, diff, ratio,
-                showHorizontalDataLabel = hasDataLabel() && __axis_rotated;
-            if (yTargets.length === 0) { // use current domain if target of axisId is none
-                return axisId === 'y2' ? y2.domain() : y.domain();
-            }
-            if (yDomainMin === yDomainMax) {
-                yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
-            }
-            domainLength = Math.abs(yDomainMax - yDomainMin);
-            padding = padding_top = padding_bottom = showHorizontalDataLabel ? 0 : domainLength * 0.1;
-            if (center) {
-                yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
-                yDomainMax = yDomainAbs - center;
-                yDomainMin = center - yDomainAbs;
-            }
-            // add padding for data label
-            if (showHorizontalDataLabel) {
-                widths = getDataLabelWidth(yDomainMin, yDomainMax);
-                diff = diffDomain(y.range());
-                ratio = [widths[0] / diff, widths[1] / diff];
-                padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
-                padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
-            }
-            if (axisId === 'y' && __axis_y_padding) {
-                padding_top = isValue(__axis_y_padding.top) ? __axis_y_padding.top : padding;
-                padding_bottom = isValue(__axis_y_padding.bottom) ? __axis_y_padding.bottom : padding;
-            }
-            if (axisId === 'y2' && __axis_y2_padding) {
-                padding_top = isValue(__axis_y2_padding.top) ? __axis_y2_padding.top : padding;
-                padding_bottom = isValue(__axis_y2_padding.bottom) ? __axis_y2_padding.bottom : padding;
-            }
-            // Bar chart with only positive values should be 0-based
-            if (hasBarType(yTargets) && !hasNegativeValueInTargets(yTargets)) {
-                padding_bottom = yDomainMin;
-            }
-            return [yDomainMin - padding_bottom, yDomainMax + padding_top];
-        }
-        function getXDomainMin(targets) {
-            return __axis_x_min ? (isTimeSeries ? parseDate(__axis_x_min) : __axis_x_min) : d3.min(targets, function (t) { return d3.min(t.values, function (v) { return v.x; }); });
-        }
-        function getXDomainMax(targets) {
-            return __axis_x_max ? (isTimeSeries ? parseDate(__axis_x_max) : __axis_x_max) : d3.max(targets, function (t) { return d3.max(t.values, function (v) { return v.x; }); });
-        }
-        function getXDomainPadding(targets) {
-            var edgeX = getEdgeX(targets), diff = edgeX[1] - edgeX[0],
-                maxDataCount, padding, paddingLeft, paddingRight;
-            if (isCategorized) {
-                padding = 0;
-            } else if (hasBarType(targets)) {
-                maxDataCount = getMaxDataCount();
-                padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
-            } else {
-                padding = diff * 0.01;
-            }
-            if (typeof __axis_x_padding === 'object' && notEmpty(__axis_x_padding)) {
-                paddingLeft = isValue(__axis_x_padding.left) ? __axis_x_padding.left : padding;
-                paddingRight = isValue(__axis_x_padding.right) ? __axis_x_padding.right : padding;
-            } else if (typeof __axis_x_padding === 'number') {
-                paddingLeft = paddingRight = __axis_x_padding;
+        }
+        return $$.d3.max(Object.keys(ys).map(function (key) { return $$.d3.max(ys[key]); }));
+    };
+    c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
+        var $$ = this, config = $$.config,
+            targetsByAxisId = targets.filter(function (t) { return $$.getAxisId(t.id) === axisId; }),
+            yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
+            yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
+            yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
+            yDomainMin = isValue(yMin) ? yMin : $$.getYDomainMin(yTargets),
+            yDomainMax = isValue(yMax) ? yMax : $$.getYDomainMax(yTargets),
+            domainLength, padding, padding_top, padding_bottom,
+            center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
+            yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative,
+            isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
+            showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
+            showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
+
+        if (yDomainMax < yDomainMin) {
+            if (isValue(yMin)) {
+                yDomainMax = yDomainMin + 10; // TODO: introduce axis.y.maxMin
             } else {
-                paddingLeft = paddingRight = padding;
+                yDomainMin = yDomainMax - 10; // TODO: introduce axis.y.minMax
             }
-            return {left: paddingLeft, right: paddingRight};
-        }
-        function getXDomain(targets) {
-            var xDomain = [getXDomainMin(targets), getXDomainMax(targets)],
-                firstX = xDomain[0], lastX = xDomain[1],
-                padding = getXDomainPadding(targets),
-                min = 0, max = 0;
-            // show center of x domain if min and max are the same
-            if ((firstX - lastX) === 0) {
-                firstX = isTimeSeries ? new Date(firstX.getTime() * 0.5) : -0.5;
-                lastX = isTimeSeries ? new Date(lastX.getTime() * 1.5) : 0.5;
-            }
-            if (firstX || firstX === 0) {
-                min = isTimeSeries ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
-            }
-            if (lastX || lastX === 0) {
-                max = isTimeSeries ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
-            }
-            return [min, max];
-        }
-        function diffDomain(d) {
-            return d[1] - d[0];
         }
 
-        //-- Cache --//
-
-        function hasCaches(ids) {
-            for (var i = 0; i < ids.length; i++) {
-                if (! (ids[i] in cache)) { return false; }
-            }
-            return true;
+        if (yTargets.length === 0) { // use current domain if target of axisId is none
+            return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
         }
-        function addCache(id, target) {
-            cache[id] = cloneTarget(target);
+        if (isNaN(yDomainMin)) { // set minimum to zero when not number
+            yDomainMin = 0;
         }
-        function getCaches(ids) {
-            var targets = [];
-            for (var i = 0; i < ids.length; i++) {
-                if (ids[i] in cache) { targets.push(cloneTarget(cache[ids[i]])); }
-            }
-            return targets;
+        if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin
+            yDomainMax = yDomainMin;
+        }
+        if (yDomainMin === yDomainMax) {
+            yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
         }
+        isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
+        isAllNegative = yDomainMin <= 0 && yDomainMax <= 0;
 
-        //-- Regions --//
+        // Cancel zerobased if axis_*_min / axis_*_max specified
+        if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) {
+            isZeroBased = false;
+        }
 
-        function regionX(d) {
-            var xPos, yScale = d.axis === 'y' ? y : y2;
-            if (d.axis === 'y' || d.axis === 'y2') {
-                xPos = __axis_rotated ? ('start' in d ? yScale(d.start) : 0) : 0;
-            } else {
-                xPos = __axis_rotated ? 0 : ('start' in d ? x(isTimeSeries ? parseDate(d.start) : d.start) : 0);
-            }
-            return xPos;
+        // Bar/Area chart should be 0-based if all positive|negative
+        if (isZeroBased) {
+            if (isAllPositive) { yDomainMin = 0; }
+            if (isAllNegative) { yDomainMax = 0; }
         }
-        function regionY(d) {
-            var yPos, yScale = d.axis === 'y' ? y : y2;
-            if (d.axis === 'y' || d.axis === 'y2') {
-                yPos = __axis_rotated ? 0 : ('end' in d ? yScale(d.end) : 0);
-            } else {
-                yPos = __axis_rotated ? ('start' in d ? x(isTimeSeries ? parseDate(d.start) : d.start) : 0) : 0;
-            }
-            return yPos;
+
+        domainLength = Math.abs(yDomainMax - yDomainMin);
+        padding = padding_top = padding_bottom = domainLength * 0.1;
+
+        if (center) {
+            yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
+            yDomainMax = yDomainAbs - center;
+            yDomainMin = center - yDomainAbs;
         }
-        function regionWidth(d) {
-            var start = regionX(d), end, yScale = d.axis === 'y' ? y : y2;
-            if (d.axis === 'y' || d.axis === 'y2') {
-                end = __axis_rotated ? ('end' in d ? yScale(d.end) : width) : width;
-            } else {
-                end = __axis_rotated ? width : ('end' in d ? x(isTimeSeries ? parseDate(d.end) : d.end) : width);
-            }
-            return end < start ? 0 : end - start;
+        // add padding for data label
+        if (showHorizontalDataLabel) {
+            lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'width');
+            diff = diffDomain($$.y.range());
+            ratio = [lengths[0] / diff, lengths[1] / diff];
+            padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
+            padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
+        } else if (showVerticalDataLabel) {
+            lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'height');
+            padding_top += lengths[1];
+            padding_bottom += lengths[0];
+        }
+        if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
+            padding_top = $$.getAxisPadding(config.axis_y_padding, 'top', padding, domainLength);
+            padding_bottom = $$.getAxisPadding(config.axis_y_padding, 'bottom', padding, domainLength);
         }
-        function regionHeight(d) {
-            var start = regionY(d), end, yScale = d.axis === 'y' ? y : y2;
-            if (d.axis === 'y' || d.axis === 'y2') {
-                end = __axis_rotated ? height : ('start' in d ? yScale(d.start) : height);
+        if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
+            padding_top = $$.getAxisPadding(config.axis_y2_padding, 'top', padding, domainLength);
+            padding_bottom = $$.getAxisPadding(config.axis_y2_padding, 'bottom', padding, domainLength);
+        }
+        // Bar/Area chart should be 0-based if all positive|negative
+        if (isZeroBased) {
+            if (isAllPositive) { padding_bottom = yDomainMin; }
+            if (isAllNegative) { padding_top = -yDomainMax; }
+        }
+        return [yDomainMin - padding_bottom, yDomainMax + padding_top];
+    };
+    c3_chart_internal_fn.getXDomainMin = function (targets) {
+        var $$ = this, config = $$.config;
+        return isDefined(config.axis_x_min) ?
+            ($$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min) :
+        $$.d3.min(targets, function (t) { return $$.d3.min(t.values, function (v) { return v.x; }); });
+    };
+    c3_chart_internal_fn.getXDomainMax = function (targets) {
+        var $$ = this, config = $$.config;
+        return isDefined(config.axis_x_max) ?
+            ($$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max) :
+        $$.d3.max(targets, function (t) { return $$.d3.max(t.values, function (v) { return v.x; }); });
+    };
+    c3_chart_internal_fn.getXDomainPadding = function (domain) {
+        var $$ = this, config = $$.config,
+            diff = domain[1] - domain[0],
+            maxDataCount, padding, paddingLeft, paddingRight;
+        if ($$.isCategorized()) {
+            padding = 0;
+        } else if ($$.hasType('bar')) {
+            maxDataCount = $$.getMaxDataCount();
+            padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
+        } else {
+            padding = diff * 0.01;
+        }
+        if (typeof config.axis_x_padding === 'object' && notEmpty(config.axis_x_padding)) {
+            paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding;
+            paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding;
+        } else if (typeof config.axis_x_padding === 'number') {
+            paddingLeft = paddingRight = config.axis_x_padding;
+        } else {
+            paddingLeft = paddingRight = padding;
+        }
+        return {left: paddingLeft, right: paddingRight};
+    };
+    c3_chart_internal_fn.getXDomain = function (targets) {
+        var $$ = this,
+            xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
+            firstX = xDomain[0], lastX = xDomain[1],
+            padding = $$.getXDomainPadding(xDomain),
+            min = 0, max = 0;
+        // show center of x domain if min and max are the same
+        if ((firstX - lastX) === 0 && !$$.isCategorized()) {
+            if ($$.isTimeSeries()) {
+                firstX = new Date(firstX.getTime() * 0.5);
+                lastX = new Date(lastX.getTime() * 1.5);
             } else {
-                end = __axis_rotated ? ('end' in d ? x(isTimeSeries ? parseDate(d.end) : d.end) : height) : height;
+                firstX = firstX === 0 ? 1 : (firstX * 0.5);
+                lastX = lastX === 0 ? -1 : (lastX * 1.5);
             }
-            return end < start ? 0 : end - start;
         }
+        if (firstX || firstX === 0) {
+            min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
+        }
+        if (lastX || lastX === 0) {
+            max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
+        }
+        return [min, max];
+    };
+    c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
+        var $$ = this, config = $$.config;
 
-        //-- Data --//
-
-        function isX(key) {
-            return (__data_x && key === __data_x) || (notEmpty(__data_xs) && hasValue(__data_xs, key));
+        if (withUpdateOrgXDomain) {
+            $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
+            $$.orgXDomain = $$.x.domain();
+            if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
+            $$.subX.domain($$.x.domain());
+            if ($$.brush) { $$.brush.scale($$.subX); }
         }
-        function isNotX(key) {
-            return !isX(key);
+        if (withUpdateXDomain) {
+            $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent());
+            if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
         }
-        function getXKey(id) {
-            return __data_x ? __data_x : notEmpty(__data_xs) ? __data_xs[id] : null;
+
+        // Trim domain when too big by zoom mousemove event
+        if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); }
+
+        return $$.x.domain();
+    };
+    c3_chart_internal_fn.trimXDomain = function (domain) {
+        var $$ = this;
+        if (domain[0] <= $$.orgXDomain[0]) {
+            domain[1] = +domain[1] + ($$.orgXDomain[0] - domain[0]);
+            domain[0] = $$.orgXDomain[0];
         }
-        function getXValuesOfXKey(key, targets) {
-            var xValues, ids = targets && notEmpty(targets) ? mapToIds(targets) : [];
-            ids.forEach(function (id) {
-                if (getXKey(id) === key) {
-                    xValues = c3.data.xs[id];
-                }
-            });
-            return xValues;
+        if ($$.orgXDomain[1] <= domain[1]) {
+            domain[0] = +domain[0] - (domain[1] - $$.orgXDomain[1]);
+            domain[1] = $$.orgXDomain[1];
         }
-        function getXValue(id, i) {
-            return id in c3.data.xs && c3.data.xs[id] && c3.data.xs[id][i] ? c3.data.xs[id][i] : i;
+        return domain;
+    };
+
+    c3_chart_internal_fn.isX = function (key) {
+        var $$ = this, config = $$.config;
+        return (config.data_x && key === config.data_x) || (notEmpty(config.data_xs) && hasValue(config.data_xs, key));
+    };
+    c3_chart_internal_fn.isNotX = function (key) {
+        return !this.isX(key);
+    };
+    c3_chart_internal_fn.getXKey = function (id) {
+        var $$ = this, config = $$.config;
+        return config.data_x ? config.data_x : notEmpty(config.data_xs) ? config.data_xs[id] : null;
+    };
+    c3_chart_internal_fn.getXValuesOfXKey = function (key, targets) {
+        var $$ = this,
+            xValues, ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : [];
+        ids.forEach(function (id) {
+            if ($$.getXKey(id) === key) {
+                xValues = $$.data.xs[id];
+            }
+        });
+        return xValues;
+    };
+    c3_chart_internal_fn.getIndexByX = function (x) {
+        var $$ = this,
+            data = $$.filterByX($$.data.targets, x);
+        return data.length ? data[0].index : null;
+    };
+    c3_chart_internal_fn.getXValue = function (id, i) {
+        var $$ = this;
+        return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
+    };
+    c3_chart_internal_fn.getOtherTargetXs = function () {
+        var $$ = this,
+            idsForX = Object.keys($$.data.xs);
+        return idsForX.length ? $$.data.xs[idsForX[0]] : null;
+    };
+    c3_chart_internal_fn.getOtherTargetX = function (index) {
+        var xs = this.getOtherTargetXs();
+        return xs && index < xs.length ? xs[index] : null;
+    };
+    c3_chart_internal_fn.addXs = function (xs) {
+        var $$ = this;
+        Object.keys(xs).forEach(function (id) {
+            $$.config.data_xs[id] = xs[id];
+        });
+    };
+    c3_chart_internal_fn.hasMultipleX = function (xs) {
+        return this.d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() > 1;
+    };
+    c3_chart_internal_fn.isMultipleX = function () {
+        return notEmpty(this.config.data_xs) || !this.config.data_xSort || this.hasType('scatter');
+    };
+    c3_chart_internal_fn.addName = function (data) {
+        var $$ = this, name;
+        if (data) {
+            name = $$.config.data_names[data.id];
+            data.name = name ? name : data.id;
         }
-        function addXs(xs) {
-            Object.keys(xs).forEach(function (id) {
-                __data_xs[id] = xs[id];
+        return data;
+    };
+    c3_chart_internal_fn.getValueOnIndex = function (values, index) {
+        var valueOnIndex = values.filter(function (v) { return v.index === index; });
+        return valueOnIndex.length ? valueOnIndex[0] : null;
+    };
+    c3_chart_internal_fn.updateTargetX = function (targets, x) {
+        var $$ = this;
+        targets.forEach(function (t) {
+            t.values.forEach(function (v, i) {
+                v.x = $$.generateTargetX(x[i], t.id, i);
             });
+            $$.data.xs[t.id] = x;
+        });
+    };
+    c3_chart_internal_fn.updateTargetXs = function (targets, xs) {
+        var $$ = this;
+        targets.forEach(function (t) {
+            if (xs[t.id]) {
+                $$.updateTargetX([t], xs[t.id]);
+            }
+        });
+    };
+    c3_chart_internal_fn.generateTargetX = function (rawX, id, index) {
+        var $$ = this, x;
+        if ($$.isTimeSeries()) {
+            x = rawX ? $$.parseDate(rawX) : $$.parseDate($$.getXValue(id, index));
         }
-        function isSingleX(xs) {
-            return d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() === 1;
+        else if ($$.isCustomX() && !$$.isCategorized()) {
+            x = isValue(rawX) ? +rawX : $$.getXValue(id, index);
         }
-
-        function addName(data) {
-            var name;
-            if (data) {
-                name = __data_names[data.id];
-                data.name = name ? name : data.id;
-            }
-            return data;
+        else {
+            x = index;
         }
-
-        function updateTargetX(targets, x) {
-            targets.forEach(function (t) {
-                t.values.forEach(function (v, i) {
-                    v.x = generateTargetX(x[i], t.id, i);
-                });
-                c3.data.xs[t.id] = x;
+        return x;
+    };
+    c3_chart_internal_fn.cloneTarget = function (target) {
+        return {
+            id : target.id,
+            id_org : target.id_org,
+            values : target.values.map(function (d) {
+                return {x: d.x, value: d.value, id: d.id};
+            })
+        };
+    };
+    c3_chart_internal_fn.updateXs = function () {
+        var $$ = this;
+        if ($$.data.targets.length) {
+            $$.xs = [];
+            $$.data.targets[0].values.forEach(function (v) {
+                $$.xs[v.index] = v.x;
             });
         }
-        function updateTargetXs(targets, xs) {
+    };
+    c3_chart_internal_fn.getPrevX = function (i) {
+        var x = this.xs[i - 1];
+        return typeof x !== 'undefined' ? x : null;
+    };
+    c3_chart_internal_fn.getNextX = function (i) {
+        var x = this.xs[i + 1];
+        return typeof x !== 'undefined' ? x : null;
+    };
+    c3_chart_internal_fn.getMaxDataCount = function () {
+        var $$ = this;
+        return $$.d3.max($$.data.targets, function (t) { return t.values.length; });
+    };
+    c3_chart_internal_fn.getMaxDataCountTarget = function (targets) {
+        var length = targets.length, max = 0, maxTarget;
+        if (length > 1) {
             targets.forEach(function (t) {
-                if (xs[t.id]) {
-                    updateTargetX([t], xs[t.id]);
+                if (t.values.length > max) {
+                    maxTarget = t;
+                    max = t.values.length;
                 }
             });
+        } else {
+            maxTarget = length ? targets[0] : null;
         }
-        function generateTargetX(rawX, id, index) {
-            var x;
-            if (isTimeSeries) {
-                x = rawX ? rawX instanceof Date ? rawX : parseDate(rawX) : parseDate(getXValue(id, index));
-            }
-            else if (isCustomX && !isCategorized) {
-                x = isValue(rawX) ? +rawX : getXValue(id, index);
-            }
-            else {
-                x = index;
+        return maxTarget;
+    };
+    c3_chart_internal_fn.getEdgeX = function (targets) {
+        var $$ = this;
+        return !targets.length ? [0, 0] : [
+            $$.d3.min(targets, function (t) { return t.values[0].x; }),
+            $$.d3.max(targets, function (t) { return t.values[t.values.length - 1].x; })
+        ];
+    };
+    c3_chart_internal_fn.mapToIds = function (targets) {
+        return targets.map(function (d) { return d.id; });
+    };
+    c3_chart_internal_fn.mapToTargetIds = function (ids) {
+        var $$ = this;
+        return ids ? (isString(ids) ? [ids] : ids) : $$.mapToIds($$.data.targets);
+    };
+    c3_chart_internal_fn.hasTarget = function (targets, id) {
+        var ids = this.mapToIds(targets), i;
+        for (i = 0; i < ids.length; i++) {
+            if (ids[i] === id) {
+                return true;
             }
-            return x;
-        }
-        function convertRowsToData(rows) {
-            var keys = rows[0], new_row = {}, new_rows = [], i, j;
-            for (i = 1; i < rows.length; i++) {
-                new_row = {};
-                for (j = 0; j < rows[i].length; j++) {
-                    new_row[keys[j]] = rows[i][j];
+        }
+        return false;
+    };
+    c3_chart_internal_fn.isTargetToShow = function (targetId) {
+        return this.hiddenTargetIds.indexOf(targetId) < 0;
+    };
+    c3_chart_internal_fn.isLegendToShow = function (targetId) {
+        return this.hiddenLegendIds.indexOf(targetId) < 0;
+    };
+    c3_chart_internal_fn.filterTargetsToShow = function (targets) {
+        var $$ = this;
+        return targets.filter(function (t) { return $$.isTargetToShow(t.id); });
+    };
+    c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
+        var $$ = this;
+        var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
+        return $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
+    };
+    c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
+        this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
+    };
+    c3_chart_internal_fn.removeHiddenTargetIds = function (targetIds) {
+        this.hiddenTargetIds = this.hiddenTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+    };
+    c3_chart_internal_fn.addHiddenLegendIds = function (targetIds) {
+        this.hiddenLegendIds = this.hiddenLegendIds.concat(targetIds);
+    };
+    c3_chart_internal_fn.removeHiddenLegendIds = function (targetIds) {
+        this.hiddenLegendIds = this.hiddenLegendIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+    };
+    c3_chart_internal_fn.getValuesAsIdKeyed = function (targets) {
+        var ys = {};
+        targets.forEach(function (t) {
+            ys[t.id] = [];
+            t.values.forEach(function (v) {
+                ys[t.id].push(v.value);
+            });
+        });
+        return ys;
+    };
+    c3_chart_internal_fn.checkValueInTargets = function (targets, checker) {
+        var ids = Object.keys(targets), i, j, values;
+        for (i = 0; i < ids.length; i++) {
+            values = targets[ids[i]].values;
+            for (j = 0; j < values.length; j++) {
+                if (checker(values[j].value)) {
+                    return true;
                 }
-                new_rows.push(new_row);
             }
-            return new_rows;
-        }
-        function convertColumnsToData(columns) {
-            var new_rows = [], i, j, key;
-            for (i = 0; i < columns.length; i++) {
-                key = columns[i][0];
-                for (j = 1; j < columns[i].length; j++) {
-                    if (isUndefined(new_rows[j - 1])) {
-                        new_rows[j - 1] = {};
-                    }
-                    new_rows[j - 1][key] = columns[i][j];
-                }
-            }
-            return new_rows;
         }
-        function convertDataToTargets(data) {
-            var ids = d3.keys(data[0]).filter(isNotX), xs = d3.keys(data[0]).filter(isX), targets;
-
-            // save x for update data by load when custom x and c3.x API
-            ids.forEach(function (id) {
-                var xKey = getXKey(id), idsForX;
-
-                if (isCustomX || isTimeSeries) {
-                    // if included in input data
-                    if (xs.indexOf(xKey) >= 0) {
-                        c3.data.xs[id] = data.map(function (d) { return d[xKey]; }).filter(isValue);
-                    }
-                    // if not included in input data, find from preloaded data of other id's x
-                    else if (__data_x) {
-                        idsForX = Object.keys(c3.data.xs);
-                        c3.data.xs[id] = idsForX.length > 0 ? c3.data.xs[idsForX[0]] : undefined;
-                    }
-                    // if not included in input data, find from preloaded data
-                    else if (notEmpty(__data_xs)) {
-                        c3.data.xs[id] = getXValuesOfXKey(xKey, c3.data.targets);
-                    }
-                    // MEMO: if no x included, use same x of current will be used
-                } else {
-                    c3.data.xs[id] = data.map(function (d, i) { return i; });
-                }
+        return false;
+    };
+    c3_chart_internal_fn.hasNegativeValueInTargets = function (targets) {
+        return this.checkValueInTargets(targets, function (v) { return v < 0; });
+    };
+    c3_chart_internal_fn.hasPositiveValueInTargets = function (targets) {
+        return this.checkValueInTargets(targets, function (v) { return v > 0; });
+    };
+    c3_chart_internal_fn.isOrderDesc = function () {
+        var config = this.config;
+        return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'desc';
+    };
+    c3_chart_internal_fn.isOrderAsc = function () {
+        var config = this.config;
+        return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'asc';
+    };
+    c3_chart_internal_fn.orderTargets = function (targets) {
+        var $$ = this, config = $$.config, orderAsc = $$.isOrderAsc(), orderDesc = $$.isOrderDesc();
+        if (orderAsc || orderDesc) {
+            targets.sort(function (t1, t2) {
+                var reducer = function (p, c) { return p + Math.abs(c.value); };
+                var t1Sum = t1.values.reduce(reducer, 0),
+                    t2Sum = t2.values.reduce(reducer, 0);
+                return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
             });
+        } else if (isFunction(config.data_order)) {
+            targets.sort(config.data_order);
+        } // TODO: accept name array for order
+        return targets;
+    };
+    c3_chart_internal_fn.filterByX = function (targets, x) {
+        return this.d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
+    };
+    c3_chart_internal_fn.filterRemoveNull = function (data) {
+        return data.filter(function (d) { return isValue(d.value); });
+    };
+    c3_chart_internal_fn.filterByXDomain = function (targets, xDomain) {
+        return targets.map(function (t) {
+            return {
+                id: t.id,
+                id_org: t.id_org,
+                values: t.values.filter(function (v) {
+                    return xDomain[0] <= v.x && v.x <= xDomain[1];
+                })
+            };
+        });
+    };
+    c3_chart_internal_fn.hasDataLabel = function () {
+        var config = this.config;
+        if (typeof config.data_labels === 'boolean' && config.data_labels) {
+            return true;
+        } else if (typeof config.data_labels === 'object' && notEmpty(config.data_labels)) {
+            return true;
+        }
+        return false;
+    };
+    c3_chart_internal_fn.getDataLabelLength = function (min, max, axisId, key) {
+        var $$ = this,
+            lengths = [0, 0], paddingCoef = 1.3;
+        $$.selectChart.select('svg').selectAll('.dummy')
+            .data([min, max])
+            .enter().append('text')
+            .text(function (d) { return $$.formatByAxisId(axisId)(d); })
+            .each(function (d, i) {
+                lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
+            })
+            .remove();
+        return lengths;
+    };
+    c3_chart_internal_fn.isNoneArc = function (d) {
+        return this.hasTarget(this.data.targets, d.id);
+    },
+    c3_chart_internal_fn.isArc = function (d) {
+        return 'data' in d && this.hasTarget(this.data.targets, d.data.id);
+    };
+    c3_chart_internal_fn.findSameXOfValues = function (values, index) {
+        var i, targetX = values[index].x, sames = [];
+        for (i = index - 1; i >= 0; i--) {
+            if (targetX !== values[i].x) { break; }
+            sames.push(values[i]);
+        }
+        for (i = index; i < values.length; i++) {
+            if (targetX !== values[i].x) { break; }
+            sames.push(values[i]);
+        }
+        return sames;
+    };
 
-            // check x is defined
-            ids.forEach(function (id) {
-                if (!c3.data.xs[id]) {
-                    throw new Error('x is not defined for id = "' + id + '".');
-                }
-            });
+    c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
+        var $$ = this, candidates;
 
-            // convert to target
-            targets = ids.map(function (id, index) {
-                var convertedId = __data_id_converter(id);
-                return {
-                    id: convertedId,
-                    id_org: id,
-                    values: data.map(function (d, i) {
-                        var xKey = getXKey(id), rawX = d[xKey], x = generateTargetX(rawX, id, i);
-                        // use x as categories if custom x and categorized
-                        if (isCustomX && isCategorized && index === 0 && rawX) {
-                            if (i === 0) { __axis_x_categories = []; }
-                            __axis_x_categories.push(rawX);
-                        }
-                        // mark as x = undefined if value is undefined and filter to remove after mapped
-                        if (typeof d[id] === 'undefined' || c3.data.xs[id].length <= i) {
-                            x = undefined;
-                        }
-                        return {x: x, value: d[id] !== null && !isNaN(d[id]) ? +d[id] : null, id: convertedId};
-                    }).filter(function (v) { return typeof v.x !== 'undefined'; })
-                };
-            });
+        // map to array of closest points of each target
+        candidates = targets.map(function (target) {
+            return $$.findClosest(target.values, pos);
+        });
 
-            // finish targets
-            targets.forEach(function (t) {
-                var i;
-                // sort values by its x
-                t.values = t.values.sort(function (v1, v2) {
-                    var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
-                        x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
-                    return x1 - x2;
-                });
-                // indexing each value
-                i = 0;
-                t.values.forEach(function (v) {
-                    v.index = i++;
-                });
-            });
+        // decide closest point and return
+        return $$.findClosest(candidates, pos);
+    };
+    c3_chart_internal_fn.findClosest = function (values, pos) {
+        var $$ = this, minDist = 100, closest;
+
+        // find mouseovering bar
+        values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
+            var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
+            if (!closest && $$.isWithinBar(shape)) {
+                closest = v;
+            }
+        });
 
-            // set target types
-            if (__data_type) {
-                setTargetType(mapToIds(targets).filter(function (id) { return ! (id in __data_types); }), __data_type);
+        // find closest point from non-bar
+        values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
+            var d = $$.dist(v, pos);
+            if (d < minDist) {
+                minDist = d;
+                closest = v;
             }
+        });
 
-            // cache as original id keyed
-            targets.forEach(function (d) {
-                addCache(d.id_org, d);
-            });
+        return closest;
+    };
+    c3_chart_internal_fn.dist = function (data, pos) {
+        var $$ = this, config = $$.config,
+            xIndex = config.axis_rotated ? 1 : 0,
+            yIndex = config.axis_rotated ? 0 : 1,
+            y = $$.circleY(data, data.index),
+            x = $$.x(data.x);
+        return Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2);
+    };
+    c3_chart_internal_fn.convertValuesToStep = function (values) {
+        var converted = [].concat(values), i;
 
-            return targets;
-        }
-        function cloneTarget(target) {
-            return {
-                id : target.id,
-                id_org : target.id_org,
-                values : target.values.map(function (d) {
-                    return {x: d.x, value: d.value, id: d.id};
-                })
-            };
-        }
-        function getPrevX(i) {
-            return i > 0 && c3.data.targets[0].values[i - 1] ? c3.data.targets[0].values[i - 1].x : undefined;
-        }
-        function getNextX(i) {
-            return i < getMaxDataCount() - 1 ? c3.data.targets[0].values[i + 1].x : undefined;
+        if (!this.isCategorized()) {
+            return values;
         }
-        function getMaxDataCount() {
-            return d3.max(c3.data.targets, function (t) { return t.values.length; });
+
+        for (i = values.length + 1; 0 < i; i--) {
+            converted[i] = converted[i - 1];
         }
-        function getMaxDataCountTarget(targets) {
-            var length = targets.length, max = 0, maxTarget;
-            if (length > 1) {
-                targets.forEach(function (t) {
-                    if (t.values.length > max) {
-                        maxTarget = t;
-                        max = t.values.length;
-                    }
-                });
+
+        converted[0] = {
+            x: converted[0].x - 1,
+            value: converted[0].value,
+            id: converted[0].id
+        };
+        converted[values.length + 1] = {
+            x: converted[values.length].x + 1,
+            value: converted[values.length].value,
+            id: converted[values.length].id
+        };
+
+        return converted;
+    };
+    c3_chart_internal_fn.updateDataAttributes = function (name, attrs) {
+        var $$ = this, config = $$.config, current = config['data_' + name];
+        if (typeof attrs === 'undefined') { return current; }
+        Object.keys(attrs).forEach(function (id) {
+            current[id] = attrs[id];
+        });
+        $$.redraw({withLegend: true});
+        return current;
+    };
+
+    c3_chart_internal_fn.convertUrlToData = function (url, mimeType, keys, done) {
+        var $$ = this, type = mimeType ? mimeType : 'csv';
+        $$.d3.xhr(url, function (error, data) {
+            var d;
+            if (type === 'json') {
+                d = $$.convertJsonToData(JSON.parse(data.response), keys);
+            } else if (type === 'tsv') {
+                d = $$.convertTsvToData(data.response);
             } else {
-                maxTarget = length ? targets[0] : null;
+                d = $$.convertCsvToData(data.response);
             }
-            return maxTarget;
-        }
-        function getEdgeX(targets) {
-            var target = getMaxDataCountTarget(targets), firstData, lastData;
-            if (!target) {
-                return [0, 0];
-            }
-            firstData = target.values[0], lastData = target.values[target.values.length - 1];
-            return [firstData.x, lastData.x];
-        }
-        function mapToIds(targets) {
-            return targets.map(function (d) { return d.id; });
+            done.call($$, d);
+        });
+    };
+    c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
+        var rows = parser.parseRows(xsv), d;
+        if (rows.length === 1) {
+            d = [{}];
+            rows[0].forEach(function (id) {
+                d[0][id] = null;
+            });
+        } else {
+            d = parser.parse(xsv);
         }
-        function mapToTargetIds(ids) {
-            return ids ? (typeof ids === 'string' ? [ids] : ids) : mapToIds(c3.data.targets);
+        return d;
+    };
+    c3_chart_internal_fn.convertCsvToData = function (csv) {
+        return this.convertXsvToData(csv, this.d3.csv);
+    };
+    c3_chart_internal_fn.convertTsvToData = function (tsv) {
+        return this.convertXsvToData(tsv, this.d3.tsv);
+    };
+    c3_chart_internal_fn.convertJsonToData = function (json, keys) {
+        var $$ = this,
+            new_rows = [], targetKeys, data;
+        if (keys) { // when keys specified, json would be an array that includes objects
+            targetKeys = keys.value;
+            if (keys.x) {
+                targetKeys.push(keys.x);
+                $$.config.data_x = keys.x;
+            }
+            new_rows.push(targetKeys);
+            json.forEach(function (o) {
+                var new_row = [];
+                targetKeys.forEach(function (key) {
+                    // convert undefined to null because undefined data will be removed in convertDataToTargets()
+                    var v = isUndefined(o[key]) ? null : o[key];
+                    new_row.push(v);
+                });
+                new_rows.push(new_row);
+            });
+            data = $$.convertRowsToData(new_rows);
+        } else {
+            Object.keys(json).forEach(function (key) {
+                new_rows.push([key].concat(json[key]));
+            });
+            data = $$.convertColumnsToData(new_rows);
         }
-        function hasTarget(targets, id) {
-            var ids = mapToIds(targets), i;
-            for (i = 0; i < ids.length; i++) {
-                if (ids[i] === id) {
-                    return true;
+        return data;
+    };
+    c3_chart_internal_fn.convertRowsToData = function (rows) {
+        var keys = rows[0], new_row = {}, new_rows = [], i, j;
+        for (i = 1; i < rows.length; i++) {
+            new_row = {};
+            for (j = 0; j < rows[i].length; j++) {
+                if (isUndefined(rows[i][j])) {
+                    throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
                 }
+                new_row[keys[j]] = rows[i][j];
             }
-            return false;
+            new_rows.push(new_row);
         }
-        function getTargets(filter) {
-            return isDefined(filter) ? c3.data.targets.filter(filter) : c3.data.targets;
-        }
-        function isTargetToShow(targetId) {
-            return hiddenTargetIds.indexOf(targetId) < 0;
-        }
-        function isLegendToShow(targetId) {
-            return hiddenLegendIds.indexOf(targetId) < 0;
-        }
-        function filterTargetsToShow(targets) {
-            return targets.filter(function (t) { return isTargetToShow(t.id); });
-        }
-        function mapTargetsToUniqueXs(targets) {
-            var xs = d3.set(d3.merge(targets.map(function (t) { return t.values.map(function (v) { return v.x; }); }))).values();
-            return isTimeSeries ? xs.map(function (x) { return new Date(x); }) : xs.map(function (x) { return +x; });
-        }
-        function generateTickValues(xs, tickCount) {
-            var tickValues = xs, targetCount, start, end, count, interval, i, tickValue;
-            if (tickCount) {
-                targetCount = typeof tickCount === 'function' ? tickCount() : tickCount;
-                // compute ticks according to __axis_x_tick_count
-                if (targetCount === 1) {
-                    tickValues = [xs[0]];
-                } else if (targetCount === 2) {
-                    tickValues = [xs[0], xs[xs.length - 1]];
-                } else if (targetCount > 2) {
-                    count = targetCount - 2;
-                    start = xs[0];
-                    end = xs[xs.length - 1];
-                    interval = (end - start) / (count + 1);
-                    // re-construct uniqueXs
-                    tickValues = [start];
-                    for (i = 0; i < count; i++) {
-                        tickValue = +start + interval * (i + 1);
-                        tickValues.push(isTimeSeries ? new Date(tickValue) : tickValue);
-                    }
-                    tickValues.push(end);
+        return new_rows;
+    };
+    c3_chart_internal_fn.convertColumnsToData = function (columns) {
+        var new_rows = [], i, j, key;
+        for (i = 0; i < columns.length; i++) {
+            key = columns[i][0];
+            for (j = 1; j < columns[i].length; j++) {
+                if (isUndefined(new_rows[j - 1])) {
+                    new_rows[j - 1] = {};
                 }
-            }
-            if (!isTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
-            return tickValues;
-        }
-        function addHiddenTargetIds(targetIds) {
-            hiddenTargetIds = hiddenTargetIds.concat(targetIds);
-        }
-        function removeHiddenTargetIds(targetIds) {
-            hiddenTargetIds = hiddenTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
-        }
-        function addHiddenLegendIds(targetIds) {
-            hiddenLegendIds = hiddenLegendIds.concat(targetIds);
-        }
-        function removeHiddenLegendIds(targetIds) {
-            hiddenLegendIds = hiddenLegendIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
-        }
-        function getValuesAsIdKeyed(targets) {
-            var ys = {};
-            targets.forEach(function (t) {
-                ys[t.id] = [];
-                t.values.forEach(function (v) {
-                    ys[t.id].push(v.value);
-                });
-            });
-            return ys;
-        }
-        function checkValueInTargets(targets, checker) {
-            var ids = Object.keys(targets), i, j, values;
-            for (i = 0; i < ids.length; i++) {
-                values = targets[ids[i]].values;
-                for (j = 0; j < values.length; j++) {
-                    if (checker(values[j].value)) {
-                        return true;
-                    }
+                if (isUndefined(columns[i][j])) {
+                    throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
                 }
+                new_rows[j - 1][key] = columns[i][j];
             }
-            return false;
         }
-        function hasNegativeValueInTargets(targets) {
-            return checkValueInTargets(targets, function (v) { return v < 0; });
-        }
-        function hasPositiveValueInTargets(targets) {
-            return checkValueInTargets(targets, function (v) { return v > 0; });
-        }
-        function categoryName(i) {
-            return i < __axis_x_categories.length ? __axis_x_categories[i] : i;
-        }
-        function generateClass(prefix, targetId) {
-            return " " + prefix + " " + prefix + getTargetSelectorSuffix(targetId);
-        }
-        function classText(d) { return generateClass(CLASS.text, d.id); }
-        function classTexts(d) { return generateClass(CLASS.texts, d.id); }
-        function classShape(d, i) { return generateClass(CLASS.shape, i); }
-        function classShapes(d) { return generateClass(CLASS.shapes, d.id); }
-        function classLine(d) { return classShape(d) + generateClass(CLASS.line, d.id); }
-        function classLines(d) { return classShapes(d) + generateClass(CLASS.lines, d.id); }
-        function classCircle(d, i) { return classShape(d, i) + generateClass(CLASS.circle, i); }
-        function classCircles(d) { return classShapes(d) + generateClass(CLASS.circles, d.id); }
-        function classBar(d, i) { return classShape(d, i) + generateClass(CLASS.bar, i); }
-        function classBars(d) { return classShapes(d) + generateClass(CLASS.bars, d.id); }
-        function classArc(d) { return classShape(d.data) + generateClass(CLASS.arc, d.data.id); }
-        function classArcs(d) { return classShapes(d.data) + generateClass(CLASS.arcs, d.data.id); }
-        function classArea(d) { return classShape(d) + generateClass(CLASS.area, d.id); }
-        function classAreas(d) { return classShapes(d) + generateClass(CLASS.areas, d.id); }
-        function classRegion(d, i) { return generateClass(CLASS.region, i) + ' ' + ('class' in d ? d.class : ''); }
-        function classEvent(d, i) { return generateClass(CLASS.eventRect, i); }
-        function classTarget(id) {
-            var additionalClassSuffix = __data_classes[id], additionalClass = '';
-            if (additionalClassSuffix) {
-                additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
+        return new_rows;
+    };
+    c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
+        var $$ = this, config = $$.config,
+            ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
+            xs = $$.d3.keys(data[0]).filter($$.isX, $$),
+            targets;
+
+        // save x for update data by load when custom x and c3.x API
+        ids.forEach(function (id) {
+            var xKey = $$.getXKey(id);
+
+            if ($$.isCustomX() || $$.isTimeSeries()) {
+                // if included in input data
+                if (xs.indexOf(xKey) >= 0) {
+                    $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
+                        data.map(function (d) { return d[xKey]; })
+                            .filter(isValue)
+                            .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
+                    );
+                }
+                // if not included in input data, find from preloaded data of other id's x
+                else if (config.data_x) {
+                    $$.data.xs[id] = $$.getOtherTargetXs();
+                }
+                // if not included in input data, find from preloaded data
+                else if (notEmpty(config.data_xs)) {
+                    $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
+                }
+                // MEMO: if no x included, use same x of current will be used
+            } else {
+                $$.data.xs[id] = data.map(function (d, i) { return i; });
             }
-            return generateClass(CLASS.target, id) + additionalClass;
-        }
-        function classChartText(d) { return CLASS.chartText + classTarget(d.id); }
-        function classChartLine(d) { return CLASS.chartLine + classTarget(d.id); }
-        function classChartBar(d) { return CLASS.chartBar + classTarget(d.id); }
-        function classChartArc(d) { return CLASS.chartArc + classTarget(d.data.id); }
+        });
 
-        function getTargetSelectorSuffix(targetId) {
-            return targetId || targetId === 0 ? '-' + (targetId.replace ? targetId.replace(/([^a-zA-Z0-9-_])/g, '-') : targetId) : '';
-        }
-        function selectorTarget(id) { return '.' + CLASS.target + getTargetSelectorSuffix(id); }
-        function selectorTargets(ids) { return ids.length ? ids.map(function (id) { return selectorTarget(id); }) : null; }
-        function selectorLegend(id) { return '.' + CLASS.legendItem + getTargetSelectorSuffix(id); }
-        function selectorLegends(ids) { return ids.length ? ids.map(function (id) { return selectorLegend(id); }) : null; }
 
-        function initialOpacity(d) {
-            return d.value !== null && withoutFadeIn[d.id] ? 1 : 0;
-        }
-        function initialOpacityForText(d) {
-            var targetOpacity = opacityForText(d);
-            return initialOpacity(d) * targetOpacity;
-        }
-        function opacityForCircle(d) {
-            return isValue(d.value) ? isScatterType(d) ? 0.5 : 1 : 0;
-        }
-        function opacityForText() {
-            return hasDataLabel() ? 1 : 0;
-        }
-        function hasDataLabel() {
-            if (typeof __data_labels === 'boolean' && __data_labels) {
-                return true;
-            } else if (typeof __data_labels === 'object' && notEmpty(__data_labels)) {
-                return true;
+        // check x is defined
+        ids.forEach(function (id) {
+            if (!$$.data.xs[id]) {
+                throw new Error('x is not defined for id = "' + id + '".');
             }
-            return false;
-        }
-        function getDataLabelWidth(min, max) {
-            var widths = [], paddingCoef = 1.3;
-            selectChart.select('svg').selectAll('.dummy')
-                .data([min, max])
-              .enter().append('text')
-                .text(function (d) { return d; })
-                .each(function (d, i) { widths[i] = this.getBoundingClientRect().width * paddingCoef; })
-              .remove();
-            return widths;
-        }
-        function getYFormat(forArc) {
-            var formatForY = forArc ? defaultArcValueFormat : yFormat,
-                formatForY2 = forArc ? defaultArcValueFormat : y2Format;
-            return function (v, ratio, id) {
-                var format = getAxisId(id) === 'y2' ? formatForY2 : formatForY;
-                return format(v, ratio);
+        });
+
+        // convert to target
+        targets = ids.map(function (id, index) {
+            var convertedId = config.data_idConverter(id);
+            return {
+                id: convertedId,
+                id_org: id,
+                values: data.map(function (d, i) {
+                    var xKey = $$.getXKey(id), rawX = d[xKey], x = $$.generateTargetX(rawX, id, i);
+                    // use x as categories if custom x and categorized
+                    if ($$.isCustomX() && $$.isCategorized() && index === 0 && rawX) {
+                        if (i === 0) { config.axis_x_categories = []; }
+                        config.axis_x_categories.push(rawX);
+                    }
+                    // mark as x = undefined if value is undefined and filter to remove after mapped
+                    if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
+                        x = undefined;
+                    }
+                    return {x: x, value: d[id] !== null && !isNaN(d[id]) ? +d[id] : null, id: convertedId};
+                }).filter(function (v) { return isDefined(v.x); })
             };
+        });
+
+        // finish targets
+        targets.forEach(function (t) {
+            var i;
+            // sort values by its x
+            if (config.data_xSort) {
+                t.values = t.values.sort(function (v1, v2) {
+                    var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
+                        x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
+                    return x1 - x2;
+                });
+            }
+            // indexing each value
+            i = 0;
+            t.values.forEach(function (v) {
+                v.index = i++;
+            });
+            // this needs to be sorted because its index and value.index is identical
+            $$.data.xs[t.id].sort(function (v1, v2) {
+                return v1 - v2;
+            });
+        });
+
+        // set target types
+        if (config.data_type) {
+            $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
         }
-        function yFormat(v) {
-            var format = __axis_y_tick_format ? __axis_y_tick_format : defaultValueFormat;
-            return format(v);
-        }
-        function y2Format(v) {
-            var format = __axis_y2_tick_format ? __axis_y2_tick_format : defaultValueFormat;
-            return format(v);
-        }
-        function defaultValueFormat(v) {
-            return isValue(v) ? +v : "";
-        }
-        function defaultArcValueFormat(v, ratio) {
-            return (ratio * 100).toFixed(1) + '%';
-        }
-        function formatByAxisId(id) {
-            var defaultFormat = function (v) { return isValue(v) ? +v : ""; }, axisId = getAxisId(id), format = defaultFormat;
-            // find format according to axis id
-            if (typeof __data_labels.format === 'function') {
-                format = __data_labels.format;
-            } else if (typeof __data_labels.format === 'object') {
-                if (typeof __data_labels.format[axisId] === 'function') {
-                    format = __data_labels.format[axisId];
-                }
+
+        // cache as original id keyed
+        targets.forEach(function (d) {
+            $$.addCache(d.id_org, d);
+        });
+
+        return targets;
+    };
+
+    c3_chart_internal_fn.load = function (targets, args) {
+        var $$ = this;
+        if (targets) {
+            // filter loading targets if needed
+            if (args.filter) {
+                targets = targets.filter(args.filter);
+            }
+            // set type if args.types || args.type specified
+            if (args.type || args.types) {
+                targets.forEach(function (t) {
+                    $$.setTargetType(t.id, args.types ? args.types[t.id] : args.type);
+                });
             }
-            return format;
+            // Update/Add data
+            $$.data.targets.forEach(function (d) {
+                for (var i = 0; i < targets.length; i++) {
+                    if (d.id === targets[i].id) {
+                        d.values = targets[i].values;
+                        targets.splice(i, 1);
+                        break;
+                    }
+                }
+            });
+            $$.data.targets = $$.data.targets.concat(targets); // add remained
         }
 
-        function xx(d) {
-            return d ? x(d.x) : null;
+        // Set targets
+        $$.updateTargets($$.data.targets);
+
+        // Redraw with new targets
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+
+        if (args.done) { args.done(); }
+    };
+    c3_chart_internal_fn.loadFromArgs = function (args) {
+        var $$ = this;
+        if (args.data) {
+            $$.load($$.convertDataToTargets(args.data), args);
+        }
+        else if (args.url) {
+            $$.convertUrlToData(args.url, args.mimeType, args.keys, function (data) {
+                $$.load($$.convertDataToTargets(data), args);
+            });
         }
-        function xv(d) {
-            return x(isTimeSeries ? parseDate(d.value) : d.value);
+        else if (args.json) {
+            $$.load($$.convertDataToTargets($$.convertJsonToData(args.json, args.keys)), args);
         }
-        function yv(d) {
-            var yScale = d.axis && d.axis === 'y2' ? y2 : y;
-            return yScale(d.value);
+        else if (args.rows) {
+            $$.load($$.convertDataToTargets($$.convertRowsToData(args.rows)), args);
         }
-        function subxx(d) {
-            return subX(d.x);
+        else if (args.columns) {
+            $$.load($$.convertDataToTargets($$.convertColumnsToData(args.columns)), args);
         }
+        else {
+            $$.load(null, args);
+        }
+    };
+    c3_chart_internal_fn.unload = function (targetIds, done) {
+        var $$ = this;
+        if (!done) {
+            done = function () {};
+        }
+        // filter existing target
+        targetIds = targetIds.filter(function (id) { return $$.hasTarget($$.data.targets, id); });
+        // If no target, call done and return
+        if (!targetIds || targetIds.length === 0) {
+            done();
+            return;
+        }
+        $$.svg.selectAll(targetIds.map(function (id) { return $$.selectorTarget(id); }))
+            .transition()
+            .style('opacity', 0)
+            .remove()
+            .call($$.endall, done);
+        targetIds.forEach(function (id) {
+            // Reset fadein for future load
+            $$.withoutFadeIn[id] = false;
+            // Remove target's elements
+            if ($$.legend) {
+                $$.legend.selectAll('.' + CLASS.legendItem + $$.getTargetSelectorSuffix(id)).remove();
+            }
+            // Remove target
+            $$.data.targets = $$.data.targets.filter(function (t) {
+                return t.id !== id;
+            });
+        });
+    };
 
-        function findSameXOfValues(values, index) {
-            var i, targetX = values[index].x, sames = [];
-            for (i = index - 1; i >= 0; i--) {
-                if (targetX !== values[i].x) { break; }
-                sames.push(values[i]);
-            }
-            for (i = index; i < values.length; i++) {
-                if (targetX !== values[i].x) { break; }
-                sames.push(values[i]);
-            }
-            return sames;
+    c3_chart_internal_fn.categoryName = function (i) {
+        var config = this.config;
+        return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
+    };
+
+    c3_chart_internal_fn.initEventRect = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.eventRects)
+            .style('fill-opacity', 0);
+    };
+    c3_chart_internal_fn.redrawEventRect = function () {
+        var $$ = this, config = $$.config,
+            eventRectUpdate, maxDataCountTarget,
+            isMultipleX = $$.isMultipleX();
+
+        // rects for mouseover
+        var eventRects = $$.main.select('.' + CLASS.eventRects)
+                .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null)
+                .classed(CLASS.eventRectsMultiple, isMultipleX)
+                .classed(CLASS.eventRectsSingle, !isMultipleX);
+
+        // clear old rects
+        eventRects.selectAll('.' + CLASS.eventRect).remove();
+
+        // open as public variable
+        $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+
+        if (isMultipleX) {
+            eventRectUpdate = $$.eventRect.data([0]);
+            // enter : only one rect will be added
+            $$.generateEventRectsForMultipleXs(eventRectUpdate.enter());
+            // update
+            $$.updateEventRect(eventRectUpdate);
+            // exit : not needed because always only one rect exists
+        }
+        else {
+            // Set data and update $$.eventRect
+            maxDataCountTarget = $$.getMaxDataCountTarget($$.data.targets);
+            eventRects.datum(maxDataCountTarget ? maxDataCountTarget.values : []);
+            $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+            eventRectUpdate = $$.eventRect.data(function (d) { return d; });
+            // enter
+            $$.generateEventRectsForSingleX(eventRectUpdate.enter());
+            // update
+            $$.updateEventRect(eventRectUpdate);
+            // exit
+            eventRectUpdate.exit().remove();
         }
+    };
+    c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
+        var $$ = this, config = $$.config,
+            x, y, w, h, rectW, rectX;
 
-        function findClosestOfValues(values, pos, _min, _max) { // MEMO: values must be sorted by x
-            var min = _min ? _min : 0,
-                max = _max ? _max : values.length - 1,
-                med = Math.floor((max - min) / 2) + min,
-                value = values[med],
-                diff = x(value.x) - pos[__axis_rotated ? 1 : 0],
-                candidates;
+        // set update selection if null
+        eventRectUpdate = eventRectUpdate || $$.eventRect.data(function (d) { return d; });
 
-            // Update range for search
-            diff > 0 ? max = med : min = med;
+        if ($$.isMultipleX()) {
+            // TODO: rotated not supported yet
+            x = 0;
+            y = 0;
+            w = $$.width;
+            h = $$.height;
+        }
+        else {
+            if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
 
-            // if candidates are two closest min and max, stop recursive call
-            if ((max - min) === 1 || (min === 0 && max === 0)) {
+                // update index for x that is used by prevX and nextX
+                $$.updateXs();
 
-                // Get candidates that has same min and max index
-                candidates = [];
-                if (values[min].x || values[min].x === 0) {
-                    candidates = candidates.concat(findSameXOfValues(values, min));
-                }
-                if (values[max].x || values[max].x === 0) {
-                    candidates = candidates.concat(findSameXOfValues(values, max));
-                }
+                rectW = function (d) {
+                    var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
 
-                // Determine the closest and return
-                return findClosest(candidates, pos);
-            }
+                    // if there this is a single data point make the eventRect full width (or height)
+                    if (prevX === null && nextX === null) {
+                        return config.axis_rotated ? $$.height : $$.width;
+                    }
 
-            return findClosestOfValues(values, pos, min, max);
-        }
-        function findClosestFromTargets(targets, pos) {
-            var candidates;
+                    if (prevX === null) { prevX = $$.x.domain()[0]; }
+                    if (nextX === null) { nextX = $$.x.domain()[1]; }
 
-            // map to array of closest points of each target
-            candidates = targets.map(function (target) {
-                return findClosestOfValues(target.values, pos);
-            });
+                    return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
+                };
+                rectX = function (d) {
+                    var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
+                        thisX = $$.data.xs[d.id][d.index];
 
-            // decide closest point and return
-            return findClosest(candidates, pos);
-        }
-        function findClosest(values, pos) {
-            var minDist, closest;
-            values.forEach(function (v) {
-                var d = dist(v, pos);
-                if (d < minDist || ! minDist) {
-                    minDist = d;
-                    closest = v;
-                }
-            });
-            return closest;
-        }
-        function filterSameX(targets, x) {
-            return d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
-        }
+                    // if there this is a single data point position the eventRect at 0
+                    if (prevX === null && nextX === null) {
+                        return 0;
+                    }
 
-        function getPathBox(path) {
-            var box = path.getBoundingClientRect();
+                    if (prevX === null) { prevX = $$.x.domain()[0]; }
 
-            if (path.pathSegList.length >= 2) {
-                var items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
-                    minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
-                return {x: minX, y: minY, width: box.width, height: box.height};
+                    return ($$.x(thisX) + $$.x(prevX)) / 2;
+                };
             } else {
-                //Some sort of fallback
-                return {x: 0, y: 0, width: 0, height: 0};
+                rectW = $$.getEventRectWidth();
+                rectX = function (d) {
+                    return $$.x(d.x) - (rectW / 2);
+                };
             }
+            x = config.axis_rotated ? 0 : rectX;
+            y = config.axis_rotated ? rectX : 0;
+            w = config.axis_rotated ? $$.width : rectW;
+            h = config.axis_rotated ? rectW : $$.height;
         }
 
-        function isOrderDesc() {
-            return __data_order && __data_order.toLowerCase() === 'desc';
-        }
-        function isOrderAsc() {
-            return __data_order && __data_order.toLowerCase() === 'asc';
-        }
-        function orderTargets(targets) {
-            var orderAsc = isOrderAsc(), orderDesc = isOrderDesc();
-            if (orderAsc || orderDesc) {
-                targets.sort(function (t1, t2) {
-                    var reducer = function (p, c) { return p + Math.abs(c.value); };
-                    var t1Sum = t1.values.reduce(reducer, 0),
-                        t2Sum = t2.values.reduce(reducer, 0);
-                    return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
+        eventRectUpdate
+            .attr('class', $$.classEvent.bind($$))
+            .attr("x", x)
+            .attr("y", y)
+            .attr("width", w)
+            .attr("height", h);
+    };
+    c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        eventRectEnter.append("rect")
+            .attr("class", $$.classEvent.bind($$))
+            .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
+            .on('mouseover', function (d) {
+                var index = d.index, selectedData, newData;
+
+                if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+                if ($$.hasArcType()) { return; }
+
+                selectedData = $$.data.targets.map(function (t) {
+                    return $$.addName($$.getValueOnIndex(t.values, index));
                 });
-            } else if (typeof __data_order === 'function') {
-                targets.sort(__data_order);
-            } // TODO: accept name array for order
-            return targets;
-        }
 
-        //-- Tooltip --//
+                // Sort selectedData as names order
+                newData = [];
+                Object.keys(config.data_names).forEach(function (id) {
+                    for (var j = 0; j < selectedData.length; j++) {
+                        if (selectedData[j] && selectedData[j].id === id) {
+                            newData.push(selectedData[j]);
+                            selectedData.shift(j);
+                            break;
+                        }
+                    }
+                });
+                selectedData = newData.concat(selectedData); // Add remained
 
-        function showTooltip(selectedData, mouse) {
-            var tWidth, tHeight, svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
-            var forArc = hasArcType(c3.data.targets),
-                dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
-            if (dataToShow.length === 0 || !__tooltip_show) {
-                return;
-            }
-            tooltip.html(__tooltip_contents(selectedData, getXAxisTickFormat(), getYFormat(forArc), color)).style("display", "block");
-            // Get tooltip dimensions
-            tWidth = tooltip.property('offsetWidth');
-            tHeight = tooltip.property('offsetHeight');
-            // Determin tooltip position
-            if (forArc) {
-                tooltipLeft = (width / 2) + mouse[0];
-                tooltipTop = (height / 2) + mouse[1] + 20;
-            } else {
-                if (__axis_rotated) {
-                    svgLeft = getSvgLeft();
-                    tooltipLeft = svgLeft + mouse[0] + 100;
-                    tooltipRight = tooltipLeft + tWidth;
-                    chartRight = getCurrentWidth() - getCurrentPaddingRight();
-                    tooltipTop = x(dataToShow[0].x) + 20;
-                } else {
-                    svgLeft = getSvgLeft();
-                    tooltipLeft = svgLeft + getCurrentPaddingLeft() + x(dataToShow[0].x) + 20;
-                    tooltipRight = tooltipLeft + tWidth;
-                    chartRight = svgLeft + getCurrentWidth() - getCurrentPaddingRight();
-                    tooltipTop = mouse[1] + 15;
-                }
+                // Expand shapes for selection
+                if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
+                $$.expandBars(index, null, true);
 
-                if (tooltipRight > chartRight) {
-                    tooltipLeft -= tWidth + 60;
-                }
-                if (tooltipTop + tHeight > getCurrentHeight()) {
-                    tooltipTop -= tHeight + 30;
-                }
-            }
-            // Set tooltip
-            tooltip
-                .style("top", tooltipTop + "px")
-                .style("left", tooltipLeft + 'px');
-        }
-        function hideTooltip() {
-            tooltip.style("display", "none");
-        }
+                // Call event handler
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    config.data_onmouseover.call($$.api, d);
+                });
+            })
+            .on('mouseout', function (d) {
+                var index = d.index;
+                if ($$.hasArcType()) { return; }
+                $$.hideXGridFocus();
+                $$.hideTooltip();
+                // Undo expanded shapes
+                $$.unexpandCircles();
+                $$.unexpandBars();
+                // Call event handler
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    config.data_onmouseout.call($$.api, d);
+                });
+            })
+            .on('mousemove', function (d) {
+                var selectedData, index = d.index,
+                    eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
 
-        function showXGridFocus(selectedData) {
-            var dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
-            if (! __tooltip_show) { return; }
-            // Hide when scatter plot exists
-            if (hasScatterType(c3.data.targets) || hasArcType(c3.data.targets)) { return; }
-            main.selectAll('line.' + CLASS.xgridFocus)
-                .style("visibility", "visible")
-                .data([dataToShow[0]])
-                .attr(__axis_rotated ? 'y1' : 'x1', xx)
-                .attr(__axis_rotated ? 'y2' : 'x2', xx);
-        }
-        function hideXGridFocus() {
-            main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
-        }
+                if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+                if ($$.hasArcType()) { return; }
 
-        //-- Circle --//
+                if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                    index -= 1;
+                }
 
-        function circleX(d) {
-            return d.x || d.x === 0 ? x(d.x) : null;
-        }
-        function circleY(d) {
-            return getYScale(d.id)(d.value);
-        }
+                // Show tooltip
+                selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
+                    return $$.addName($$.getValueOnIndex(t.values, index));
+                });
 
-        //-- Bar --//
+                if (config.tooltip_grouped) {
+                    $$.showTooltip(selectedData, d3.mouse(this));
+                    $$.showXGridFocus(selectedData);
+                }
 
-        function getBarIndices() {
-            var indices = {}, i = 0, j, k;
-            filterTargetsToShow(getTargets(isBarType)).forEach(function (d) {
-                for (j = 0; j < __data_groups.length; j++) {
-                    if (__data_groups[j].indexOf(d.id) < 0) { continue; }
-                    for (k = 0; k < __data_groups[j].length; k++) {
-                        if (__data_groups[j][k] in indices) {
-                            indices[d.id] = indices[__data_groups[j][k]];
-                            break;
+                if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) {
+                    return;
+                }
+
+                $$.main.selectAll('.' + CLASS.shape + '-' + index)
+                    .each(function () {
+                        d3.select(this).classed(CLASS.EXPANDED, true);
+                        if (config.data_selection_enabled) {
+                            eventRect.style('cursor', config.data_selection_grouped ? 'pointer' : null);
                         }
-                    }
+                        if (!config.tooltip_grouped) {
+                            $$.hideXGridFocus();
+                            $$.hideTooltip();
+                            if (!config.data_selection_grouped) {
+                                $$.unexpandCircles(index);
+                                $$.unexpandBars(index);
+                            }
+                        }
+                    })
+                    .filter(function (d) {
+                        return $$.isWithinShape(this, d);
+                    })
+                    .each(function (d) {
+                        if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
+                            eventRect.style('cursor', 'pointer');
+                        }
+                        if (!config.tooltip_grouped) {
+                            $$.showTooltip([d], d3.mouse(this));
+                            $$.showXGridFocus([d]);
+                            if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
+                            $$.expandBars(index, d.id, true);
+                        }
+                    });
+            })
+            .on('click', function (d) {
+                var index = d.index;
+                if ($$.hasArcType() || !$$.toggleShape) { return; }
+                if ($$.cancelClick) {
+                    $$.cancelClick = false;
+                    return;
                 }
-                if (isUndefined(indices[d.id])) { indices[d.id] = i++; }
-            });
-            indices.__max__ = i - 1;
-            return indices;
-        }
-        function getBarX(barW, barTargetsNum, barIndices, isSub) {
-            var scale = isSub ? subX : x;
-            return function (d) {
-                var barIndex = d.id in barIndices ? barIndices[d.id] : 0;
-                return d.x || d.x === 0 ? scale(d.x) - barW * (barTargetsNum / 2 - barIndex) : 0;
-            };
-        }
-        function getBarY(isSub) {
-            return function (d) {
-                var scale = isSub ? getSubYScale(d.id) : getYScale(d.id);
-                return scale(d.value);
-            };
-        }
-        function getBarOffset(barIndices, isSub) {
-            var targets = orderTargets(filterTargetsToShow(getTargets(isBarType))),
-                targetIds = targets.map(function (t) { return t.id; });
-            return function (d, i) {
-                var scale = isSub ? getSubYScale(d.id) : getYScale(d.id),
-                    y0 = scale(0), offset = y0;
-                targets.forEach(function (t) {
-                    if (t.id === d.id || barIndices[t.id] !== barIndices[d.id]) { return; }
-                    if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id) && t.values[i].value * d.value > 0) {
-                        offset += scale(t.values[i].value) - y0;
+                if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                    index -= 1;
+                }
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
+                        $$.toggleShape(this, d, index);
+                        $$.config.data_onclick.call($$.api, d, this);
                     }
                 });
-                return offset;
-            };
-        }
-        function getBarW(axis, barTargetsNum) {
-            return typeof __bar_width === 'number' ? __bar_width : barTargetsNum ? (axis.tickOffset() * 2 * __bar_width_ratio) / barTargetsNum : 0;
-        }
+            })
+            .call(
+                d3.behavior.drag().origin(Object)
+                    .on('drag', function () { $$.drag(d3.mouse(this)); })
+                    .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                    .on('dragend', function () { $$.dragend(); })
+            );
+    };
 
-        //-- Type --//
+    c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+
+        function mouseout() {
+            $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
+            $$.hideXGridFocus();
+            $$.hideTooltip();
+            $$.unexpandCircles();
+            $$.unexpandBars();
+        }
+
+        eventRectEnter.append('rect')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('width', $$.width)
+            .attr('height', $$.height)
+            .attr('class', CLASS.eventRect)
+            .on('mouseout', function () {
+                if ($$.hasArcType()) { return; }
+                mouseout();
+            })
+            .on('mousemove', function () {
+                var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+                var mouse, closest, sameXData, selectedData;
+
+                if ($$.dragging) { return; } // do nothing when dragging
+                if ($$.hasArcType(targetsToShow)) { return; }
+
+                mouse = d3.mouse(this);
+                closest = $$.findClosestFromTargets(targetsToShow, mouse);
+
+                if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
+                    config.data_onmouseout.call($$.api, $$.mouseover);
+                    $$.mouseover = undefined;
+                }
 
-        function setTargetType(targetIds, type) {
-            mapToTargetIds(targetIds).forEach(function (id) {
-                withoutFadeIn[id] = (type === __data_types[id]);
-                __data_types[id] = type;
-            });
-        }
-        function hasType(targets, type) {
-            var has = false;
-            targets.forEach(function (t) {
-                if (__data_types[t.id] === type) { has = true; }
-                if (!(t.id in __data_types) && type === 'line') { has = true; }
-            });
-            return has;
-        }
+                if (! closest) {
+                    mouseout();
+                    return;
+                }
 
-        /* not used
-        function hasLineType(targets) {
-            return hasType(targets, 'line');
-        }
-        */
-        function hasBarType(targets) {
-            return hasType(targets, 'bar');
-        }
-        function hasScatterType(targets) {
-            return hasType(targets, 'scatter');
-        }
-        function hasPieType(targets) {
-            return hasType(targets, 'pie');
-        }
-        function hasDonutType(targets) {
-            return hasType(targets, 'donut');
-        }
-        function hasArcType(targets) {
-            return hasPieType(targets) || hasDonutType(targets);
-        }
-        function isLineType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return !(id in __data_types) || __data_types[id] === 'line' || __data_types[id] === 'spline' || __data_types[id] === 'area' || __data_types[id] === 'area-spline';
-        }
-        function isSplineType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return __data_types[id] === 'spline' || __data_types[id] === 'area-spline';
-        }
-        function isBarType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return __data_types[id] === 'bar';
-        }
-        function isScatterType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return __data_types[id] === 'scatter';
-        }
-        function isPieType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return __data_types[id] === 'pie';
-        }
-        function isDonutType(d) {
-            var id = (typeof d === 'string') ? d : d.id;
-            return __data_types[id] === 'donut';
-        }
-        function isArcType(d) {
-            return isPieType(d) || isDonutType(d);
-        }
-        function lineData(d) {
-            return isLineType(d) ? [d] : [];
-        }
-        function arcData(d) {
-            return isArcType(d.data) ? [d] : [];
-        }
-        /* not used
-        function scatterData(d) {
-            return isScatterType(d) ? d.values : [];
-        }
-        */
-        function barData(d) {
-            return isBarType(d) ? d.values : [];
-        }
-        function lineOrScatterData(d) {
-            return isLineType(d) || isScatterType(d) ? d.values : [];
-        }
-        function barOrLineData(d) {
-            return isBarType(d) || isLineType(d) ? d.values : [];
-        }
-
-        function shouldExpand(id) {
-            return (isDonutType(id) && __donut_expand) || (isPieType(id) && __pie_expand);
-        }
+                if ($$.isScatterType(closest) || !config.tooltip_grouped) {
+                    sameXData = [closest];
+                } else {
+                    sameXData = $$.filterByX(targetsToShow, closest.x);
+                }
 
-        //-- Color --//
+                // show tooltip when cursor is close to some point
+                selectedData = sameXData.map(function (d) {
+                    return $$.addName(d);
+                });
+                $$.showTooltip(selectedData, mouse);
 
-        function generateColor(colors, pattern, callback) {
-            var ids = [];
+                // expand points
+                if (config.point_focus_expand_enabled) {
+                    $$.expandCircles(closest.index, closest.id, true);
+                }
+                $$.expandBars(closest.index, closest.id, true);
 
-            return function (d) {
-                var id = d.id || d, color;
+                // Show xgrid focus line
+                $$.showXGridFocus(selectedData);
 
-                // if callback function is provided
-                if (colors[id] instanceof Function) {
-                    color = colors[id](d);
-                }
-                // if specified, choose that color
-                else if (id in colors) {
-                    color = colors[id];
-                }
-                // if not specified, choose from pattern
-                else {
-                    if (ids.indexOf(id) < 0) { ids.push(id); }
-                    color = pattern[ids.indexOf(id) % pattern.length];
+                // Show cursor as pointer if point is close to mouse position
+                if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                    $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
+                    if (!$$.mouseover) {
+                        config.data_onmouseover.call($$.api, closest);
+                        $$.mouseover = closest;
+                    }
                 }
-                return callback instanceof Function ? callback(color, d) : color;
-            };
-        }
+            })
+            .on('click', function () {
+                var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+                var mouse, closest;
 
-        //-- Date --//
+                if ($$.hasArcType(targetsToShow)) { return; }
 
-        function parseDate(date) {
-            var parsedDate;
-            try {
-                parsedDate = __data_x_format ? d3.time.format(__data_x_format).parse(date) : new Date(date);
-            } catch (e) {
-                window.console.error("Failed to parse x '" + date + "' to Date with format " + __data_x_format);
-            }
-            return parsedDate;
-        }
+                mouse = d3.mouse(this);
+                closest = $$.findClosestFromTargets(targetsToShow, mouse);
 
-        //-- Util --//
+                if (! closest) { return; }
 
-        function isWithinCircle(_this, _r) {
-            var mouse = d3.mouse(_this), d3_this = d3.select(_this);
-            var cx = d3_this.attr("cx") * 1, cy = d3_this.attr("cy") * 1;
-            return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < _r;
-        }
-        function isWithinBar(_this) {
-            var mouse = d3.mouse(_this), box = _this.getBoundingClientRect(),
-                seg0 = _this.pathSegList.getItem(0), seg1 = _this.pathSegList.getItem(1);
-            var x = seg0.x, y = Math.min(seg0.y, seg1.y), w = box.width, h = box.height, offset = 2;
-            var sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
-            return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
-        }
-        function isWithinRegions(x, regions) {
-            var i;
-            for (i = 0; i < regions.length; i++) {
-                if (regions[i].start < x && x <= regions[i].end) { return true; }
-            }
-            return false;
-        }
+                // select if selection enabled
+                if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                    $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
+                        if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
+                            $$.toggleShape(this, closest, closest.index);
+                            $$.config.data_onclick.call($$.api, closest, this);
+                        }
+                    });
+                }
+            })
+            .call(
+                d3.behavior.drag().origin(Object)
+                    .on('drag', function () { $$.drag(d3.mouse(this)); })
+                    .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                    .on('dragend', function () { $$.dragend(); })
+            );
+    };
+    c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
+        var $$ = this,
+            selector = '.' + CLASS.eventRect + (!$$.isMultipleX() ? '-' + index : ''),
+            eventRect = $$.main.select(selector).node(),
+            box = eventRect.getBoundingClientRect(),
+            x = box.left + (mouse ? mouse[0] : 0),
+            y = box.top + (mouse ? mouse[1] : 0),
+            event = document.createEvent("MouseEvents");
+
+        event.initMouseEvent(type, true, true, window, 0, x, y, x, y,
+                             false, false, false, false, 0, null);
+        eventRect.dispatchEvent(event);
+    };
 
-        function isEmpty(o) {
-            return !o || (typeof o === 'string' && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
-        }
-        function notEmpty(o) {
-            return Object.keys(o).length > 0;
-        }
-        function hasValue(dict, value) {
-            var found = false;
-            Object.keys(dict).forEach(function (key) {
-                if (dict[key] === value) { found = true; }
-            });
-            return found;
+    c3_chart_internal_fn.getCurrentWidth = function () {
+        var $$ = this, config = $$.config;
+        return config.size_width ? config.size_width : $$.getParentWidth();
+    };
+    c3_chart_internal_fn.getCurrentHeight = function () {
+        var $$ = this, config = $$.config,
+            h = config.size_height ? config.size_height : $$.getParentHeight();
+        return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
+    };
+    c3_chart_internal_fn.getCurrentPaddingTop = function () {
+        var config = this.config;
+        return isValue(config.padding_top) ? config.padding_top : 0;
+    };
+    c3_chart_internal_fn.getCurrentPaddingBottom = function () {
+        var config = this.config;
+        return isValue(config.padding_bottom) ? config.padding_bottom : 0;
+    };
+    c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
+        var $$ = this, config = $$.config;
+        if (isValue(config.padding_left)) {
+            return config.padding_left;
+        } else if (config.axis_rotated) {
+            return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
+        } else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
+            return $$.getYAxisLabelPosition().isOuter ? 30 : 1;
+        } else {
+            return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
         }
-
-        function dist(data, pos) {
-            var yScale = getAxisId(data.id) === 'y' ? y : y2,
-                xIndex = __axis_rotated ? 1 : 0,
-                yIndex = __axis_rotated ? 0 : 1;
-            return Math.pow(x(data.x) - pos[xIndex], 2) + Math.pow(yScale(data.value) - pos[yIndex], 2);
+    };
+    c3_chart_internal_fn.getCurrentPaddingRight = function () {
+        var $$ = this, config = $$.config,
+            defaultPadding = 10, legendWidthOnRight = $$.isLegendRight ? $$.getLegendWidth() + 20 : 0;
+        if (isValue(config.padding_right)) {
+            return config.padding_right + 1; // 1 is needed not to hide tick line
+        } else if (config.axis_rotated) {
+            return defaultPadding + legendWidthOnRight;
+        } else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
+            return defaultPadding + legendWidthOnRight + ($$.getY2AxisLabelPosition().isOuter ? 20 : 0);
+        } else {
+            return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
         }
+    };
 
-        function endall(transition, callback) {
-            var n = 0;
-            transition
-                .each(function () { ++n; })
-                .each("end", function () {
-                    if (!--n) { callback.apply(this, arguments); }
-                });
+    c3_chart_internal_fn.getParentRectValue = function (key) {
+        var parent = this.selectChart.node(), v;
+        while (parent && parent.tagName !== 'BODY') {
+            v = parent.getBoundingClientRect()[key];
+            if (v) {
+                break;
+            }
+            parent = parent.parentNode;
         }
+        return v;
+    };
+    c3_chart_internal_fn.getParentWidth = function () {
+        return this.getParentRectValue('width');
+    };
+    c3_chart_internal_fn.getParentHeight = function () {
+        var h = this.selectChart.style('height');
+        return h.indexOf('px') > 0 ? +h.replace('px', '') : 0;
+    };
 
-        //-- Selection --//
 
-        function selectPoint(target, d, i) {
-            __data_onselected(d, target.node());
-            // add selected-circle on low layer g
-            main.select('.' + CLASS.selectedCircles + getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
-                .data([d])
-              .enter().append('circle')
-                .attr("class", function () { return generateClass(CLASS.selectedCircle, i); })
-                .attr("cx", __axis_rotated ? circleY : circleX)
-                .attr("cy", __axis_rotated ? circleX : circleY)
-                .attr("stroke", function () { return color(d); })
-                .attr("r", pointSelectR(d) * 1.4)
-              .transition().duration(100)
-                .attr("r", pointSelectR);
-        }
-        function unselectPoint(target, d, i) {
-            __data_onunselected(d, target.node());
-            // remove selected-circle from low layer g
-            main.select('.' + CLASS.selectedCircles + getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
-              .transition().duration(100).attr('r', 0)
-                .remove();
-        }
-        function togglePoint(selected, target, d, i) {
-            selected ? selectPoint(target, d, i) : unselectPoint(target, d, i);
-        }
+    c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
+        var $$ = this, config = $$.config,
+            leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
+            leftAxis = $$.main.select('.' + leftAxisClass).node(),
+            svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
+            chartRect = $$.selectChart.node().getBoundingClientRect(),
+            hasArc = $$.hasArcType(),
+            svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
+        return svgLeft > 0 ? svgLeft : 0;
+    };
 
-        function selectBar(target, d) {
-            __data_onselected(d, target.node());
-            target.transition().duration(100).style("fill", function () { return d3.rgb(color(d)).brighter(0.75); });
-        }
-        function unselectBar(target, d) {
-            __data_onunselected(d, target.node());
-            target.transition().duration(100).style("fill", function () { return color(d); });
-        }
-        function toggleBar(selected, target, d, i) {
-            selected ? selectBar(target, d, i) : unselectBar(target, d, i);
-        }
-        function toggleArc(selected, target, d, i) {
-            toggleBar(selected, target, d.data, i);
-        }
-        function getToggle(that) {
-            return that.nodeName === 'circle' ? togglePoint : (d3.select(that).classed(CLASS.bar) ? toggleBar : toggleArc);
-        }
 
-        function filterRemoveNull(data) {
-            return data.filter(function (d) { return isValue(d.value); });
-        }
+    c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
+        var $$ = this, position = $$.getAxisLabelPositionById(id);
+        return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
+    };
+    c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
+        var $$ = this, config = $$.config, h = 30;
+        if (axisId === 'x' && !config.axis_x_show) { return 8; }
+        if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
+        if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
+        if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
+        // Calculate x axis height when tick rotated
+        if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
+            h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
+        }
+        return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
+    };
 
-        //-- Point --//
+    c3_chart_internal_fn.getEventRectWidth = function () {
+        var $$ = this;
+        var target = $$.getMaxDataCountTarget($$.data.targets),
+            firstData, lastData, base, maxDataCount, ratio, w;
+        if (!target) {
+            return 0;
+        }
+        firstData = target.values[0], lastData = target.values[target.values.length - 1];
+        base = $$.x(lastData.x) - $$.x(firstData.x);
+        if (base === 0) {
+            return $$.config.axis_rotated ? $$.height : $$.width;
+        }
+        maxDataCount = $$.getMaxDataCount();
+        ratio = ($$.hasType('bar') ? (maxDataCount - ($$.isCategorized() ? 0.25 : 1)) / maxDataCount : 1);
+        w = maxDataCount > 1 ? (base * ratio) / (maxDataCount - 1) : base;
+        return w < 1 ? 1 : w;
+    };
 
-        function pointR(d) {
-            return __point_show ? (typeof __point_r === 'function' ? __point_r(d) : __point_r) : 0;
+    c3_chart_internal_fn.getShapeIndices = function (typeFilter) {
+        var $$ = this, config = $$.config,
+            indices = {}, i = 0, j, k;
+        $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)).forEach(function (d) {
+            for (j = 0; j < config.data_groups.length; j++) {
+                if (config.data_groups[j].indexOf(d.id) < 0) { continue; }
+                for (k = 0; k < config.data_groups[j].length; k++) {
+                    if (config.data_groups[j][k] in indices) {
+                        indices[d.id] = indices[config.data_groups[j][k]];
+                        break;
+                    }
+                }
+            }
+            if (isUndefined(indices[d.id])) { indices[d.id] = i++; }
+        });
+        indices.__max__ = i - 1;
+        return indices;
+    };
+    c3_chart_internal_fn.getShapeX = function (offset, targetsNum, indices, isSub) {
+        var $$ = this, scale = isSub ? $$.subX : $$.x;
+        return function (d) {
+            var index = d.id in indices ? indices[d.id] : 0;
+            return d.x || d.x === 0 ? scale(d.x) - offset * (targetsNum / 2 - index) : 0;
+        };
+    };
+    c3_chart_internal_fn.getShapeY = function (isSub) {
+        var $$ = this;
+        return function (d) {
+            var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id);
+            return scale(d.value);
+        };
+    };
+    c3_chart_internal_fn.getShapeOffset = function (typeFilter, indices, isSub) {
+        var $$ = this,
+            targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))),
+            targetIds = targets.map(function (t) { return t.id; });
+        return function (d, i) {
+            var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
+                y0 = scale(0), offset = y0;
+            targets.forEach(function (t) {
+                var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
+                if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
+                if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
+                    if (values[i].value * d.value >= 0) {
+                        offset += scale(values[i].value) - y0;
+                    }
+                }
+            });
+            return offset;
+        };
+    };
+    c3_chart_internal_fn.isWithinShape = function (that, d) {
+        var $$ = this,
+            shape = $$.d3.select(that), isWithin;
+        if (!$$.isTargetToShow(d.id)) {
+            isWithin = false;
         }
-        function pointExpandedR(d) {
-            return __point_focus_expand_enabled ? (__point_focus_expand_r ? __point_focus_expand_r : pointR(d) * 1.75) : pointR(d);
+        else if (that.nodeName === 'circle') {
+            isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
         }
-        function pointSelectR(d) {
-            return __point_select_r ? __point_select_r : pointR(d) * 4;
+        else if (that.nodeName === 'path') {
+            isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true;
         }
+        return isWithin;
+    };
 
-        //-- Shape --//
 
-        function getCircles(i, id) {
-            return (id ? main.selectAll('.' + CLASS.circles + getTargetSelectorSuffix(id)) : main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
-        }
-        function expandCircles(i, id) {
-            getCircles(i, id)
-                .classed(CLASS.EXPANDED, true)
-                .attr('r', pointExpandedR);
-        }
-        function unexpandCircles(i) {
-            getCircles(i)
-                .filter(function () { return d3.select(this).classed(CLASS.EXPANDED); })
-                .classed(CLASS.EXPANDED, false)
-                .attr('r', pointR);
-        }
-        function getBars(i) {
-            return main.selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
-        }
-        function expandBars(i) {
-            getBars(i).classed(CLASS.EXPANDED, true);
-        }
-        function unexpandBars(i) {
-            getBars(i).classed(CLASS.EXPANDED, false);
-        }
+    c3_chart_internal_fn.getInterpolate = function (d) {
+        var $$ = this;
+        return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? $$.config.line_step_type : "linear";
+    };
 
-        // For main region
-        var lineOnMain = (function () {
-            var line = d3.svg.line()
-                .x(__axis_rotated ? function (d) { return getYScale(d.id)(d.value); } : xx)
-                .y(__axis_rotated ? xx : function (d) { return getYScale(d.id)(d.value); });
-            if (!__line_connect_null) { line = line.defined(function (d) { return d.value != null; }); }
-            return function (d) {
-                var data = __line_connect_null ? filterRemoveNull(d.values) : d.values, x0, y0;
-                if (isLineType(d)) {
-                    isSplineType(d) ? line.interpolate("cardinal") : line.interpolate("linear");
-                    return __data_regions[d.id] ? lineWithRegions(data, x, getYScale(d.id), __data_regions[d.id]) : line(data);
-                } else {
-                    x0 = data[0] ? x(data[0].x) : 0;
-                    y0 = data[0] ? getYScale(d.id)(data[0].value) : 0;
-                    return __axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
-                }
+    c3_chart_internal_fn.initLine = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartLines);
+    };
+    c3_chart_internal_fn.updateTargetsForLine = function (targets) {
+        var $$ = this, config = $$.config,
+            mainLineUpdate, mainLineEnter,
+            classChartLine = $$.classChartLine.bind($$),
+            classLines = $$.classLines.bind($$),
+            classAreas = $$.classAreas.bind($$),
+            classCircles = $$.classCircles.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainLineUpdate = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+            .data(targets)
+            .attr('class', function (d) { return classChartLine(d) + classFocus(d); });
+        mainLineEnter = mainLineUpdate.enter().append('g')
+            .attr('class', classChartLine)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        // Lines for each data
+        mainLineEnter.append('g')
+            .attr("class", classLines);
+        // Areas
+        mainLineEnter.append('g')
+            .attr('class', classAreas);
+        // Circles for each data point on lines
+        mainLineEnter.append('g')
+            .attr("class", function (d) { return $$.generateClass(CLASS.selectedCircles, d.id); });
+        mainLineEnter.append('g')
+            .attr("class", classCircles)
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
+        // Update date for selected circles
+        targets.forEach(function (t) {
+            $$.main.selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d) {
+                d.value = t.values[d.index].value;
+            });
+        });
+        // MEMO: can not keep same color...
+        //mainLineUpdate.exit().remove();
+    };
+    c3_chart_internal_fn.redrawLine = function (durationForExit) {
+        var $$ = this;
+        $$.mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+            .data($$.lineData.bind($$));
+        $$.mainLine.enter().append('path')
+            .attr('class', $$.classLine.bind($$))
+            .style("stroke", $$.color);
+        $$.mainLine
+            .style("opacity", $$.initialOpacity.bind($$))
+            .style('shape-rendering', function (d) { return $$.isStepType(d) ? 'crispEdges' : ''; })
+            .attr('transform', null);
+        $$.mainLine.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForLine = function (transitions, drawLine) {
+        var $$ = this;
+        transitions.push($$.mainLine.transition()
+                         .attr("d", drawLine)
+                         .style("stroke", $$.color)
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
+        var $$ = this, config = $$.config,
+            line = $$.d3.svg.line(),
+            getPoints = $$.generateGetLinePoints(lineIndices, isSub),
+            yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+            xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+            yValue = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
             };
-        })();
 
-        var areaOnMain = (function () {
-            var area;
-
-            if (__axis_rotated) {
-                area = d3.svg.area()
-                    .x0(function (d) { return getYScale(d.id)(0); })
-                    .x1(function (d) { return getYScale(d.id)(d.value); })
-                    .y(xx);
-            } else {
-                area = d3.svg.area()
-                    .x(xx)
-                    .y0(function (d) { return getYScale(d.id)(0); })
-                    .y1(function (d) { return getYScale(d.id)(d.value); });
-            }
-
-            return function (d) {
-                var data = filterRemoveNull(d.values), x0, y0;
-
-                if (hasType([d], 'area') || hasType([d], 'area-spline')) {
-                    isSplineType(d) ? area.interpolate("cardinal") : area.interpolate("linear");
-                    return area(data);
+        line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
+        if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); }
+        return function (d) {
+            var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+                x = isSub ? $$.x : $$.subX, y = yScaleGetter.call($$, d.id), x0 = 0, y0 = 0, path;
+            if ($$.isLineType(d)) {
+                if (config.data_regions[d.id]) {
+                    path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
                 } else {
-                    x0 = data[0] ? x(data[0].x) : 0;
-                    y0 = data[0] ? getYScale(d.id)(data[0].value) : 0;
-                    return __axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+                    if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+                    path = line.interpolate($$.getInterpolate(d))(values);
                 }
-            };
-        })();
-
-        function generateDrawBar(barIndices, isSub) {
-            var getPoints = generateGetBarPoints(barIndices, isSub);
-            return function (d, i) {
-                // 4 points that make a bar
-                var points = getPoints(d, i);
+            } else {
+                if (values[0]) {
+                    x0 = x(values[0].x);
+                    y0 = y(values[0].value);
+                }
+                path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+            }
+            return path ? path : "M 0 0";
+        };
+    };
+    c3_chart_internal_fn.generateGetLinePoints = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
+        var $$ = this, config = $$.config,
+            lineTargetsNum = lineIndices.__max__ + 1,
+            x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
+            y = $$.getShapeY(!!isSub),
+            lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = lineOffset(d, i) || y0, // offset is for stacked area chart
+                posX = x(d), posY = y(d);
+            // fix posY not to overflow opposite quadrant
+            if (config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 1 point that marks the line position
+            return [
+                [posX, posY - (y0 - offset)],
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, posY - (y0 - offset)]  // needed for compatibility
+            ];
+        };
+    };
 
-                // switch points if axis is rotated, not applicable for sub chart
-                var indexX = __axis_rotated ? 1 : 0;
-                var indexY = __axis_rotated ? 0 : 1;
 
-                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';
+    c3_chart_internal_fn.lineWithRegions = function (d, x, y, _regions) {
+        var $$ = this, config = $$.config,
+            prev = -1, i, j,
+            s = "M", sWithRegion,
+            xp, yp, dx, dy, dd, diff, diffx2,
+            xValue, yValue,
+            regions = [];
 
-                return path;
-            };
-        }
-        function generateXYForText(barIndices, forX) {
-            var getPoints = generateGetBarPoints(barIndices, false),
-                getter = forX ? getXForText : getYForText;
-            return function (d, i) {
-                return getter(getPoints(d, i), d, this);
-            };
-        }
-        function getXForText(points, d) {
-            var padding;
-            if (__axis_rotated) {
-                padding = isBarType(d) ? 4 : 6;
-                return points[2][1] + padding * (d.value < 0 ? -1 : 1);
-            } else {
-                return points[0][0] + (points[2][0] - points[0][0]) / 2;
+        function isWithinRegions(x, regions) {
+            var i;
+            for (i = 0; i < regions.length; i++) {
+                if (regions[i].start < x && x <= regions[i].end) { return true; }
             }
+            return false;
         }
-        function getYForText(points, d, textElement) {
-            var box = textElement.getBoundingClientRect();
-            if (__axis_rotated) {
-                return (points[0][0] + points[2][0] + box.height * 0.6) / 2;
-            } else {
-                return points[2][1] + (d.value < 0 ? box.height : isBarType(d) ? -3 : -6);
+
+        // Check start/end of regions
+        if (isDefined(_regions)) {
+            for (i = 0; i < _regions.length; i++) {
+                regions[i] = {};
+                if (isUndefined(_regions[i].start)) {
+                    regions[i].start = d[0].x;
+                } else {
+                    regions[i].start = $$.isTimeSeries() ? $$.parseDate(_regions[i].start) : _regions[i].start;
+                }
+                if (isUndefined(_regions[i].end)) {
+                    regions[i].end = d[d.length - 1].x;
+                } else {
+                    regions[i].end = $$.isTimeSeries() ? $$.parseDate(_regions[i].end) : _regions[i].end;
+                }
             }
         }
 
-        function generateGetBarPoints(barIndices, isSub) {
-            var barTargetsNum = barIndices.__max__ + 1,
-                barW = getBarW(xAxis, barTargetsNum),
-                barX = getBarX(barW, barTargetsNum, barIndices, !!isSub),
-                barY = getBarY(!!isSub),
-                barOffset = getBarOffset(barIndices, !!isSub),
-                yScale = isSub ? getSubYScale : getYScale;
-            return function (d, i) {
-                var y0 = yScale(d.id)(0),
-                    offset = barOffset(d, i) || y0, // offset is for stacked bar chart
-                    posX = barX(d), posY = barY(d);
-                // fix posY not to overflow opposite quadrant
-                if (__axis_rotated) {
-                    if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
-                }
-                // 4 points that make a bar
-                return [
-                    [posX, offset],
-                    [posX, posY - (y0 - offset)],
-                    [posX + barW, posY - (y0 - offset)],
-                    [posX + barW, offset]
-                ];
+        // Set scales
+        xValue = config.axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); };
+        yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
+
+        // Define svg generator function for region
+        if ($$.isTimeSeries()) {
+            sWithRegion = function (d0, d1, j, diff) {
+                var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
+                    xv0 = new Date(x0 + x_diff * j),
+                    xv1 = new Date(x0 + x_diff * (j + diff));
+                return "M" + x(xv0) + " " + y(yp(j)) + " " + x(xv1) + " " + y(yp(j + diff));
+            };
+        } else {
+            sWithRegion = function (d0, d1, j, diff) {
+                return "M" + x(xp(j), true) + " " + y(yp(j)) + " " + x(xp(j + diff), true) + " " + y(yp(j + diff));
             };
         }
 
-        // For brush region
-        var lineOnSub = (function () {
-            var line = d3.svg.line()
-                .x(__axis_rotated ? function (d) { return getSubYScale(d.id)(d.value); } : subxx)
-                .y(__axis_rotated ? subxx : function (d) { return getSubYScale(d.id)(d.value); });
-            return function (d) {
-                var data = filterRemoveNull(d.values);
-                return isLineType(d) ? line(data) : "M " + subX(data[0].x) + " " + getSubYScale(d.id)(data[0].value);
-            };
-        })();
-
-        function lineWithRegions(d, x, y, _regions) {
-            var prev = -1, i, j;
-            var s = "M", sWithRegion;
-            var xp, yp, dx, dy, dd, diff;
-            var xValue, yValue;
-            var regions = [];
-
-            // Check start/end of regions
-            if (isDefined(_regions)) {
-                for (i = 0; i < _regions.length; i++) {
-                    regions[i] = {};
-                    if (isUndefined(_regions[i].start)) {
-                        regions[i].start = d[0].x;
-                    } else {
-                        regions[i].start = isTimeSeries ? parseDate(_regions[i].start) : _regions[i].start;
-                    }
-                    if (isUndefined(_regions[i].end)) {
-                        regions[i].end = d[d.length - 1].x;
-                    } else {
-                        regions[i].end = isTimeSeries ? parseDate(_regions[i].end) : _regions[i].end;
-                    }
-                }
-            }
+        // Generate
+        for (i = 0; i < d.length; i++) {
 
-            // Set scales
-            xValue = __axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); };
-            yValue = __axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
-
-            // Define svg generator function for region
-            if (isTimeSeries) {
-                sWithRegion = function (d0, d1, j, diff) {
-                    var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
-                        xv0 = new Date(x0 + x_diff * j),
-                        xv1 = new Date(x0 + x_diff * (j + diff));
-                    return "M" + x(xv0) + " " + y(yp(j)) + " " + x(xv1) + " " + y(yp(j + diff));
-                };
-            } else {
-                sWithRegion = function (d0, d1, j, diff) {
-                    return "M" + x(xp(j)) + " " + y(yp(j)) + " " + x(xp(j + diff)) + " " + y(yp(j + diff));
-                };
+            // Draw as normal
+            if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) {
+                s += " " + xValue(d[i]) + " " + yValue(d[i]);
             }
+            // Draw with region // TODO: Fix for horizotal charts
+            else {
+                xp = $$.getScale(d[i - 1].x, d[i].x, $$.isTimeSeries());
+                yp = $$.getScale(d[i - 1].value, d[i].value);
 
-            // Generate
-            for (i = 0; i < d.length; i++) {
-                // Draw as normal
-                if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) {
-                    s += " " + xValue(d[i]) + " " + yValue(d[i]);
-                }
-                // Draw with region // TODO: Fix for horizotal charts
-                else {
-                    xp = getX(d[i - 1].x, d[i].x);
-                    yp = getY(d[i - 1].value, d[i].value);
-
-                    dx = x(d[i].x) - x(d[i - 1].x);
-                    dy = y(d[i].value) - y(d[i - 1].value);
-                    dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
-                    diff = 2 / dd;
-                    var diffx2 = diff * 2;
+                dx = x(d[i].x) - x(d[i - 1].x);
+                dy = y(d[i].value) - y(d[i - 1].value);
+                dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
+                diff = 2 / dd;
+                diffx2 = diff * 2;
 
-                    for (j = diff; j <= 1; j += diffx2) {
-                        s += sWithRegion(d[i - 1], d[i], j, diff);
-                    }
+                for (j = diff; j <= 1; j += diffx2) {
+                    s += sWithRegion(d[i - 1], d[i], j, diff);
                 }
-                prev = d[i].x;
             }
-
-            return s;
+            prev = d[i].x;
         }
 
-        //-- Define brush/zoom -//
+        return s;
+    };
 
-        var brush, zoom = function () {};
 
-        brush = d3.svg.brush().on("brush", redrawForBrush);
-        brush.update = function () {
-            if (context) { context.select('.' + CLASS.brush).call(this); }
-            return this;
+    c3_chart_internal_fn.redrawArea = function (durationForExit) {
+        var $$ = this, d3 = $$.d3;
+        $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+            .data($$.lineData.bind($$));
+        $$.mainArea.enter().append('path')
+            .attr("class", $$.classArea.bind($$))
+            .style("fill", $$.color)
+            .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+        $$.mainArea
+            .style("opacity", $$.orgAreaOpacity);
+        $$.mainArea.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForArea = function (transitions, drawArea) {
+        var $$ = this;
+        transitions.push($$.mainArea.transition()
+                         .attr("d", drawArea)
+                         .style("fill", $$.color)
+                         .style("opacity", $$.orgAreaOpacity));
+    };
+    c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
+        var $$ = this, config = $$.config, area = $$.d3.svg.area(),
+            getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
+            yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+            xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+            value0 = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
+            },
+            value1 = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
+            };
+
+        area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
+        if (!config.line_connectNull) {
+            area = area.defined(function (d) { return d.value !== null; });
+        }
+
+        return function (d) {
+            var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+                x0 = 0, y0 = 0, path;
+            if ($$.isAreaType(d)) {
+                if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+                path = area.interpolate($$.getInterpolate(d))(values);
+            } else {
+                if (values[0]) {
+                    x0 = $$.x(values[0].x);
+                    y0 = $$.getYScale(d.id)(values[0].value);
+                }
+                path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+            }
+            return path ? path : "M 0 0";
         };
-        brush.scale = function (scale) {
-            return __axis_rotated ? this.y(scale) : this.x(scale);
+    };
+
+    c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
+        var $$ = this, config = $$.config,
+            areaTargetsNum = areaIndices.__max__ + 1,
+            x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
+            y = $$.getShapeY(!!isSub),
+            areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = areaOffset(d, i) || y0, // offset is for stacked area chart
+                posX = x(d), posY = y(d);
+            // fix posY not to overflow opposite quadrant
+            if (config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 1 point that marks the area position
+            return [
+                [posX, offset],
+                [posX, posY - (y0 - offset)],
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, offset] // needed for compatibility
+            ];
         };
+    };
 
-        if (__zoom_enabled) {
-            zoom = d3.behavior.zoom()
-                .on("zoomstart", function () { zoom.altDomain = d3.event.sourceEvent.altKey ? x.orgDomain() : null; })
-                .on("zoom", __zoom_enabled ? redrawForZoom : null);
-            zoom.scale = function (scale) {
-                return __axis_rotated ? this.y(scale) : this.x(scale);
-            };
-            zoom.orgScaleExtent = function () {
-                var extent = __zoom_extent ? __zoom_extent : [1, 10];
-                return [extent[0], Math.max(getMaxDataCount() / extent[1], extent[1])];
+
+    c3_chart_internal_fn.redrawCircle = function () {
+        var $$ = this;
+        $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
+            .data($$.lineOrScatterData.bind($$));
+        $$.mainCircle.enter().append("circle")
+            .attr("class", $$.classCircle.bind($$))
+            .attr("r", $$.pointR.bind($$))
+            .style("fill", $$.color);
+        $$.mainCircle
+            .style("opacity", $$.initialOpacityForCircle.bind($$));
+        $$.mainCircle.exit().remove();
+    };
+    c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
+        var $$ = this;
+        transitions.push($$.mainCircle.transition()
+                         .style('opacity', $$.opacityForCircle.bind($$))
+                         .style("fill", $$.color)
+                         .attr("cx", cx)
+                         .attr("cy", cy));
+        transitions.push($$.main.selectAll('.' + CLASS.selectedCircle).transition()
+                         .attr("cx", cx)
+                         .attr("cy", cy));
+    };
+    c3_chart_internal_fn.circleX = function (d) {
+        return d.x || d.x === 0 ? this.x(d.x) : null;
+    };
+    c3_chart_internal_fn.updateCircleY = function () {
+        var $$ = this, lineIndices, getPoints;
+        if ($$.config.data_groups.length > 0) {
+            lineIndices = $$.getShapeIndices($$.isLineType),
+            getPoints = $$.generateGetLinePoints(lineIndices);
+            $$.circleY = function (d, i) {
+                return getPoints(d, i)[0][1];
             };
-            zoom.updateScaleExtent = function () {
-                var ratio = diffDomain(x.orgDomain()) / diffDomain(orgXDomain), extent = this.orgScaleExtent();
-                this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
-                return this;
+        } else {
+            $$.circleY = function (d) {
+                return $$.getYScale(d.id)(d.value);
             };
         }
+    };
+    c3_chart_internal_fn.getCircles = function (i, id) {
+        var $$ = this;
+        return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
+    };
+    c3_chart_internal_fn.expandCircles = function (i, id, reset) {
+        var $$ = this,
+            r = $$.pointExpandedR.bind($$);
+        if (reset) { $$.unexpandCircles(); }
+        $$.getCircles(i, id)
+            .classed(CLASS.EXPANDED, true)
+            .attr('r', r);
+    };
+    c3_chart_internal_fn.unexpandCircles = function (i) {
+        var $$ = this,
+            r = $$.pointR.bind($$);
+        $$.getCircles(i)
+            .filter(function () { return $$.d3.select(this).classed(CLASS.EXPANDED); })
+            .classed(CLASS.EXPANDED, false)
+            .attr('r', r);
+    };
+    c3_chart_internal_fn.pointR = function (d) {
+        var $$ = this, config = $$.config;
+        return $$.isStepType(d) ? 0 : (isFunction(config.point_r) ? config.point_r(d) : config.point_r);
+    };
+    c3_chart_internal_fn.pointExpandedR = function (d) {
+        var $$ = this, config = $$.config;
+        return config.point_focus_expand_enabled ? (config.point_focus_expand_r ? config.point_focus_expand_r : $$.pointR(d) * 1.75) : $$.pointR(d);
+    };
+    c3_chart_internal_fn.pointSelectR = function (d) {
+        var $$ = this, config = $$.config;
+        return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
+    };
+    c3_chart_internal_fn.isWithinCircle = function (that, r) {
+        var d3 = this.d3,
+            mouse = d3.mouse(that), d3_this = d3.select(that),
+            cx = +d3_this.attr("cx"), cy = +d3_this.attr("cy");
+        return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
+    };
+    c3_chart_internal_fn.isWithinStep = function (that, y) {
+        return Math.abs(y - this.d3.mouse(that)[1]) < 30;
+    };
 
-        /*-- Draw Chart --*/
-
-        // for svg elements
-        var svg, defs, main, context, legend, tooltip, selectChart;
-
-        // for brush area culculation
-        var orgXDomain;
-
-        // for save value
-        var orgAreaOpacity, withoutFadeIn = {};
+    c3_chart_internal_fn.initBar = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartBars);
+    };
+    c3_chart_internal_fn.updateTargetsForBar = function (targets) {
+        var $$ = this, config = $$.config,
+            mainBarUpdate, mainBarEnter,
+            classChartBar = $$.classChartBar.bind($$),
+            classBars = $$.classBars.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainBarUpdate = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+            .data(targets)
+            .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
+        mainBarEnter = mainBarUpdate.enter().append('g')
+            .attr('class', classChartBar)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        // Bars for each data
+        mainBarEnter.append('g')
+            .attr("class", classBars)
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
 
-        function init(data) {
-            var eventRect, grid, i;
+    };
+    c3_chart_internal_fn.redrawBar = function (durationForExit) {
+        var $$ = this,
+            barData = $$.barData.bind($$),
+            classBar = $$.classBar.bind($$),
+            initialOpacity = $$.initialOpacity.bind($$),
+            color = function (d) { return $$.color(d.id); };
+        $$.mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+            .data(barData);
+        $$.mainBar.enter().append('path')
+            .attr("class", classBar)
+            .style("stroke", color)
+            .style("fill", color);
+        $$.mainBar
+            .style("opacity", initialOpacity);
+        $$.mainBar.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForBar = function (transitions, drawBar) {
+        var $$ = this;
+        transitions.push($$.mainBar.transition()
+                         .attr('d', drawBar)
+                         .style("fill", $$.color)
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
+        var $$ = this, config = $$.config,
+            w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
+        return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
+    };
+    c3_chart_internal_fn.getBars = function (i, id) {
+        var $$ = this;
+        return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
+    };
+    c3_chart_internal_fn.expandBars = function (i, id, reset) {
+        var $$ = this;
+        if (reset) { $$.unexpandBars(); }
+        $$.getBars(i, id).classed(CLASS.EXPANDED, true);
+    };
+    c3_chart_internal_fn.unexpandBars = function (i) {
+        var $$ = this;
+        $$.getBars(i).classed(CLASS.EXPANDED, false);
+    };
+    c3_chart_internal_fn.generateDrawBar = function (barIndices, isSub) {
+        var $$ = this, config = $$.config,
+            getPoints = $$.generateGetBarPoints(barIndices, isSub);
+        return function (d, i) {
+            // 4 points that make a bar
+            var points = getPoints(d, i);
+
+            // switch points if axis is rotated, not applicable for sub chart
+            var indexX = config.axis_rotated ? 1 : 0;
+            var indexY = config.axis_rotated ? 0 : 1;
+
+            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';
+
+            return path;
+        };
+    };
+    c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
+        var $$ = this,
+            axis = isSub ? $$.subXAxis : $$.xAxis,
+            barTargetsNum = barIndices.__max__ + 1,
+            barW = $$.getBarW(axis, barTargetsNum),
+            barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
+            barY = $$.getShapeY(!!isSub),
+            barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = barOffset(d, i) || y0, // offset is for stacked bar chart
+                posX = barX(d), posY = barY(d);
+            // fix posY not to overflow opposite quadrant
+            if ($$.config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 4 points that make a bar
+            return [
+                [posX, offset],
+                [posX, posY - (y0 - offset)],
+                [posX + barW, posY - (y0 - offset)],
+                [posX + barW, offset]
+            ];
+        };
+    };
+    c3_chart_internal_fn.isWithinBar = function (that) {
+        var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
+            seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
+            x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
+            w = box.width, h = box.height, offset = 2,
+            sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
+        return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
+    };
 
-            selectChart = d3.select(__bindto);
-            if (selectChart.empty()) {
-                throw new Error('Bind element not found. Check the selector specified by "bindto" and existance of that element. Default "bindto" is "#chart".');
-            }
-            selectChart.html("").classed("c3", true);
+    c3_chart_internal_fn.initText = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartTexts);
+        $$.mainText = $$.d3.selectAll([]);
+    };
+    c3_chart_internal_fn.updateTargetsForText = function (targets) {
+        var $$ = this, mainTextUpdate, mainTextEnter,
+            classChartText = $$.classChartText.bind($$),
+            classTexts = $$.classTexts.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainTextUpdate = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
+            .data(targets)
+            .attr('class', function (d) { return classChartText(d) + classFocus(d); });
+        mainTextEnter = mainTextUpdate.enter().append('g')
+            .attr('class', classChartText)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        mainTextEnter.append('g')
+            .attr('class', classTexts);
+    };
+    c3_chart_internal_fn.redrawText = function (durationForExit) {
+        var $$ = this, config = $$.config,
+            barOrLineData = $$.barOrLineData.bind($$),
+            classText = $$.classText.bind($$);
+        $$.mainText = $$.main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text)
+            .data(barOrLineData);
+        $$.mainText.enter().append('text')
+            .attr("class", classText)
+            .attr('text-anchor', function (d) { return config.axis_rotated ? (d.value < 0 ? 'end' : 'start') : 'middle'; })
+            .style("stroke", 'none')
+            .style("fill", function (d) { return $$.color(d); })
+            .style("fill-opacity", 0);
+        $$.mainText
+            .text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
+        $$.mainText.exit()
+            .transition().duration(durationForExit)
+            .style('fill-opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForText = function (transitions, xForText, yForText, forFlow) {
+        var $$ = this,
+            opacityForText = forFlow ? 0 : $$.opacityForText.bind($$);
+        transitions.push($$.mainText.transition()
+                         .attr('x', xForText)
+                         .attr('y', yForText)
+                         .style("fill", $$.color)
+                         .style("fill-opacity", opacityForText));
+    };
+    c3_chart_internal_fn.getTextRect = function (text, cls) {
+        var body = this.d3.select('body').classed('c3', true),
+            svg = body.append("svg").style('visibility', 'hidden'), rect;
+        svg.selectAll('.dummy')
+            .data([text])
+          .enter().append('text')
+            .classed(cls ? cls : "", true)
+            .text(text)
+          .each(function () { rect = this.getBoundingClientRect(); });
+        svg.remove();
+        body.classed('c3', false);
+        return rect;
+    };
+    c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
+        var $$ = this,
+            getAreaPoints = $$.generateGetAreaPoints(barIndices, false),
+            getBarPoints = $$.generateGetBarPoints(barIndices, false),
+            getLinePoints = $$.generateGetLinePoints(lineIndices, false),
+            getter = forX ? $$.getXForText : $$.getYForText;
+        return function (d, i) {
+            var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
+            return getter.call($$, getPoints(d, i), d, this);
+        };
+    };
+    c3_chart_internal_fn.getXForText = function (points, d, textElement) {
+        var $$ = this,
+            box = textElement.getBoundingClientRect(), xPos, padding;
+        if ($$.config.axis_rotated) {
+            padding = $$.isBarType(d) ? 4 : 6;
+            xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
+        } else {
+            xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
+        }
+        return d.value !== null ? xPos : xPos > $$.width ? $$.width - box.width : xPos;
+    };
+    c3_chart_internal_fn.getYForText = function (points, d, textElement) {
+        var $$ = this,
+            box = textElement.getBoundingClientRect(), yPos;
+        if ($$.config.axis_rotated) {
+            yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
+        } else {
+            yPos = points[2][1] + (d.value < 0 ? box.height : $$.isBarType(d) ? -3 : -6);
+        }
+        return d.value !== null ? yPos : yPos < box.height ? box.height : yPos;
+    };
 
-            // Init data as targets
-            c3.data.xs = {};
-            c3.data.targets = convertDataToTargets(data);
+    c3_chart_internal_fn.setTargetType = function (targetIds, type) {
+        var $$ = this, config = $$.config;
+        $$.mapToTargetIds(targetIds).forEach(function (id) {
+            $$.withoutFadeIn[id] = (type === config.data_types[id]);
+            config.data_types[id] = type;
+        });
+        if (!targetIds) {
+            config.data_type = type;
+        }
+    };
+    c3_chart_internal_fn.hasType = function (type, targets) {
+        var $$ = this, types = $$.config.data_types, has = false;
+        targets = targets || $$.data.targets;
+        if (targets && targets.length) {
+            targets.forEach(function (target) {
+                var t = types[target.id];
+                if ((t && t.indexOf(type) >= 0) || (!t && type === 'line')) {
+                    has = true;
+                }
+            });
+        } else if (Object.keys(types).length) {
+            Object.keys(types).forEach(function (id) {
+                if (types[id] === type) { has = true; }
+            });
+        } else {
+            has = $$.config.data_type === type;
+        }
+        return has;
+    };
+    c3_chart_internal_fn.hasArcType = function (targets) {
+        return this.hasType('pie', targets) || this.hasType('donut', targets) || this.hasType('gauge', targets);
+    };
+    c3_chart_internal_fn.isLineType = function (d) {
+        var config = this.config, id = isString(d) ? d : d.id;
+        return !config.data_types[id] || ['line', 'spline', 'area', 'area-spline', 'step', 'area-step'].indexOf(config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isStepType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['step', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isSplineType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['spline', 'area-spline'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isAreaType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['area', 'area-spline', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isBarType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'bar';
+    };
+    c3_chart_internal_fn.isScatterType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'scatter';
+    };
+    c3_chart_internal_fn.isPieType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'pie';
+    };
+    c3_chart_internal_fn.isGaugeType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'gauge';
+    };
+    c3_chart_internal_fn.isDonutType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'donut';
+    };
+    c3_chart_internal_fn.isArcType = function (d) {
+        return this.isPieType(d) || this.isDonutType(d) || this.isGaugeType(d);
+    };
+    c3_chart_internal_fn.lineData = function (d) {
+        return this.isLineType(d) ? [d] : [];
+    };
+    c3_chart_internal_fn.arcData = function (d) {
+        return this.isArcType(d.data) ? [d] : [];
+    };
+    /* not used
+     function scatterData(d) {
+     return isScatterType(d) ? d.values : [];
+     }
+     */
+    c3_chart_internal_fn.barData = function (d) {
+        return this.isBarType(d) ? d.values : [];
+    };
+    c3_chart_internal_fn.lineOrScatterData = function (d) {
+        return this.isLineType(d) || this.isScatterType(d) ? d.values : [];
+    };
+    c3_chart_internal_fn.barOrLineData = function (d) {
+        return this.isBarType(d) || this.isLineType(d) ? d.values : [];
+    };
 
-            // Set targets to hide if needed
-            if (__data_hide) {
-                addHiddenTargetIds(__data_hide === true ? mapToIds(c3.data.targets) : __data_hide);
-            }
+    c3_chart_internal_fn.initGrid = function () {
+        var $$ = this, config = $$.config, d3 = $$.d3;
+        $$.grid = $$.main.append('g')
+            .attr("clip-path", $$.clipPathForGrid)
+            .attr('class', CLASS.grid);
+        if (config.grid_x_show) {
+            $$.grid.append("g").attr("class", CLASS.xgrids);
+        }
+        if (config.grid_y_show) {
+            $$.grid.append('g').attr('class', CLASS.ygrids);
+        }
+        if (config.grid_focus_show) {
+            $$.grid.append('g')
+                .attr("class", CLASS.xgridFocus)
+                .append('line')
+                .attr('class', CLASS.xgridFocus);
+        }
+        $$.xgrid = d3.selectAll([]);
+        if (!config.grid_lines_front) { $$.initGridLines(); }
+    };
+    c3_chart_internal_fn.initGridLines = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.gridLines = $$.main.append('g')
+            .attr("clip-path", $$.clipPathForGrid)
+            .attr('class', CLASS.grid + ' ' + CLASS.gridLines);
+        $$.gridLines.append('g').attr("class", CLASS.xgridLines);
+        $$.gridLines.append('g').attr('class', CLASS.ygridLines);
+        $$.xgridLines = d3.selectAll([]);
+    };
+    c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
+        var $$ = this, config = $$.config, d3 = $$.d3,
+            xgridData = $$.generateGridData(config.grid_x_type, $$.x),
+            tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0;
+
+        $$.xgridAttr = config.axis_rotated ? {
+            'x1': 0,
+            'x2': $$.width,
+            'y1': function (d) { return $$.x(d) - tickOffset; },
+            'y2': function (d) { return $$.x(d) - tickOffset; }
+        } : {
+            'x1': function (d) { return $$.x(d) + tickOffset; },
+            'x2': function (d) { return $$.x(d) + tickOffset; },
+            'y1': 0,
+            'y2': $$.height
+        };
 
-            // Init sizes and scales
-            updateSizes();
-            updateScales();
-
-            // Set domains for each scale
-            x.domain(d3.extent(getXDomain(c3.data.targets)));
-            y.domain(getYDomain(c3.data.targets, 'y'));
-            y2.domain(getYDomain(c3.data.targets, 'y2'));
-            subX.domain(x.domain());
-            subY.domain(y.domain());
-            subY2.domain(y2.domain());
-
-            // Save original x domain for zoom update
-            orgXDomain = x.domain();
-
-            // Set initialized scales to brush and zoom
-            brush.scale(subX);
-            if (__zoom_enabled) { zoom.scale(x); }
-
-            /*-- Basic Elements --*/
-
-            // Define svgs
-            svg = selectChart.append("svg")
-                .on('mouseenter', __onenter)
-                .on('mouseleave', __onleave);
-
-            // Define defs
-            defs = svg.append("defs");
-            defs.append("clipPath").attr("id", clipId).append("rect");
-            defs.append("clipPath").attr("id", clipIdForXAxis).append("rect");
-            defs.append("clipPath").attr("id", clipIdForYAxis).append("rect");
-            updateSvgSize();
-
-            // Define regions
-            main = svg.append("g").attr("transform", translate.main);
-            context = svg.append("g").attr("transform", translate.context);
-            legend = svg.append("g").attr("transform", translate.legend);
-
-            if (!__subchart_show) {
-                context.style('visibility', 'hidden');
-            }
+        $$.xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid)
+            .data(xgridData);
+        $$.xgrid.enter().append('line').attr("class", CLASS.xgrid);
+        if (!withoutUpdate) {
+            $$.xgrid.attr($$.xgridAttr)
+                .style("opacity", function () { return +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1') === (config.axis_rotated ? $$.height : 0) ? 0 : 1; });
+        }
+        $$.xgrid.exit().remove();
+    };
 
-            if (!__legend_show) {
-                legend.style('visibility', 'hidden');
-                hiddenLegendIds = mapToIds(c3.data.targets);
-            }
+    c3_chart_internal_fn.updateYGrid = function () {
+        var $$ = this, config = $$.config,
+            gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
+        $$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
+            .data(gridValues);
+        $$.ygrid.enter().append('line')
+            .attr('class', CLASS.ygrid);
+        $$.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);
+        $$.ygrid.exit().remove();
+        $$.smoothLines($$.ygrid, 'grid');
+    };
 
-            // Define tooltip
-            tooltip = d3.select(__bindto)
-                .style("position", "relative")
-              .append("div")
-                .style("position", "absolute")
-                .style("pointer-events", "none")
-                .style("z-index", "10")
-                .style("display", "none");
-
-            // MEMO: call here to update legend box and tranlate for all
-            // MEMO: translate will be upated by this, so transform not needed in updateLegend()
-            updateLegend(mapToIds(c3.data.targets), {withTransform: false, withTransitionForTransform: false});
-
-            /*-- Main Region --*/
-
-            // Grids
-            grid = main.append('g')
-                .attr("clip-path", clipPath)
-                .attr('class', CLASS.grid);
-
-            // X-Grid
-            if (__grid_x_show) {
-                grid.append("g").attr("class", CLASS.xgrids);
-            }
-            if (notEmpty(__grid_x_lines)) {
-                grid.append('g').attr("class", CLASS.xgridLines);
-            }
-            if (__point_focus_line_enabled) {
-                grid.append('g')
-                    .attr("class", CLASS.xgridFocus)
-                  .append('line')
-                    .attr('class', CLASS.xgridFocus);
-            }
 
-            // Y-Grid
-            if (__grid_y_show) {
-                grid.append('g').attr('class', CLASS.ygrids);
+    c3_chart_internal_fn.redrawGrid = function (duration) {
+        var $$ = this, main = $$.main, config = $$.config,
+            xgridLine, ygridLine, yv;
+
+        // hide if arc type
+        $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+        main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+        if (config.grid_x_show) {
+            $$.updateXGrid();
+        }
+        $$.xgridLines = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine)
+            .data(config.grid_x_lines);
+        // enter
+        xgridLine = $$.xgridLines.enter().append('g')
+            .attr("class", function (d) { return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : ''); });
+        xgridLine.append('line')
+            .style("opacity", 0);
+        xgridLine.append('text')
+            .attr("text-anchor", "end")
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+            .attr('dy', -5)
+            .style("opacity", 0);
+        // udpate
+        // done in d3.transition() of the end of this function
+        // exit
+        $$.xgridLines.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+
+        // Y-Grid
+        if (config.grid_y_show) {
+            $$.updateYGrid();
+        }
+        $$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
+            .data(config.grid_y_lines);
+        // enter
+        ygridLine = $$.ygridLines.enter().append('g')
+            .attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
+        ygridLine.append('line')
+            .style("opacity", 0);
+        ygridLine.append('text')
+            .attr("text-anchor", "end")
+            .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+            .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+            .attr('dy', -5)
+            .style("opacity", 0);
+        // update
+        yv = $$.yv.bind($$);
+        $$.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);
+        $$.ygridLines.select('text')
+          .transition().duration(duration)
+            .attr("x", config.axis_rotated ? 0 : $$.width)
+            .attr("y", yv)
+            .text(function (d) { return d.text; })
+            .style("opacity", 1);
+        // exit
+        $$.ygridLines.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForGrid = function (transitions) {
+        var $$ = this, config = $$.config, xv = $$.xv.bind($$);
+        transitions.push($$.xgridLines.select('line').transition()
+                         .attr("x1", config.axis_rotated ? 0 : xv)
+                         .attr("x2", config.axis_rotated ? $$.width : xv)
+                         .attr("y1", config.axis_rotated ? xv : $$.margin.top)
+                         .attr("y2", config.axis_rotated ? xv : $$.height)
+                         .style("opacity", 1));
+        transitions.push($$.xgridLines.select('text').transition()
+                         .attr("x", config.axis_rotated ? $$.width : 0)
+                         .attr("y", xv)
+                         .text(function (d) { return d.text; })
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.showXGridFocus = function (selectedData) {
+        var $$ = this, config = $$.config,
+            dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
+            focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
+            xx = $$.xx.bind($$);
+        if (! config.tooltip_show) { return; }
+        // Hide when scatter plot exists
+        if ($$.hasType('scatter') || $$.hasArcType()) { return; }
+        focusEl
+            .style("visibility", "visible")
+            .data([dataToShow[0]])
+            .attr(config.axis_rotated ? 'y1' : 'x1', xx)
+            .attr(config.axis_rotated ? 'y2' : 'x2', xx);
+        $$.smoothLines(focusEl, 'grid');
+    };
+    c3_chart_internal_fn.hideXGridFocus = function () {
+        this.main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+    };
+    c3_chart_internal_fn.updateXgridFocus = function () {
+        var $$ = this, config = $$.config;
+        $$.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);
+    };
+    c3_chart_internal_fn.generateGridData = function (type, scale) {
+        var $$ = this,
+            gridData = [], xDomain, firstYear, lastYear, i,
+            tickNum = $$.main.select("." + CLASS.axisX).selectAll('.tick').size();
+        if (type === 'year') {
+            xDomain = $$.getXDomain();
+            firstYear = xDomain[0].getFullYear();
+            lastYear = xDomain[1].getFullYear();
+            for (i = firstYear; i <= lastYear; i++) {
+                gridData.push(new Date(i + '-01-01 00:00:00'));
+            }
+        } else {
+            gridData = scale.ticks(10);
+            if (gridData.length > tickNum) { // use only int
+                gridData = gridData.filter(function (d) { return ("" + d).indexOf('.') < 0; });
+            }
+        }
+        return gridData;
+    };
+    c3_chart_internal_fn.getGridFilterToRemove = function (params) {
+        return params ? function (line) {
+            var found = false;
+            [].concat(params).forEach(function (param) {
+                if ((('value' in param && line.value === param.value) || ('class' in param && line['class'] === param['class']))) {
+                    found = true;
+                }
+            });
+            return found;
+        } : function () { return true; };
+    };
+    c3_chart_internal_fn.removeGridLines = function (params, forX) {
+        var $$ = this, config = $$.config,
+            toRemove = $$.getGridFilterToRemove(params),
+            toShow = function (line) { return !toRemove(line); },
+            classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
+            classLine = forX ? CLASS.xgridLine : CLASS.ygridLine;
+        $$.main.select('.' + classLines).selectAll('.' + classLine).filter(toRemove)
+            .transition().duration(config.transition_duration)
+            .style('opacity', 0).remove();
+        if (forX) {
+            config.grid_x_lines = config.grid_x_lines.filter(toShow);
+        } else {
+            config.grid_y_lines = config.grid_y_lines.filter(toShow);
+        }
+    };
+
+    c3_chart_internal_fn.initTooltip = function () {
+        var $$ = this, config = $$.config, i;
+        $$.tooltip = $$.selectChart
+            .style("position", "relative")
+          .append("div")
+            .attr('class', CLASS.tooltipContainer)
+            .style("position", "absolute")
+            .style("pointer-events", "none")
+            .style("display", "none");
+        // Show tooltip if needed
+        if (config.tooltip_init_show) {
+            if ($$.isTimeSeries() && isString(config.tooltip_init_x)) {
+                config.tooltip_init_x = $$.parseDate(config.tooltip_init_x);
+                for (i = 0; i < $$.data.targets[0].values.length; i++) {
+                    if (($$.data.targets[0].values[i].x - config.tooltip_init_x) === 0) { break; }
+                }
+                config.tooltip_init_x = i;
+            }
+            $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
+                return $$.addName(d.values[config.tooltip_init_x]);
+            }), $$.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
+            $$.tooltip.style("top", config.tooltip_init_position.top)
+                .style("left", config.tooltip_init_position.left)
+                .style("display", "block");
+        }
+    };
+    c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
+        var $$ = this, config = $$.config,
+            titleFormat = config.tooltip_format_title || defaultTitleFormat,
+            nameFormat = config.tooltip_format_name || function (name) { return name; },
+            valueFormat = config.tooltip_format_value || defaultValueFormat,
+            text, i, title, value, name, bgcolor;
+        for (i = 0; i < d.length; i++) {
+            if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
+
+            if (! text) {
+                title = titleFormat ? titleFormat(d[i].x) : d[i].x;
+                text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
+            }
+
+            name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
+            value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
+            bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
+
+            text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
+            text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
+            text += "<td class='value'>" + value + "</td>";
+            text += "</tr>";
+        }
+        return text + "</table>";
+    };
+    c3_chart_internal_fn.showTooltip = function (selectedData, mouse) {
+        var $$ = this, config = $$.config;
+        var tWidth, tHeight, svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
+        var forArc = $$.hasArcType(),
+            dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
+        if (dataToShow.length === 0 || !config.tooltip_show) {
+            return;
+        }
+        $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
+
+        // Get tooltip dimensions
+        tWidth = $$.tooltip.property('offsetWidth');
+        tHeight = $$.tooltip.property('offsetHeight');
+        // Determin tooltip position
+        if (forArc) {
+            tooltipLeft = ($$.width / 2) + mouse[0];
+            tooltipTop = ($$.height / 2) + mouse[1] + 20;
+        } else {
+            svgLeft = $$.getSvgLeft(true);
+            if (config.axis_rotated) {
+                tooltipLeft = svgLeft + mouse[0] + 100;
+                tooltipRight = tooltipLeft + tWidth;
+                chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
+                tooltipTop = $$.x(dataToShow[0].x) + 20;
+            } else {
+                tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
+                tooltipRight = tooltipLeft + tWidth;
+                chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
+                tooltipTop = mouse[1] + 15;
+            }
+
+            if (tooltipRight > chartRight) {
+                tooltipLeft -= tooltipRight - chartRight;
+            }
+            if (tooltipTop + tHeight > $$.currentHeight) {
+                tooltipTop -= tHeight + 30;
+            }
+        }
+        if (tooltipTop < 0) {
+            tooltipTop = 0;
+        }
+        // Set tooltip
+        $$.tooltip
+            .style("top", tooltipTop + "px")
+            .style("left", tooltipLeft + 'px');
+    };
+    c3_chart_internal_fn.hideTooltip = function () {
+        this.tooltip.style("display", "none");
+    };
+
+    c3_chart_internal_fn.initLegend = function () {
+        var $$ = this;
+        $$.legendHasRendered = false;
+        $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
+        if (!$$.config.legend_show) {
+            $$.legend.style('visibility', 'hidden');
+            $$.hiddenLegendIds = $$.mapToIds($$.data.targets);
+            return;
+        }
+        // MEMO: call here to update legend box and tranlate for all
+        // MEMO: translate will be upated by this, so transform not needed in updateLegend()
+        $$.updateLegendWithDefaults();
+    };
+    c3_chart_internal_fn.updateLegendWithDefaults = function () {
+        var $$ = this;
+        $$.updateLegend($$.mapToIds($$.data.targets), {withTransform: false, withTransitionForTransform: false, withTransition: false});
+    };
+    c3_chart_internal_fn.updateSizeForLegend = function (legendHeight, legendWidth) {
+        var $$ = this, config = $$.config, insetLegendPosition = {
+            top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
+            left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
+        };
+
+        $$.margin3 = {
+            top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
+            right: NaN,
+            bottom: 0,
+            left: $$.isLegendRight ? $$.currentWidth - legendWidth : $$.isLegendInset ? insetLegendPosition.left : 0
+        };
+    };
+    c3_chart_internal_fn.transformLegend = function (withTransition) {
+        var $$ = this;
+        (withTransition ? $$.legend.transition() : $$.legend).attr("transform", $$.getTranslate('legend'));
+    };
+    c3_chart_internal_fn.updateLegendStep = function (step) {
+        this.legendStep = step;
+    };
+    c3_chart_internal_fn.updateLegendItemWidth = function (w) {
+        this.legendItemWidth = w;
+    };
+    c3_chart_internal_fn.updateLegendItemHeight = function (h) {
+        this.legendItemHeight = h;
+    };
+    c3_chart_internal_fn.getLegendWidth = function () {
+        var $$ = this;
+        return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
+    };
+    c3_chart_internal_fn.getLegendHeight = function () {
+        var $$ = this, h = 0;
+        if ($$.config.legend_show) {
+            if ($$.isLegendRight) {
+                h = $$.currentHeight;
+            } else {
+                h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
+            }
+        }
+        return h;
+    };
+    c3_chart_internal_fn.opacityForLegend = function (legendItem) {
+        return legendItem.classed(CLASS.legendItemHidden) ? null : 1;
+    };
+    c3_chart_internal_fn.opacityForUnfocusedLegend = function (legendItem) {
+        return legendItem.classed(CLASS.legendItemHidden) ? null : 0.3;
+    };
+    c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
+        var $$ = this;
+        targetIds = $$.mapToTargetIds(targetIds);
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .filter(function (id) { return targetIds.indexOf(id) >= 0; })
+            .classed(CLASS.legendItemFocused, focus)
+          .transition().duration(100)
+            .style('opacity', function () {
+                var opacity = focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
+                return opacity.call($$, $$.d3.select(this));
+            });
+    };
+    c3_chart_internal_fn.revertLegend = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .classed(CLASS.legendItemFocused, false)
+            .transition().duration(100)
+            .style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
+    };
+    c3_chart_internal_fn.showLegend = function (targetIds) {
+        var $$ = this, config = $$.config;
+        if (!config.legend_show) {
+            config.legend_show = true;
+            $$.legend.style('visibility', 'visible');
+            if (!$$.legendHasRendered) {
+                $$.updateLegendWithDefaults();
+            }
+        }
+        $$.removeHiddenLegendIds(targetIds);
+        $$.legend.selectAll($$.selectorLegends(targetIds))
+            .style('visibility', 'visible')
+            .transition()
+            .style('opacity', function () { return $$.opacityForLegend($$.d3.select(this)); });
+    };
+    c3_chart_internal_fn.hideLegend = function (targetIds) {
+        var $$ = this, config = $$.config;
+        if (config.legend_show && isEmpty(targetIds)) {
+            config.legend_show = false;
+            $$.legend.style('visibility', 'hidden');
+        }
+        $$.addHiddenLegendIds(targetIds);
+        $$.legend.selectAll($$.selectorLegends(targetIds))
+            .style('opacity', 0)
+            .style('visibility', 'hidden');
+    };
+    var legendItemTextBox = {};
+    c3_chart_internal_fn.clearLegendItemTextBoxCache = function () {
+        legendItemTextBox = {};
+    };
+    c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
+        var $$ = this, config = $$.config;
+        var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
+        var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
+        var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
+        var withTransition, withTransitionForTransform;
+        var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
+        var texts, rects, tiles, background;
+
+        options = options || {};
+        withTransition = getOption(options, "withTransition", true);
+        withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
+
+        function getTextBox(textElement, id) {
+            if (!legendItemTextBox[id]) {
+                legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
+            }
+            return legendItemTextBox[id];
+        }
+
+        function updatePositions(textElement, id, index) {
+            var reset = index === 0, isLast = index === targetIds.length - 1,
+                box = getTextBox(textElement, id),
+                itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
+                itemHeight = box.height + paddingTop,
+                itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
+                areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
+                margin, maxLength;
+
+            // MEMO: care about condifion of step, totalLength
+            function updateValues(id, withoutStep) {
+                if (!withoutStep) {
+                    margin = (areaLength - totalLength - itemLength) / 2;
+                    if (margin < posMin) {
+                        margin = (areaLength - itemLength) / 2;
+                        totalLength = 0;
+                        step++;
+                    }
+                }
+                steps[id] = step;
+                margins[step] = $$.isLegendInset ? 10 : margin;
+                offsets[id] = totalLength;
+                totalLength += itemLength;
+            }
+
+            if (reset) {
+                totalLength = 0;
+                step = 0;
+                maxWidth = 0;
+                maxHeight = 0;
+            }
+
+            if (config.legend_show && !$$.isLegendToShow(id)) {
+                widths[id] = heights[id] = steps[id] = offsets[id] = 0;
+                return;
             }
-            if (notEmpty(__grid_y_lines)) {
-                grid.append('g').attr('class', CLASS.ygridLines);
+
+            widths[id] = itemWidth;
+            heights[id] = itemHeight;
+
+            if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; }
+            if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; }
+            maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth;
+
+            if (config.legend_equally) {
+                Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; });
+                Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; });
+                margin = (areaLength - maxLength * targetIds.length) / 2;
+                if (margin < posMin) {
+                    totalLength = 0;
+                    step = 0;
+                    targetIds.forEach(function (id) { updateValues(id); });
+                }
+                else {
+                    updateValues(id, true);
+                }
+            } else {
+                updateValues(id);
+            }
+        }
+
+        if ($$.isLegendInset) {
+            step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
+            $$.updateLegendStep(step);
+        }
+
+        if ($$.isLegendRight) {
+            xForLegend = function (id) { return maxWidth * steps[id]; };
+            yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+        } else if ($$.isLegendInset) {
+            xForLegend = function (id) { return maxWidth * steps[id] + 10; };
+            yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+        } else {
+            xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+            yForLegend = function (id) { return maxHeight * steps[id]; };
+        }
+        xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
+        yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
+        xForLegendRect = function (id, i) { return xForLegend(id, i); };
+        yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
+
+        // Define g for legend area
+        l = $$.legend.selectAll('.' + CLASS.legendItem)
+            .data(targetIds)
+            .enter().append('g')
+            .attr('class', function (id) { return $$.generateClass(CLASS.legendItem, id); })
+            .style('visibility', function (id) { return $$.isLegendToShow(id) ? 'visible' : 'hidden'; })
+            .style('cursor', 'pointer')
+            .on('click', function (id) {
+                if (config.legend_item_onclick) {
+                    config.legend_item_onclick.call($$, id);
+                } else {
+                    if ($$.d3.event.altKey) {
+                        $$.api.hide();
+                        $$.api.show(id);
+                    } else {
+                        $$.api.toggle(id);
+                        $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
+                    }
+                }
+            })
+            .on('mouseover', function (id) {
+                $$.d3.select(this).classed(CLASS.legendItemFocused, true);
+                if (!$$.transiting && $$.isTargetToShow(id)) {
+                    $$.api.focus(id);
+                }
+                if (config.legend_item_onmouseover) {
+                    config.legend_item_onmouseover.call($$, id);
+                }
+            })
+            .on('mouseout', function (id) {
+                $$.d3.select(this).classed(CLASS.legendItemFocused, false);
+                $$.api.revert();
+                if (config.legend_item_onmouseout) {
+                    config.legend_item_onmouseout.call($$, id);
+                }
+            });
+        l.append('text')
+            .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
+            .each(function (id, i) { updatePositions(this, id, i); })
+            .style("pointer-events", "none")
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
+        l.append('rect')
+            .attr("class", CLASS.legendItemEvent)
+            .style('fill-opacity', 0)
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
+        l.append('rect')
+            .attr("class", CLASS.legendItemTile)
+            .style("pointer-events", "none")
+            .style('fill', $$.color)
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
+            .attr('width', 10)
+            .attr('height', 10);
+
+        // Set background for inset legend
+        background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
+        if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
+            background = $$.legend.insert('g', '.' + CLASS.legendItem)
+                .attr("class", CLASS.legendBackground)
+                .append('rect');
+        }
+
+        texts = $$.legend.selectAll('text')
+            .data(targetIds)
+            .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update
+            .each(function (id, i) { updatePositions(this, id, i); });
+        (withTransition ? texts.transition() : texts)
+            .attr('x', xForLegendText)
+            .attr('y', yForLegendText);
+
+        rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent)
+            .data(targetIds);
+        (withTransition ? rects.transition() : rects)
+            .attr('width', function (id) { return widths[id]; })
+            .attr('height', function (id) { return heights[id]; })
+            .attr('x', xForLegendRect)
+            .attr('y', yForLegendRect);
+
+        tiles = $$.legend.selectAll('rect.' + CLASS.legendItemTile)
+            .data(targetIds);
+        (withTransition ? tiles.transition() : tiles)
+            .style('fill', $$.color)
+            .attr('x', xForLegend)
+            .attr('y', yForLegend);
+
+        if (background) {
+            (withTransition ? background.transition() : background)
+                .attr('height', $$.getLegendHeight() - 12)
+                .attr('width', maxWidth * (step + 1) + 10);
+        }
+
+        // toggle legend state
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
+            .transition()
+            .style('opacity', function (id) {
+                var This = $$.d3.select(this);
+                if ($$.isTargetToShow(id)) {
+                    return !hasFocused || This.classed(CLASS.legendItemFocused) ? $$.opacityForLegend(This) : $$.opacityForUnfocusedLegend(This);
+                } else {
+                    return null; // c3-legend-item-hidden will be applied
+                }
+            });
+
+        // Update all to reflect change of legend
+        $$.updateLegendItemWidth(maxWidth);
+        $$.updateLegendItemHeight(maxHeight);
+        $$.updateLegendStep(step);
+        // Update size and scale
+        $$.updateSizes();
+        $$.updateScales();
+        $$.updateSvgSize();
+        // Update g positions
+        $$.transformAll(withTransitionForTransform, transitions);
+        $$.legendHasRendered = true;
+    };
+
+    c3_chart_internal_fn.initAxis = function () {
+        var $$ = this, config = $$.config, main = $$.main;
+        $$.axes.x = main.append("g")
+            .attr("class", CLASS.axis + ' ' + CLASS.axisX)
+            .attr("clip-path", $$.clipPathForXAxis)
+            .attr("transform", $$.getTranslate('x'))
+            .style("visibility", config.axis_x_show ? 'visible' : 'hidden');
+        $$.axes.x.append("text")
+            .attr("class", CLASS.axisXLabel)
+            .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+            .style("text-anchor", $$.textAnchorForXAxisLabel.bind($$));
+
+        $$.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');
+        $$.axes.y.append("text")
+            .attr("class", CLASS.axisYLabel)
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .style("text-anchor", $$.textAnchorForYAxisLabel.bind($$));
+
+        $$.axes.y2 = main.append("g")
+            .attr("class", CLASS.axis + ' ' + CLASS.axisY2)
+            // clip-path?
+            .attr("transform", $$.getTranslate('y2'))
+            .style("visibility", config.axis_y2_show ? 'visible' : 'hidden');
+        $$.axes.y2.append("text")
+            .attr("class", CLASS.axisY2Label)
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .style("text-anchor", $$.textAnchorForY2AxisLabel.bind($$));
+    };
+    c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+        var $$ = this, config = $$.config,
+            axisParams = {
+                isCategory: $$.isCategorized(),
+                withOuterTick: withOuterTick,
+                tickMultiline: config.axis_x_tick_multiline,
+                tickWidth: config.axis_x_tick_width
+            },
+            axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
+
+        if ($$.isTimeSeries() && tickValues) {
+            tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
+        }
+
+        // Set tick
+        axis.tickFormat(tickFormat).tickValues(tickValues);
+        if ($$.isCategorized()) {
+            axis.tickCentered(config.axis_x_tick_centered);
+            if (isEmpty(config.axis_x_tick_culling)) {
+                config.axis_x_tick_culling = false;
             }
+        } else {
+            // TODO: move this to c3_axis
+            axis.tickOffset = function () {
+                var scale = this.scale(),
+                    edgeX = $$.getEdgeX($$.data.targets), diff = scale(edgeX[1]) - scale(edgeX[0]),
+                    base = diff ? diff : (config.axis_rotated ? $$.height : $$.width);
+                return (base / $$.getMaxDataCount()) / 2;
+            };
+        }
 
-            // Add Axis
-            if (__axis_x_show) {
-                main.append("g")
-                    .attr("class", CLASS.axisX)
-                    .attr("clip-path", clipPathForXAxis)
-                    .attr("transform", translate.x)
-                  .append("text")
-                    .attr("class", CLASS.axisXLabel)
-                    .attr("transform", __axis_rotated ? "rotate(-90)" : "")
-                    .style("text-anchor", textAnchorForXAxisLabel);
+        return axis;
+    };
+    c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+        var axisParams = {withOuterTick: withOuterTick},
+            axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
+        if (this.isTimeSeriesY()) {
+            axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
+        } else {
+            axis.tickValues(tickValues);
+        }
+        return axis;
+    };
+    c3_chart_internal_fn.getAxisId = function (id) {
+        var config = this.config;
+        return id in config.data_axes ? config.data_axes[id] : 'y';
+    };
+    c3_chart_internal_fn.getXAxisTickFormat = function () {
+        var $$ = this, config = $$.config,
+            format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
+        if (config.axis_x_tick_format) {
+            if (isFunction(config.axis_x_tick_format)) {
+                format = config.axis_x_tick_format;
+            } else if ($$.isTimeSeries()) {
+                format = function (date) {
+                    return date ? $$.axisTimeFormat(config.axis_x_tick_format)(date) : "";
+                };
+            }
+        }
+        return isFunction(format) ? function (v) { return format.call($$, v); } : format;
+    };
+    c3_chart_internal_fn.getAxisTickValues = function (tickValues, axis) {
+        return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
+    };
+    c3_chart_internal_fn.getXAxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_x_tick_values, this.xAxis);
+    };
+    c3_chart_internal_fn.getYAxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_y_tick_values, this.yAxis);
+    };
+    c3_chart_internal_fn.getY2AxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_y2_tick_values, this.y2Axis);
+    };
+    c3_chart_internal_fn.getAxisLabelOptionByAxisId = function (axisId) {
+        var $$ = this, config = $$.config, option;
+        if (axisId === 'y') {
+            option = config.axis_y_label;
+        } else if (axisId === 'y2') {
+            option = config.axis_y2_label;
+        } else if (axisId === 'x') {
+            option = config.axis_x_label;
+        }
+        return option;
+    };
+    c3_chart_internal_fn.getAxisLabelText = function (axisId) {
+        var option = this.getAxisLabelOptionByAxisId(axisId);
+        return isString(option) ? option : option ? option.text : null;
+    };
+    c3_chart_internal_fn.setAxisLabelText = function (axisId, text) {
+        var $$ = this, config = $$.config,
+            option = $$.getAxisLabelOptionByAxisId(axisId);
+        if (isString(option)) {
+            if (axisId === 'y') {
+                config.axis_y_label = text;
+            } else if (axisId === 'y2') {
+                config.axis_y2_label = text;
+            } else if (axisId === 'x') {
+                config.axis_x_label = text;
             }
+        } else if (option) {
+            option.text = text;
+        }
+    };
+    c3_chart_internal_fn.getAxisLabelPosition = function (axisId, defaultPosition) {
+        var option = this.getAxisLabelOptionByAxisId(axisId),
+            position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
+        return {
+            isInner: position.indexOf('inner') >= 0,
+            isOuter: position.indexOf('outer') >= 0,
+            isLeft: position.indexOf('left') >= 0,
+            isCenter: position.indexOf('center') >= 0,
+            isRight: position.indexOf('right') >= 0,
+            isTop: position.indexOf('top') >= 0,
+            isMiddle: position.indexOf('middle') >= 0,
+            isBottom: position.indexOf('bottom') >= 0
+        };
+    };
+    c3_chart_internal_fn.getXAxisLabelPosition = function () {
+        return this.getAxisLabelPosition('x', this.config.axis_rotated ? 'inner-top' : 'inner-right');
+    };
+    c3_chart_internal_fn.getYAxisLabelPosition = function () {
+        return this.getAxisLabelPosition('y', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+    };
+    c3_chart_internal_fn.getY2AxisLabelPosition = function () {
+        return this.getAxisLabelPosition('y2', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+    };
+    c3_chart_internal_fn.getAxisLabelPositionById = function (id) {
+        return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
+    };
+    c3_chart_internal_fn.textForXAxisLabel = function () {
+        return this.getAxisLabelText('x');
+    };
+    c3_chart_internal_fn.textForYAxisLabel = function () {
+        return this.getAxisLabelText('y');
+    };
+    c3_chart_internal_fn.textForY2AxisLabel = function () {
+        return this.getAxisLabelText('y2');
+    };
+    c3_chart_internal_fn.xForAxisLabel = function (forHorizontal, position) {
+        var $$ = this;
+        if (forHorizontal) {
+            return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
+        } else {
+            return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
+        }
+    };
+    c3_chart_internal_fn.dxForAxisLabel = function (forHorizontal, position) {
+        if (forHorizontal) {
+            return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
+        } else {
+            return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
+        }
+    };
+    c3_chart_internal_fn.textAnchorForAxisLabel = function (forHorizontal, position) {
+        if (forHorizontal) {
+            return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
+        } else {
+            return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
+        }
+    };
+    c3_chart_internal_fn.xForXAxisLabel = function () {
+        return this.xForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.xForYAxisLabel = function () {
+        return this.xForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.xForY2AxisLabel = function () {
+        return this.xForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForXAxisLabel = function () {
+        return this.dxForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForYAxisLabel = function () {
+        return this.dxForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForY2AxisLabel = function () {
+        return this.dxForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+    };
+    c3_chart_internal_fn.dyForXAxisLabel = function () {
+        var $$ = this, config = $$.config,
+            position = $$.getXAxisLabelPosition();
+        if (config.axis_rotated) {
+            return position.isInner ? "1.2em" : -25 - $$.getMaxTickWidth('x');
+        } else {
+            return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
+        }
+    };
+    c3_chart_internal_fn.dyForYAxisLabel = function () {
+        var $$ = this,
+            position = $$.getYAxisLabelPosition();
+        if ($$.config.axis_rotated) {
+            return position.isInner ? "-0.5em" : "3em";
+        } else {
+            return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : ($$.getMaxTickWidth('y') + 10));
+        }
+    };
+    c3_chart_internal_fn.dyForY2AxisLabel = function () {
+        var $$ = this,
+            position = $$.getY2AxisLabelPosition();
+        if ($$.config.axis_rotated) {
+            return position.isInner ? "1.2em" : "-2.2em";
+        } else {
+            return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth('y2') + 15));
+        }
+    };
+    c3_chart_internal_fn.textAnchorForXAxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel(!$$.config.axis_rotated, $$.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.textAnchorForYAxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.textAnchorForY2AxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getY2AxisLabelPosition());
+    };
 
-            if (__axis_y_show) {
-                main.append("g")
-                    .attr("class", CLASS.axisY)
-                    .attr("clip-path", clipPathForYAxis)
-                    .attr("transform", translate.y)
-                  .append("text")
-                    .attr("class", CLASS.axisYLabel)
-                    .attr("transform", __axis_rotated ? "" : "rotate(-90)")
-                    .style("text-anchor", textAnchorForYAxisLabel);
+    c3_chart_internal_fn.xForRotatedTickText = function (r) {
+        return 8 * Math.sin(Math.PI * (r / 180));
+    };
+    c3_chart_internal_fn.yForRotatedTickText = function (r) {
+        return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
+    };
+    c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
+        axis.selectAll('.tick text')
+            .style("text-anchor", rotate > 0 ? "start" : "end");
+        transition.selectAll('.tick text')
+            .attr("y", this.yForRotatedTickText(rotate))
+            .attr("transform", "rotate(" + rotate + ")")
+          .selectAll('tspan')
+            .attr('dx', this.xForRotatedTickText(rotate));
+    };
+
+    c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
+        var $$ = this, config = $$.config,
+            maxWidth = 0, targetsToShow, scale, axis;
+        if (withoutRecompute && $$.currentMaxTickWidths[id]) {
+            return $$.currentMaxTickWidths[id];
+        }
+        if ($$.svg) {
+            targetsToShow = $$.filterTargetsToShow($$.data.targets);
+            if (id === 'y') {
+                scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
+                axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
+            } else if (id === 'y2') {
+                scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
+                axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
+            } else {
+                scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
+                axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
             }
+            $$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
+                $$.d3.select(this).selectAll('text tspan').each(function () {
+                    var box = this.getBoundingClientRect();
+                    if (box.left > 0 && maxWidth < box.width) { maxWidth = box.width; }
+                });
+            }).remove();
+        }
+        $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
+        return $$.currentMaxTickWidths[id];
+    };
+
+    c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
+        var $$ = this;
+        var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
+            axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
+            axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
+        (withTransition ? axisXLabel.transition() : axisXLabel)
+            .attr("x", $$.xForXAxisLabel.bind($$))
+            .attr("dx", $$.dxForXAxisLabel.bind($$))
+            .attr("dy", $$.dyForXAxisLabel.bind($$))
+            .text($$.textForXAxisLabel.bind($$));
+        (withTransition ? axisYLabel.transition() : axisYLabel)
+            .attr("x", $$.xForYAxisLabel.bind($$))
+            .attr("dx", $$.dxForYAxisLabel.bind($$))
+            .attr("dy", $$.dyForYAxisLabel.bind($$))
+            .text($$.textForYAxisLabel.bind($$));
+        (withTransition ? axisY2Label.transition() : axisY2Label)
+            .attr("x", $$.xForY2AxisLabel.bind($$))
+            .attr("dx", $$.dxForY2AxisLabel.bind($$))
+            .attr("dy", $$.dyForY2AxisLabel.bind($$))
+            .text($$.textForY2AxisLabel.bind($$));
+    };
+
+    c3_chart_internal_fn.getAxisPadding = function (padding, key, defaultValue, all) {
+        var ratio = padding.unit === 'ratio' ? all : 1;
+        return isValue(padding[key]) ? padding[key] * ratio : defaultValue;
+    };
 
-            if (__axis_y2_show) {
-                main.append("g")
-                    .attr("class", CLASS.axisY2)
-                    // clip-path?
-                    .attr("transform", translate.y2)
-                  .append("text")
-                    .attr("class", CLASS.axisY2Label)
-                    .attr("transform", __axis_rotated ? "" : "rotate(-90)")
-                    .style("text-anchor", textAnchorForY2AxisLabel);
+    c3_chart_internal_fn.generateTickValues = function (values, tickCount, forTimeSeries) {
+        var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
+        if (tickCount) {
+            targetCount = isFunction(tickCount) ? tickCount() : tickCount;
+            // compute ticks according to tickCount
+            if (targetCount === 1) {
+                tickValues = [values[0]];
+            } else if (targetCount === 2) {
+                tickValues = [values[0], values[values.length - 1]];
+            } else if (targetCount > 2) {
+                count = targetCount - 2;
+                start = values[0];
+                end = values[values.length - 1];
+                interval = (end - start) / (count + 1);
+                // re-construct unique values
+                tickValues = [start];
+                for (i = 0; i < count; i++) {
+                    tickValue = +start + interval * (i + 1);
+                    tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
+                }
+                tickValues.push(end);
             }
+        }
+        if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
+        return tickValues;
+    };
+    c3_chart_internal_fn.generateAxisTransitions = function (duration) {
+        var $$ = this, axes = $$.axes;
+        return {
+            axisX: duration ? axes.x.transition().duration(duration) : axes.x,
+            axisY: duration ? axes.y.transition().duration(duration) : axes.y,
+            axisY2: duration ? axes.y2.transition().duration(duration) : axes.y2,
+            axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
+        };
+    };
+    c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
+        var $$ = this, config = $$.config;
+        $$.axes.x.style("opacity", isHidden ? 0 : 1);
+        $$.axes.y.style("opacity", isHidden ? 0 : 1);
+        $$.axes.y2.style("opacity", isHidden ? 0 : 1);
+        $$.axes.subx.style("opacity", isHidden ? 0 : 1);
+        transitions.axisX.call($$.xAxis);
+        transitions.axisY.call($$.yAxis);
+        transitions.axisY2.call($$.y2Axis);
+        transitions.axisSubX.call($$.subXAxis);
+        // rotate tick text if needed
+        if (!config.axis_rotated && config.axis_x_tick_rotate) {
+            $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
+            $$.rotateTickText($$.axes.subx, transitions.axisSubX, config.axis_x_tick_rotate);
+        }
+    };
+
+    c3_chart_internal_fn.getClipPath = function (id) {
+        var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
+        return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
+    };
+    c3_chart_internal_fn.appendClip = function (parent, id) {
+        return parent.append("clipPath").attr("id", id).append("rect");
+    };
+    c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
+        // axis line width + padding for left
+        var left = Math.max(30, this.margin.left);
+        return forHorizontal ? -(1 + left) : -(left - 1);
+    };
+    c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
+        return forHorizontal ? -20 : -this.margin.top;
+    };
+    c3_chart_internal_fn.getXAxisClipX = function () {
+        var $$ = this;
+        return $$.getAxisClipX(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getXAxisClipY = function () {
+        var $$ = this;
+        return $$.getAxisClipY(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipX = function () {
+        var $$ = this;
+        return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipY = function () {
+        var $$ = this;
+        return $$.getAxisClipY($$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
+        var $$ = this,
+            left = Math.max(30, $$.margin.left),
+            right = Math.max(30, $$.margin.right);
+        // width + axis line width + padding for left/right
+        return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
+    };
+    c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
+        return (forHorizontal ? this.margin.bottom : (this.margin.top + this.height)) + 8;
+    };
+    c3_chart_internal_fn.getXAxisClipWidth = function () {
+        var $$ = this;
+        return $$.getAxisClipWidth(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getXAxisClipHeight = function () {
+        var $$ = this;
+        return $$.getAxisClipHeight(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipWidth = function () {
+        var $$ = this;
+        return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
+    };
+    c3_chart_internal_fn.getYAxisClipHeight = function () {
+        var $$ = this;
+        return $$.getAxisClipHeight($$.config.axis_rotated);
+    };
+
+    c3_chart_internal_fn.initPie = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        $$.pie = d3.layout.pie().value(function (d) {
+            return d.values.reduce(function (a, b) { return a + b.value; }, 0);
+        });
+        if (!config.data_order) {
+            $$.pie.sort(null);
+        }
+    };
+
+    c3_chart_internal_fn.updateRadius = function () {
+        var $$ = this, config = $$.config,
+            w = config.gauge_width || config.donut_width;
+        $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2;
+        $$.radius = $$.radiusExpanded * 0.95;
+        $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
+        $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
+    };
+
+    c3_chart_internal_fn.updateArc = function () {
+        var $$ = this;
+        $$.svgArc = $$.getSvgArc();
+        $$.svgArcExpanded = $$.getSvgArcExpanded();
+        $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
+    };
+
+    c3_chart_internal_fn.updateAngle = function (d) {
+        var $$ = this, config = $$.config,
+            found = false, index = 0,
+            gMin = config.gauge_min, gMax = config.gauge_max, gTic, gValue;
+        $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
+            if (! found && t.data.id === d.data.id) {
+                found = true;
+                d = t;
+                d.index = index;
+            }
+            index++;
+        });
+        if (isNaN(d.endAngle)) {
+            d.endAngle = d.startAngle;
+        }
+        if ($$.isGaugeType(d.data)) {
+            gTic = (Math.PI) / (gMax - gMin);
+            gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
+            d.startAngle = -1 * (Math.PI / 2);
+            d.endAngle = d.startAngle + gTic * gValue;
+        }
+        return found ? d : null;
+    };
+
+    c3_chart_internal_fn.getSvgArc = function () {
+        var $$ = this,
+            arc = $$.d3.svg.arc().outerRadius($$.radius).innerRadius($$.innerRadius),
+            newArc = function (d, withoutUpdate) {
+                var updated;
+                if (withoutUpdate) { return arc(d); } // for interpolate
+                updated = $$.updateAngle(d);
+                return updated ? arc(updated) : "M 0 0";
+            };
+        // TODO: extends all function
+        newArc.centroid = arc.centroid;
+        return newArc;
+    };
+
+    c3_chart_internal_fn.getSvgArcExpanded = function (rate) {
+        var $$ = this,
+            arc = $$.d3.svg.arc().outerRadius($$.radiusExpanded * (rate ? rate : 1)).innerRadius($$.innerRadius);
+        return function (d) {
+            var updated = $$.updateAngle(d);
+            return updated ? arc(updated) : "M 0 0";
+        };
+    };
+
+    c3_chart_internal_fn.getArc = function (d, withoutUpdate, force) {
+        return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
+    };
+
+
+    c3_chart_internal_fn.transformForArcLabel = function (d) {
+        var $$ = this,
+            updated = $$.updateAngle(d), c, x, y, h, ratio, translate = "";
+        if (updated && !$$.hasType('gauge')) {
+            c = this.svgArc.centroid(updated);
+            x = isNaN(c[0]) ? 0 : c[0];
+            y = isNaN(c[1]) ? 0 : c[1];
+            h = Math.sqrt(x * x + y * y);
+            // TODO: ratio should be an option?
+            ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
+            translate = "translate(" + (x * ratio) +  ',' + (y * ratio) +  ")";
+        }
+        return translate;
+    };
+
+    c3_chart_internal_fn.getArcRatio = function (d) {
+        var $$ = this,
+            whole = $$.hasType('gauge') ? Math.PI : (Math.PI * 2);
+        return d ? (d.endAngle - d.startAngle) / whole : null;
+    };
+
+    c3_chart_internal_fn.convertToArcData = function (d) {
+        return this.addName({
+            id: d.data.id,
+            value: d.value,
+            ratio: this.getArcRatio(d),
+            index: d.index
+        });
+    };
+
+    c3_chart_internal_fn.textForArcLabel = function (d) {
+        var $$ = this,
+            updated, value, ratio, id, format;
+        if (! $$.shouldShowArcLabel()) { return ""; }
+        updated = $$.updateAngle(d);
+        value = updated ? updated.value : null;
+        ratio = $$.getArcRatio(updated);
+        id = d.data.id;
+        if (! $$.hasType('gauge') && ! $$.meetsArcLabelThreshold(ratio)) { return ""; }
+        format = $$.getArcLabelFormat();
+        return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
+    };
+
+    c3_chart_internal_fn.expandArc = function (targetIds) {
+        var $$ = this, interval;
+
+        // MEMO: avoid to cancel transition
+        if ($$.transiting) {
+            interval = window.setInterval(function () {
+                if (!$$.transiting) {
+                    window.clearInterval(interval);
+                    if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
+                        $$.expandArc(targetIds);
+                    }
+                }
+            }, 10);
+            return;
+        }
+
+        targetIds = $$.mapToTargetIds(targetIds);
+
+        $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
+            if (! $$.shouldExpand(d.data.id)) { return; }
+            $$.d3.select(this).selectAll('path')
+                .transition().duration(50)
+                .attr("d", $$.svgArcExpanded)
+                .transition().duration(100)
+                .attr("d", $$.svgArcExpandedSub)
+                .each(function (d) {
+                    if ($$.isDonutType(d.data)) {
+                        // callback here
+                    }
+                });
+        });
+    };
+
+    c3_chart_internal_fn.unexpandArc = function (targetIds) {
+        var $$ = this;
+
+        if ($$.transiting) { return; }
+
+        targetIds = $$.mapToTargetIds(targetIds);
+
+        $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
+            .transition().duration(50)
+            .attr("d", $$.svgArc);
+        $$.svg.selectAll('.' + CLASS.arc)
+            .style("opacity", 1);
+    };
+
+    c3_chart_internal_fn.shouldExpand = function (id) {
+        var $$ = this, config = $$.config;
+        return ($$.isDonutType(id) && config.donut_expand) || ($$.isGaugeType(id) && config.gauge_expand) || ($$.isPieType(id) && config.pie_expand);
+    };
+
+    c3_chart_internal_fn.shouldShowArcLabel = function () {
+        var $$ = this, config = $$.config, shouldShow = true;
+        if ($$.hasType('donut')) {
+            shouldShow = config.donut_label_show;
+        } else if ($$.hasType('pie')) {
+            shouldShow = config.pie_label_show;
+        }
+        // when gauge, always true
+        return shouldShow;
+    };
+
+    c3_chart_internal_fn.meetsArcLabelThreshold = function (ratio) {
+        var $$ = this, config = $$.config,
+            threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
+        return ratio >= threshold;
+    };
+
+    c3_chart_internal_fn.getArcLabelFormat = function () {
+        var $$ = this, config = $$.config,
+            format = config.pie_label_format;
+        if ($$.hasType('gauge')) {
+            format = config.gauge_label_format;
+        } else if ($$.hasType('donut')) {
+            format = config.donut_label_format;
+        }
+        return format;
+    };
+
+    c3_chart_internal_fn.getArcTitle = function () {
+        var $$ = this;
+        return $$.hasType('donut') ? $$.config.donut_title : "";
+    };
+
+    c3_chart_internal_fn.updateTargetsForArc = function (targets) {
+        var $$ = this, main = $$.main,
+            mainPieUpdate, mainPieEnter,
+            classChartArc = $$.classChartArc.bind($$),
+            classArcs = $$.classArcs.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
+            .data($$.pie(targets))
+            .attr("class", function (d) { return classChartArc(d) + classFocus(d.data); });
+        mainPieEnter = mainPieUpdate.enter().append("g")
+            .attr("class", classChartArc);
+        mainPieEnter.append('g')
+            .attr('class', classArcs);
+        mainPieEnter.append("text")
+            .attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
+            .style("opacity", 0)
+            .style("text-anchor", "middle")
+            .style("pointer-events", "none");
+        // MEMO: can not keep same color..., but not bad to update color in redraw
+        //mainPieUpdate.exit().remove();
+    };
 
-            // Regions
-            main.append('g')
-                .attr("clip-path", clipPath)
-                .attr("class", CLASS.regions);
-
-            // Define g for chart area
-            main.append('g')
-                .attr("clip-path", clipPath)
-                .attr('class', CLASS.chart);
-
-            // Cover whole with rects for events
-            eventRect = main.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.eventRects)
-                .style('fill-opacity', 0)
-                .style('cursor', __zoom_enabled ? __axis_rotated ? 'ns-resize' : 'ew-resize' : null);
-
-            // Define g for bar chart area
-            main.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartBars);
-
-            // Define g for line chart area
-            main.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartLines);
-
-            // Define g for arc chart area
-            main.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartArcs)
-                .attr("transform", translate.arc)
-              .append('text')
-                .attr('class', CLASS.chartArcsTitle)
+    c3_chart_internal_fn.initArc = function () {
+        var $$ = this;
+        $$.arcs = $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartArcs)
+            .attr("transform", $$.getTranslate('arc'));
+        $$.arcs.append('text')
+            .attr('class', CLASS.chartArcsTitle)
+            .style("text-anchor", "middle")
+            .text($$.getArcTitle());
+    };
+
+    c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransform) {
+        var $$ = this, d3 = $$.d3, config = $$.config, main = $$.main,
+            mainArc;
+        mainArc = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc)
+            .data($$.arcData.bind($$));
+        mainArc.enter().append('path')
+            .attr("class", $$.classArc.bind($$))
+            .style("fill", function (d) { return $$.color(d.data); })
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; })
+            .style("opacity", 0)
+            .each(function (d) {
+                if ($$.isGaugeType(d.data)) {
+                    d.startAngle = d.endAngle = -1 * (Math.PI / 2);
+                }
+                this._current = d;
+            })
+            .on('mouseover', function (d) {
+                var updated, arcData;
+                if ($$.transiting) { // skip while transiting
+                    return;
+                }
+                updated = $$.updateAngle(d);
+                arcData = $$.convertToArcData(updated);
+                // transitions
+                $$.expandArc(updated.data.id);
+                $$.api.focus(updated.data.id);
+                $$.toggleFocusLegend(updated.data.id, true);
+                $$.config.data_onmouseover(arcData, this);
+            })
+            .on('mousemove', function (d) {
+                var updated = $$.updateAngle(d),
+                    arcData = $$.convertToArcData(updated),
+                    selectedData = [arcData];
+                $$.showTooltip(selectedData, d3.mouse(this));
+            })
+            .on('mouseout', function (d) {
+                var updated, arcData;
+                if ($$.transiting) { // skip while transiting
+                    return;
+                }
+                updated = $$.updateAngle(d);
+                arcData = $$.convertToArcData(updated);
+                // transitions
+                $$.unexpandArc(updated.data.id);
+                $$.api.revert();
+                $$.revertLegend();
+                $$.hideTooltip();
+                $$.config.data_onmouseout(arcData, this);
+            })
+            .on('click', function (d, i) {
+                var updated = $$.updateAngle(d),
+                    arcData = $$.convertToArcData(updated);
+                if ($$.toggleShape) { $$.toggleShape(this, arcData, i); }
+                $$.config.data_onclick.call($$.api, arcData, this);
+            });
+        mainArc
+            .attr("transform", function (d) { return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : ""; })
+            .style("opacity", function (d) { return d === this._current ? 0 : 1; })
+            .each(function () { $$.transiting = true; })
+            .transition().duration(duration)
+            .attrTween("d", function (d) {
+                var updated = $$.updateAngle(d), interpolate;
+                if (! updated) {
+                    return function () { return "M 0 0"; };
+                }
+                //                if (this._current === d) {
+                //                    this._current = {
+                //                        startAngle: Math.PI*2,
+                //                        endAngle: Math.PI*2,
+                //                    };
+                //                }
+                if (isNaN(this._current.endAngle)) {
+                    this._current.endAngle = this._current.startAngle;
+                }
+                interpolate = d3.interpolate(this._current, updated);
+                this._current = interpolate(0);
+                return function (t) {
+                    var interpolated = interpolate(t);
+                    interpolated.data = d.data; // data.id will be updated by interporator
+                    return $$.getArc(interpolated, true);
+                };
+            })
+            .attr("transform", withTransform ? "scale(1)" : "")
+            .style("fill", function (d) {
+                return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
+            }) // Where gauge reading color would receive customization.
+            .style("opacity", 1)
+            .call($$.endall, function () {
+                $$.transiting = false;
+            });
+        mainArc.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+        main.selectAll('.' + CLASS.chartArc).select('text')
+            .style("opacity", 0)
+            .attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
+            .text($$.textForArcLabel.bind($$))
+            .attr("transform", $$.transformForArcLabel.bind($$))
+            .style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
+          .transition().duration(duration)
+            .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
+        main.select('.' + CLASS.chartArcsTitle)
+            .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
+
+        if ($$.hasType('gauge')) {
+            $$.arcs.select('.' + CLASS.chartArcsBackground)
+                .attr("d", function () {
+                    var d = {
+                        data: [{value: config.gauge_max}],
+                        startAngle: -1 * (Math.PI / 2),
+                        endAngle: Math.PI / 2
+                    };
+                    return $$.getArc(d, true, true);
+                });
+            $$.arcs.select('.' + CLASS.chartArcsGaugeUnit)
+                .attr("dy", ".75em")
+                .text(config.gauge_label_show ? config.gauge_units : '');
+            $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
+                .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
+                .attr("dy", "1.2em")
+                .text(config.gauge_label_show ? config.gauge_min : '');
+            $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
+                .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
+                .attr("dy", "1.2em")
+                .text(config.gauge_label_show ? config.gauge_max : '');
+        }
+    };
+    c3_chart_internal_fn.initGauge = function () {
+        var arcs = this.arcs;
+        if (this.hasType('gauge')) {
+            arcs.append('path')
+                .attr("class", CLASS.chartArcsBackground);
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeUnit)
+                .style("text-anchor", "middle")
+                .style("pointer-events", "none");
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeMin)
+                .style("text-anchor", "middle")
+                .style("pointer-events", "none");
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeMax)
                 .style("text-anchor", "middle")
-                .text(getArcTitle());
+                .style("pointer-events", "none");
+        }
+    };
+    c3_chart_internal_fn.getGaugeLabelHeight = function () {
+        return this.config.gauge_label_show ? 20 : 0;
+    };
+
+    c3_chart_internal_fn.initRegion = function () {
+        var $$ = this;
+        $$.region = $$.main.append('g')
+            .attr("clip-path", $$.clipPath)
+            .attr("class", CLASS.regions);
+    };
+    c3_chart_internal_fn.redrawRegion = function (duration) {
+        var $$ = this, config = $$.config;
+
+        // hide if arc type
+        $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+        $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
+            .data(config.regions);
+        $$.mainRegion.enter().append('g')
+            .attr('class', $$.classRegion.bind($$))
+          .append('rect')
+            .style("fill-opacity", 0);
+        $$.mainRegion.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForRegion = function (transitions) {
+        var $$ = this,
+            x = $$.regionX.bind($$),
+            y = $$.regionY.bind($$),
+            w = $$.regionWidth.bind($$),
+            h = $$.regionHeight.bind($$);
+        transitions.push($$.mainRegion.selectAll('rect').transition()
+                         .attr("x", x)
+                         .attr("y", y)
+                         .attr("width", w)
+                         .attr("height", h)
+                         .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; }));
+    };
+    c3_chart_internal_fn.regionX = function (d) {
+        var $$ = this, config = $$.config,
+            xPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            xPos = config.axis_rotated ? ('start' in d ? yScale(d.start) : 0) : 0;
+        } else {
+            xPos = config.axis_rotated ? 0 : ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0);
+        }
+        return xPos;
+    };
+    c3_chart_internal_fn.regionY = function (d) {
+        var $$ = this, config = $$.config,
+            yPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            yPos = config.axis_rotated ? 0 : ('end' in d ? yScale(d.end) : 0);
+        } else {
+            yPos = config.axis_rotated ? ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0) : 0;
+        }
+        return yPos;
+    };
+    c3_chart_internal_fn.regionWidth = function (d) {
+        var $$ = this, config = $$.config,
+            start = $$.regionX(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            end = config.axis_rotated ? ('end' in d ? yScale(d.end) : $$.width) : $$.width;
+        } else {
+            end = config.axis_rotated ? $$.width : ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.width);
+        }
+        return end < start ? 0 : end - start;
+    };
+    c3_chart_internal_fn.regionHeight = function (d) {
+        var $$ = this, config = $$.config,
+            start = this.regionY(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            end = config.axis_rotated ? $$.height : ('start' in d ? yScale(d.start) : $$.height);
+        } else {
+            end = config.axis_rotated ? ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.height) : $$.height;
+        }
+        return end < start ? 0 : end - start;
+    };
+    c3_chart_internal_fn.isRegionOnX = function (d) {
+        return !d.axis || d.axis === 'x';
+    };
+
+    c3_chart_internal_fn.drag = function (mouse) {
+        var $$ = this, config = $$.config, main = $$.main, d3 = $$.d3;
+        var sx, sy, mx, my, minX, maxX, minY, maxY;
+
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        if (config.zoom_enabled && ! $$.zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior
+        if (!config.data_selection_multiple) { return; } // skip when single selection because drag is used for multiple selection
+
+        sx = $$.dragStart[0];
+        sy = $$.dragStart[1];
+        mx = mouse[0];
+        my = mouse[1];
+        minX = Math.min(sx, mx);
+        maxX = Math.max(sx, mx);
+        minY = (config.data_selection_grouped) ? $$.margin.top : Math.min(sy, my);
+        maxY = (config.data_selection_grouped) ? $$.height : Math.max(sy, my);
+
+        main.select('.' + CLASS.dragarea)
+            .attr('x', minX)
+            .attr('y', minY)
+            .attr('width', maxX - minX)
+            .attr('height', maxY - minY);
+        // TODO: binary search when multiple xs
+        main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape)
+            .filter(function (d) { return config.data_selection_isselectable(d); })
+            .each(function (d, i) {
+                var shape = d3.select(this),
+                    isSelected = shape.classed(CLASS.SELECTED),
+                    isIncluded = shape.classed(CLASS.INCLUDED),
+                    _x, _y, _w, _h, toggle, isWithin = false, box;
+                if (shape.classed(CLASS.circle)) {
+                    _x = shape.attr("cx") * 1;
+                    _y = shape.attr("cy") * 1;
+                    toggle = $$.togglePoint;
+                    isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
+                }
+                else if (shape.classed(CLASS.bar)) {
+                    box = getPathBox(this);
+                    _x = box.x;
+                    _y = box.y;
+                    _w = box.width;
+                    _h = box.height;
+                    toggle = $$.togglePath;
+                    isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
+                } else {
+                    // line/area selection not supported yet
+                    return;
+                }
+                if (isWithin ^ isIncluded) {
+                    shape.classed(CLASS.INCLUDED, !isIncluded);
+                    // TODO: included/unincluded callback here
+                    shape.classed(CLASS.SELECTED, !isSelected);
+                    toggle.call($$, !isSelected, shape, d, i);
+                }
+            });
+    };
+
+    c3_chart_internal_fn.dragstart = function (mouse) {
+        var $$ = this, config = $$.config;
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        $$.dragStart = mouse;
+        $$.main.select('.' + CLASS.chart).append('rect')
+            .attr('class', CLASS.dragarea)
+            .style('opacity', 0.1);
+        $$.dragging = true;
+        $$.config.data_ondragstart.call($$.api);
+    };
+
+    c3_chart_internal_fn.dragend = function () {
+        var $$ = this, config = $$.config;
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        $$.main.select('.' + CLASS.dragarea)
+            .transition().duration(100)
+            .style('opacity', 0)
+            .remove();
+        $$.main.selectAll('.' + CLASS.shape)
+            .classed(CLASS.INCLUDED, false);
+        $$.dragging = false;
+        $$.config.data_ondragend.call($$.api);
+    };
+
+
+    c3_chart_internal_fn.selectPoint = function (target, d, i) {
+        var $$ = this, config = $$.config,
+            cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
+            cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
+            r = $$.pointSelectR.bind($$);
+        config.data_onselected.call($$.api, d, target.node());
+        // add selected-circle on low layer g
+        $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+            .data([d])
+            .enter().append('circle')
+            .attr("class", function () { return $$.generateClass(CLASS.selectedCircle, i); })
+            .attr("cx", cx)
+            .attr("cy", cy)
+            .attr("stroke", function () { return $$.color(d); })
+            .attr("r", function (d) { return $$.pointSelectR(d) * 1.4; })
+            .transition().duration(100)
+            .attr("r", r);
+    };
+    c3_chart_internal_fn.unselectPoint = function (target, d, i) {
+        var $$ = this;
+        $$.config.data_onunselected(d, target.node());
+        // remove selected-circle from low layer g
+        $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+            .transition().duration(100).attr('r', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.togglePoint = function (selected, target, d, i) {
+        selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
+    };
+    c3_chart_internal_fn.selectPath = function (target, d) {
+        var $$ = this;
+        $$.config.data_onselected.call($$, d, target.node());
+        target.transition().duration(100)
+            .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
+    };
+    c3_chart_internal_fn.unselectPath = function (target, d) {
+        var $$ = this;
+        $$.config.data_onunselected.call($$, d, target.node());
+        target.transition().duration(100)
+            .style("fill", function () { return $$.color(d); });
+    };
+    c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
+        selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
+    };
+    c3_chart_internal_fn.getToggle = function (that, d) {
+        var $$ = this, toggle;
+        if (that.nodeName === 'circle') {
+            if ($$.isStepType(d)) {
+                // circle is hidden in step chart, so treat as within the click area
+                toggle = function () {}; // TODO: how to select step chart?
+            } else {
+                toggle = $$.togglePoint;
+            }
+        }
+        else if (that.nodeName === 'path') {
+            toggle = $$.togglePath;
+        }
+        return toggle;
+    };
+    c3_chart_internal_fn.toggleShape = function (that, d, i) {
+        var $$ = this, d3 = $$.d3, config = $$.config,
+            shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED),
+            toggle = $$.getToggle(that, d).bind($$);
+
+        if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
+            if (!config.data_selection_multiple) {
+                $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
+                    var shape = d3.select(this);
+                    if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
+                });
+            }
+            shape.classed(CLASS.SELECTED, !isSelected);
+            toggle(!isSelected, shape, d, i);
+        }
+    };
+
+    c3_chart_internal_fn.initBrush = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.brush = d3.svg.brush().on("brush", function () { $$.redrawForBrush(); });
+        $$.brush.update = function () {
+            if ($$.context) { $$.context.select('.' + CLASS.brush).call(this); }
+            return this;
+        };
+        $$.brush.scale = function (scale) {
+            return $$.config.axis_rotated ? this.y(scale) : this.x(scale);
+        };
+    };
+    c3_chart_internal_fn.initSubchart = function () {
+        var $$ = this, config = $$.config,
+            context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context'));
+
+        if (!config.subchart_show) {
+            context.style('visibility', 'hidden');
+        }
+
+        // Define g for chart area
+        context.append('g')
+            .attr("clip-path", $$.clipPathForSubchart)
+            .attr('class', CLASS.chart);
+
+        // Define g for bar chart area
+        context.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartBars);
+
+        // Define g for line chart area
+        context.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartLines);
+
+        // Add extent rect for Brush
+        context.append("g")
+            .attr("clip-path", $$.clipPath)
+            .attr("class", CLASS.brush)
+            .call($$.brush)
+            .selectAll("rect")
+            .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
+
+        // ATTENTION: This must be called AFTER chart added
+        // Add Axis
+        $$.axes.subx = context.append("g")
+            .attr("class", CLASS.axisX)
+            .attr("transform", $$.getTranslate('subx'))
+            .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis);
+    };
+    c3_chart_internal_fn.updateTargetsForSubchart = function (targets) {
+        var $$ = this, context = $$.context, config = $$.config,
+            contextLineEnter, contextLineUpdate, contextBarEnter, contextBarUpdate,
+            classChartBar = $$.classChartBar.bind($$),
+            classBars = $$.classBars.bind($$),
+            classChartLine = $$.classChartLine.bind($$),
+            classLines = $$.classLines.bind($$),
+            classAreas = $$.classAreas.bind($$);
+
+        if (config.subchart_show) {
+            contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+                .data(targets)
+                .attr('class', classChartBar);
+            contextBarEnter = contextBarUpdate.enter().append('g')
+                .style('opacity', 0)
+                .attr('class', classChartBar);
+            // Bars for each data
+            contextBarEnter.append('g')
+                .attr("class", classBars);
+
+            //-- Line --//
+            contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+                .data(targets)
+                .attr('class', classChartLine);
+            contextLineEnter = contextLineUpdate.enter().append('g')
+                .style('opacity', 0)
+                .attr('class', classChartLine);
+            // Lines for each data
+            contextLineEnter.append("g")
+                .attr("class", classLines);
+            // Area
+            contextLineEnter.append("g")
+                .attr("class", classAreas);
+        }
+    };
+    c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
+        var $$ = this, d3 = $$.d3, context = $$.context, config = $$.config,
+            contextLine,  contextArea, contextBar, drawAreaOnSub, drawBarOnSub, drawLineOnSub,
+            barData = $$.barData.bind($$),
+            lineData = $$.lineData.bind($$),
+            classBar = $$.classBar.bind($$),
+            classLine = $$.classLine.bind($$),
+            classArea = $$.classArea.bind($$),
+            initialOpacity = $$.initialOpacity.bind($$);
 
-            main.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartTexts);
+        // subchart
+        if (config.subchart_show) {
+            // reflect main chart to extent on subchart if zoomed
+            if (d3.event && d3.event.type === 'zoom') {
+                $$.brush.extent($$.x.orgDomain()).update();
+            }
+            // update subchart elements if needed
+            if (withSubchart) {
 
-            if (__zoom_enabled) { // TODO: __zoom_privileged here?
-                // if zoom privileged, insert rect to forefront
-                main.insert('rect', __zoom_privileged ? null : 'g.' + CLASS.grid)
-                    .attr('class', CLASS.zoomRect)
-                    .attr('width', width)
-                    .attr('height', height)
+                // extent rect
+                if (!$$.brush.empty()) {
+                    $$.brush.extent($$.x.orgDomain()).update();
+                }
+                // setup drawer - MEMO: this must be called after axis updated
+                drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
+                drawBarOnSub = $$.generateDrawBar(barIndices, true);
+                drawLineOnSub = $$.generateDrawLine(lineIndices, true);
+                // bars
+                contextBar = context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+                    .data(barData);
+                contextBar.enter().append('path')
+                    .attr("class", classBar)
+                    .style("stroke", 'none')
+                    .style("fill", $$.color);
+                contextBar
+                    .style("opacity", initialOpacity)
+                    .transition().duration(duration)
+                    .attr('d', drawBarOnSub)
+                    .style('opacity', 1);
+                contextBar.exit().transition().duration(duration)
+                    .style('opacity', 0)
+                    .remove();
+                // lines
+                contextLine = context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+                    .data(lineData);
+                contextLine.enter().append('path')
+                    .attr('class', classLine)
+                    .style('stroke', $$.color);
+                contextLine
+                    .style("opacity", initialOpacity)
+                    .transition().duration(duration)
+                    .attr("d", drawLineOnSub)
+                    .style('opacity', 1);
+                contextLine.exit().transition().duration(duration)
+                    .style('opacity', 0)
+                    .remove();
+                // area
+                contextArea = context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+                    .data(lineData);
+                contextArea.enter().append('path')
+                    .attr("class", classArea)
+                    .style("fill", $$.color)
+                    .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+                contextArea
+                    .style("opacity", 0)
+                    .transition().duration(duration)
+                    .attr("d", drawAreaOnSub)
+                    .style("fill", $$.color)
+                    .style("opacity", $$.orgAreaOpacity);
+                contextArea.exit().transition().duration(durationForExit)
                     .style('opacity', 0)
-                    .style('cursor', __axis_rotated ? 'ns-resize' : 'ew-resize')
-                    .call(zoom).on("dblclick.zoom", null);
+                    .remove();
+            }
+        }
+    };
+    c3_chart_internal_fn.redrawForBrush = function () {
+        var $$ = this, x = $$.x;
+        $$.redraw({
+            withTransition: false,
+            withY: $$.config.zoom_rescale,
+            withSubchart: false,
+            withUpdateXDomain: true,
+            withDimension: false
+        });
+        $$.config.subchart_onbrush.call($$.api, x.orgDomain());
+    };
+    c3_chart_internal_fn.transformContext = function (withTransition, transitions) {
+        var $$ = this, subXAxis;
+        if (transitions && transitions.axisSubX) {
+            subXAxis = transitions.axisSubX;
+        } else {
+            subXAxis = $$.context.select('.' + CLASS.axisX);
+            if (withTransition) { subXAxis = subXAxis.transition(); }
+        }
+        $$.context.attr("transform", $$.getTranslate('context'));
+        subXAxis.attr("transform", $$.getTranslate('subx'));
+    };
+    c3_chart_internal_fn.getDefaultExtent = function () {
+        var $$ = this, config = $$.config,
+            extent = isFunction(config.axis_x_extent) ? config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
+        if ($$.isTimeSeries()) {
+            extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
+        }
+        return extent;
+    };
+
+    c3_chart_internal_fn.initZoom = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
+
+        $$.zoom = d3.behavior.zoom()
+            .on("zoomstart", function () {
+                startEvent = d3.event.sourceEvent;
+                $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
+                config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
+            })
+            .on("zoom", function () {
+                $$.redrawForZoom.call($$);
+            })
+            .on('zoomend', function () {
+                var event = d3.event.sourceEvent;
+                // if click, do nothing. otherwise, click interaction will be canceled.
+                if (event && startEvent.clientX === event.clientX && startEvent.clientY === event.clientY) {
+                    return;
+                }
+                $$.redrawEventRect();
+                $$.updateZoom();
+                config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
+            });
+        $$.zoom.scale = function (scale) {
+            return config.axis_rotated ? this.y(scale) : this.x(scale);
+        };
+        $$.zoom.orgScaleExtent = function () {
+            var extent = config.zoom_extent ? config.zoom_extent : [1, 10];
+            return [extent[0], Math.max($$.getMaxDataCount() / extent[1], extent[1])];
+        };
+        $$.zoom.updateScaleExtent = function () {
+            var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.orgXDomain),
+                extent = this.orgScaleExtent();
+            this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
+            return this;
+        };
+    };
+    c3_chart_internal_fn.updateZoom = function () {
+        var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
+        $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
+        $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
+    };
+    c3_chart_internal_fn.redrawForZoom = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
+        if (!config.zoom_enabled) {
+            return;
+        }
+        if ($$.filterTargetsToShow($$.data.targets).length === 0) {
+            return;
+        }
+        if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) {
+            x.domain(zoom.altDomain);
+            zoom.scale(x).updateScaleExtent();
+            return;
+        }
+        if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
+            x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
+        }
+        $$.redraw({
+            withTransition: false,
+            withY: config.zoom_rescale,
+            withSubchart: false,
+            withEventRect: false,
+            withDimension: false
+        });
+        if (d3.event.sourceEvent.type === 'mousemove') {
+            $$.cancelClick = true;
+        }
+        config.zoom_onzoom.call($$.api, x.orgDomain());
+    };
+
+    c3_chart_internal_fn.generateColor = function () {
+        var $$ = this, config = $$.config, d3 = $$.d3,
+            colors = config.data_colors,
+            pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.scale.category10().range(),
+            callback = config.data_color,
+            ids = [];
+
+        return function (d) {
+            var id = d.id || d, color;
+
+            // if callback function is provided
+            if (colors[id] instanceof Function) {
+                color = colors[id](d);
+            }
+            // if specified, choose that color
+            else if (colors[id]) {
+                color = colors[id];
+            }
+            // if not specified, choose from pattern
+            else {
+                if (ids.indexOf(id) < 0) { ids.push(id); }
+                color = pattern[ids.indexOf(id) % pattern.length];
+                colors[id] = color;
             }
+            return callback instanceof Function ? callback(color, d) : color;
+        };
+    };
+    c3_chart_internal_fn.generateLevelColor = function () {
+        var $$ = this, config = $$.config,
+            colors = config.color_pattern,
+            threshold = config.color_threshold,
+            asValue = threshold.unit === 'value',
+            values = threshold.values && threshold.values.length ? threshold.values : [],
+            max = threshold.max || 100;
+        return notEmpty(config.color_threshold) ? function (value) {
+            var i, v, color = colors[colors.length - 1];
+            for (i = 0; i < values.length; i++) {
+                v = asValue ? value : (value * 100 / max);
+                if (v < values[i]) {
+                    color = colors[i];
+                    break;
+                }
+            }
+            return color;
+        } : null;
+    };
+
+    c3_chart_internal_fn.getYFormat = function (forArc) {
+        var $$ = this,
+            formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
+            formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
+        return function (v, ratio, id) {
+            var format = $$.getAxisId(id) === 'y2' ? formatForY2 : formatForY;
+            return format.call($$, v, ratio);
+        };
+    };
+    c3_chart_internal_fn.yFormat = function (v) {
+        var $$ = this, config = $$.config,
+            format = config.axis_y_tick_format ? config.axis_y_tick_format : $$.defaultValueFormat;
+        return format(v);
+    };
+    c3_chart_internal_fn.y2Format = function (v) {
+        var $$ = this, config = $$.config,
+            format = config.axis_y2_tick_format ? config.axis_y2_tick_format : $$.defaultValueFormat;
+        return format(v);
+    };
+    c3_chart_internal_fn.defaultValueFormat = function (v) {
+        return isValue(v) ? +v : "";
+    };
+    c3_chart_internal_fn.defaultArcValueFormat = function (v, ratio) {
+        return (ratio * 100).toFixed(1) + '%';
+    };
+    c3_chart_internal_fn.formatByAxisId = function (axisId) {
+        var $$ = this, data_labels = $$.config.data_labels,
+            format = function (v) { return isValue(v) ? +v : ""; };
+        // find format according to axis id
+        if (typeof data_labels.format === 'function') {
+            format = data_labels.format;
+        } else if (typeof data_labels.format === 'object') {
+            if (data_labels.format[axisId]) {
+                format = data_labels.format[axisId];
+            }
+        }
+        return format;
+    };
+
+    c3_chart_internal_fn.hasCaches = function (ids) {
+        for (var i = 0; i < ids.length; i++) {
+            if (! (ids[i] in this.cache)) { return false; }
+        }
+        return true;
+    };
+    c3_chart_internal_fn.addCache = function (id, target) {
+        this.cache[id] = this.cloneTarget(target);
+    };
+    c3_chart_internal_fn.getCaches = function (ids) {
+        var targets = [], i;
+        for (i = 0; i < ids.length; i++) {
+            if (ids[i] in this.cache) { targets.push(this.cloneTarget(this.cache[ids[i]])); }
+        }
+        return targets;
+    };
+
+    var CLASS = c3_chart_internal_fn.CLASS = {
+        target: 'c3-target',
+        chart: 'c3-chart',
+        chartLine: 'c3-chart-line',
+        chartLines: 'c3-chart-lines',
+        chartBar: 'c3-chart-bar',
+        chartBars: 'c3-chart-bars',
+        chartText: 'c3-chart-text',
+        chartTexts: 'c3-chart-texts',
+        chartArc: 'c3-chart-arc',
+        chartArcs: 'c3-chart-arcs',
+        chartArcsTitle: 'c3-chart-arcs-title',
+        chartArcsBackground: 'c3-chart-arcs-background',
+        chartArcsGaugeUnit: 'c3-chart-arcs-gauge-unit',
+        chartArcsGaugeMax: 'c3-chart-arcs-gauge-max',
+        chartArcsGaugeMin: 'c3-chart-arcs-gauge-min',
+        selectedCircle: 'c3-selected-circle',
+        selectedCircles: 'c3-selected-circles',
+        eventRect: 'c3-event-rect',
+        eventRects: 'c3-event-rects',
+        eventRectsSingle: 'c3-event-rects-single',
+        eventRectsMultiple: 'c3-event-rects-multiple',
+        zoomRect: 'c3-zoom-rect',
+        brush: 'c3-brush',
+        focused: 'c3-focused',
+        defocused: 'c3-defocused',
+        region: 'c3-region',
+        regions: 'c3-regions',
+        tooltipContainer: 'c3-tooltip-container',
+        tooltip: 'c3-tooltip',
+        tooltipName: 'c3-tooltip-name',
+        shape: 'c3-shape',
+        shapes: 'c3-shapes',
+        line: 'c3-line',
+        lines: 'c3-lines',
+        bar: 'c3-bar',
+        bars: 'c3-bars',
+        circle: 'c3-circle',
+        circles: 'c3-circles',
+        arc: 'c3-arc',
+        arcs: 'c3-arcs',
+        area: 'c3-area',
+        areas: 'c3-areas',
+        empty: 'c3-empty',
+        text: 'c3-text',
+        texts: 'c3-texts',
+        gaugeValue: 'c3-gauge-value',
+        grid: 'c3-grid',
+        gridLines: 'c3-grid-lines',
+        xgrid: 'c3-xgrid',
+        xgrids: 'c3-xgrids',
+        xgridLine: 'c3-xgrid-line',
+        xgridLines: 'c3-xgrid-lines',
+        xgridFocus: 'c3-xgrid-focus',
+        ygrid: 'c3-ygrid',
+        ygrids: 'c3-ygrids',
+        ygridLine: 'c3-ygrid-line',
+        ygridLines: 'c3-ygrid-lines',
+        axis: 'c3-axis',
+        axisX: 'c3-axis-x',
+        axisXLabel: 'c3-axis-x-label',
+        axisY: 'c3-axis-y',
+        axisYLabel: 'c3-axis-y-label',
+        axisY2: 'c3-axis-y2',
+        axisY2Label: 'c3-axis-y2-label',
+        legendBackground: 'c3-legend-background',
+        legendItem: 'c3-legend-item',
+        legendItemEvent: 'c3-legend-item-event',
+        legendItemTile: 'c3-legend-item-tile',
+        legendItemHidden: 'c3-legend-item-hidden',
+        legendItemFocused: 'c3-legend-item-focused',
+        dragarea: 'c3-dragarea',
+        EXPANDED: '_expanded_',
+        SELECTED: '_selected_',
+        INCLUDED: '_included_'
+    };
+    c3_chart_internal_fn.generateClass = function (prefix, targetId) {
+        return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId);
+    };
+    c3_chart_internal_fn.classText = function (d) {
+        return this.generateClass(CLASS.text, d.index);
+    };
+    c3_chart_internal_fn.classTexts = function (d) {
+        return this.generateClass(CLASS.texts, d.id);
+    };
+    c3_chart_internal_fn.classShape = function (d) {
+        return this.generateClass(CLASS.shape, d.index);
+    };
+    c3_chart_internal_fn.classShapes = function (d) {
+        return this.generateClass(CLASS.shapes, d.id);
+    };
+    c3_chart_internal_fn.classLine = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.line, d.id);
+    };
+    c3_chart_internal_fn.classLines = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
+    };
+    c3_chart_internal_fn.classCircle = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
+    };
+    c3_chart_internal_fn.classCircles = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
+    };
+    c3_chart_internal_fn.classBar = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
+    };
+    c3_chart_internal_fn.classBars = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
+    };
+    c3_chart_internal_fn.classArc = function (d) {
+        return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
+    };
+    c3_chart_internal_fn.classArcs = function (d) {
+        return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
+    };
+    c3_chart_internal_fn.classArea = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.area, d.id);
+    };
+    c3_chart_internal_fn.classAreas = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
+    };
+    c3_chart_internal_fn.classRegion = function (d, i) {
+        return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
+    };
+    c3_chart_internal_fn.classEvent = function (d) {
+        return this.generateClass(CLASS.eventRect, d.index);
+    };
+    c3_chart_internal_fn.classTarget = function (id) {
+        var $$ = this;
+        var additionalClassSuffix = $$.config.data_classes[id], additionalClass = '';
+        if (additionalClassSuffix) {
+            additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
+        }
+        return $$.generateClass(CLASS.target, id) + additionalClass;
+    };
+    c3_chart_internal_fn.classFocus = function (d) {
+        return this.classFocused(d) + this.classDefocused(d);
+    };
+    c3_chart_internal_fn.classFocused = function (d) {
+        return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
+    };
+    c3_chart_internal_fn.classDefocused = function (d) {
+        return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
+    };
+    c3_chart_internal_fn.classChartText = function (d) {
+        return CLASS.chartText + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartLine = function (d) {
+        return CLASS.chartLine + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartBar = function (d) {
+        return CLASS.chartBar + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartArc = function (d) {
+        return CLASS.chartArc + this.classTarget(d.data.id);
+    };
+    c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
+        return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g, '-') : '';
+    };
+    c3_chart_internal_fn.selectorTarget = function (id, prefix) {
+        return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
+    };
+    c3_chart_internal_fn.selectorTargets = function (ids, prefix) {
+        var $$ = this;
+        ids = ids || [];
+        return ids.length ? ids.map(function (id) { return $$.selectorTarget(id, prefix); }) : null;
+    };
+    c3_chart_internal_fn.selectorLegend = function (id) {
+        return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
+    };
+    c3_chart_internal_fn.selectorLegends = function (ids) {
+        var $$ = this;
+        return ids && ids.length ? ids.map(function (id) { return $$.selectorLegend(id); }) : null;
+    };
+
+    var isValue = c3_chart_internal_fn.isValue = function (v) {
+        return v || v === 0;
+    },
+        isFunction = c3_chart_internal_fn.isFunction = function (o) {
+            return typeof o === 'function';
+        },
+        isString = c3_chart_internal_fn.isString = function (o) {
+            return typeof o === 'string';
+        },
+        isUndefined = c3_chart_internal_fn.isUndefined = function (v) {
+            return typeof v === 'undefined';
+        },
+        isDefined = c3_chart_internal_fn.isDefined = function (v) {
+            return typeof v !== 'undefined';
+        },
+        ceil10 = c3_chart_internal_fn.ceil10 = function (v) {
+            return Math.ceil(v / 10) * 10;
+        },
+        asHalfPixel = c3_chart_internal_fn.asHalfPixel = function (n) {
+            return Math.ceil(n) + 0.5;
+        },
+        diffDomain = c3_chart_internal_fn.diffDomain = function (d) {
+            return d[1] - d[0];
+        },
+        isEmpty = c3_chart_internal_fn.isEmpty = function (o) {
+            return !o || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
+        },
+        notEmpty = c3_chart_internal_fn.notEmpty = function (o) {
+            return Object.keys(o).length > 0;
+        },
+        getOption = c3_chart_internal_fn.getOption = function (options, key, defaultValue) {
+            return isDefined(options[key]) ? options[key] : defaultValue;
+        },
+        hasValue = c3_chart_internal_fn.hasValue = function (dict, value) {
+            var found = false;
+            Object.keys(dict).forEach(function (key) {
+                if (dict[key] === value) { found = true; }
+            });
+            return found;
+        },
+        getPathBox = c3_chart_internal_fn.getPathBox = function (path) {
+            var box = path.getBoundingClientRect(),
+                items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
+                minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
+            return {x: minX, y: minY, width: box.width, height: box.height};
+        };
 
-            // Set default extent if defined
-            if (__axis_x_default) {
-                brush.extent(typeof __axis_x_default !== 'function' ? __axis_x_default : __axis_x_default(getXDomain()));
-            }
+    c3_chart_fn.focus = function (targetIds) {
+        var $$ = this.internal, candidates;
 
-            /*-- Context Region --*/
-
-            // Define g for chart area
-            context.append('g')
-                .attr("clip-path", clipPath)
-                .attr('class', CLASS.chart);
-
-            // Define g for bar chart area
-            context.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartBars);
-
-            // Define g for line chart area
-            context.select('.' + CLASS.chart).append("g")
-                .attr("class", CLASS.chartLines);
-
-            // Add extent rect for Brush
-            context.append("g")
-                .attr("clip-path", clipPath)
-                .attr("class", CLASS.brush)
-                .call(brush)
-              .selectAll("rect")
-                .attr(__axis_rotated ? "width" : "height", __axis_rotated ? width2 : height2);
-
-            // ATTENTION: This must be called AFTER chart added
-            // Add Axis
-            context.append("g")
-                .attr("class", CLASS.axisX)
-                .attr("transform", translate.subx)
-                .attr("clip-path", __axis_rotated ? "" : clipPathForXAxis);
-
-            // Set targets
-            updateTargets(c3.data.targets);
-
-            // Update ticks for width calculation
-            if (__axis_rotated) {
-                main.select('.' + CLASS.axisX).style("opacity", 0).call(xAxis);
-            } else {
-                main.select('.' + CLASS.axisY).style("opacity", 0).call(yAxis);
-                main.select('.' + CLASS.axisY2).style("opacity", 0).call(y2Axis);
-            }
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
 
-            // Update sizes according to tick width updated by above
-            updateSizes();
-            updateScales();
-            updateSvgSize();
-            transformAll(false);
-
-            // Draw with targets
-            redraw({withTransform: true, withUpdateXDomain: true, withUpdateOrgXDomain: true, withTransitionForAxis: false});
-
-            // Show tooltip if needed
-            if (__tooltip_init_show) {
-                if (isTimeSeries && typeof __tooltip_init_x === 'string') {
-                    __tooltip_init_x = parseDate(__tooltip_init_x);
-                    for (i = 0; i < c3.data.targets[0].values.length; i++) {
-                        if ((c3.data.targets[0].values[i].x - __tooltip_init_x) === 0) { break; }
-                    }
-                    __tooltip_init_x = i;
-                }
-                tooltip.html(__tooltip_contents(c3.data.targets.map(function (d) {
-                    return addName(d.values[__tooltip_init_x]);
-                }), getXAxisTickFormat(), getYFormat(hasArcType(c3.data.targets)), color));
-                tooltip.style("top", __tooltip_init_position.top)
-                       .style("left", __tooltip_init_position.left)
-                       .style("display", "block");
-            }
+        this.revert();
+        this.defocus();
+        candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
+        if ($$.hasArcType()) {
+            $$.expandArc(targetIds);
         }
+        $$.toggleFocusLegend(targetIds, true);
 
-        function generateEventRectsForSingleX(eventRectEnter) {
-            eventRectEnter.append("rect")
-                .attr("class", classEvent)
-                .style("cursor", __data_selection_enabled && __data_selection_grouped ? "pointer" : null)
-                .on('mouseover', function (_, i) {
-                    if (dragging) { return; } // do nothing if dragging
-                    if (hasArcType(c3.data.targets)) { return; }
-
-                    var selectedData = c3.data.targets.map(function (d) { return addName(d.values[i]); });
-                    var j, newData;
-
-                    // Sort selectedData as names order
-                    if (Object.keys(__data_names).length > 0) {
-                        newData = [];
-                        for (var id in __data_names) {
-                            for (j = 0; j < selectedData.length; j++) {
-                                if (selectedData[j].id === id) {
-                                    newData.push(selectedData[j]);
-                                    selectedData.shift(j);
-                                    break;
-                                }
-                            }
-                        }
-                        selectedData = newData.concat(selectedData); // Add remained
-                    }
-
-                    // Expand shapes if needed
-                    if (__point_focus_expand_enabled) { expandCircles(i); }
-                    expandBars(i);
-
-                    // Call event handler
-                    main.selectAll('.' + CLASS.shape + '-' + i).each(function (d) {
-                        __data_onenter(d);
-                    });
-                })
-                .on('mouseout', function (_, i) {
-                    if (hasArcType(c3.data.targets)) { return; }
-                    hideXGridFocus();
-                    hideTooltip();
-                    // Undo expanded shapes
-                    unexpandCircles(i);
-                    unexpandBars();
-                    // Call event handler
-                    main.selectAll('.' + CLASS.shape + '-' + i).each(function (d) {
-                        __data_onleave(d);
-                    });
-                })
-                .on('mousemove', function (_, i) {
-                    var selectedData;
-
-                    if (dragging) { return; } // do nothing when dragging
-                    if (hasArcType(c3.data.targets)) { return; }
+        $$.focusedTargetIds = targetIds;
+        $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
+            return targetIds.indexOf(id) < 0;
+        });
+    };
 
-                    // Show tooltip
-                    selectedData = filterTargetsToShow(c3.data.targets).map(function (d) {
-                        return addName(d.values[i]);
-                    });
-                    showTooltip(selectedData, d3.mouse(this));
-
-                    // Show xgrid focus line
-                    showXGridFocus(selectedData);
-
-                    if (! __data_selection_enabled) { return; }
-                    if (__data_selection_grouped) { return; } // nothing to do when grouped
-
-                    main.selectAll('.' + CLASS.shape + '-' + i)
-                        .filter(function (d) { return __data_selection_isselectable(d); })
-                        .each(function () {
-                            var _this = d3.select(this).classed(CLASS.EXPANDED, true);
-                            if (this.nodeName === 'circle') { _this.attr('r', pointExpandedR); }
-                            svg.select('.' + CLASS.eventRect + '-' + i).style('cursor', null);
-                        })
-                        .filter(function (d) {
-                            if (this.nodeName === 'circle') {
-                                return isWithinCircle(this, pointSelectR(d));
-                            }
-                            else if (this.nodeName === 'path') {
-                                return isWithinBar(this);
-                            }
-                        })
-                        .each(function () {
-                            var _this = d3.select(this);
-                            if (! _this.classed(CLASS.EXPANDED)) {
-                                _this.classed(CLASS.EXPANDED, true);
-                                if (this.nodeName === 'circle') { _this.attr('r', pointSelectR); }
-                            }
-                            svg.select('.' + CLASS.eventRect + '-' + i).style('cursor', 'pointer');
-                        });
-                })
-                .on('click', function (_, i) {
-                    if (hasArcType(c3.data.targets)) { return; }
-                    if (cancelClick) {
-                        cancelClick = false;
-                        return;
-                    }
-                    main.selectAll('.' + CLASS.shape + '-' + i).each(function (d) { toggleShape(this, d, i); });
-                })
-                .call(
-                    d3.behavior.drag().origin(Object)
-                        .on('drag', function () { drag(d3.mouse(this)); })
-                        .on('dragstart', function () { dragstart(d3.mouse(this)); })
-                        .on('dragend', function () { dragend(); })
-                )
-                .call(zoom).on("dblclick.zoom", null);
-        }
-
-        function generateEventRectsForMultipleXs(eventRectEnter) {
-            eventRectEnter.append('rect')
-                .attr('x', 0)
-                .attr('y', 0)
-                .attr('width', width)
-                .attr('height', height)
-                .attr('class', CLASS.eventRect)
-                .on('mouseout', function () {
-                    if (hasArcType(c3.data.targets)) { return; }
-                    hideXGridFocus();
-                    hideTooltip();
-                    unexpandCircles();
-                })
-                .on('mousemove', function () {
-                    var targetsToShow = filterTargetsToShow(c3.data.targets);
-                    var mouse, closest, sameXData, selectedData;
+    c3_chart_fn.defocus = function (targetIds) {
+        var $$ = this.internal, candidates;
 
-                    if (dragging) { return; } // do nothing when dragging
-                    if (hasArcType(targetsToShow)) { return; }
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
 
-                    mouse = d3.mouse(this);
-                    closest = findClosestFromTargets(targetsToShow, mouse);
+        this.revert();
+        candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
+        if ($$.hasArcType()) {
+            $$.unexpandArc(targetIds);
+        }
+        $$.toggleFocusLegend(targetIds, false);
 
-                    if (! closest) { return; }
+        $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
+            return targetIds.indexOf(id) < 0;
+        });
+        $$.defocusedTargetIds = targetIds;
+    };
 
-                    if (isScatterType(closest)) {
-                        sameXData = [closest];
-                    } else {
-                        sameXData = filterSameX(targetsToShow, closest.x);
-                    }
+    c3_chart_fn.revert = function (targetIds) {
+        var $$ = this.internal, candidates;
 
-                    // show tooltip when cursor is close to some point
-                    selectedData = sameXData.map(function (d) {
-                        return addName(d);
-                    });
-                    showTooltip(selectedData, mouse);
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
 
-                    // expand points
-                    if (__point_focus_expand_enabled) {
-                        unexpandCircles();
-                        expandCircles(closest.index, closest.id);
-                    }
+        candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
+        if ($$.hasArcType()) {
+            $$.unexpandArc(targetIds);
+        }
+        $$.showLegend(targetIds);
 
-                    // Show xgrid focus line
-                    showXGridFocus(selectedData);
+        $$.focusedTargetIds = [];
+        $$.defocusedTargetIds = [];
+    };
 
-                    // Show cursor as pointer if point is close to mouse position
-                    if (dist(closest, mouse) < 100) {
-                        svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
-                        if (!mouseover) {
-                            __data_onenter(closest);
-                            mouseover = true;
-                        }
-                    } else {
-                        svg.select('.' + CLASS.eventRect).style('cursor', null);
-                        __data_onleave(closest);
-                        mouseover = false;
-                    }
-                })
-                .on('click', function () {
-                    var targetsToShow = filterTargetsToShow(c3.data.targets);
-                    var mouse, closest;
+    c3_chart_fn.show = function (targetIds, options) {
+        var $$ = this.internal, targets;
 
-                    if (hasArcType(targetsToShow)) { return; }
+        targetIds = $$.mapToTargetIds(targetIds);
+        options = options || {};
 
-                    mouse = d3.mouse(this);
-                    closest = findClosestFromTargets(targetsToShow, mouse);
+        $$.removeHiddenTargetIds(targetIds);
+        targets = $$.svg.selectAll($$.selectorTargets(targetIds));
 
-                    if (! closest) { return; }
+        targets.transition()
+            .style('opacity', 1, 'important')
+            .call($$.endall, function () {
+                targets.style('opacity', null).style('opacity', 1);
+            });
 
-                    // select if selection enabled
-                    if (dist(closest, mouse) < 100) {
-                        main.select('.' + CLASS.circles + '-' + getTargetSelectorSuffix(closest.id)).select('.' + CLASS.circle + '-' + closest.index).each(function () {
-                            toggleShape(this, closest, closest.index);
-                        });
-                    }
-                })
-                .call(
-                    d3.behavior.drag().origin(Object)
-                        .on('drag', function () { drag(d3.mouse(this)); })
-                        .on('dragstart', function () { dragstart(d3.mouse(this)); })
-                        .on('dragend', function () { dragend(); })
-                )
-                .call(zoom).on("dblclick.zoom", null);
-        }
-
-        function toggleShape(that, d, i) {
-            var shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED), isWithin,  toggle;
-            if (that.nodeName === 'circle') {
-                isWithin = isWithinCircle(that, pointSelectR(d) * 1.5);
-                toggle = togglePoint;
-            }
-            else if (that.nodeName === 'path') {
-                if (shape.classed(CLASS.bar)) {
-                    isWithin = isWithinBar(that);
-                    toggle = toggleBar;
-                } else { // would be arc
-                    isWithin = true;
-                    toggle = toggleArc;
-                }
-            }
-            if (__data_selection_grouped || isWithin) {
-                if (__data_selection_enabled && __data_selection_isselectable(d)) {
-                    if (!__data_selection_multiple) {
-                        main.selectAll('.' + CLASS.shapes + (__data_selection_grouped ? getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
-                            var shape = d3.select(this);
-                            if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
-                        });
-                    }
-                    shape.classed(CLASS.SELECTED, !isSelected);
-                    toggle(!isSelected, shape, d, i);
-                }
-                __data_onclick(d, that);
-            }
+        if (options.withLegend) {
+            $$.showLegend(targetIds);
         }
 
-        function drag(mouse) {
-            var sx, sy, mx, my, minX, maxX, minY, maxY;
-
-            if (hasArcType(c3.data.targets)) { return; }
-            if (! __data_selection_enabled) { return; } // do nothing if not selectable
-            if (__zoom_enabled && ! zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior
-            if (!__data_selection_multiple) { return; } // skip when single selection becuase drag is used for multiple selection
-
-            sx = dragStart[0];
-            sy = dragStart[1];
-            mx = mouse[0];
-            my = mouse[1];
-            minX = Math.min(sx, mx);
-            maxX = Math.max(sx, mx);
-            minY = (__data_selection_grouped) ? margin.top : Math.min(sy, my);
-            maxY = (__data_selection_grouped) ? height : Math.max(sy, my);
-
-            main.select('.' + CLASS.dragarea)
-                .attr('x', minX)
-                .attr('y', minY)
-                .attr('width', maxX - minX)
-                .attr('height', maxY - minY);
-            // TODO: binary search when multiple xs
-            main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape)
-                .filter(function (d) { return __data_selection_isselectable(d); })
-                .each(function (d, i) {
-                    var _this = d3.select(this),
-                        isSelected = _this.classed(CLASS.SELECTED),
-                        isIncluded = _this.classed(CLASS.INCLUDED),
-                        _x, _y, _w, _h, toggle, isWithin = false, box;
-                    if (this.nodeName === 'circle') {
-                        _x = _this.attr("cx") * 1;
-                        _y = _this.attr("cy") * 1;
-                        toggle = togglePoint;
-                        isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
-                    }
-                    else if (this.nodeName === 'path') {
-                        box = getPathBox(this);
-                        _x = box.x;
-                        _y = box.y;
-                        _w = box.width;
-                        _h = box.height;
-                        toggle = toggleBar;
-                        isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
-                    }
-                    if (isWithin ^ isIncluded) {
-                        _this.classed(CLASS.INCLUDED, !isIncluded);
-                        // TODO: included/unincluded callback here
-                        _this.classed(CLASS.SELECTED, !isSelected);
-                        toggle(!isSelected, _this, d, i);
-                    }
-                });
-        }
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+    };
 
-        function dragstart(mouse) {
-            if (hasArcType(c3.data.targets)) { return; }
-            if (! __data_selection_enabled) { return; } // do nothing if not selectable
-            dragStart = mouse;
-            main.select('.' + CLASS.chart).append('rect')
-                .attr('class', CLASS.dragarea)
-                .style('opacity', 0.1);
-            dragging = true;
-            __data_ondragstart();
-        }
+    c3_chart_fn.hide = function (targetIds, options) {
+        var $$ = this.internal, targets;
 
-        function dragend() {
-            if (hasArcType(c3.data.targets)) { return; }
-            if (! __data_selection_enabled) { return; } // do nothing if not selectable
-            main.select('.' + CLASS.dragarea)
-                .transition().duration(100)
-                .style('opacity', 0)
-                .remove();
-            main.selectAll('.' + CLASS.shape)
-                .classed(CLASS.INCLUDED, false);
-            dragging = false;
-            __data_ondragend();
-        }
-
-        function redraw(options) {
-            var xaxis, subxaxis, yaxis, y2axis, xgrid, xgridData, xgridLines, xgridLine, ygrid, ygridLines, ygridLine;
-            var mainLine, mainArea, mainCircle, mainBar, mainArc, mainRegion, mainText, contextLine, contextBar, eventRect, eventRectUpdate;
-            var barIndices = getBarIndices(), maxDataCountTarget;
-            var rectX, rectW;
-            var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis, withTransform, withUpdateXDomain, withUpdateOrgXDomain, withLegend;
-            var hideAxis = hasArcType(c3.data.targets);
-            var drawBar, drawBarOnSub, xForText, yForText;
-            var transitions, duration, durationForExit, durationForAxis;
-            var targetsToShow = filterTargetsToShow(c3.data.targets), tickValues, i, intervalForCulling;
-
-            options = isDefined(options) ? options : {};
-            withY = isDefined(options.withY) ? options.withY : true;
-            withSubchart = isDefined(options.withSubchart) ? options.withSubchart : true;
-            withTransition = isDefined(options.withTransition) ? options.withTransition : true;
-            withTransform = isDefined(options.withTransform) ? options.withTransform : false;
-            withUpdateXDomain = isDefined(options.withUpdateXDomain) ? options.withUpdateXDomain : false;
-            withUpdateOrgXDomain = isDefined(options.withUpdateOrgXDomain) ? options.withUpdateOrgXDomain : false;
-            withLegend = isDefined(options.withLegend) ? options.withLegend : false;
-
-            withTransitionForExit = isDefined(options.withTransitionForExit) ? options.withTransitionForExit : withTransition;
-            withTransitionForAxis = isDefined(options.withTransitionForAxis) ? options.withTransitionForAxis : withTransition;
-
-            duration = withTransition ? __transition_duration : 0;
-            durationForExit = withTransitionForExit ? duration : 0;
-            durationForAxis = withTransitionForAxis ? duration : 0;
-
-            xaxis = main.select('.' + CLASS.axisX).style("opacity", hideAxis ? 0 : 1);
-            yaxis = main.select('.' + CLASS.axisY).style("opacity", hideAxis ? 0 : 1);
-            y2axis = main.select('.' + CLASS.axisY2).style("opacity", hideAxis ? 0 : 1);
-            subxaxis = context.select('.' + CLASS.axisX).style("opacity", hideAxis ? 0 : 1);
-
-            transitions = {
-                axisX: xaxis.transition().duration(durationForAxis),
-                axisY: yaxis.transition().duration(durationForAxis),
-                axisY2: y2axis.transition().duration(durationForAxis),
-                axisSubX: subxaxis.transition().duration(durationForAxis),
-            };
+        targetIds = $$.mapToTargetIds(targetIds);
+        options = options || {};
 
-            // update legend and transform each g
-            if (withLegend && __legend_show) {
-                updateLegend(mapToIds(c3.data.targets), options, transitions);
-            }
+        $$.addHiddenTargetIds(targetIds);
+        targets = $$.svg.selectAll($$.selectorTargets(targetIds));
 
-            if (isCategorized) {
-                // ATTENTION: need to update domain with current domain when categoryAxis
-                if (targetsToShow.length === 0 || !withUpdateOrgXDomain || !withUpdateXDomain) {
-                    x.domain([0, xaxis.selectAll('.tick').size()]);
-                }
-            }
+        targets.transition()
+            .style('opacity', 0, 'important')
+            .call($$.endall, function () {
+                targets.style('opacity', null).style('opacity', 0);
+            });
 
-            if (targetsToShow.length) {
-                if (withUpdateOrgXDomain) {
-                    x.domain(d3.extent(getXDomain(targetsToShow)));
-                    orgXDomain = x.domain();
-                    if (__zoom_enabled) { zoom.scale(x).updateScaleExtent(); }
-                    subX.domain(x.domain());
-                    brush.scale(subX);
-                }
-                // ATTENTION: call here to update tickOffset
-                if (withUpdateXDomain) {
-                    x.domain(brush.empty() ? orgXDomain : brush.extent());
-                    if (__zoom_enabled) { zoom.scale(x).updateScaleExtent(); }
-                }
-                // update axis tick values according to options
-                if (!__axis_x_tick_values && (__axis_x_tick_fit || __axis_x_tick_count)) {
-                    tickValues = generateTickValues(mapTargetsToUniqueXs(targetsToShow), __axis_x_tick_count);
-                    xAxis.tickValues(tickValues);
-                    subXAxis.tickValues(tickValues);
-                }
-            }
+        if (options.withLegend) {
+            $$.hideLegend(targetIds);
+        }
 
-            y.domain(getYDomain(targetsToShow, 'y'));
-            y2.domain(getYDomain(targetsToShow, 'y2'));
-
-            // axes
-            transitions.axisX.call(xAxis);
-            transitions.axisY.call(yAxis);
-            transitions.axisY2.call(y2Axis);
-            transitions.axisSubX.call(subXAxis);
-
-            // show/hide if manual culling needed
-            if (withUpdateXDomain && targetsToShow.length) {
-                if (__axis_x_tick_culling && tickValues) {
-                    for (i = 1; i < tickValues.length; i++) {
-                        if (tickValues.length / i < __axis_x_tick_culling_max) {
-                            intervalForCulling = i;
-                            break;
-                        }
-                    }
-                    svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
-                        var index = tickValues.indexOf(e);
-                        if (index >= 0) {
-                            d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
-                        }
-                    });
-                } else {
-                    svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
-                }
-            }
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+    };
 
-            // rotate tick text if needed
-            if (!__axis_rotated && __axis_x_tick_rotate) {
-                rotateTickText(xaxis, transitions.axisX, __axis_x_tick_rotate);
+    c3_chart_fn.toggle = function (targetIds) {
+        var that = this, $$ = this.internal;
+        $$.mapToTargetIds(targetIds).forEach(function (targetId) {
+            $$.isTargetToShow(targetId) ? that.hide(targetId) : that.show(targetId);
+        });
+    };
+
+    c3_chart_fn.zoom = function (domain) {
+        var $$ = this.internal;
+        if (domain) {
+            if ($$.isTimeSeries()) {
+                domain = domain.map(function (x) { return $$.parseDate(x); });
             }
+            $$.brush.extent(domain);
+            $$.redraw({withUpdateXDomain: true, withY: $$.config.zoom_rescale});
+            $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
+        }
+        return $$.brush.extent();
+    };
+    c3_chart_fn.zoom.enable = function (enabled) {
+        var $$ = this.internal;
+        $$.config.zoom_enabled = enabled;
+        $$.updateAndRedraw();
+    };
+    c3_chart_fn.unzoom = function () {
+        var $$ = this.internal;
+        $$.brush.clear().update();
+        $$.redraw({withUpdateXDomain: true});
+    };
 
-            // setup drawer - MEMO: these must be called after axis updated
-            drawBar = generateDrawBar(barIndices);
-            xForText = generateXYForText(barIndices, true);
-            yForText = generateXYForText(barIndices, false);
+    c3_chart_fn.load = function (args) {
+        var $$ = this.internal, config = $$.config;
+        // update xs if specified
+        if (args.xs) {
+            $$.addXs(args.xs);
+        }
+        // update classes if exists
+        if ('classes' in args) {
+            Object.keys(args.classes).forEach(function (id) {
+                config.data_classes[id] = args.classes[id];
+            });
+        }
+        // update categories if exists
+        if ('categories' in args && $$.isCategorized()) {
+            config.axis_x_categories = args.categories;
+        }
+        // update axes if exists
+        if ('axes' in args) {
+            Object.keys(args.axes).forEach(function (id) {
+                config.data_axes[id] = args.axes[id];
+            });
+        }
+        // use cache if exists
+        if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
+            $$.load($$.getCaches(args.cacheIds), args.done);
+            return;
+        }
+        // unload if needed
+        if ('unload' in args) {
+            // TODO: do not unload if target will load (included in url/rows/columns)
+            $$.unload($$.mapToTargetIds((typeof args.unload === 'boolean' && args.unload) ? null : args.unload), function () {
+                $$.loadFromArgs(args);
+            });
+        } else {
+            $$.loadFromArgs(args);
+        }
+    };
 
-            // Update axis label
-            updateAxisLabels();
+    c3_chart_fn.unload = function (args) {
+        var $$ = this.internal;
+        args = args || {};
+        if (args instanceof Array) {
+            args = {ids: args};
+        } else if (typeof args === 'string') {
+            args = {ids: [args]};
+        }
+        $$.unload($$.mapToTargetIds(args.ids), function () {
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+            if (args.done) { args.done(); }
+        });
+    };
 
-            // Update sub domain
-            subY.domain(y.domain());
-            subY2.domain(y2.domain());
+    c3_chart_fn.flow = function (args) {
+        var $$ = this.internal,
+            targets, data, notfoundIds = [], orgDataCount = $$.getMaxDataCount(),
+            dataCount, domain, baseTarget, baseValue, length = 0, tail = 0, diff, to;
 
-            // tooltip
-            tooltip.style("display", "none");
+        if (args.json) {
+            data = $$.convertJsonToData(args.json, args.keys);
+        }
+        else if (args.rows) {
+            data = $$.convertRowsToData(args.rows);
+        }
+        else if (args.columns) {
+            data = $$.convertColumnsToData(args.columns);
+        }
+        else {
+            return;
+        }
+        targets = $$.convertDataToTargets(data, true);
 
-            // xgrid focus
-            updateXgridFocus();
+        // Update/Add data
+        $$.data.targets.forEach(function (t) {
+            var found = false, i, j;
+            for (i = 0; i < targets.length; i++) {
+                if (t.id === targets[i].id) {
+                    found = true;
 
-            // grid
-            main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
-            if (__grid_x_show) {
-                if (__grid_x_type === 'year') {
-                    xgridData = [];
-                    var xDomain = getXDomain();
-                    var firstYear = xDomain[0].getFullYear();
-                    var lastYear = xDomain[1].getFullYear();
-                    for (var year = firstYear; year <= lastYear; year++) {
-                        xgridData.push(new Date(year + '-01-01 00:00:00'));
+                    if (t.values[t.values.length - 1]) {
+                        tail = t.values[t.values.length - 1].index + 1;
                     }
-                } else {
-                    xgridData = x.ticks(10);
-                }
+                    length = targets[i].values.length;
 
-                xgrid = main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid)
-                    .data(xgridData);
-                xgrid.enter().append('line').attr("class", CLASS.xgrid);
-                xgrid.attr("x1", __axis_rotated ? 0 : function (d) { return x(d) - xAxis.tickOffset(); })
-                    .attr("x2", __axis_rotated ? width : function (d) { return x(d) - xAxis.tickOffset(); })
-                    .attr("y1", __axis_rotated ? function (d) { return x(d) - xAxis.tickOffset(); } : margin.top)
-                    .attr("y2", __axis_rotated ? function (d) { return x(d) - xAxis.tickOffset(); } : height)
-                    .style("opacity", function () { return +d3.select(this).attr(__axis_rotated ? 'y1' : 'x1') === (__axis_rotated ? height : 0) ? 0 : 1; });
-                xgrid.exit().remove();
-            }
-            if (notEmpty(__grid_x_lines)) {
-                xgridLines = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine)
-                    .data(__grid_x_lines);
-                // enter
-                xgridLine = xgridLines.enter().append('g')
-                    .attr("class", function (d) { return CLASS.xgridLine + (d.class ? d.class : ''); });
-                xgridLine.append('line')
-                    .style("opacity", 0);
-                xgridLine.append('text')
-                    .attr("text-anchor", "end")
-                    .attr("transform", __axis_rotated ? "" : "rotate(-90)")
-                    .attr('dx', __axis_rotated ? 0 : -margin.top)
-                    .attr('dy', -5)
-                    .style("opacity", 0);
-                // udpate
-                xgridLines.select('line')
-                  .transition().duration(duration)
-                    .attr("x1", __axis_rotated ? 0 : xv)
-                    .attr("x2", __axis_rotated ? width : xv)
-                    .attr("y1", __axis_rotated ? xv : margin.top)
-                    .attr("y2", __axis_rotated ? xv : height)
-                    .style("opacity", 1);
-                xgridLines.select('text')
-                  .transition().duration(duration)
-                    .attr("x", __axis_rotated ? width : 0)
-                    .attr("y", xv)
-                    .text(function (d) { return d.text; })
-                    .style("opacity", 1);
-                // exit
-                xgridLines.exit().transition().duration(duration)
-                    .style("opacity", 0)
-                    .remove();
-            }
-            // Y-Grid
-            if (withY && __grid_y_show) {
-                ygrid = main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
-                    .data(y.ticks(__grid_y_ticks));
-                ygrid.enter().append('line')
-                    .attr('class', CLASS.ygrid);
-                ygrid.attr("x1", __axis_rotated ? y : 0)
-                    .attr("x2", __axis_rotated ? y : width)
-                    .attr("y1", __axis_rotated ? 0 : y)
-                    .attr("y2", __axis_rotated ? height : y);
-                ygrid.exit().remove();
-            }
-            if (withY && notEmpty(__grid_y_lines)) {
-                ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
-                    .data(__grid_y_lines);
-                // enter
-                ygridLine = ygridLines.enter().append('g')
-                    .attr("class", function (d) { return CLASS.ygridLine + (d.class ? d.class : ''); });
-                ygridLine.append('line')
-                    .style("opacity", 0);
-                ygridLine.append('text')
-                    .attr("text-anchor", "end")
-                    .attr("transform", __axis_rotated ? "rotate(-90)" : "")
-                    .attr('dx', __axis_rotated ? 0 : -margin.top)
-                    .attr('dy', -5)
-                    .style("opacity", 0);
-                // update
-                ygridLines.select('line')
-                  .transition().duration(duration)
-                    .attr("x1", __axis_rotated ? yv : 0)
-                    .attr("x2", __axis_rotated ? yv : width)
-                    .attr("y1", __axis_rotated ? 0 : yv)
-                    .attr("y2", __axis_rotated ? height : yv)
-                    .style("opacity", 1);
-                ygridLines.select('text')
-                  .transition().duration(duration)
-                    .attr("x", __axis_rotated ? 0 : width)
-                    .attr("y", yv)
-                    .text(function (d) { return d.text; })
-                    .style("opacity", 1);
-                // exit
-                ygridLines.exit().transition().duration(duration)
-                    .style("opacity", 0)
-                    .remove();
-            }
-
-            // rect for regions
-            mainRegion = main.select('.' + CLASS.regions).selectAll('rect.' + CLASS.region)
-                .data(__regions);
-            mainRegion.enter().append('rect')
-                .style("fill-opacity", 0);
-            mainRegion
-                .attr('class', classRegion)
-                .attr("x", regionX)
-                .attr("y", regionY)
-                .attr("width", regionWidth)
-                .attr("height", regionHeight)
-              .transition().duration(duration)
-                .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; });
-            mainRegion.exit().transition().duration(duration)
-                .style("fill-opacity", 0)
-                .remove();
-
-            // bars
-            mainBar = main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
-                .data(barData);
-            mainBar.enter().append('path')
-                .attr("class", classBar)
-                .style("stroke", 'none')
-                .style("fill", color);
-            mainBar
-                .style("opacity", initialOpacity)
-              .transition().duration(duration)
-                .attr('d', drawBar)
-                .style("fill", color)
-                .style("opacity", 1);
-            mainBar.exit().transition().duration(durationForExit)
-                .style('opacity', 0)
-                .remove();
-
-            // lines and cricles
-            mainLine = main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
-                .data(lineData);
-            mainLine.enter().append('path')
-                .attr('class', classLine)
-                .style("stroke", color);
-            mainLine
-                .style("opacity", initialOpacity)
-              .transition().duration(duration)
-                .attr("d", lineOnMain)
-                .style("opacity", 1);
-            mainLine.exit().transition().duration(durationForExit)
-                .style('opacity', 0)
-                .remove();
-
-            mainArea = main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
-                .data(lineData);
-            mainArea.enter().append('path')
-                .attr("class", classArea)
-                .style("fill", color)
-                .style("opacity", function () { orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
-            mainArea
-                .style("opacity", 0)
-              .transition().duration(duration)
-                .attr("d", areaOnMain)
-                .style("opacity", orgAreaOpacity);
-            mainArea.exit().transition().duration(durationForExit)
-                .style('opacity', 0)
-                .remove();
-
-            mainCircle = main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
-                .data(lineOrScatterData);
-            mainCircle.enter().append("circle")
-                .attr("class", classCircle)
-                .attr("r", pointR);
-            mainCircle
-                .style("opacity", initialOpacity)
-              .transition().duration(duration)
-                .style('opacity', opacityForCircle)
-                .attr("cx", __axis_rotated ? circleY : circleX)
-                .attr("cy", __axis_rotated ? circleX : circleY);
-            mainCircle.exit().remove();
-
-            mainText = main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text)
-                .data(barOrLineData);
-            mainText.enter().append('text')
-                .attr("class", classText)
-                .attr('text-anchor', function (d) { return __axis_rotated ? (d.value < 0 ? 'end' : 'start') : 'middle'; })
-                .style("stroke", 'none')
-                .style("fill-opacity", 0);
-            mainText
-                .text(function (d) { return formatByAxisId(d.id)(d.value, d.id); })
-                .style("fill-opacity", initialOpacityForText)
-              .transition().duration(duration)
-                .attr('x', xForText)
-                .attr('y', yForText)
-                .style("fill-opacity", opacityForText);
-            mainText.exit()
-              .transition().duration(durationForExit)
-                .style('fill-opacity', 0)
-                .remove();
-
-            // arc
-            mainArc = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc)
-                .data(arcData);
-            mainArc.enter().append('path')
-                .attr("class", classArc)
-                .style("fill", function (d) { return color(d.data); })
-                .style("cursor", function (d) { return __data_selection_isselectable(d) ? "pointer" : null; })
-                .style("opacity", 0)
-                .each(function (d) { this._current = d; })
-                .on('mouseover', function (d, i) {
-                    var updated, arcData, callback;
-                    if (transiting) { // skip while transiting
-                        return;
-                    }
-                    updated = updateAngle(d);
-                    arcData = convertToArcData(updated);
-                    callback = getArcOnMouseOver();
-                    // transitions
-                    expandArc(updated.data.id);
-                    toggleFocusLegend(updated.data.id, true);
-                    callback(arcData, i);
-                })
-                .on('mousemove', function (d) {
-                    var updated = updateAngle(d), arcData = convertToArcData(updated), selectedData = [arcData];
-                    showTooltip(selectedData, d3.mouse(this));
-                })
-                .on('mouseout', function (d, i) {
-                    var updated, arcData, callback;
-                    if (transiting) { // skip while transiting
-                        return;
-                    }
-                    updated = updateAngle(d);
-                    arcData = convertToArcData(updated);
-                    callback = getArcOnMouseOut();
-                    // transitions
-                    unexpandArc(updated.data.id);
-                    revertLegend();
-                    hideTooltip();
-                    callback(arcData, i);
-                })
-                .on('click', function (d, i) {
-                    var updated = updateAngle(d), arcData = convertToArcData(updated), callback = getArcOnClick();
-                    toggleShape(this, d, i);
-                    callback(arcData, i);
-                });
-            mainArc
-                .attr("transform", withTransform ? "scale(0)" : "")
-                .style("opacity", function (d) { return d === this._current ? 0 : 1; })
-                .each(function () { transiting = true; })
-              .transition().duration(duration)
-                .attrTween("d", function (d) {
-                    var updated = updateAngle(d), interpolate;
-                    if (! updated) {
-                        return function () { return "M 0 0"; };
-                    }
-/*
-                    if (this._current === d) {
-                        this._current = {
-                            startAngle: Math.PI*2,
-                            endAngle: Math.PI*2,
-                        };
+                    for (j = 0; j < length; j++) {
+                        targets[i].values[j].index = tail + j;
+                        if (!$$.isTimeSeries()) {
+                            targets[i].values[j].x = tail + j;
+                        }
                     }
-*/
-                    interpolate = d3.interpolate(this._current, updated);
-                    this._current = interpolate(0);
-                    return function (t) { return getArc(interpolate(t), true); };
-                })
-                .attr("transform", withTransform ? "scale(1)" : "")
-                .style("opacity", 1)
-                .call(endall, function () {
-                    transiting = false;
-                });
-            mainArc.exit().transition().duration(durationForExit)
-                .style('opacity', 0)
-                .remove();
-            main.selectAll('.' + CLASS.chartArc).select('text')
-                .attr("transform", transformForArcLabel)
-                .style("opacity", 0)
-              .transition().duration(duration)
-                .text(textForArcLabel)
-                .style("opacity", function (d) { return isTargetToShow(d.data.id) && isArcType(d.data) ? 1 : 0; });
-            main.select('.' + CLASS.chartArcsTitle)
-                .style("opacity", hasDonutType(c3.data.targets) ? 1 : 0);
+                    t.values = t.values.concat(targets[i].values);
 
-            // subchart
-            if (__subchart_show) {
-                // reflect main chart to extent on subchart if zoomed
-                if (d3.event !== null && d3.event.type === 'zoom') {
-                    brush.extent(x.orgDomain()).update();
+                    targets.splice(i, 1);
+                    break;
                 }
-                // update subchart elements if needed
-                if (withSubchart) {
-
-                    // rotate tick text if needed
-                    if (!__axis_rotated && __axis_x_tick_rotate) {
-                        rotateTickText(subxaxis, transitions.axisSubX, __axis_x_tick_rotate);
-                    }
+            }
+            if (!found) { notfoundIds.push(t.id); }
+        });
 
-                    // extent rect
-                    if (!brush.empty()) {
-                        brush.extent(x.orgDomain()).update();
+        // Append null for not found targets
+        $$.data.targets.forEach(function (t) {
+            var i, j;
+            for (i = 0; i < notfoundIds.length; i++) {
+                if (t.id === notfoundIds[i]) {
+                    tail = t.values[t.values.length - 1].index + 1;
+                    for (j = 0; j < length; j++) {
+                        t.values.push({
+                            id: t.id,
+                            index: tail + j,
+                            x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
+                            value: null
+                        });
                     }
-                    // setup drawer - MEMO: this must be called after axis updated
-                    drawBarOnSub = generateDrawBar(barIndices, true);
-                    // bars
-                    contextBar = context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
-                        .data(barData);
-                    contextBar.enter().append('path')
-                        .attr("class", classBar)
-                        .style("stroke", 'none')
-                        .style("fill", color);
-                    contextBar
-                        .style("opacity", initialOpacity)
-                      .transition().duration(duration)
-                        .attr('d', drawBarOnSub)
-                        .style('opacity', 1);
-                    contextBar.exit().transition().duration(duration)
-                        .style('opacity', 0)
-                        .remove();
-                    // lines
-                    contextLine = context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
-                        .data(lineData);
-                    contextLine.enter().append('path')
-                        .attr('class', classLine)
-                        .style('stroke', color);
-                    contextLine
-                        .style("opacity", initialOpacity)
-                      .transition().duration(duration)
-                        .attr("d", lineOnSub)
-                        .style('opacity', 1);
-                    contextLine.exit().transition().duration(duration)
-                        .style('opacity', 0)
-                        .remove();
                 }
             }
+        });
 
-            // circles for select
-            main.selectAll('.' + CLASS.selectedCircles)
-                .filter(function (d) { return isBarType(d); })
-                .selectAll('circle')
-                .remove();
-            main.selectAll('.' + CLASS.selectedCircle)
-              .transition().duration(duration)
-                .attr("cx", __axis_rotated ? circleY : circleX)
-                .attr("cy", __axis_rotated ? circleX : circleY);
-
-            // rect for mouseover
-            eventRect = main.select('.' + CLASS.eventRects);
-            if (notEmpty(__data_xs) && !isSingleX(__data_xs)) {
-
-                if (!eventRect.classed(CLASS.eventRectsMultiple)) {
-                    eventRect.classed(CLASS.eventRectsMultiple, true).classed(CLASS.eventRectsSingle, false)
-                        .selectAll('.' + CLASS.eventRect).remove();
+        // Generate null values for new target
+        if ($$.data.targets.length) {
+            targets.forEach(function (t) {
+                var i, missing = [];
+                for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
+                    missing.push({
+                        id: t.id,
+                        index: i,
+                        x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
+                        value: null
+                    });
                 }
+                t.values.forEach(function (v) {
+                    v.index += tail;
+                    if (!$$.isTimeSeries()) {
+                        v.x += tail;
+                    }
+                });
+                t.values = missing.concat(t.values);
+            });
+        }
+        $$.data.targets = $$.data.targets.concat(targets); // add remained
 
-                eventRectUpdate = main.select('.' + CLASS.eventRects).selectAll('.' + CLASS.eventRect)
-                    .data([0]);
-                // enter : only one rect will be added
-                generateEventRectsForMultipleXs(eventRectUpdate.enter());
-                // update
-                eventRectUpdate
-                    .attr('x', 0)
-                    .attr('y', 0)
-                    .attr('width', width)
-                    .attr('height', height);
-                // exit : not needed becuase always only one rect exists
-            } else {
+        // check data count because behavior needs to change when it's only one
+        dataCount = $$.getMaxDataCount();
+        baseTarget = $$.data.targets[0];
+        baseValue = baseTarget.values[0];
 
-                if (!eventRect.classed(CLASS.eventRectsSingle)) {
-                    eventRect.classed(CLASS.eventRectsMultiple, false).classed(CLASS.eventRectsSingle, true)
-                        .selectAll('.' + CLASS.eventRect).remove();
-                }
+        // Update length to flow if needed
+        if (isDefined(args.to)) {
+            length = 0;
+            to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
+            baseTarget.values.forEach(function (v) {
+                if (v.x < to) { length++; }
+            });
+        } else if (isDefined(args.length)) {
+            length = args.length;
+        }
 
-                if (isCustomX && !isCategorized) {
-                    rectW = function (d, i) {
-                        var prevX = getPrevX(i), nextX = getNextX(i), dx = c3.data.xs[d.id][i];
-                        return (x(nextX ? nextX : dx + 50) - x(prevX ? prevX : dx - 50)) / 2;
-                    };
-                    rectX = function (d, i) {
-                        var prevX = getPrevX(i), dx = c3.data.xs[d.id][i];
-                        return (x(dx) + x(prevX ? prevX : dx - 50)) / 2;
-                    };
+        // If only one data, update the domain to flow from left edge of the chart
+        if (!orgDataCount) {
+            if ($$.isTimeSeries()) {
+                if (baseTarget.values.length > 1) {
+                    diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
                 } else {
-                    rectW = getEventRectWidth();
-                    rectX = function (d) {
-                        return x(d.x) - (rectW / 2);
-                    };
+                    diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
                 }
-                // Set data
-                maxDataCountTarget = getMaxDataCountTarget(c3.data.targets);
-                main.select('.' + CLASS.eventRects)
-                    .datum(maxDataCountTarget ? maxDataCountTarget.values : []);
-                // Update rects
-                eventRectUpdate = main.select('.' + CLASS.eventRects).selectAll('.' + CLASS.eventRect)
-                    .data(function (d) { return d; });
-                // enter
-                generateEventRectsForSingleX(eventRectUpdate.enter());
-                // update
-                eventRectUpdate
-                    .attr('class', classEvent)
-                    .attr("x", __axis_rotated ? 0 : rectX)
-                    .attr("y", __axis_rotated ? rectX : 0)
-                    .attr("width", __axis_rotated ? width : rectW)
-                    .attr("height", __axis_rotated ? rectW : height);
-                // exit
-                eventRectUpdate.exit().remove();
-            }
-
-            // update fadein condition
-            mapToIds(c3.data.targets).forEach(function (id) {
-                withoutFadeIn[id] = true;
-            });
-        }
-        function redrawForBrush() {
-            redraw({
-                withTransition: false,
-                withY: false,
-                withSubchart: false,
-                withUpdateXDomain: true
-            });
-        }
-        function redrawForZoom() {
-            if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) {
-                x.domain(zoom.altDomain);
-                zoom.scale(x).updateScaleExtent();
-                return;
-            }
-            if (isCategorized && x.orgDomain()[0] === orgXDomain[0]) {
-                x.domain([orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
-            }
-            redraw({
-                withTransition: false,
-                withY: false,
-                withSubchart: false
-            });
-            if (d3.event.sourceEvent.type === 'mousemove') {
-                cancelClick = true;
+            } else {
+                diff = 1;
             }
-        }
-
-        function generateResize() {
-            var resizeFunctions = [];
-            function callResizeFunctions() {
-                resizeFunctions.forEach(function (f) {
-                    f();
-                });
+            domain = [baseValue.x - diff, baseValue.x];
+            $$.updateXDomain(null, true, true, false, domain);
+        } else if (orgDataCount === 1) {
+            if ($$.isTimeSeries()) {
+                diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
+                domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
+                $$.updateXDomain(null, true, true, false, domain);
             }
-            callResizeFunctions.add = function (f) {
-                resizeFunctions.push(f);
-            };
-            return callResizeFunctions;
-        }
-
-        function updateSvgSize() {
-            svg.attr('width', currentWidth).attr('height', currentHeight);
-            svg.select('#' + clipId).select('rect')
-                .attr('width', width)
-                .attr('height', height);
-            svg.select('#' + clipIdForXAxis).select('rect')
-                .attr('x', getXAxisClipX)
-                .attr('y', getXAxisClipY)
-                .attr('width', getXAxisClipWidth)
-                .attr('height', getXAxisClipHeight);
-            svg.select('#' + clipIdForYAxis).select('rect')
-                .attr('x', getYAxisClipX)
-                .attr('y', getYAxisClipY)
-                .attr('width', getYAxisClipWidth)
-                .attr('height', getYAxisClipHeight);
-            svg.select('.' + CLASS.zoomRect)
-                .attr('width', width)
-                .attr('height', height);
-            // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
-            selectChart.style('max-height', currentHeight + "px");
-        }
-
-        function updateAndRedraw(options) {
-            options = options || {};
-            // same with redraw
-            options.withTransition = isDefined(options.withTransition) ? options.withTransition : true;
-            options.withTransform = isDefined(options.withTransform) ? options.withTransform : false;
-            options.withLegend = isDefined(options.withLegend) ? options.withLegend : false;
-            // NOT same with redraw
-            options.withUpdateXDomain = true;
-            options.withUpdateOrgXDomain = true;
-            options.withTransitionForExit = false;
-            // Update sizes and scales
-            updateSizes();
-            updateScales();
-            updateSvgSize();
-            // Update g positions
-            transformAll(options.withTransition);
-            // Draw with new sizes & scales
-            redraw(options);
         }
 
-        function updateTargets(targets) {
-            var mainLineEnter, mainLineUpdate, mainBarEnter, mainBarUpdate, mainPieEnter, mainPieUpdate, mainTextUpdate, mainTextEnter;
-            var contextLineEnter, contextLineUpdate, contextBarEnter, contextBarUpdate;
-
-            /*-- Main --*/
-
-            //-- Text --//
-            mainTextUpdate = main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
-                .data(targets)
-                .attr('class', classChartText);
-            mainTextEnter = mainTextUpdate.enter().append('g')
-                .attr('class', classChartText)
-                .style('opacity', 0)
-                .style("pointer-events", "none");
-            mainTextEnter.append('g')
-                .attr('class', classTexts)
-                .style("fill", color);
+        // Set targets
+        $$.updateTargets($$.data.targets);
 
-            //-- Bar --//
-            mainBarUpdate = main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
-                .data(targets)
-                .attr('class', classChartBar);
-            mainBarEnter = mainBarUpdate.enter().append('g')
-                .attr('class', classChartBar)
-                .style('opacity', 0)
-                .style("pointer-events", "none");
-            // Bars for each data
-            mainBarEnter.append('g')
-                .attr("class", classBars)
-                .style("cursor", function (d) { return __data_selection_isselectable(d) ? "pointer" : null; });
+        // Redraw with new targets
+        $$.redraw({
+            flow: {
+                index: baseValue.index,
+                length: length,
+                duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
+                done: args.done,
+                orgDataCount: orgDataCount,
+            },
+            withLegend: true,
+            withTransition: orgDataCount > 1,
+            withTrimXDomain: false,
+            withUpdateXAxis: true,
+        });
+    };
 
-            //-- Line --//
-            mainLineUpdate = main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
-                .data(targets)
-                .attr('class', classChartLine);
-            mainLineEnter = mainLineUpdate.enter().append('g')
-                .attr('class', classChartLine)
-                .style('opacity', 0)
-                .style("pointer-events", "none");
-            // Lines for each data
-            mainLineEnter.append('g')
-                .attr("class", classLines);
-            // Areas
-            mainLineEnter.append('g')
-                .attr('class', classAreas);
-            // Circles for each data point on lines
-            mainLineEnter.append('g')
-                .attr("class", function (d) { return generateClass(CLASS.selectedCircles, d.id); });
-            mainLineEnter.append('g')
-                .attr("class", classCircles)
-                .style("fill", color)
-                .style("cursor", function (d) { return __data_selection_isselectable(d) ? "pointer" : null; });
-            // Update date for selected circles
-            targets.forEach(function (t) {
-                main.selectAll('.' + CLASS.selectedCircles + getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d, i) {
-                    d.value = t.values[i].value;
-                });
+    c3_chart_internal_fn.generateFlow = function (args) {
+        var $$ = this, config = $$.config, d3 = $$.d3;
+
+        return function () {
+            var targets = args.targets,
+                flow = args.flow,
+                drawBar = args.drawBar,
+                drawLine = args.drawLine,
+                drawArea = args.drawArea,
+                cx = args.cx,
+                cy = args.cy,
+                xv = args.xv,
+                xForText = args.xForText,
+                yForText = args.yForText,
+                duration = args.duration;
+
+            var translateX, scaleX = 1, transform,
+                flowIndex = flow.index,
+                flowLength = flow.length,
+                flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
+                flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
+                orgDomain = $$.x.domain(), domain,
+                durationForFlow = flow.duration || duration,
+                done = flow.done || function () {},
+                wait = $$.generateWait();
+
+            var xgrid = $$.xgrid || d3.selectAll([]),
+                xgridLines = $$.xgridLines || d3.selectAll([]),
+                mainRegion = $$.mainRegion || d3.selectAll([]),
+                mainText = $$.mainText || d3.selectAll([]),
+                mainBar = $$.mainBar || d3.selectAll([]),
+                mainLine = $$.mainLine || d3.selectAll([]),
+                mainArea = $$.mainArea || d3.selectAll([]),
+                mainCircle = $$.mainCircle || d3.selectAll([]);
+
+            // set flag
+            $$.flowing = true;
+
+            // remove head data after rendered
+            $$.data.targets.forEach(function (d) {
+                d.values.splice(0, flowLength);
             });
-            // MEMO: can not keep same color...
-            //mainLineUpdate.exit().remove();
-
-            //-- Pie --//
-            mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
-                .data(pie(targets))
-                .attr("class", classChartArc);
-            mainPieEnter = mainPieUpdate.enter().append("g")
-                .attr("class", classChartArc);
-            mainPieEnter.append('g')
-                .attr('class', classArcs);
-            mainPieEnter.append("text")
-                .attr("dy", ".35em")
-                .style("opacity", 0)
-                .style("text-anchor", "middle")
-                .style("pointer-events", "none");
-            // MEMO: can not keep same color..., but not bad to update color in redraw
-            //mainPieUpdate.exit().remove();
-
-            /*-- Context --*/
-
-            if (__subchart_show) {
 
-                contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
-                    .data(targets)
-                    .attr('class', classChartBar);
-                contextBarEnter = contextBarUpdate.enter().append('g')
-                    .style('opacity', 0)
-                    .attr('class', classChartBar);
-                // Bars for each data
-                contextBarEnter.append('g')
-                    .attr("class", classBars);
-
-                //-- Line --//
-                contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
-                    .data(targets)
-                    .attr('class', classChartLine);
-                contextLineEnter = contextLineUpdate.enter().append('g')
-                    .style('opacity', 0)
-                    .attr('class', classChartLine);
-                // Lines for each data
-                contextLineEnter.append('g')
-                    .attr("class", classLines);
-            }
-
-            /*-- Show --*/
+            // update x domain to generate axis elements for flow
+            domain = $$.updateXDomain(targets, true, true);
+            // update elements related to x scale
+            if ($$.updateXGrid) { $$.updateXGrid(true); }
 
-            // Fade-in each chart
-            svg.selectAll('.' + CLASS.target).filter(function (d) { return isTargetToShow(d.id); })
-                .transition().duration(__transition_duration)
-                .style("opacity", 1);
-        }
-
-        function load(targets, args) {
-            // set type if args.types || args.type specified
-            if (args.type || args.types) {
-                targets.forEach(function (t) {
-                    args.types ? setTargetType(t.id, args.types[t.id]) : setTargetType(t.id, args.type);
-                });
+            // generate transform to flow
+            if (!flow.orgDataCount) { // if empty
+                if ($$.data.targets[0].values.length !== 1) {
+                    translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+                } else {
+                    if ($$.isTimeSeries()) {
+                        flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
+                        flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
+                        translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
+                    } else {
+                        translateX = diffDomain(domain) / 2;
+                    }
+                }
+            } else if (flow.orgDataCount === 1 || flowStart.x === flowEnd.x) {
+                translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+            } else {
+                if ($$.isTimeSeries()) {
+                    translateX = ($$.x(orgDomain[0]) - $$.x(domain[0]));
+                } else {
+                    translateX = ($$.x(flowStart.x) - $$.x(flowEnd.x));
+                }
             }
-            // Update/Add data
-            c3.data.targets.forEach(function (d) {
-                for (var i = 0; i < targets.length; i++) {
-                    if (d.id === targets[i].id) {
-                        d.values = targets[i].values;
-                        targets.splice(i, 1);
-                        break;
+            scaleX = (diffDomain(orgDomain) / diffDomain(domain));
+            transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
+
+            // hide tooltip
+            $$.hideXGridFocus();
+            $$.hideTooltip();
+
+            d3.transition().ease('linear').duration(durationForFlow).each(function () {
+                wait.add($$.axes.x.transition().call($$.xAxis));
+                wait.add(mainBar.transition().attr('transform', transform));
+                wait.add(mainLine.transition().attr('transform', transform));
+                wait.add(mainArea.transition().attr('transform', transform));
+                wait.add(mainCircle.transition().attr('transform', transform));
+                wait.add(mainText.transition().attr('transform', transform));
+                wait.add(mainRegion.filter($$.isRegionOnX).transition().attr('transform', transform));
+                wait.add(xgrid.transition().attr('transform', transform));
+                wait.add(xgridLines.transition().attr('transform', transform));
+            })
+            .call(wait, function () {
+                var i, shapes = [], texts = [], eventRects = [];
+
+                // remove flowed elements
+                if (flowLength) {
+                    for (i = 0; i < flowLength; i++) {
+                        shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
+                        texts.push('.' + CLASS.text + '-' + (flowIndex + i));
+                        eventRects.push('.' + CLASS.eventRect + '-' + (flowIndex + i));
                     }
+                    $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
+                    $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
+                    $$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove();
+                    $$.svg.select('.' + CLASS.xgrid).remove();
                 }
-            });
-            c3.data.targets = c3.data.targets.concat(targets); // add remained
 
-            // Set targets
-            updateTargets(c3.data.targets);
-
-            // Redraw with new targets
-            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
-
-            if (typeof args.done === 'function') {
-                args.done();
-            }
-        }
-        function loadFromArgs(args) {
-            // load data
-            if ('data' in args) {
-                load(convertDataToTargets(args.data), args);
-            }
-            else if ('url' in args) {
-                d3.csv(args.url, function (error, data) {
-                    load(convertDataToTargets(data), args);
-                });
-            }
-            else if ('rows' in args) {
-                load(convertDataToTargets(convertRowsToData(args.rows)), args);
-            }
-            else if ('columns' in args) {
-                load(convertDataToTargets(convertColumnsToData(args.columns)), args);
-            }
-            else {
-                throw Error('url or rows or columns is required.');
-            }
-        }
+                // draw again for removing flowed elements and reverting attr
+                xgrid
+                    .attr('transform', null)
+                    .attr($$.xgridAttr);
+                xgridLines
+                    .attr('transform', null);
+                xgridLines.select('line')
+                    .attr("x1", config.axis_rotated ? 0 : xv)
+                    .attr("x2", config.axis_rotated ? $$.width : xv);
+                xgridLines.select('text')
+                    .attr("x", config.axis_rotated ? $$.width : 0)
+                    .attr("y", xv);
+                mainBar
+                    .attr('transform', null)
+                    .attr("d", drawBar);
+                mainLine
+                    .attr('transform', null)
+                    .attr("d", drawLine);
+                mainArea
+                    .attr('transform', null)
+                    .attr("d", drawArea);
+                mainCircle
+                    .attr('transform', null)
+                    .attr("cx", cx)
+                    .attr("cy", cy);
+                mainText
+                    .attr('transform', null)
+                    .attr('x', xForText)
+                    .attr('y', yForText)
+                    .style('fill-opacity', $$.opacityForText.bind($$));
+                mainRegion
+                    .attr('transform', null);
+                mainRegion.select('rect').filter($$.isRegionOnX)
+                    .attr("x", $$.regionX.bind($$))
+                    .attr("width", $$.regionWidth.bind($$));
+
+                if (config.interaction_enabled) {
+                    $$.redrawEventRect();
+                }
 
-        function unload(targetIds, done) {
-            if (typeof done !== 'function') {
-                done = function () {};
-            }
-            // filter existing target
-            targetIds = targetIds.filter(function (id) { return hasTarget(c3.data.targets, id); });
-            // If no target, call done and return
-            if (!targetIds || targetIds.length === 0) {
+                // callback for end of flow
                 done();
-                return;
-            }
-            svg.selectAll(targetIds.map(function (id) { return selectorTarget(id); }))
-              .transition()
-                .style('opacity', 0)
-                .remove()
-                .call(endall, done);
-            targetIds.forEach(function (id) {
-                // Reset fadein for future load
-                withoutFadeIn[id] = false;
-                // Remove target's elements
-                legend.selectAll('.' + CLASS.legendItem + getTargetSelectorSuffix(id)).remove();
-                // Remove target
-                c3.data.targets = c3.data.targets.filter(function (t) {
-                    return t.id !== id;
-                });
-            });
-        }
 
-        /*-- Draw Legend --*/
-
-        function opacityForLegend(legendItem) {
-            return legendItem.classed(CLASS.legendItemHidden) ? legendOpacityForHidden : 1;
-        }
-        function opacityForUnfocusedLegend(legendItem) {
-            return legendItem.classed(CLASS.legendItemHidden) ? legendOpacityForHidden : 0.3;
-        }
-        function toggleFocusLegend(id, focus) {
-            legend.selectAll('.' + CLASS.legendItem)
-              .transition().duration(100)
-                .style('opacity', function (_id) {
-                    var This = d3.select(this);
-                    if (id && _id !== id) {
-                        return focus ? opacityForUnfocusedLegend(This) : opacityForLegend(This);
-                    } else {
-                        return focus ? opacityForLegend(This) : opacityForUnfocusedLegend(This);
-                    }
-                });
-        }
-        function revertLegend() {
-            legend.selectAll('.' + CLASS.legendItem)
-              .transition().duration(100)
-                .style('opacity', function () { return opacityForLegend(d3.select(this)); });
-        }
-        function showLegend(targetIds) {
-            if (!__legend_show) {
-                __legend_show = true;
-                legend.style('visibility', 'visible');
+                $$.flowing = false;
+            });
+        };
+    };
+
+    c3_chart_fn.selected = function (targetId) {
+        var $$ = this.internal, d3 = $$.d3;
+        return d3.merge(
+            $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
+                .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
+                .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
+        );
+    };
+    c3_chart_fn.select = function (ids, indices, resetOther) {
+        var $$ = this.internal, d3 = $$.d3, config = $$.config;
+        if (! config.data_selection_enabled) { return; }
+        $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+            var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+                toggle = $$.getToggle(this, d).bind($$),
+                isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+                isTargetIndex = !indices || indices.indexOf(i) >= 0,
+                isSelected = shape.classed(CLASS.SELECTED);
+            // line/area selection not supported yet
+            if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+                return;
             }
-            removeHiddenLegendIds(targetIds);
-            legend.selectAll(selectorLegends(targetIds))
-                .style('visibility', 'visible')
-              .transition()
-                .style('opacity', function () { return opacityForLegend(d3.select(this)); });
-        }
-        function hideLegend(targetIds) {
-            if (__legend_show && isEmpty(targetIds)) {
-                __legend_show = false;
-                legend.style('visibility', 'hidden');
+            if (isTargetId && isTargetIndex) {
+                if (config.data_selection_isselectable(d) && !isSelected) {
+                    toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
+                }
+            } else if (isDefined(resetOther) && resetOther) {
+                if (isSelected) {
+                    toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+                }
             }
-            addHiddenLegendIds(targetIds);
-            legend.selectAll(selectorLegends(targetIds))
-                .style('opacity', 0)
-                .style('visibility', 'hidden');
-        }
-
-        function updateLegend(targetIds, options, transitions) {
-            var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
-            var paddingTop = 4, paddingRight = 26, maxWidth = 0, maxHeight = 0, posMin = 10;
-            var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
-            var withTransition, withTransitionForTransform;
-            var hasFocused = legend.selectAll('.' + CLASS.legendItemFocused).size();
-
-            options = options || {};
-            withTransition = isDefined(options.withTransition) ? options.withTransition : true;
-            withTransitionForTransform = isDefined(options.withTransitionForTransform) ? options.withTransitionForTransform : true;
-
-            function updatePositions(textElement, id, reset) {
-                var box = textElement.getBoundingClientRect(),
-                    itemWidth = Math.ceil((box.width + paddingRight) / 10) * 10,
-                    itemHeight = Math.ceil((box.height + paddingTop) / 10) * 10,
-                    itemLength = isLegendRight ? itemHeight : itemWidth,
-                    areaLength = isLegendRight ? getLegendHeight() : getLegendWidth(),
-                    margin, maxLength;
-
-                // MEMO: care about condifion of step, totalLength
-                function updateValues(id, withoutStep) {
-                    if (!withoutStep) {
-                        margin = (areaLength - totalLength - itemLength) / 2;
-                        if (margin < posMin) {
-                            margin = (areaLength - itemLength) / 2;
-                            totalLength = 0;
-                            step++;
-                        }
+        });
+    };
+    c3_chart_fn.unselect = function (ids, indices) {
+        var $$ = this.internal, d3 = $$.d3, config = $$.config;
+        if (! config.data_selection_enabled) { return; }
+        $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+            var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+                toggle = $$.getToggle(this, d).bind($$),
+                isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+                isTargetIndex = !indices || indices.indexOf(i) >= 0,
+                isSelected = shape.classed(CLASS.SELECTED);
+            // line/area selection not supported yet
+            if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+                return;
+            }
+            if (isTargetId && isTargetIndex) {
+                if (config.data_selection_isselectable(d)) {
+                    if (isSelected) {
+                        toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
                     }
-                    steps[id] = step;
-                    margins[step] = margin;
-                    offsets[id] = totalLength;
-                    totalLength += itemLength;
                 }
+            }
+        });
+    };
 
-                if (reset) {
-                    totalLength = 0;
-                    step = 0;
-                    maxWidth = 0;
-                    maxHeight = 0;
-                }
+    c3_chart_fn.transform = function (type, targetIds) {
+        var $$ = this.internal,
+            options = ['pie', 'donut'].indexOf(type) >= 0 ? {withTransform: true} : null;
+        $$.transformTo(targetIds, type, options);
+    };
 
-                if (__legend_show && !isLegendToShow(id)) {
-                    widths[id] = heights[id] = steps[id] = offsets[id] = 0;
-                    return;
-                }
+    c3_chart_internal_fn.transformTo = function (targetIds, type, optionsForRedraw) {
+        var $$ = this,
+            withTransitionForAxis = !$$.hasArcType(),
+            options = optionsForRedraw || {withTransitionForAxis: withTransitionForAxis};
+        options.withTransitionForTransform = false;
+        $$.transiting = false;
+        $$.setTargetType(targetIds, type);
+        $$.updateAndRedraw(options);
+    };
 
-                widths[id] = itemWidth;
-                heights[id] = itemHeight;
+    c3_chart_fn.groups = function (groups) {
+        var $$ = this.internal, config = $$.config;
+        if (isUndefined(groups)) { return config.data_groups; }
+        config.data_groups = groups;
+        $$.redraw();
+        return config.data_groups;
+    };
 
-                if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; }
-                if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; }
-                maxLength = isLegendRight ? maxHeight : maxWidth;
+    c3_chart_fn.xgrids = function (grids) {
+        var $$ = this.internal, config = $$.config;
+        if (! grids) { return config.grid_x_lines; }
+        config.grid_x_lines = grids;
+        $$.redrawWithoutRescale();
+        return config.grid_x_lines;
+    };
+    c3_chart_fn.xgrids.add = function (grids) {
+        var $$ = this.internal;
+        return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
+    };
+    c3_chart_fn.xgrids.remove = function (params) { // TODO: multiple
+        var $$ = this.internal;
+        $$.removeGridLines(params, true);
+    };
 
-                if (__legend_equally) {
-                    Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; });
-                    Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; });
-                    margin = (areaLength - maxLength * targetIds.length) / 2;
-                    if (margin < posMin) {
-                        totalLength = 0;
-                        step = 0;
-                        targetIds.forEach(function (id) { updateValues(id); });
-                    }
-                    else {
-                        updateValues(id, true);
-                    }
-                } else {
-                    updateValues(id);
-                }
-            }
+    c3_chart_fn.ygrids = function (grids) {
+        var $$ = this.internal, config = $$.config;
+        if (! grids) { return config.grid_y_lines; }
+        config.grid_y_lines = grids;
+        $$.redrawWithoutRescale();
+        return config.grid_y_lines;
+    };
+    c3_chart_fn.ygrids.add = function (grids) {
+        var $$ = this.internal;
+        return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
+    };
+    c3_chart_fn.ygrids.remove = function (params) { // TODO: multiple
+        var $$ = this.internal;
+        $$.removeGridLines(params, false);
+    };
 
-            if (isLegendRight) {
-                xForLegend = function (id) { return maxWidth * (0.2 + steps[id]); };
-                yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
-            } else {
-                xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
-                yForLegend = function (id) { return maxHeight * (0.2 + steps[id]); };
-            }
-            xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
-            yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
-            xForLegendRect = function (id, i) { return xForLegend(id, i) - 4; };
-            yForLegendRect = function (id, i) { return yForLegend(id, i) - 7; };
-
-            // Define g for legend area
-            l = legend.selectAll('.' + CLASS.legendItem)
-                .data(targetIds)
-              .enter().append('g')
-                .attr('class', function (id) { return generateClass(CLASS.legendItem, id); })
-                .style('visibility', function (id) { return isLegendToShow(id) ? 'visible' : 'hidden'; })
-                .style('cursor', 'pointer')
-                .on('click', function (id) {
-                    typeof __legend_item_onclick === 'function' ? __legend_item_onclick(id) : c3.toggle(id);
-                })
-                .on('mouseover', function (id) {
-                    d3.select(this).classed(CLASS.legendItemFocused, true);
-                    if (!transiting) {
-                        c3.focus(id);
-                    }
-                    if (typeof __legend_item_onmouseover === 'function') {
-                        __legend_item_onmouseover(id);
-                    }
-                })
-                .on('mouseout', function (id) {
-                    d3.select(this).classed(CLASS.legendItemFocused, false);
-                    if (!transiting) {
-                        c3.revert();
-                    }
-                    if (typeof __legend_item_onmouseout === 'function') {
-                        __legend_item_onmouseout(id);
-                    }
-                });
-            l.append('text')
-                .text(function (id) { return isDefined(__data_names[id]) ? __data_names[id] : id; })
-                .each(function (id, i) { updatePositions(this, id, i === 0); })
-                .style("pointer-events", "none")
-                .attr('x', isLegendRight ? xForLegendText : -200)
-                .attr('y', isLegendRight ? -200 : yForLegendText);
-            l.append('rect')
-                .attr("class", CLASS.legendItemEvent)
-                .style('fill-opacity', 0)
-                .attr('x', isLegendRight ? xForLegendRect : -200)
-                .attr('y', isLegendRight ? -200 : yForLegendRect)
-                .attr('width', function (id) { return widths[id]; })
-                .attr('height', function (id) { return heights[id]; });
-            l.append('rect')
-                .attr("class", CLASS.legendItemTile)
-                .style("pointer-events", "none")
-                .style('fill', function (id) { return color(id); })
-                .attr('x', isLegendRight ? xForLegendText : -200)
-                .attr('y', isLegendRight ? -200 : yForLegend)
-                .attr('width', 10)
-                .attr('height', 10);
-
-            legend.selectAll('text')
-                .data(targetIds)
-                .text(function (id) { return isDefined(__data_names[id]) ? __data_names[id] : id; }) // MEMO: needed for update
-                .each(function (id, i) { updatePositions(this, id, i === 0); })
-              .transition().duration(withTransition ? 250 : 0)
-                .attr('x', xForLegendText)
-                .attr('y', yForLegendText);
-
-            legend.selectAll('rect.' + CLASS.legendItemEvent)
-                .data(targetIds)
-              .transition().duration(withTransition ? 250 : 0)
-                .attr('x', xForLegendRect)
-                .attr('y', yForLegendRect);
-
-            legend.selectAll('rect.' + CLASS.legendItemTile)
-                .data(targetIds)
-              .transition().duration(withTransition ? 250 : 0)
-                .attr('x', xForLegend)
-                .attr('y', yForLegend);
-
-            // toggle legend state
-            legend.selectAll('.' + CLASS.legendItem)
-                .classed(CLASS.legendItemHidden, function (id) { return !isTargetToShow(id); })
-              .transition()
-                .style('opacity', function (id) {
-                    var This = d3.select(this);
-                    if (isTargetToShow(id)) {
-                        return !hasFocused || This.classed(CLASS.legendItemFocused) ? opacityForLegend(This) : opacityForUnfocusedLegend(This);
-                    } else {
-                        return legendOpacityForHidden;
-                    }
-                });
+    c3_chart_fn.regions = function (regions) {
+        var $$ = this.internal, config = $$.config;
+        if (!regions) { return config.regions; }
+        config.regions = regions;
+        $$.redrawWithoutRescale();
+        return config.regions;
+    };
+    c3_chart_fn.regions.add = function (regions) {
+        var $$ = this.internal, config = $$.config;
+        if (!regions) { return config.regions; }
+        config.regions = config.regions.concat(regions);
+        $$.redrawWithoutRescale();
+        return config.regions;
+    };
+    c3_chart_fn.regions.remove = function (options) {
+        var $$ = this.internal, config = $$.config,
+            duration, classes, regions;
 
-            // Update all to reflect change of legend
-            updateLegendItemWidth(maxWidth);
-            updateLegendItemHeight(maxHeight);
-            updateLegendStep(step);
-            // Update size and scale
-            updateSizes();
-            updateScales();
-            updateSvgSize();
-            // Update g positions
-            transformAll(withTransitionForTransform, transitions);
-        }
+        options = options || {};
+        duration = $$.getOption(options, "duration", config.transition_duration);
+        classes = $$.getOption(options, "classes", [CLASS.region]);
 
-        /*-- Event Handling --*/
+        regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) { return '.' + c; }));
+        (duration ? regions.transition().duration(duration) : regions)
+            .style('opacity', 0)
+            .remove();
 
-        function isNoneArc(d) {
-            return hasTarget(c3.data.targets, d.id);
-        }
-        function isArc(d) {
-            return 'data' in d && hasTarget(c3.data.targets, d.data.id);
-        }
-        function getGridFilter(params) {
-            var value = params && params.value ? params.value : null,
-                klass = params && params['class'] ? params['class'] : null;
-            return value ? function (line) { return line.value !== value; } : klass ? function (line) { return line['class'] !== klass; } : function () { return true; };
+        config.regions = config.regions.filter(function (region) {
+            var found = false;
+            if (!region['class']) {
+                return true;
+            }
+            region['class'].split(' ').forEach(function (c) {
+                if (classes.indexOf(c) >= 0) { found = true; }
+            });
+            return !found;
+        });
+
+        return config.regions;
+    };
+
+    c3_chart_fn.data = function (targetIds) {
+        var targets = this.internal.data.targets;
+        return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
+            return [].concat(targetIds).indexOf(t.id) >= 0;
+        });
+    };
+    c3_chart_fn.data.shown = function (targetIds) {
+        return this.internal.filterTargetsToShow(this.data(targetIds));
+    };
+    c3_chart_fn.data.values = function (targetId) {
+        var targets, values = null;
+        if (targetId) {
+            targets = this.data(targetId);
+            values = targets[0] ? targets[0].values.map(function (d) { return d.value; }) : null;
         }
-        function transformTo(targetIds, type, optionsForRedraw) {
-            var withTransitionForAxis = !hasArcType(c3.data.targets);
-            transiting = false;
-            setTargetType(targetIds, type);
-            updateAndRedraw(optionsForRedraw || {withTransitionForAxis: withTransitionForAxis});
+        return values;
+    };
+    c3_chart_fn.data.names = function (names) {
+        this.internal.clearLegendItemTextBoxCache();
+        return this.internal.updateDataAttributes('names', names);
+    };
+    c3_chart_fn.data.colors = function (colors) {
+        return this.internal.updateDataAttributes('colors', colors);
+    };
+    c3_chart_fn.data.axes = function (axes) {
+        return this.internal.updateDataAttributes('axes', axes);
+    };
+
+    c3_chart_fn.category = function (i, category) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length > 1) {
+            config.axis_x_categories[i] = category;
+            $$.redraw();
         }
+        return config.axis_x_categories[i];
+    };
+    c3_chart_fn.categories = function (categories) {
+        var $$ = this.internal, config = $$.config;
+        if (!arguments.length) { return config.axis_x_categories; }
+        config.axis_x_categories = categories;
+        $$.redraw();
+        return config.axis_x_categories;
+    };
 
-        c3.focus = function (targetId) {
-            var candidates = svg.selectAll(selectorTarget(targetId)),
-                candidatesForNoneArc = candidates.filter(isNoneArc),
-                candidatesForArc = candidates.filter(isArc);
-            function focus(targets) {
-                filterTargetsToShow(targets).transition().duration(100).style('opacity', 1);
-            }
-            c3.revert();
-            c3.defocus();
-            focus(candidatesForNoneArc.classed(CLASS.focused, true));
-            focus(candidatesForArc);
-            if (hasArcType(c3.data.targets)) {
-                expandArc(targetId, true);
-            }
-            toggleFocusLegend(targetId, true);
-        };
+    // TODO: fix
+    c3_chart_fn.color = function (id) {
+        var $$ = this.internal;
+        return $$.color(id); // more patterns
+    };
 
-        c3.defocus = function (targetId) {
-            var candidates = svg.selectAll(selectorTarget(targetId)),
-                candidatesForNoneArc = candidates.filter(isNoneArc),
-                candidatesForArc = candidates.filter(isArc);
-            function defocus(targets) {
-                filterTargetsToShow(targets).transition().duration(100).style('opacity', 0.3);
-            }
-            c3.revert();
-            defocus(candidatesForNoneArc.classed(CLASS.focused, false));
-            defocus(candidatesForArc);
-            if (hasArcType(c3.data.targets)) {
-                unexpandArc(targetId);
-            }
-            toggleFocusLegend(targetId, false);
-        };
+    c3_chart_fn.x = function (x) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            $$.updateTargetX($$.data.targets, x);
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        }
+        return $$.data.xs;
+    };
+    c3_chart_fn.xs = function (xs) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            $$.updateTargetXs($$.data.targets, xs);
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        }
+        return $$.data.xs;
+    };
 
-        c3.revert = function (targetId) {
-            var candidates = svg.selectAll(selectorTarget(targetId)),
-                candidatesForNoneArc = candidates.filter(isNoneArc),
-                candidatesForArc = candidates.filter(isArc);
-            function revert(targets) {
-                filterTargetsToShow(targets).transition().duration(100).style('opacity', 1);
+    c3_chart_fn.axis = function () {};
+    c3_chart_fn.axis.labels = function (labels) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            Object.keys(labels).forEach(function (axisId) {
+                $$.setAxisLabelText(axisId, labels[axisId]);
+            });
+            $$.updateAxisLabels();
+        }
+        // TODO: return some values?
+    };
+    c3_chart_fn.axis.max = function (max) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length) {
+            if (typeof max === 'object') {
+                if (isValue(max.x)) { config.axis_x_max = max.x; }
+                if (isValue(max.y)) { config.axis_y_max = max.y; }
+                if (isValue(max.y2)) { config.axis_y2_max = max.y2; }
+            } else {
+                config.axis_y_max = config.axis_y2_max = max;
             }
-            revert(candidatesForNoneArc.classed(CLASS.focused, false));
-            revert(candidatesForArc);
-            if (hasArcType(c3.data.targets)) {
-                unexpandArc(targetId);
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        } else {
+            return {
+                x: config.axis_x_max,
+                y: config.axis_y_max,
+                y2: config.axis_y2_max
+            };
+        }
+    };
+    c3_chart_fn.axis.min = function (min) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length) {
+            if (typeof min === 'object') {
+                if (isValue(min.x)) { config.axis_x_min = min.x; }
+                if (isValue(min.y)) { config.axis_y_min = min.y; }
+                if (isValue(min.y2)) { config.axis_y2_min = min.y2; }
+            } else {
+                config.axis_y_min = config.axis_y2_min = min;
             }
-            revertLegend();
-        };
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        } else {
+            return {
+                x: config.axis_x_min,
+                y: config.axis_y_min,
+                y2: config.axis_y2_min
+            };
+        }
+    };
+    c3_chart_fn.axis.range = function (range) {
+        if (arguments.length) {
+            if (isDefined(range.max)) { this.axis.max(range.max); }
+            if (isDefined(range.min)) { this.axis.min(range.min); }
+        } else {
+            return {
+                max: this.axis.max(),
+                min: this.axis.min()
+            };
+        }
+    };
 
-        c3.show = function (targetIds, options) {
-            targetIds = mapToTargetIds(targetIds);
-            options = options || {};
+    c3_chart_fn.legend = function () {};
+    c3_chart_fn.legend.show = function (targetIds) {
+        var $$ = this.internal;
+        $$.showLegend($$.mapToTargetIds(targetIds));
+        $$.updateAndRedraw({withLegend: true});
+    };
+    c3_chart_fn.legend.hide = function (targetIds) {
+        var $$ = this.internal;
+        $$.hideLegend($$.mapToTargetIds(targetIds));
+        $$.updateAndRedraw({withLegend: true});
+    };
 
-            removeHiddenTargetIds(targetIds);
-            svg.selectAll(selectorTargets(targetIds))
-              .transition()
-                .style('opacity', 1);
+    c3_chart_fn.resize = function (size) {
+        var $$ = this.internal, config = $$.config;
+        config.size_width = size ? size.width : null;
+        config.size_height = size ? size.height : null;
+        this.flush();
+    };
 
-            if (options.withLegend) {
-                showLegend(targetIds);
-            }
+    c3_chart_fn.flush = function () {
+        var $$ = this.internal;
+        $$.updateAndRedraw({withLegend: true, withTransition: false, withTransitionForTransform: false});
+    };
 
-            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
-        };
+    c3_chart_fn.destroy = function () {
+        var $$ = this.internal;
+        $$.data.targets = undefined;
+        $$.data.xs = {};
+        $$.selectChart.classed('c3', false).html("");
+        window.clearInterval($$.intervalForObserveInserted);
+        window.onresize = null;
+    };
 
-        c3.hide = function (targetIds, options) {
-            targetIds = mapToTargetIds(targetIds);
-            options = options || {};
+    c3_chart_fn.tooltip = function () {};
+    c3_chart_fn.tooltip.show = function (args) {
+        var $$ = this.internal, index, mouse;
 
-            addHiddenTargetIds(targetIds);
-            svg.selectAll(selectorTargets(targetIds))
-              .transition()
-                .style('opacity', 0);
+        // determine mouse position on the chart
+        if (args.mouse) {
+            mouse = args.mouse;
+        }
 
-            if (options.withLegend) {
-                hideLegend(targetIds);
+        // determine focus data
+        if (args.data) {
+            if ($$.isMultipleX()) {
+                // if multiple xs, target point will be determined by mouse
+                mouse = [$$.x(args.data.x), $$.getYScale(args.data.id)(args.data.value)];
+                index = null;
+            } else {
+                // TODO: when tooltip_grouped = false
+                index = isValue(args.data.index) ? args.data.index : $$.getIndexByX(args.data.x);
             }
+        }
+        else if (typeof args.x !== 'undefined') {
+            index = $$.getIndexByX(args.x);
+        }
+        else if (typeof args.index !== 'undefined') {
+            index = args.index;
+        }
 
-            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
-        };
+        // emulate mouse events to show
+        $$.dispatchEvent('mouseover', index, mouse);
+        $$.dispatchEvent('mousemove', index, mouse);
+    };
+    c3_chart_fn.tooltip.hide = function () {
+        // TODO: get target data by checking the state of focus
+        this.internal.dispatchEvent('mouseout', 0);
+    };
 
-        c3.toggle = function (targetId) {
-            isTargetToShow(targetId) ? c3.hide(targetId) : c3.show(targetId);
-        };
+    // Features:
+    // 1. category axis
+    // 2. ceil values of translate/x/y to int for half pixel antialiasing
+    // 3. multiline tick text
+    var tickTextCharSize;
+    function c3_axis(d3, params) {
+        var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
 
-        c3.unzoom = function () {
-            brush.clear().update();
-            redraw({withUpdateXDomain: true});
-        };
+        var tickOffset = 0, tickCulling = true, tickCentered;
 
-        c3.load = function (args) {
-            // update xs if specified
-            if (args.xs) {
-                addXs(args.xs);
+        params = params || {};
+        outerTickSize = params.withOuterTick ? 6 : 0;
+
+        function axisX(selection, x) {
+            selection.attr("transform", function (d) {
+                return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
+            });
+        }
+        function axisY(selection, y) {
+            selection.attr("transform", function (d) {
+                return "translate(0," + Math.ceil(y(d)) + ")";
+            });
+        }
+        function scaleExtent(domain) {
+            var start = domain[0], stop = domain[domain.length - 1];
+            return start < stop ? [ start, stop ] : [ stop, start ];
+        }
+        function generateTicks(scale) {
+            var i, domain, ticks = [];
+            if (scale.ticks) {
+                return scale.ticks.apply(scale, tickArguments);
             }
-            // update classes if exists
-            if ('classes' in args) {
-                Object.keys(args.classes).forEach(function (id) {
-                    __data_classes[id] = args.classes[id];
-                });
+            domain = scale.domain();
+            for (i = Math.ceil(domain[0]); i < domain[1]; i++) {
+                ticks.push(i);
             }
-            // update categories if exists
-            if ('categories' in args && isCategorized) {
-                __axis_x_categories = args.categories;
-                xAxis.categories(__axis_x_categories);
+            if (ticks.length > 0 && ticks[0] > 0) {
+                ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
             }
-            // use cache if exists
-            if ('cacheIds' in args && hasCaches(args.cacheIds)) {
-                load(getCaches(args.cacheIds), args.done);
-                return;
+            return ticks;
+        }
+        function copyScale() {
+            var newScale = scale.copy(), domain;
+            if (params.isCategory) {
+                domain = scale.domain();
+                newScale.domain([domain[0], domain[1] - 1]);
             }
-            // unload if needed
-            if ('unload' in args) {
-                // TODO: do not unload if target will load (included in url/rows/columns)
-                unload(mapToTargetIds((typeof args.unload === 'boolean' && args.unload) ? null : args.unload), function () {
-                    loadFromArgs(args);
-                });
-            } else {
-                loadFromArgs(args);
+            return newScale;
+        }
+        function textFormatted(v) {
+            return tickFormat ? tickFormat(v) : v;
+        }
+        function getSizeFor1Char(tick) {
+            if (tickTextCharSize) {
+                return tickTextCharSize;
             }
-        };
-
-        c3.unload = function (targetIds, done) {
-            unload(mapToTargetIds(targetIds), function () {
-                redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
-            });
-        };
-
-        c3.selected = function (targetId) {
-            return d3.merge(
-                main.selectAll('.' + CLASS.shapes + getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
-                    .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
-                    .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
-            );
-        };
-
-        c3.select = function (ids, indices, resetOther) {
-            if (! __data_selection_enabled) { return; }
-            main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
-                var shape = d3.select(this), id = d.data ? d.data.id : d.id, toggle = getToggle(this),
-                    isTargetId = __data_selection_grouped || !ids || ids.indexOf(id) >= 0,
-                    isTargetIndex = !indices || indices.indexOf(i) >= 0,
-                    isSelected = shape.classed(CLASS.SELECTED);
-                if (isTargetId && isTargetIndex) {
-                    if (__data_selection_isselectable(d) && !isSelected) {
-                        toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
-                    }
-                } else if (isDefined(resetOther) && resetOther) {
-                    if (isSelected) {
-                        toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
-                    }
+            var size = {
+                h: 11.5,
+                w: 5.5
+            };
+            tick.select('text').text(textFormatted).each(function (d) {
+                var box = this.getBoundingClientRect(),
+                    text = textFormatted(d),
+                    h = box.height,
+                    w = text ? (box.width / text.length) : undefined;
+                if (h && w) {
+                    size.h = h;
+                    size.w = w;
                 }
-            });
-        };
+            }).text('');
+            tickTextCharSize = size;
+            return size;
+        }
+        function axis(g) {
+            g.each(function () {
+                var g = d3.select(this);
+                var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale();
+
+                var ticks = tickValues ? tickValues : generateTicks(scale1),
+                    tick = g.selectAll(".tick").data(ticks, scale1),
+                    tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
+                    // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
+                    tickExit = tick.exit().remove(),
+                    tickUpdate = d3.transition(tick).style("opacity", 1),
+                    tickTransform, tickX, tickY;
+
+                var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
+                    path = g.selectAll(".domain").data([ 0 ]),
+                    pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path));
+                tickEnter.append("line");
+                tickEnter.append("text");
+
+                var lineEnter = tickEnter.select("line"),
+                    lineUpdate = tickUpdate.select("line"),
+                    textEnter = tickEnter.select("text"),
+                    textUpdate = tickUpdate.select("text");
 
-        c3.unselect = function (ids, indices) {
-            if (! __data_selection_enabled) { return; }
-            main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
-                var shape = d3.select(this), id = d.data ? d.data.id : d.id, toggle = getToggle(this),
-                    isTargetId = __data_selection_grouped || !ids || ids.indexOf(id) >= 0,
-                    isTargetIndex = !indices || indices.indexOf(i) >= 0,
-                    isSelected = shape.classed(CLASS.SELECTED);
-                if (isTargetId && isTargetIndex) {
-                    if (__data_selection_isselectable(d)) {
-                        if (isSelected) {
-                            toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
-                        }
-                    }
+                if (params.isCategory) {
+                    tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
+                    tickX = tickCentered ? 0 : tickOffset;
+                    tickY = tickCentered ? tickOffset : 0;
+                } else {
+                    tickOffset = tickX = 0;
                 }
-            });
-        };
-
-        c3.toLine = function (targetIds) {
-            transformTo(targetIds, 'line');
-        };
-
-        c3.toSpline = function (targetIds) {
-            transformTo(targetIds, 'spline');
-        };
 
-        c3.toBar = function (targetIds) {
-            transformTo(targetIds, 'bar');
-        };
+                var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = [];
+                var tickLength = Math.max(innerTickSize, 0) + tickPadding,
+                    isVertical = orient === 'left' || orient === 'right';
 
-        c3.toScatter = function (targetIds) {
-            transformTo(targetIds, 'scatter');
-        };
+                // this should be called only when category axis
+                function splitTickText(d, maxWidth) {
+                    var tickText = textFormatted(d),
+                        subtext, spaceIndex, textWidth, splitted = [];
 
-        c3.toArea = function (targetIds) {
-            transformTo(targetIds, 'area');
-        };
+                    if (Object.prototype.toString.call(tickText) === "[object Array]") {
+                        return tickText;
+                    }
 
-        c3.toAreaSpline = function (targetIds) {
-            transformTo(targetIds, 'area-spline');
-        };
+                    if (!maxWidth || maxWidth <= 0) {
+                        maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110;
+                    }
 
-        c3.toPie = function (targetIds) {
-            transformTo(targetIds, 'pie', {withTransform: true});
-        };
+                    function split(splitted, text) {
+                        spaceIndex = undefined;
+                        for (var i = 1; i < text.length; i++) {
+                            if (text.charAt(i) === ' ') {
+                                spaceIndex = i;
+                            }
+                            subtext = text.substr(0, i + 1);
+                            textWidth = sizeFor1Char.w * subtext.length;
+                            // if text width gets over tick width, split by space index or crrent index
+                            if (maxWidth < textWidth) {
+                                return split(
+                                    splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)),
+                                    text.slice(spaceIndex ? spaceIndex + 1 : i)
+                                );
+                            }
+                        }
+                        return splitted.concat(text);
+                    }
 
-        c3.toDonut = function (targetIds) {
-            transformTo(targetIds, 'donut', {withTransform: true});
-        };
+                    return split(splitted, tickText + "");
+                }
 
-        c3.groups = function (groups) {
-            if (isUndefined(groups)) { return __data_groups; }
-            __data_groups = groups;
-            redraw();
-            return __data_groups;
-        };
+                function tspanDy(d, i) {
+                    var dy = sizeFor1Char.h;
+                    if (i === 0) {
+                        if (orient === 'left' || orient === 'right') {
+                            dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - (params.isCategory ? 2 : 3));
+                        } else {
+                            dy = ".71em";
+                        }
+                    }
+                    return dy;
+                }
 
-        c3.xgrids = function (grids) {
-            if (! grids) { return __grid_x_lines; }
-            __grid_x_lines = grids;
-            redraw();
-            return __grid_x_lines;
-        };
-        c3.xgrids.add = function (grids) {
-            if (! grids) { return; }
-            return c3.xgrids(__grid_x_lines.concat(grids));
-        };
-        c3.xgrids.remove = function (params) { // TODO: multiple
-            var filter = getGridFilter(params);
-            return c3.xgrids(__grid_x_lines.filter(filter));
-        };
+                function tickSize(d) {
+                    var tickPosition = scale(d) + tickOffset;
+                    return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0;
+                }
 
-        c3.ygrids = function (grids) {
-            if (! grids) { return __grid_y_lines; }
-            __grid_y_lines = grids;
-            redraw();
-            return __grid_y_lines;
-        };
-        c3.ygrids.add = function (grids) {
-            if (! grids) { return; }
-            return c3.ygrids(__grid_y_lines.concat(grids));
-        };
-        c3.ygrids.remove = function (params) { // TODO: multiple
-            var filter = getGridFilter(params);
-            return c3.ygrids(__grid_y_lines.filter(filter));
-        };
+                text = tick.select("text");
+                tspan = text.selectAll('tspan')
+                    .data(function (d, i) {
+                        var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
+                        counts[i] = splitted.length;
+                        return splitted.map(function (s) {
+                            return { index: i, splitted: s };
+                        });
+                    });
+                tspan.enter().append('tspan');
+                tspan.exit().remove();
+                tspan.text(function (d) { return d.splitted; });
 
-        c3.regions = function (regions) {
-            if (isUndefined(regions)) { return __regions; }
-            __regions = regions;
-            redraw();
-            return __regions;
-        };
-        c3.regions.add = function (regions) {
-            if (isUndefined(regions)) { return __regions; }
-            __regions = __regions.concat(regions);
-            redraw();
-            return __regions;
-        };
-        c3.regions.remove = function (classes, options) {
-            var regionClasses = [].concat(classes);
-            options = isDefined(options) ? options : {};
-            regionClasses.forEach(function (cls) {
-                var duration = isValue(options.duration) ? options.duration : 0;
-                svg.selectAll('.' + cls)
-                  .transition().duration(duration)
-                    .style('fill-opacity', 0)
-                    .remove();
-                __regions = __regions.filter(function (region) {
-                    return region.classes.indexOf(cls) < 0;
-                });
+                switch (orient) {
+                case "bottom":
+                    {
+                        tickTransform = axisX;
+                        lineEnter.attr("y2", innerTickSize);
+                        textEnter.attr("y", tickLength);
+                        lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
+                        textUpdate.attr("x", 0).attr("y", tickLength);
+                        text.style("text-anchor", "middle");
+                        tspan.attr('x', 0).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+                        break;
+                    }
+                case "top":
+                    {
+                        tickTransform = axisX;
+                        lineEnter.attr("y2", -innerTickSize);
+                        textEnter.attr("y", -tickLength);
+                        lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+                        textUpdate.attr("x", 0).attr("y", -tickLength);
+                        text.style("text-anchor", "middle");
+                        tspan.attr('x', 0).attr("dy", "0em");
+                        pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+                        break;
+                    }
+                case "left":
+                    {
+                        tickTransform = axisY;
+                        lineEnter.attr("x2", -innerTickSize);
+                        textEnter.attr("x", -tickLength);
+                        lineUpdate.attr("x2", -innerTickSize).attr("y1", tickY).attr("y2", tickY);
+                        textUpdate.attr("x", -tickLength).attr("y", tickOffset);
+                        text.style("text-anchor", "end");
+                        tspan.attr('x', -tickLength).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+                        break;
+                    }
+                case "right":
+                    {
+                        tickTransform = axisY;
+                        lineEnter.attr("x2", innerTickSize);
+                        textEnter.attr("x", tickLength);
+                        lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+                        textUpdate.attr("x", tickLength).attr("y", 0);
+                        text.style("text-anchor", "start");
+                        tspan.attr('x', tickLength).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
+                        break;
+                    }
+                }
+                if (scale1.rangeBand) {
+                    var x = scale1, dx = x.rangeBand() / 2;
+                    scale0 = scale1 = function (d) {
+                        return x(d) + dx;
+                    };
+                } else if (scale0.rangeBand) {
+                    scale0 = scale1;
+                } else {
+                    tickExit.call(tickTransform, scale1);
+                }
+                tickEnter.call(tickTransform, scale0);
+                tickUpdate.call(tickTransform, scale1);
             });
-            return __regions;
-        };
-
-        c3.data.get = function (targetId) {
-            var target = c3.data.getAsTarget(targetId);
-            return isDefined(target) ? target.values.map(function (d) { return d.value; }) : undefined;
+        }
+        axis.scale = function (x) {
+            if (!arguments.length) { return scale; }
+            scale = x;
+            return axis;
         };
-        c3.data.getAsTarget = function (targetId) {
-            var targets = getTargets(function (t) { return t.id === targetId; });
-            return targets.length > 0 ? targets[0] : undefined;
+        axis.orient = function (x) {
+            if (!arguments.length) { return orient; }
+            orient = x in {top: 1, right: 1, bottom: 1, left: 1} ? x + "" : "bottom";
+            return axis;
         };
-        c3.data.names = function (names) {
-            if (!arguments.length) { return __data_names; }
-            Object.keys(names).forEach(function (id) {
-                __data_names[id] = names[id];
-            });
-            updateLegend(mapToIds(c3.data.targets), {withTransition: true});
-            return __data_names;
+        axis.tickFormat = function (format) {
+            if (!arguments.length) { return tickFormat; }
+            tickFormat = format;
+            return axis;
         };
-
-        c3.x = function (x) {
-            if (arguments.length) {
-                updateTargetX(c3.data.targets, x);
-                redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
-            }
-            return c3.data.xs;
+        axis.tickCentered = function (isCentered) {
+            if (!arguments.length) { return tickCentered; }
+            tickCentered = isCentered;
+            return axis;
         };
-        c3.xs = function (xs) {
-            if (arguments.length) {
-                updateTargetXs(c3.data.targets, xs);
-                redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
-            }
-            return c3.data.xs;
+        axis.tickOffset = function () { // This will be overwritten when normal x axis
+            return tickOffset;
         };
-
-        c3.axis.labels = function (labels) {
-            if (arguments.length) {
-                Object.keys(labels).forEach(function (axisId) {
-                    setAxisLabelText(axisId, labels[axisId]);
-                });
-                updateAxisLabels();
-            }
-            // TODO: return some values?
+        axis.ticks = function () {
+            if (!arguments.length) { return tickArguments; }
+            tickArguments = arguments;
+            return axis;
         };
-        c3.axis.max = function (max) {
-            if (arguments.length) {
-                if (typeof max === 'object') {
-                    if (isValue(max.y)) { __axis_y_max = +max.y; }
-                    if (isValue(max.y2)) { __axis_y2_max = +max.y2; }
-                } else {
-                    __axis_y_max = __axis_y2_max = +max;
-                }
-                redraw();
-            }
+        axis.tickCulling = function (culling) {
+            if (!arguments.length) { return tickCulling; }
+            tickCulling = culling;
+            return axis;
         };
-        c3.axis.min = function (min) {
-            if (arguments.length) {
-                if (typeof min === 'object') {
-                    if (isValue(min.y)) { __axis_y_min = +min.y; }
-                    if (isValue(min.y2)) { __axis_y2_min = +min.y2; }
-                } else {
-                    __axis_y_min = __axis_y2_min = +min;
-                }
-                redraw();
+        axis.tickValues = function (x) {
+            if (typeof x === 'function') {
+                tickValues = function () {
+                    return x(scale.domain());
+                };
             }
-        };
-        c3.axis.range = function (range) {
-            if (arguments.length) {
-                if (typeof range.max !== 'undefined') { c3.axis.max(range.max); }
-                if (typeof range.min !== 'undefined') { c3.axis.min(range.min); }
+            else {
+                if (!arguments.length) { return tickValues; }
+                tickValues = x;
             }
+            return axis;
         };
-
-        c3.legend.show = function (targetIds) {
-            showLegend(mapToTargetIds(targetIds));
-            redraw({withLegend: __legend_show});
-        };
-        c3.legend.hide = function (targetIds) {
-            hideLegend(mapToTargetIds(targetIds));
-            redraw({withLegend: true});
-        };
-
-        c3.resize = function (size) {
-            __size_width = size ? size.width : null;
-            __size_height = size ? size.height : null;
-            updateAndRedraw({withLegend: __legend_show, withTransition: false, withTransitionForTransform: false});
-        };
-
-        c3.destroy = function () {
-            c3.data.targets = undefined;
-            c3.data.xs = {};
-            selectChart.html("");
-            window.onresize = null;
-        };
-
-        /*-- Load data and init chart with defined functions --*/
-
-        if ('url' in config.data) {
-            d3.xhr(config.data.url, function (error, data) {
-                // TODO: other mine/type
-                var rows = d3.csv.parseRows(data.response), d;
-                if (rows.length === 1) {
-                    d = [{}];
-                    rows[0].forEach(function (id) {
-                        d[0][id] = null;
-                    });
-                } else {
-                    d = d3.csv.parse(data.response);
-                }
-                init(d);
-            });
-        }
-        else if ('rows' in config.data) {
-            init(convertRowsToData(config.data.rows));
-        }
-        else if ('columns' in config.data) {
-            init(convertColumnsToData(config.data.columns));
-        }
-        else {
-            throw Error('url or rows or columns is required.');
-        }
-
-        return c3;
-    };
-
-    function isValue(v) {
-        return v || v === 0;
-    }
-    function isUndefined(v) {
-        return typeof v === 'undefined';
-    }
-    function isDefined(v) {
-        return typeof v !== 'undefined';
+        return axis;
     }
 
-    if (typeof window.define === "function" && window.define.amd) {
-        window.define("c3", ["d3"], c3);
+    if (typeof define === 'function' && define.amd) {
+        define("c3", ["d3"], c3);
+    } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
+        module.exports = c3;
     } else {
         window.c3 = c3;
     }
-    // TODO: module.exports
 
 })(window);
diff --git a/c3.js.orig b/c3.js.orig
new file mode 100644
index 0000000..18da8aa
--- /dev/null
+++ b/c3.js.orig
@@ -0,0 +1,7113 @@
+(function (window) {
+    'use strict';
+
+    /*global define, module, exports, require */
+
+    var c3 = { version: "0.4.6" };
+
+    var c3_chart_fn, c3_chart_internal_fn;
+
+    function Chart(config) {
+        var $$ = this.internal = new ChartInternal(this);
+        $$.loadConfig(config);
+        $$.init();
+
+        // bind "this" to nested API
+        (function bindThis(fn, target, argThis) {
+            Object.keys(fn).forEach(function (key) {
+                target[key] = fn[key].bind(argThis);
+                if (Object.keys(fn[key]).length > 0) {
+                    bindThis(fn[key], target[key], argThis);
+                }
+            });
+        })(c3_chart_fn, this, this);
+    }
+
+    function ChartInternal(api) {
+        var $$ = this;
+        $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
+        $$.api = api;
+        $$.config = $$.getDefaultConfig();
+        $$.data = {};
+        $$.cache = {};
+        $$.axes = {};
+    }
+
+    c3.generate = function (config) {
+        return new Chart(config);
+    };
+
+    c3.chart = {
+        fn: Chart.prototype,
+        internal: {
+            fn: ChartInternal.prototype
+        }
+    };
+    c3_chart_fn = c3.chart.fn;
+    c3_chart_internal_fn = c3.chart.internal.fn;
+
+<<<<<<< HEAD
+                text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
+                text += "<td class='name'><span style='background-color:" + color(d[i].id) + "'></span>" + name + "</td>";
+                text += "<td class='value'>" + value + "</td>";
+                text += "</tr>";
+            }
+            return text + "</table>";
+        }),
+            __tooltip_init_show = getConfig(['tooltip', 'init', 'show'], false),
+            __tooltip_init_x = getConfig(['tooltip', 'init', 'x'], 0),
+            __tooltip_init_position = getConfig(['tooltip', 'init', 'position'], {top: '0px', left: '50px'});
+
+        /*-- Set Variables --*/
+
+        var clipId = (typeof __bindto === "string" ? __bindto.replace('#', '') : __bindto.id)  + '-clip',
+            clipIdForXAxis = clipId + '-xaxis',
+            clipIdForYAxis = clipId + '-yaxis',
+            clipPath = getClipPath(clipId),
+            clipPathForXAxis = getClipPath(clipIdForXAxis),
+            clipPathForYAxis = getClipPath(clipIdForYAxis);
+
+        var isTimeSeries = (__axis_x_type === 'timeseries'),
+            isCategorized = (__axis_x_type === 'categorized'),
+            isCustomX = !isTimeSeries && (__data_x || notEmpty(__data_xs));
+
+        var dragStart = null, dragging = false, cancelClick = false, mouseover = false, transiting = false;
+
+        var defaultColorPattern = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'], //same as d3.scale.category10()
+            color = generateColor(__data_colors, notEmpty(__color_pattern) ? __color_pattern : defaultColorPattern, __data_color);
+
+        var xTimeFormat = __axis_x_localtime ? d3.time.format : d3.time.format.utc,
+            defaultTimeFormat = (function () {
+            var formats = [
+                [xTimeFormat("%Y/%-m/%-d"), function () { return true; }],
+                [xTimeFormat("%-m/%-d"), function (d) { return d.getMonth(); }],
+                [xTimeFormat("%-m/%-d"), function (d) { return d.getDate() !== 1; }],
+                [xTimeFormat("%-m/%-d"), function (d) { return d.getDay() && d.getDate() !== 1; }],
+                [xTimeFormat("%I %p"), function (d) { return d.getHours(); }],
+                [xTimeFormat("%I:%M"), function (d) { return d.getMinutes(); }],
+                [xTimeFormat(":%S"), function (d) { return d.getSeconds(); }],
+                [xTimeFormat(".%L"), function (d) { return d.getMilliseconds(); }]
+            ];
+            return function (date) {
+                var i = formats.length - 1, f = formats[i];
+                while (!f[1](date)) { f = formats[--i]; }
+                return f[0](date);
+            };
+        })();
+
+        var hiddenTargetIds = [], hiddenLegendIds = [];
+
+        /*-- Set Chart Params --*/
+
+        var margin, margin2, margin3, width, width2, height, height2, currentWidth, currentHeight;
+        var radius, radiusExpanded, innerRadius, svgArc, svgArcExpanded, svgArcExpandedSub, pie;
+        var xMin, xMax, yMin, yMax, subXMin, subXMax, subYMin, subYMax;
+        var x, y, y2, subX, subY, subY2, xAxis, yAxis, y2Axis, subXAxis;
+
+        var xOrient = __axis_rotated ? "left" : "bottom",
+            yOrient = __axis_rotated ? (__axis_y_inner ? "top" : "bottom") : (__axis_y_inner ? "right" : "left"),
+            y2Orient = __axis_rotated ? (__axis_y2_inner ? "bottom" : "top") : (__axis_y2_inner ? "left" : "right"),
+            subXOrient = __axis_rotated ? "left" : "bottom";
+
+        var translate = {
+            main : function () { return "translate(" + margin.left + "," + margin.top + ")"; },
+            context : function () { return "translate(" + margin2.left + "," + margin2.top + ")"; },
+            legend : function () { return "translate(" + margin3.left + "," + margin3.top + ")"; },
+            x : function () {
+              if (__legend_show === true) {
+                return "translate(0," + (__axis_rotated ? 0 : height) + ")";
+              }
+              return "translate(0," + (__axis_rotated ? 0 : height + margin3.top) + ")";
+            },
+            y : function () { return "translate(0," + (__axis_rotated ? height : 0) + ")"; },
+            y2 : function () { return "translate(" + (__axis_rotated ? 0 : width) + "," + (__axis_rotated ? 1 : 0) + ")"; },
+            subx : function () { return "translate(0," + (__axis_rotated ? 0 : height2) + ")"; },
+            arc: function () { return "translate(" + width / 2 + "," + height / 2 + ")"; }
+        };
+=======
+>>>>>>> upstream/master
+
+    c3_chart_internal_fn.init = function () {
+        var $$ = this, config = $$.config;
+
+        $$.initParams();
+
+        if (config.data_url) {
+            $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_keys, $$.initWithData);
+        }
+        else if (config.data_json) {
+            $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
+        }
+        else if (config.data_rows) {
+            $$.initWithData($$.convertRowsToData(config.data_rows));
+        }
+        else if (config.data_columns) {
+            $$.initWithData($$.convertColumnsToData(config.data_columns));
+        }
+        else {
+            throw Error('url or json or rows or columns is required.');
+        }
+    };
+
+    c3_chart_internal_fn.initParams = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+
+        // MEMO: clipId needs to be unique because it conflicts when multiple charts exist
+        $$.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);
+        $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid),
+        $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart),
+
+        $$.dragStart = null;
+        $$.dragging = false;
+        $$.flowing = false;
+        $$.cancelClick = false;
+        $$.mouseover = false;
+        $$.transiting = false;
+
+        $$.color = $$.generateColor();
+        $$.levelColor = $$.generateLevelColor();
+
+        $$.dataTimeFormat = config.data_xLocaltime ? d3.time.format : d3.time.format.utc;
+        $$.axisTimeFormat = config.axis_x_localtime ? d3.time.format : d3.time.format.utc;
+        $$.defaultAxisTimeFormat = $$.axisTimeFormat.multi([
+            [".%L", function (d) { return d.getMilliseconds(); }],
+            [":%S", function (d) { return d.getSeconds(); }],
+            ["%I:%M", function (d) { return d.getMinutes(); }],
+            ["%I %p", function (d) { return d.getHours(); }],
+            ["%-m/%-d", function (d) { return d.getDay() && d.getDate() !== 1; }],
+            ["%-m/%-d", function (d) { return d.getDate() !== 1; }],
+            ["%-m/%-d", function (d) { return d.getMonth(); }],
+            ["%Y/%-m/%-d", function () { return true; }]
+        ]);
+
+        $$.hiddenTargetIds = [];
+        $$.hiddenLegendIds = [];
+        $$.focusedTargetIds = [];
+        $$.defocusedTargetIds = [];
+
+        $$.xOrient = config.axis_rotated ? "left" : "bottom";
+        $$.yOrient = config.axis_rotated ? (config.axis_y_inner ? "top" : "bottom") : (config.axis_y_inner ? "right" : "left");
+        $$.y2Orient = config.axis_rotated ? (config.axis_y_inner ? "bottom" : "top") : (config.axis_y_inner ? "left" : "right");
+        $$.subXOrient = config.axis_rotated ? "left" : "bottom";
+
+        $$.isLegendRight = config.legend_position === 'right';
+        $$.isLegendInset = config.legend_position === 'inset';
+        $$.isLegendTop = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'top-right';
+        $$.isLegendLeft = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'bottom-left';
+        $$.legendStep = 0;
+        $$.legendItemWidth = 0;
+        $$.legendItemHeight = 0;
+
+        $$.currentMaxTickWidths = {
+            x: 0,
+            y: 0,
+            y2: 0
+        };
+
+        $$.rotated_padding_left = 30;
+        $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
+        $$.rotated_padding_top = 5;
+
+        $$.withoutFadeIn = {};
+
+        $$.intervalForObserveInserted = undefined;
+
+        $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
+    };
+
+    c3_chart_internal_fn.initChartElements = function () {
+        if (this.initBar) { this.initBar(); }
+        if (this.initLine) { this.initLine(); }
+        if (this.initArc) { this.initArc(); }
+        if (this.initGauge) { this.initGauge(); }
+        if (this.initText) { this.initText(); }
+    };
+
+    c3_chart_internal_fn.initWithData = function (data) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        var defs, main, binding = true;
+
+        if ($$.initPie) { $$.initPie(); }
+        if ($$.initBrush) { $$.initBrush(); }
+        if ($$.initZoom) { $$.initZoom(); }
+
+<<<<<<< HEAD
+            if (isLegendRight && hasArcType(c3.data.targets)) {
+                margin3.left = width / 2 + radiusExpanded;
+            }
+        }
+        function updateXgridFocus() {
+            main.select('line.' + CLASS.xgridFocus)
+                .attr("x1", __axis_rotated ? 0 : -10)
+                .attr("x2", __axis_rotated ? width : -10)
+                .attr("y1", __axis_rotated ? -10 : margin.top)
+                .attr("y2", __axis_rotated ? -10 : height);
+        }
+        function updateRadius() {
+            radiusExpanded = height / 2;
+            radius = radiusExpanded * 0.95;
+            innerRadius = hasDonutType(c3.data.targets) ? radius * 0.6 : 0;
+        }
+        function getSvgLeft() {
+            var leftAxisClass = __axis_rotated ? CLASS.axisX : CLASS.axisY,
+                leftAxis = main.select('.' + leftAxisClass).node(),
+                svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
+                chartRect = d3.select(__bindto).node().getBoundingClientRect(),
+                svgLeft = svgRect.right - chartRect.left - getCurrentPaddingLeft();
+            return svgLeft > 0 ? svgLeft : 0;
+        }
+        function getCurrentWidth() {
+            var result = __size_width ? __size_width : getParentWidth();
+            if (isNaN(result)) {
+                return 0;
+            }
+            return result;
+        }
+        function getCurrentHeight() {
+            var h = __size_height ? __size_height : getParentHeight();
+            return h > 0 ? h : 320;
+        }
+        function getCurrentPaddingLeft() {
+            if (hasArcType(c3.data.targets)) {
+                return 0;
+            } else if (__padding_left) {
+                return __padding_left;
+            } else if (__axis_rotated) {
+                return !__axis_x_show ? 1 : getAxisWidthByAxisId('x');
+            } else {
+                return !__axis_y_show || __axis_y_inner ? 1 : getAxisWidthByAxisId('y');
+            }
+        }
+        function getCurrentPaddingRight() {
+            var defaultPadding = 1;
+            if (hasArcType(c3.data.targets)) {
+                return 0;
+            } else if (__padding_right) {
+                return __padding_right;
+            } else if (isLegendRight) {
+                return getLegendWidth() + (__axis_y2_show && !__axis_rotated ? getAxisWidthByAxisId('y2') : defaultPadding);
+            } else if (__axis_y2_show) {
+                return __axis_y2_inner || __axis_rotated ? defaultPadding : getAxisWidthByAxisId('y2');
+            } else {
+                return defaultPadding;
+            }
+        }
+        function getAxisWidthByAxisId(id) {
+            var position = getAxisLabelPositionById(id);
+            return position.isInner ? 20 + getMaxTickWidth(id) : 40 + getMaxTickWidth(id);
+        }
+        function getHorizontalAxisHeight(axisId) {
+            if (axisId === 'x' && !__axis_x_show) { return 0; }
+            if (axisId === 'x' && __axis_x_height) { return __axis_x_height; }
+            if (axisId === 'y' && !__axis_y_show) { return __legend_show && !isLegendRight ? 10 : 1; }
+            if (axisId === 'y2' && !__axis_y2_show) { return rotated_padding_top; }
+            return (getAxisLabelPositionById(axisId).isInner ? 30 : 40) + (axisId === 'y2' ? -10 : 0);
+        }
+        function getParentWidth() {
+            return +d3.select(__bindto).style("width").replace('px', ''); // TODO: if rotated, use height
+        }
+        function getParentHeight() {
+            return +d3.select(__bindto).style('height').replace('px', ''); // TODO: if rotated, use width
+        }
+        function getAxisClipX(forHorizontal) {
+            return forHorizontal ? -(1 + 4) : -(margin.left - 1);
+        }
+        function getAxisClipY(forHorizontal) {
+            return forHorizontal ? -20 : -4;
+=======
+        $$.selectChart = typeof config.bindto.node === 'function' ? config.bindto : d3.select(config.bindto);
+        if ($$.selectChart.empty()) {
+            $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
+            $$.observeInserted($$.selectChart);
+            binding = false;
+>>>>>>> upstream/master
+        }
+        $$.selectChart.html("").classed("c3", true);
+
+        // Init data as targets
+        $$.data.xs = {};
+        $$.data.targets = $$.convertDataToTargets(data);
+
+        if (config.data_filter) {
+            $$.data.targets = $$.data.targets.filter(config.data_filter);
+        }
+
+        // Set targets to hide if needed
+        if (config.data_hide) {
+            $$.addHiddenTargetIds(config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide);
+        }
+        if (config.legend_hide) {
+            $$.addHiddenLegendIds(config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide);
+        }
+
+        // when gauge, hide legend // TODO: fix
+        if ($$.hasType('gauge')) {
+            config.legend_show = false;
+        }
+
+        // Init sizes and scales
+        $$.updateSizes();
+        $$.updateScales();
+
+        // Set domains for each scale
+        $$.x.domain(d3.extent($$.getXDomain($$.data.targets)));
+        $$.y.domain($$.getYDomain($$.data.targets, 'y'));
+        $$.y2.domain($$.getYDomain($$.data.targets, 'y2'));
+        $$.subX.domain($$.x.domain());
+        $$.subY.domain($$.y.domain());
+        $$.subY2.domain($$.y2.domain());
+
+        // Save original x domain for zoom update
+        $$.orgXDomain = $$.x.domain();
+
+        // Set initialized scales to brush and zoom
+        if ($$.brush) { $$.brush.scale($$.subX); }
+        if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+
+        /*-- Basic Elements --*/
+
+        // Define svgs
+        $$.svg = $$.selectChart.append("svg")
+            .style("overflow", "hidden")
+            .on('mouseenter', function () { return config.onmouseover.call($$); })
+            .on('mouseleave', function () { return config.onmouseout.call($$); });
+
+        // Define defs
+        defs = $$.svg.append("defs");
+        $$.clipChart = $$.appendClip(defs, $$.clipId);
+        $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
+        $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
+        $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
+        $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
+        $$.updateSvgSize();
+
+        // Define regions
+        main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main'));
+
+        if ($$.initSubchart) { $$.initSubchart(); }
+        if ($$.initTooltip) { $$.initTooltip(); }
+        if ($$.initLegend) { $$.initLegend(); }
+
+        /*-- Main Region --*/
+
+        // text when empty
+        main.append("text")
+            .attr("class", CLASS.text + ' ' + CLASS.empty)
+            .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
+            .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
+
+        // Regions
+        $$.initRegion();
+
+        // Grids
+        $$.initGrid();
+
+        // Define g for chart area
+        main.append('g')
+            .attr("clip-path", $$.clipPath)
+            .attr('class', CLASS.chart);
+
+        // Grid lines
+        if (config.grid_lines_front) { $$.initGridLines(); }
+
+        // Cover whole with rects for events
+        $$.initEventRect();
+
+        // Define g for chart
+        $$.initChartElements();
+
+        // if zoom privileged, insert rect to forefront
+        // TODO: is this needed?
+        main.insert('rect', config.zoom_privileged ? null : 'g.' + CLASS.regions)
+            .attr('class', CLASS.zoomRect)
+            .attr('width', $$.width)
+            .attr('height', $$.height)
+            .style('opacity', 0)
+            .on("dblclick.zoom", null);
+
+        // Set default extent if defined
+        if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
+
+        // Add Axis
+        $$.initAxis();
+
+        // Set targets
+        $$.updateTargets($$.data.targets);
+
+        // Draw with targets
+        if (binding) {
+            $$.updateDimension();
+            $$.config.oninit.call($$);
+            $$.redraw({
+                withTransform: true,
+                withUpdateXDomain: true,
+                withUpdateOrgXDomain: true,
+                withTransitionForAxis: false
+            });
+        }
+
+        // Bind resize event
+        if (window.onresize == null) {
+            window.onresize = $$.generateResize();
+        }
+        if (window.onresize.add) {
+            window.onresize.add(function () {
+                config.onresize.call($$);
+            });
+            window.onresize.add(function () {
+                $$.api.flush();
+            });
+            window.onresize.add(function () {
+                config.onresized.call($$);
+            });
+        }
+
+        // export element of the chart
+        $$.api.element = $$.selectChart.node();
+    };
+
+    c3_chart_internal_fn.smoothLines = function (el, type) {
+        var $$ = this;
+        if (type === 'grid') {
+            el.each(function () {
+                var g = $$.d3.select(this),
+                    x1 = g.attr('x1'),
+                    x2 = g.attr('x2'),
+                    y1 = g.attr('y1'),
+                    y2 = g.attr('y2');
+                g.attr({
+                    'x1': Math.ceil(x1),
+                    'x2': Math.ceil(x2),
+                    'y1': Math.ceil(y1),
+                    'y2': Math.ceil(y2)
+                });
+            });
+        }
+    };
+
+
+    c3_chart_internal_fn.updateSizes = function () {
+        var $$ = this, config = $$.config;
+        var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
+            legendWidth = $$.legend ? $$.getLegendWidth() : 0,
+            legendHeightForBottom = $$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
+            hasArc = $$.hasArcType(),
+            xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
+            subchartHeight = config.subchart_show && !hasArc ? (config.subchart_size_height + xAxisHeight) : 0;
+
+        $$.currentWidth = $$.getCurrentWidth();
+        $$.currentHeight = $$.getCurrentHeight();
+
+        // for main
+        $$.margin = config.axis_rotated ? {
+            top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
+            right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+            bottom: $$.getHorizontalAxisHeight('y') + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+            left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
+        } : {
+            top: 4 + $$.getCurrentPaddingTop(), // for top tick text
+            right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+            bottom: xAxisHeight + subchartHeight + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+            left: hasArc ? 0 : $$.getCurrentPaddingLeft()
+        };
+
+        // for subchart
+        $$.margin2 = config.axis_rotated ? {
+            top: $$.margin.top,
+            right: NaN,
+            bottom: 20 + legendHeightForBottom,
+            left: $$.rotated_padding_left
+        } : {
+            top: $$.currentHeight - subchartHeight - legendHeightForBottom,
+            right: NaN,
+            bottom: xAxisHeight + legendHeightForBottom,
+            left: $$.margin.left
+        };
+
+        // for legend
+        $$.margin3 = {
+            top: 0,
+            right: NaN,
+            bottom: 0,
+            left: 0
+        };
+        if ($$.updateSizeForLegend) { $$.updateSizeForLegend(legendHeight, legendWidth); }
+
+        $$.width = $$.currentWidth - $$.margin.left - $$.margin.right;
+        $$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom;
+        if ($$.width < 0) { $$.width = 0; }
+        if ($$.height < 0) { $$.height = 0; }
+
+        $$.width2 = config.axis_rotated ? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right : $$.width;
+        $$.height2 = config.axis_rotated ? $$.height : $$.currentHeight - $$.margin2.top - $$.margin2.bottom;
+        if ($$.width2 < 0) { $$.width2 = 0; }
+        if ($$.height2 < 0) { $$.height2 = 0; }
+
+        // for arc
+        $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
+        $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
+        if ($$.hasType('gauge')) {
+            $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
+        }
+        if ($$.updateRadius) { $$.updateRadius(); }
+
+        if ($$.isLegendRight && hasArc) {
+            $$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1;
+        }
+    };
+
+    c3_chart_internal_fn.updateTargets = function (targets) {
+        var $$ = this, config = $$.config;
+
+        /*-- Main --*/
+
+        //-- Text --//
+        $$.updateTargetsForText(targets);
+
+        //-- Bar --//
+        $$.updateTargetsForBar(targets);
+
+        //-- Line --//
+        $$.updateTargetsForLine(targets);
+
+        //-- Arc --//
+        if ($$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
+        if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
+
+        /*-- Show --*/
+
+        // Fade-in each chart
+        $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); })
+          .transition().duration(config.transition_duration)
+            .style("opacity", 1);
+    };
+
+    c3_chart_internal_fn.redraw = function (options, transitions) {
+        var $$ = this, main = $$.main, d3 = $$.d3, config = $$.config;
+        var areaIndices = $$.getShapeIndices($$.isAreaType), barIndices = $$.getShapeIndices($$.isBarType), lineIndices = $$.getShapeIndices($$.isLineType);
+        var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis,
+            withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend,
+            withEventRect, withDimension, withUpdateXAxis;
+        var hideAxis = $$.hasArcType();
+        var drawArea, drawBar, drawLine, xForText, yForText;
+        var duration, durationForExit, durationForAxis;
+        var waitForDraw, flow;
+        var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling, xDomainForZoom;
+        var xv = $$.xv.bind($$), cx, cy;
+
+        options = options || {};
+        withY = getOption(options, "withY", true);
+        withSubchart = getOption(options, "withSubchart", true);
+        withTransition = getOption(options, "withTransition", true);
+        withTransform = getOption(options, "withTransform", false);
+        withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
+        withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
+        withTrimXDomain = getOption(options, "withTrimXDomain", true);
+        withUpdateXAxis = getOption(options, "withUpdateXAxis", withUpdateXDomain);
+        withLegend = getOption(options, "withLegend", false);
+        withEventRect = getOption(options, "withEventRect", true);
+        withDimension = getOption(options, "withDimension", true);
+        withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
+        withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
+
+        duration = withTransition ? config.transition_duration : 0;
+        durationForExit = withTransitionForExit ? duration : 0;
+        durationForAxis = withTransitionForAxis ? duration : 0;
+
+        transitions = transitions || $$.generateAxisTransitions(durationForAxis);
+
+        // update legend and transform each g
+        if (withLegend && config.legend_show) {
+            $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
+        } else if (withDimension) {
+            // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
+            // no need to update axis in it because they will be updated in redraw()
+            $$.updateDimension(true);
+        }
+
+        // MEMO: needed for grids calculation
+        if ($$.isCategorized() && targetsToShow.length === 0) {
+            $$.x.domain([0, $$.axes.x.selectAll('.tick').size()]);
+        }
+
+        if (targetsToShow.length) {
+            $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
+            if (!config.axis_x_tick_values) {
+                if (config.axis_x_tick_fit || config.axis_x_tick_count) {
+                    tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count, $$.isTimeSeries());
+                } else {
+                    tickValues = undefined;
+                }
+                $$.xAxis.tickValues(tickValues);
+                $$.subXAxis.tickValues(tickValues);
+            }
+        } else {
+            $$.xAxis.tickValues([]);
+            $$.subXAxis.tickValues([]);
+        }
+
+        if (config.zoom_rescale && !options.flow) {
+            xDomainForZoom = $$.x.orgDomain();
+        }
+
+        $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
+        $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
+
+        if (!config.axis_y_tick_values && config.axis_y_tick_count) {
+            $$.yAxis.tickValues($$.generateTickValues($$.y.domain(), config.axis_y_tick_count));
+        }
+        if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
+            $$.y2Axis.tickValues($$.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
+        }
+
+        // axes
+        $$.redrawAxis(transitions, hideAxis);
+
+        // Update axis label
+        $$.updateAxisLabels(withTransition);
+
+        // show/hide if manual culling needed
+        if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
+            if (config.axis_x_tick_culling && tickValues) {
+                for (i = 1; i < tickValues.length; i++) {
+                    if (tickValues.length / i < config.axis_x_tick_culling_max) {
+                        intervalForCulling = i;
+                        break;
+                    }
+                }
+                $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
+                    var index = tickValues.indexOf(e);
+                    if (index >= 0) {
+                        d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
+                    }
+                });
+            } else {
+                $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
+            }
+        }
+
+        // setup drawer - MEMO: these must be called after axis updated
+        drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
+        drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
+        drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
+        xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
+        yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false);
+
+        // Update sub domain
+        if (withY) {
+            $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
+            $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
+        }
+
+        // tooltip
+        $$.tooltip.style("display", "none");
+
+        // xgrid focus
+        $$.updateXgridFocus();
+
+        // Data empty label positioning and text.
+        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);
+
+        // grid
+        $$.redrawGrid(duration);
+
+        // rect for regions
+        $$.redrawRegion(duration);
+
+        // bars
+        $$.redrawBar(durationForExit);
+
+        // lines, areas and cricles
+        $$.redrawLine(durationForExit);
+        $$.redrawArea(durationForExit);
+        $$.redrawCircle();
+
+        // text
+        if ($$.hasDataLabel()) {
+            $$.redrawText(durationForExit);
+        }
+
+        // arc
+        if ($$.redrawArc) { $$.redrawArc(duration, durationForExit, withTransform); }
+
+        // subchart
+        if ($$.redrawSubchart) {
+            $$.redrawSubchart(withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices);
+        }
+
+        // circles for select
+        main.selectAll('.' + CLASS.selectedCircles)
+            .filter($$.isBarType.bind($$))
+            .selectAll('circle')
+            .remove();
+
+        // event rects will redrawn when flow called
+        if (config.interaction_enabled && !options.flow && withEventRect) {
+            $$.redrawEventRect();
+            if ($$.updateZoom) { $$.updateZoom(); }
+        }
+
+        // update circleY based on updated parameters
+        $$.updateCircleY();
+
+        // generate circle x/y functions depending on updated params
+        cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
+        cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
+
+        // transition should be derived from one transition
+        d3.transition().duration(duration).each(function () {
+            var transitions = [];
+
+            $$.addTransitionForBar(transitions, drawBar);
+            $$.addTransitionForLine(transitions, drawLine);
+            $$.addTransitionForArea(transitions, drawArea);
+            $$.addTransitionForCircle(transitions, cx, cy);
+            $$.addTransitionForText(transitions, xForText, yForText, options.flow);
+            $$.addTransitionForRegion(transitions);
+            $$.addTransitionForGrid(transitions);
+
+            // Wait for end of transitions if called from flow API
+            if (options.flow) {
+                waitForDraw = $$.generateWait();
+                transitions.forEach(function (t) {
+                    waitForDraw.add(t);
+                });
+                flow = $$.generateFlow({
+                    targets: targetsToShow,
+                    flow: options.flow,
+                    duration: duration,
+                    drawBar: drawBar,
+                    drawLine: drawLine,
+                    drawArea: drawArea,
+                    cx: cx,
+                    cy: cy,
+                    xv: xv,
+                    xForText: xForText,
+                    yForText: yForText
+                });
+            }
+        })
+        .call(waitForDraw || function () {}, flow || function () {});
+
+        // update fadein condition
+        $$.mapToIds($$.data.targets).forEach(function (id) {
+            $$.withoutFadeIn[id] = true;
+        });
+    };
+
+    c3_chart_internal_fn.updateAndRedraw = function (options) {
+        var $$ = this, config = $$.config, transitions;
+        options = options || {};
+        // same with redraw
+        options.withTransition = getOption(options, "withTransition", true);
+        options.withTransform = getOption(options, "withTransform", false);
+        options.withLegend = getOption(options, "withLegend", false);
+        // NOT same with redraw
+        options.withUpdateXDomain = true;
+        options.withUpdateOrgXDomain = true;
+        options.withTransitionForExit = false;
+        options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
+        // MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
+        $$.updateSizes();
+        // MEMO: called in updateLegend in redraw if withLegend
+        if (!(options.withLegend && config.legend_show)) {
+            transitions = $$.generateAxisTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
+            // Update scales
+            $$.updateScales();
+            $$.updateSvgSize();
+            // Update g positions
+            $$.transformAll(options.withTransitionForTransform, transitions);
+        }
+        // Draw with new sizes & scales
+        $$.redraw(options, transitions);
+    };
+    c3_chart_internal_fn.redrawWithoutRescale = function () {
+        this.redraw({
+            withY: false,
+            withSubchart: false,
+            withEventRect: false,
+            withTransitionForAxis: false
+        });
+    };
+
+    c3_chart_internal_fn.isTimeSeries = function () {
+        return this.config.axis_x_type === 'timeseries';
+    };
+    c3_chart_internal_fn.isCategorized = function () {
+        return this.config.axis_x_type.indexOf('categor') >= 0;
+    };
+    c3_chart_internal_fn.isCustomX = function () {
+        var $$ = this, config = $$.config;
+        return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
+    };
+
+    c3_chart_internal_fn.isTimeSeriesY = function () {
+        return this.config.axis_y_type === 'timeseries';
+    };
+
+    c3_chart_internal_fn.getTranslate = function (target) {
+        var $$ = this, config = $$.config, x, y;
+        if (target === 'main') {
+            x = asHalfPixel($$.margin.left);
+            y = asHalfPixel($$.margin.top);
+        } else if (target === 'context') {
+            x = asHalfPixel($$.margin2.left);
+            y = asHalfPixel($$.margin2.top);
+        } else if (target === 'legend') {
+            x = $$.margin3.left;
+            y = $$.margin3.top;
+        } else if (target === 'x') {
+            x = 0;
+            y = config.axis_rotated ? 0 : $$.height;
+        } else if (target === 'y') {
+            x = 0;
+            y = config.axis_rotated ? $$.height : 0;
+        } else if (target === 'y2') {
+            x = config.axis_rotated ? 0 : $$.width;
+            y = config.axis_rotated ? 1 : 0;
+        } else if (target === 'subx') {
+            x = 0;
+            y = config.axis_rotated ? 0 : $$.height2;
+        } else if (target === 'arc') {
+            x = $$.arcWidth / 2;
+            y = $$.arcHeight / 2;
+        }
+        return "translate(" + x + "," + y + ")";
+    };
+    c3_chart_internal_fn.initialOpacity = function (d) {
+        return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
+    };
+    c3_chart_internal_fn.initialOpacityForCircle = function (d) {
+        return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
+    };
+    c3_chart_internal_fn.opacityForCircle = function (d) {
+        var opacity = this.config.point_show ? 1 : 0;
+        return isValue(d.value) ? (this.isScatterType(d) ? 0.5 : opacity) : 0;
+    };
+    c3_chart_internal_fn.opacityForText = function () {
+        return this.hasDataLabel() ? 1 : 0;
+    };
+    c3_chart_internal_fn.xx = function (d) {
+        return d ? this.x(d.x) : null;
+    };
+    c3_chart_internal_fn.xv = function (d) {
+        var $$ = this;
+        return Math.ceil($$.x($$.isTimeSeries() ? $$.parseDate(d.value) : d.value));
+    };
+    c3_chart_internal_fn.yv = function (d) {
+        var $$ = this,
+            yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y;
+        return Math.ceil(yScale(d.value));
+    };
+    c3_chart_internal_fn.subxx = function (d) {
+        return d ? this.subX(d.x) : null;
+    };
+
+    c3_chart_internal_fn.transformMain = function (withTransition, transitions) {
+        var $$ = this,
+            xAxis, yAxis, y2Axis;
+        if (transitions && transitions.axisX) {
+            xAxis = transitions.axisX;
+        } else {
+            xAxis  = $$.main.select('.' + CLASS.axisX);
+            if (withTransition) { xAxis = xAxis.transition(); }
+        }
+        if (transitions && transitions.axisY) {
+            yAxis = transitions.axisY;
+        } else {
+            yAxis = $$.main.select('.' + CLASS.axisY);
+            if (withTransition) { yAxis = yAxis.transition(); }
+        }
+        if (transitions && transitions.axisY2) {
+            y2Axis = transitions.axisY2;
+        } else {
+            y2Axis = $$.main.select('.' + CLASS.axisY2);
+            if (withTransition) { y2Axis = y2Axis.transition(); }
+        }
+        (withTransition ? $$.main.transition() : $$.main).attr("transform", $$.getTranslate('main'));
+        xAxis.attr("transform", $$.getTranslate('x'));
+        yAxis.attr("transform", $$.getTranslate('y'));
+        y2Axis.attr("transform", $$.getTranslate('y2'));
+        $$.main.select('.' + CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
+    };
+    c3_chart_internal_fn.transformAll = function (withTransition, transitions) {
+        var $$ = this;
+        $$.transformMain(withTransition, transitions);
+        if ($$.config.subchart_show) { $$.transformContext(withTransition, transitions); }
+        if ($$.legend) { $$.transformLegend(withTransition); }
+    };
+
+    c3_chart_internal_fn.updateSvgSize = function () {
+        var $$ = this,
+            brush = $$.svg.select(".c3-brush .background");
+        $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
+        $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect')
+            .attr('width', $$.width)
+            .attr('height', $$.height);
+        $$.svg.select('#' + $$.clipIdForXAxis).select('rect')
+            .attr('x', $$.getXAxisClipX.bind($$))
+            .attr('y', $$.getXAxisClipY.bind($$))
+            .attr('width', $$.getXAxisClipWidth.bind($$))
+            .attr('height', $$.getXAxisClipHeight.bind($$));
+        $$.svg.select('#' + $$.clipIdForYAxis).select('rect')
+            .attr('x', $$.getYAxisClipX.bind($$))
+            .attr('y', $$.getYAxisClipY.bind($$))
+            .attr('width', $$.getYAxisClipWidth.bind($$))
+            .attr('height', $$.getYAxisClipHeight.bind($$));
+        $$.svg.select('#' + $$.clipIdForSubchart).select('rect')
+            .attr('width', $$.width)
+            .attr('height', brush.size() ? brush.attr('height') : 0);
+        $$.svg.select('.' + CLASS.zoomRect)
+            .attr('width', $$.width)
+            .attr('height', $$.height);
+        // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
+        $$.selectChart.style('max-height', $$.currentHeight + "px");
+    };
+
+
+    c3_chart_internal_fn.updateDimension = function (withoutAxis) {
+        var $$ = this;
+        if (!withoutAxis) {
+            if ($$.config.axis_rotated) {
+                $$.axes.x.call($$.xAxis);
+                $$.axes.subx.call($$.subXAxis);
+            } else {
+                $$.axes.y.call($$.yAxis);
+                $$.axes.y2.call($$.y2Axis);
+            }
+        }
+        $$.updateSizes();
+        $$.updateScales();
+        $$.updateSvgSize();
+        $$.transformAll(false);
+    };
+
+    c3_chart_internal_fn.observeInserted = function (selection) {
+        var $$ = this, observer = new MutationObserver(function (mutations) {
+            mutations.forEach(function (mutation) {
+                if (mutation.type === 'childList' && mutation.previousSibling) {
+                    observer.disconnect();
+                    // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
+                    $$.intervalForObserveInserted = window.setInterval(function () {
+                        // parentNode will NOT be null when completed
+                        if (selection.node().parentNode) {
+                            window.clearInterval($$.intervalForObserveInserted);
+                            $$.updateDimension();
+                            $$.config.oninit.call($$);
+                            $$.redraw({
+                                withTransform: true,
+                                withUpdateXDomain: true,
+                                withUpdateOrgXDomain: true,
+                                withTransition: false,
+                                withTransitionForTransform: false,
+                                withLegend: true
+                            });
+                            selection.transition().style('opacity', 1);
+                        }
+                    }, 10);
+                }
+            });
+        });
+        observer.observe(selection.node(), {attributes: true, childList: true, characterData: true});
+    };
+
+
+    c3_chart_internal_fn.generateResize = function () {
+        var resizeFunctions = [];
+        function callResizeFunctions() {
+            resizeFunctions.forEach(function (f) {
+                f();
+            });
+        }
+        callResizeFunctions.add = function (f) {
+            resizeFunctions.push(f);
+        };
+        return callResizeFunctions;
+    };
+
+    c3_chart_internal_fn.endall = function (transition, callback) {
+        var n = 0;
+        transition
+            .each(function () { ++n; })
+            .each("end", function () {
+                if (!--n) { callback.apply(this, arguments); }
+            });
+    };
+    c3_chart_internal_fn.generateWait = function () {
+        var transitionsToWait = [],
+            f = function (transition, callback) {
+                var timer = setInterval(function () {
+                    var done = 0;
+                    transitionsToWait.forEach(function (t) {
+                        if (t.empty()) {
+                            done += 1;
+                            return;
+                        }
+                        try {
+                            t.transition();
+                        } catch (e) {
+                            done += 1;
+                        }
+                    });
+                    if (done === transitionsToWait.length) {
+                        clearInterval(timer);
+                        if (callback) { callback(); }
+                    }
+                }, 10);
+            };
+        f.add = function (transition) {
+            transitionsToWait.push(transition);
+        };
+        return f;
+    };
+
+    c3_chart_internal_fn.parseDate = function (date) {
+        var $$ = this, parsedDate;
+        if (date instanceof Date) {
+            parsedDate = date;
+        } else if (typeof date === 'number') {
+            parsedDate = new Date(date);
+        } else {
+            parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
+        }
+        if (!parsedDate || isNaN(+parsedDate)) {
+            window.console.error("Failed to parse x '" + date + "' to Date object");
+        }
+        return parsedDate;
+    };
+
+    c3_chart_internal_fn.getDefaultConfig = function () {
+        var config = {
+            bindto: '#chart',
+            size_width: undefined,
+            size_height: undefined,
+            padding_left: undefined,
+            padding_right: undefined,
+            padding_top: undefined,
+            padding_bottom: undefined,
+            zoom_enabled: false,
+            zoom_extent: undefined,
+            zoom_privileged: false,
+            zoom_rescale: false,
+            zoom_onzoom: function () {},
+            zoom_onzoomstart: function () {},
+            zoom_onzoomend: function () {},
+            interaction_enabled: true,
+            onmouseover: function () {},
+            onmouseout: function () {},
+            onresize: function () {},
+            onresized: function () {},
+            oninit: function () {},
+            transition_duration: 350,
+            data_x: undefined,
+            data_xs: {},
+            data_xFormat: '%Y-%m-%d',
+            data_xLocaltime: true,
+            data_xSort: true,
+            data_idConverter: function (id) { return id; },
+            data_names: {},
+            data_classes: {},
+            data_groups: [],
+            data_axes: {},
+            data_type: undefined,
+            data_types: {},
+            data_labels: {},
+            data_order: 'desc',
+            data_regions: {},
+            data_color: undefined,
+            data_colors: {},
+            data_hide: false,
+            data_filter: undefined,
+            data_selection_enabled: false,
+            data_selection_grouped: false,
+            data_selection_isselectable: function () { return true; },
+            data_selection_multiple: true,
+            data_onclick: function () {},
+            data_onmouseover: function () {},
+            data_onmouseout: function () {},
+            data_onselected: function () {},
+            data_onunselected: function () {},
+            data_ondragstart: function () {},
+            data_ondragend: function () {},
+            data_url: undefined,
+            data_json: undefined,
+            data_rows: undefined,
+            data_columns: undefined,
+            data_mimeType: undefined,
+            data_keys: undefined,
+            // configuration for no plot-able data supplied.
+            data_empty_label_text: "",
+            // subchart
+            subchart_show: false,
+            subchart_size_height: 60,
+            subchart_onbrush: function () {},
+            // color
+            color_pattern: [],
+            color_threshold: {},
+            // legend
+            legend_show: true,
+            legend_hide: false,
+            legend_position: 'bottom',
+            legend_inset_anchor: 'top-left',
+            legend_inset_x: 10,
+            legend_inset_y: 0,
+            legend_inset_step: undefined,
+            legend_item_onclick: undefined,
+            legend_item_onmouseover: undefined,
+            legend_item_onmouseout: undefined,
+            legend_equally: false,
+            // axis
+            axis_rotated: false,
+            axis_x_show: true,
+            axis_x_type: 'indexed',
+            axis_x_localtime: true,
+            axis_x_categories: [],
+            axis_x_tick_centered: false,
+            axis_x_tick_format: undefined,
+            axis_x_tick_culling: {},
+            axis_x_tick_culling_max: 10,
+            axis_x_tick_count: undefined,
+            axis_x_tick_fit: true,
+            axis_x_tick_values: null,
+            axis_x_tick_rotate: 0,
+            axis_x_tick_outer: true,
+            axis_x_tick_multiline: true,
+            axis_x_tick_width: null,
+            axis_x_max: undefined,
+            axis_x_min: undefined,
+            axis_x_padding: {},
+            axis_x_height: undefined,
+            axis_x_extent: undefined,
+            axis_x_label: {},
+            axis_y_show: true,
+            axis_y_type: undefined,
+            axis_y_max: undefined,
+            axis_y_min: undefined,
+            axis_y_center: undefined,
+            axis_y_inner: undefined,
+            axis_y_label: {},
+            axis_y_tick_format: undefined,
+            axis_y_tick_outer: true,
+            axis_y_tick_values: null,
+            axis_y_tick_count: undefined,
+            axis_y_tick_time_value: undefined,
+            axis_y_tick_time_interval: undefined,
+            axis_y_padding: {},
+            axis_y_default: undefined,
+            axis_y2_show: false,
+            axis_y2_max: undefined,
+            axis_y2_min: undefined,
+            axis_y2_center: undefined,
+            axis_y2_inner: undefined,
+            axis_y2_label: {},
+            axis_y2_tick_format: undefined,
+            axis_y2_tick_outer: true,
+            axis_y2_tick_values: null,
+            axis_y2_tick_count: undefined,
+            axis_y2_padding: {},
+            axis_y2_default: undefined,
+            // grid
+            grid_x_show: false,
+            grid_x_type: 'tick',
+            grid_x_lines: [],
+            grid_y_show: false,
+            // not used
+            // grid_y_type: 'tick',
+            grid_y_lines: [],
+            grid_y_ticks: 10,
+            grid_focus_show: true,
+            grid_lines_front: true,
+            // point - point of each data
+            point_show: true,
+            point_r: 2.5,
+            point_focus_expand_enabled: true,
+            point_focus_expand_r: undefined,
+            point_select_r: undefined,
+            // line
+            line_connectNull: false,
+            line_step_type: 'step',
+            // bar
+            bar_width: undefined,
+            bar_width_ratio: 0.6,
+            bar_width_max: undefined,
+            bar_zerobased: true,
+            // area
+            area_zerobased: true,
+            // pie
+            pie_label_show: true,
+            pie_label_format: undefined,
+            pie_label_threshold: 0.05,
+            pie_expand: true,
+            // gauge
+            gauge_label_show: true,
+            gauge_label_format: undefined,
+            gauge_expand: true,
+            gauge_min: 0,
+            gauge_max: 100,
+            gauge_units: undefined,
+            gauge_width: undefined,
+            // donut
+            donut_label_show: true,
+            donut_label_format: undefined,
+            donut_label_threshold: 0.05,
+            donut_width: undefined,
+            donut_expand: true,
+            donut_title: "",
+            // region - region to change style
+            regions: [],
+            // tooltip - show when mouseover on each data
+            tooltip_show: true,
+            tooltip_grouped: true,
+            tooltip_format_title: undefined,
+            tooltip_format_name: undefined,
+            tooltip_format_value: undefined,
+            tooltip_contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
+                return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
+            },
+            tooltip_init_show: false,
+            tooltip_init_x: 0,
+            tooltip_init_position: {top: '0px', left: '50px'}
+        };
+
+        Object.keys(this.additionalConfig).forEach(function (key) {
+            config[key] = this.additionalConfig[key];
+        }, this);
+
+<<<<<<< HEAD
+        function updateAngle(d) {
+            var found = false;
+
+            if (isNaN(d)) {
+                return null;
+            }
+
+            pie(filterTargetsToShow(c3.data.targets)).forEach(function (t) {
+                if (! found && t.data.id === d.data.id) {
+                    found = true;
+                    d = t;
+                    return;
+                }
+            });
+            return found ? d : null;
+        }
+=======
+        return config;
+    };
+    c3_chart_internal_fn.additionalConfig = {};
+>>>>>>> upstream/master
+
+    c3_chart_internal_fn.loadConfig = function (config) {
+        var this_config = this.config, target, keys, read;
+        function find() {
+            var key = keys.shift();
+    //        console.log("key =>", key, ", target =>", target);
+            if (key && target && typeof target === 'object' && key in target) {
+                target = target[key];
+                return find();
+            }
+            else if (!key) {
+                return target;
+            }
+            else {
+                return undefined;
+            }
+        }
+        Object.keys(this_config).forEach(function (key) {
+            target = config;
+            keys = key.split('_');
+            read = find();
+    //        console.log("CONFIG : ", key, read);
+            if (isDefined(read)) {
+                this_config[key] = read;
+            }
+        });
+    };
+
+    c3_chart_internal_fn.getScale = function (min, max, forTimeseries) {
+        return (forTimeseries ? this.d3.time.scale() : this.d3.scale.linear()).range([min, max]);
+    };
+    c3_chart_internal_fn.getX = function (min, max, domain, offset) {
+        var $$ = this,
+            scale = $$.getScale(min, max, $$.isTimeSeries()),
+            _scale = domain ? scale.domain(domain) : scale, key;
+        // Define customized scale if categorized axis
+        if ($$.isCategorized()) {
+            offset = offset || function () { return 0; };
+            scale = function (d, raw) {
+                var v = _scale(d) + offset(d);
+                return raw ? v : Math.ceil(v);
+            };
+        } else {
+            scale = function (d, raw) {
+                var v = _scale(d);
+                return raw ? v : Math.ceil(v);
+            };
+        }
+        // define functions
+        for (key in _scale) {
+            scale[key] = _scale[key];
+        }
+        scale.orgDomain = function () {
+            return _scale.domain();
+        };
+        // define custom domain() for categorized axis
+        if ($$.isCategorized()) {
+            scale.domain = function (domain) {
+                if (!arguments.length) {
+                    domain = this.orgDomain();
+                    return [domain[0], domain[1] + 1];
+                }
+                _scale.domain(domain);
+                return scale;
+            };
+        }
+        return scale;
+    };
+    c3_chart_internal_fn.getY = function (min, max, domain) {
+        var scale = this.getScale(min, max, this.isTimeSeriesY());
+        if (domain) { scale.domain(domain); }
+        return scale;
+    };
+    c3_chart_internal_fn.getYScale = function (id) {
+        return this.getAxisId(id) === 'y2' ? this.y2 : this.y;
+    };
+    c3_chart_internal_fn.getSubYScale = function (id) {
+        return this.getAxisId(id) === 'y2' ? this.subY2 : this.subY;
+    };
+    c3_chart_internal_fn.updateScales = function () {
+        var $$ = this, config = $$.config,
+            forInit = !$$.x;
+        // update edges
+        $$.xMin = config.axis_rotated ? 1 : 0;
+        $$.xMax = config.axis_rotated ? $$.height : $$.width;
+        $$.yMin = config.axis_rotated ? 0 : $$.height;
+        $$.yMax = config.axis_rotated ? $$.width : 1;
+        $$.subXMin = $$.xMin;
+        $$.subXMax = $$.xMax;
+        $$.subYMin = config.axis_rotated ? 0 : $$.height2;
+        $$.subYMax = config.axis_rotated ? $$.width2 : 1;
+        // update scales
+        $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () { return $$.xAxis.tickOffset(); });
+        $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
+        $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
+        $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) { return d % 1 ? 0 : $$.subXAxis.tickOffset(); });
+        $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
+        $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
+        // update axes
+        $$.xAxisTickFormat = $$.getXAxisTickFormat();
+        $$.xAxisTickValues = $$.getXAxisTickValues();
+        $$.yAxisTickValues = $$.getYAxisTickValues();
+        $$.y2AxisTickValues = $$.getY2AxisTickValues();
+
+        $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+        $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+        $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
+        $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
+
+        // Set initialized scales to brush and zoom
+        if (!forInit) {
+            if ($$.brush) { $$.brush.scale($$.subX); }
+            if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+        }
+        // update for arc
+        if ($$.updateArc) { $$.updateArc(); }
+    };
+
+    c3_chart_internal_fn.getYDomainMin = function (targets) {
+        var $$ = this, config = $$.config,
+            ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+            j, k, baseId, idsInGroup, id, hasNegativeValue;
+        if (config.data_groups.length > 0) {
+            hasNegativeValue = $$.hasNegativeValueInTargets(targets);
+            for (j = 0; j < config.data_groups.length; j++) {
+                // Determine baseId
+                idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+                if (idsInGroup.length === 0) { continue; }
+                baseId = idsInGroup[0];
+                // Consider negative values
+                if (hasNegativeValue && ys[baseId]) {
+                    ys[baseId].forEach(function (v, i) {
+                        ys[baseId][i] = v < 0 ? v : 0;
+                    });
+                }
+                // Compute min
+                for (k = 1; k < idsInGroup.length; k++) {
+                    id = idsInGroup[k];
+                    if (! ys[id]) { continue; }
+                    ys[id].forEach(function (v, i) {
+                        if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
+                            ys[baseId][i] += +v;
+                        }
+                    });
+                }
+            }
+        }
+        return $$.d3.min(Object.keys(ys).map(function (key) { return $$.d3.min(ys[key]); }));
+    };
+    c3_chart_internal_fn.getYDomainMax = function (targets) {
+        var $$ = this, config = $$.config,
+            ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+            j, k, baseId, idsInGroup, id, hasPositiveValue;
+        if (config.data_groups.length > 0) {
+            hasPositiveValue = $$.hasPositiveValueInTargets(targets);
+            for (j = 0; j < config.data_groups.length; j++) {
+                // Determine baseId
+                idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+                if (idsInGroup.length === 0) { continue; }
+                baseId = idsInGroup[0];
+                // Consider positive values
+                if (hasPositiveValue && ys[baseId]) {
+                    ys[baseId].forEach(function (v, i) {
+                        ys[baseId][i] = v > 0 ? v : 0;
+                    });
+                }
+                // Compute max
+                for (k = 1; k < idsInGroup.length; k++) {
+                    id = idsInGroup[k];
+                    if (! ys[id]) { continue; }
+                    ys[id].forEach(function (v, i) {
+                        if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
+                            ys[baseId][i] += +v;
+                        }
+                    });
+                }
+            }
+        }
+        return $$.d3.max(Object.keys(ys).map(function (key) { return $$.d3.max(ys[key]); }));
+    };
+    c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
+        var $$ = this, config = $$.config,
+            targetsByAxisId = targets.filter(function (t) { return $$.getAxisId(t.id) === axisId; }),
+            yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
+            yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
+            yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
+            yDomainMin = isValue(yMin) ? yMin : $$.getYDomainMin(yTargets),
+            yDomainMax = isValue(yMax) ? yMax : $$.getYDomainMax(yTargets),
+            domainLength, padding, padding_top, padding_bottom,
+            center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
+            yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative,
+            isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
+            showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
+            showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
+
+        if (yDomainMax < yDomainMin) {
+            if (isValue(yMin)) {
+                yDomainMax = yDomainMin + 10; // TODO: introduce axis.y.maxMin
+            } else {
+                yDomainMin = yDomainMax - 10; // TODO: introduce axis.y.minMax
+            }
+        }
+
+        if (yTargets.length === 0) { // use current domain if target of axisId is none
+            return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
+        }
+        if (isNaN(yDomainMin)) { // set minimum to zero when not number
+            yDomainMin = 0;
+        }
+        if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin
+            yDomainMax = yDomainMin;
+        }
+        if (yDomainMin === yDomainMax) {
+            yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
+        }
+        isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
+        isAllNegative = yDomainMin <= 0 && yDomainMax <= 0;
+
+        // Cancel zerobased if axis_*_min / axis_*_max specified
+        if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) {
+            isZeroBased = false;
+        }
+
+        // Bar/Area chart should be 0-based if all positive|negative
+        if (isZeroBased) {
+            if (isAllPositive) { yDomainMin = 0; }
+            if (isAllNegative) { yDomainMax = 0; }
+        }
+
+        domainLength = Math.abs(yDomainMax - yDomainMin);
+        padding = padding_top = padding_bottom = domainLength * 0.1;
+
+        if (center) {
+            yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
+            yDomainMax = yDomainAbs - center;
+            yDomainMin = center - yDomainAbs;
+        }
+        // add padding for data label
+        if (showHorizontalDataLabel) {
+            lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'width');
+            diff = diffDomain($$.y.range());
+            ratio = [lengths[0] / diff, lengths[1] / diff];
+            padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
+            padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
+        } else if (showVerticalDataLabel) {
+            lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'height');
+            padding_top += lengths[1];
+            padding_bottom += lengths[0];
+        }
+        if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
+            padding_top = $$.getAxisPadding(config.axis_y_padding, 'top', padding, domainLength);
+            padding_bottom = $$.getAxisPadding(config.axis_y_padding, 'bottom', padding, domainLength);
+        }
+        if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
+            padding_top = $$.getAxisPadding(config.axis_y2_padding, 'top', padding, domainLength);
+            padding_bottom = $$.getAxisPadding(config.axis_y2_padding, 'bottom', padding, domainLength);
+        }
+        // Bar/Area chart should be 0-based if all positive|negative
+        if (isZeroBased) {
+            if (isAllPositive) { padding_bottom = yDomainMin; }
+            if (isAllNegative) { padding_top = -yDomainMax; }
+        }
+        return [yDomainMin - padding_bottom, yDomainMax + padding_top];
+    };
+    c3_chart_internal_fn.getXDomainMin = function (targets) {
+        var $$ = this, config = $$.config;
+        return isDefined(config.axis_x_min) ?
+            ($$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min) :
+        $$.d3.min(targets, function (t) { return $$.d3.min(t.values, function (v) { return v.x; }); });
+    };
+    c3_chart_internal_fn.getXDomainMax = function (targets) {
+        var $$ = this, config = $$.config;
+        return isDefined(config.axis_x_max) ?
+            ($$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max) :
+        $$.d3.max(targets, function (t) { return $$.d3.max(t.values, function (v) { return v.x; }); });
+    };
+    c3_chart_internal_fn.getXDomainPadding = function (domain) {
+        var $$ = this, config = $$.config,
+            diff = domain[1] - domain[0],
+            maxDataCount, padding, paddingLeft, paddingRight;
+        if ($$.isCategorized()) {
+            padding = 0;
+        } else if ($$.hasType('bar')) {
+            maxDataCount = $$.getMaxDataCount();
+            padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
+        } else {
+            padding = diff * 0.01;
+        }
+        if (typeof config.axis_x_padding === 'object' && notEmpty(config.axis_x_padding)) {
+            paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding;
+            paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding;
+        } else if (typeof config.axis_x_padding === 'number') {
+            paddingLeft = paddingRight = config.axis_x_padding;
+        } else {
+            paddingLeft = paddingRight = padding;
+        }
+        return {left: paddingLeft, right: paddingRight};
+    };
+    c3_chart_internal_fn.getXDomain = function (targets) {
+        var $$ = this,
+            xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
+            firstX = xDomain[0], lastX = xDomain[1],
+            padding = $$.getXDomainPadding(xDomain),
+            min = 0, max = 0;
+        // show center of x domain if min and max are the same
+        if ((firstX - lastX) === 0 && !$$.isCategorized()) {
+            if ($$.isTimeSeries()) {
+                firstX = new Date(firstX.getTime() * 0.5);
+                lastX = new Date(lastX.getTime() * 1.5);
+            } else {
+                firstX = firstX === 0 ? 1 : (firstX * 0.5);
+                lastX = lastX === 0 ? -1 : (lastX * 1.5);
+            }
+        }
+        if (firstX || firstX === 0) {
+            min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
+        }
+        if (lastX || lastX === 0) {
+            max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
+        }
+        return [min, max];
+    };
+    c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
+        var $$ = this, config = $$.config;
+
+        if (withUpdateOrgXDomain) {
+            $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
+            $$.orgXDomain = $$.x.domain();
+            if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
+            $$.subX.domain($$.x.domain());
+            if ($$.brush) { $$.brush.scale($$.subX); }
+        }
+        if (withUpdateXDomain) {
+            $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent());
+            if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
+        }
+
+        // Trim domain when too big by zoom mousemove event
+        if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); }
+
+        return $$.x.domain();
+    };
+    c3_chart_internal_fn.trimXDomain = function (domain) {
+        var $$ = this;
+        if (domain[0] <= $$.orgXDomain[0]) {
+            domain[1] = +domain[1] + ($$.orgXDomain[0] - domain[0]);
+            domain[0] = $$.orgXDomain[0];
+        }
+        if ($$.orgXDomain[1] <= domain[1]) {
+            domain[0] = +domain[0] - (domain[1] - $$.orgXDomain[1]);
+            domain[1] = $$.orgXDomain[1];
+        }
+        return domain;
+    };
+
+    c3_chart_internal_fn.isX = function (key) {
+        var $$ = this, config = $$.config;
+        return (config.data_x && key === config.data_x) || (notEmpty(config.data_xs) && hasValue(config.data_xs, key));
+    };
+    c3_chart_internal_fn.isNotX = function (key) {
+        return !this.isX(key);
+    };
+    c3_chart_internal_fn.getXKey = function (id) {
+        var $$ = this, config = $$.config;
+        return config.data_x ? config.data_x : notEmpty(config.data_xs) ? config.data_xs[id] : null;
+    };
+    c3_chart_internal_fn.getXValuesOfXKey = function (key, targets) {
+        var $$ = this,
+            xValues, ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : [];
+        ids.forEach(function (id) {
+            if ($$.getXKey(id) === key) {
+                xValues = $$.data.xs[id];
+            }
+        });
+        return xValues;
+    };
+    c3_chart_internal_fn.getIndexByX = function (x) {
+        var $$ = this,
+            data = $$.filterByX($$.data.targets, x);
+        return data.length ? data[0].index : null;
+    };
+    c3_chart_internal_fn.getXValue = function (id, i) {
+        var $$ = this;
+        return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
+    };
+    c3_chart_internal_fn.getOtherTargetXs = function () {
+        var $$ = this,
+            idsForX = Object.keys($$.data.xs);
+        return idsForX.length ? $$.data.xs[idsForX[0]] : null;
+    };
+    c3_chart_internal_fn.getOtherTargetX = function (index) {
+        var xs = this.getOtherTargetXs();
+        return xs && index < xs.length ? xs[index] : null;
+    };
+    c3_chart_internal_fn.addXs = function (xs) {
+        var $$ = this;
+        Object.keys(xs).forEach(function (id) {
+            $$.config.data_xs[id] = xs[id];
+        });
+    };
+    c3_chart_internal_fn.hasMultipleX = function (xs) {
+        return this.d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() > 1;
+    };
+    c3_chart_internal_fn.isMultipleX = function () {
+        return notEmpty(this.config.data_xs) || !this.config.data_xSort || this.hasType('scatter');
+    };
+    c3_chart_internal_fn.addName = function (data) {
+        var $$ = this, name;
+        if (data) {
+            name = $$.config.data_names[data.id];
+            data.name = name ? name : data.id;
+        }
+        return data;
+    };
+    c3_chart_internal_fn.getValueOnIndex = function (values, index) {
+        var valueOnIndex = values.filter(function (v) { return v.index === index; });
+        return valueOnIndex.length ? valueOnIndex[0] : null;
+    };
+    c3_chart_internal_fn.updateTargetX = function (targets, x) {
+        var $$ = this;
+        targets.forEach(function (t) {
+            t.values.forEach(function (v, i) {
+                v.x = $$.generateTargetX(x[i], t.id, i);
+            });
+            $$.data.xs[t.id] = x;
+        });
+    };
+    c3_chart_internal_fn.updateTargetXs = function (targets, xs) {
+        var $$ = this;
+        targets.forEach(function (t) {
+            if (xs[t.id]) {
+                $$.updateTargetX([t], xs[t.id]);
+            }
+        });
+    };
+    c3_chart_internal_fn.generateTargetX = function (rawX, id, index) {
+        var $$ = this, x;
+        if ($$.isTimeSeries()) {
+            x = rawX ? $$.parseDate(rawX) : $$.parseDate($$.getXValue(id, index));
+        }
+        else if ($$.isCustomX() && !$$.isCategorized()) {
+            x = isValue(rawX) ? +rawX : $$.getXValue(id, index);
+        }
+        else {
+            x = index;
+        }
+        return x;
+    };
+    c3_chart_internal_fn.cloneTarget = function (target) {
+        return {
+            id : target.id,
+            id_org : target.id_org,
+            values : target.values.map(function (d) {
+                return {x: d.x, value: d.value, id: d.id};
+            })
+        };
+    };
+    c3_chart_internal_fn.updateXs = function () {
+        var $$ = this;
+        if ($$.data.targets.length) {
+            $$.xs = [];
+            $$.data.targets[0].values.forEach(function (v) {
+                $$.xs[v.index] = v.x;
+            });
+        }
+    };
+    c3_chart_internal_fn.getPrevX = function (i) {
+        var x = this.xs[i - 1];
+        return typeof x !== 'undefined' ? x : null;
+    };
+    c3_chart_internal_fn.getNextX = function (i) {
+        var x = this.xs[i + 1];
+        return typeof x !== 'undefined' ? x : null;
+    };
+    c3_chart_internal_fn.getMaxDataCount = function () {
+        var $$ = this;
+        return $$.d3.max($$.data.targets, function (t) { return t.values.length; });
+    };
+    c3_chart_internal_fn.getMaxDataCountTarget = function (targets) {
+        var length = targets.length, max = 0, maxTarget;
+        if (length > 1) {
+            targets.forEach(function (t) {
+                if (t.values.length > max) {
+                    maxTarget = t;
+                    max = t.values.length;
+                }
+            });
+        } else {
+            maxTarget = length ? targets[0] : null;
+        }
+        return maxTarget;
+    };
+    c3_chart_internal_fn.getEdgeX = function (targets) {
+        var $$ = this;
+        return !targets.length ? [0, 0] : [
+            $$.d3.min(targets, function (t) { return t.values[0].x; }),
+            $$.d3.max(targets, function (t) { return t.values[t.values.length - 1].x; })
+        ];
+    };
+    c3_chart_internal_fn.mapToIds = function (targets) {
+        return targets.map(function (d) { return d.id; });
+    };
+    c3_chart_internal_fn.mapToTargetIds = function (ids) {
+        var $$ = this;
+        return ids ? (isString(ids) ? [ids] : ids) : $$.mapToIds($$.data.targets);
+    };
+    c3_chart_internal_fn.hasTarget = function (targets, id) {
+        var ids = this.mapToIds(targets), i;
+        for (i = 0; i < ids.length; i++) {
+            if (ids[i] === id) {
+                return true;
+            }
+        }
+        return false;
+    };
+    c3_chart_internal_fn.isTargetToShow = function (targetId) {
+        return this.hiddenTargetIds.indexOf(targetId) < 0;
+    };
+    c3_chart_internal_fn.isLegendToShow = function (targetId) {
+        return this.hiddenLegendIds.indexOf(targetId) < 0;
+    };
+    c3_chart_internal_fn.filterTargetsToShow = function (targets) {
+        var $$ = this;
+        return targets.filter(function (t) { return $$.isTargetToShow(t.id); });
+    };
+    c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
+        var $$ = this;
+        var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
+        return $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
+    };
+    c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
+        this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
+    };
+    c3_chart_internal_fn.removeHiddenTargetIds = function (targetIds) {
+        this.hiddenTargetIds = this.hiddenTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+    };
+    c3_chart_internal_fn.addHiddenLegendIds = function (targetIds) {
+        this.hiddenLegendIds = this.hiddenLegendIds.concat(targetIds);
+    };
+    c3_chart_internal_fn.removeHiddenLegendIds = function (targetIds) {
+        this.hiddenLegendIds = this.hiddenLegendIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+    };
+    c3_chart_internal_fn.getValuesAsIdKeyed = function (targets) {
+        var ys = {};
+        targets.forEach(function (t) {
+            ys[t.id] = [];
+            t.values.forEach(function (v) {
+                ys[t.id].push(v.value);
+            });
+        });
+        return ys;
+    };
+    c3_chart_internal_fn.checkValueInTargets = function (targets, checker) {
+        var ids = Object.keys(targets), i, j, values;
+        for (i = 0; i < ids.length; i++) {
+            values = targets[ids[i]].values;
+            for (j = 0; j < values.length; j++) {
+                if (checker(values[j].value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    };
+    c3_chart_internal_fn.hasNegativeValueInTargets = function (targets) {
+        return this.checkValueInTargets(targets, function (v) { return v < 0; });
+    };
+    c3_chart_internal_fn.hasPositiveValueInTargets = function (targets) {
+        return this.checkValueInTargets(targets, function (v) { return v > 0; });
+    };
+    c3_chart_internal_fn.isOrderDesc = function () {
+        var config = this.config;
+        return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'desc';
+    };
+    c3_chart_internal_fn.isOrderAsc = function () {
+        var config = this.config;
+        return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'asc';
+    };
+    c3_chart_internal_fn.orderTargets = function (targets) {
+        var $$ = this, config = $$.config, orderAsc = $$.isOrderAsc(), orderDesc = $$.isOrderDesc();
+        if (orderAsc || orderDesc) {
+            targets.sort(function (t1, t2) {
+                var reducer = function (p, c) { return p + Math.abs(c.value); };
+                var t1Sum = t1.values.reduce(reducer, 0),
+                    t2Sum = t2.values.reduce(reducer, 0);
+                return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
+            });
+        } else if (isFunction(config.data_order)) {
+            targets.sort(config.data_order);
+        } // TODO: accept name array for order
+        return targets;
+    };
+    c3_chart_internal_fn.filterByX = function (targets, x) {
+        return this.d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
+    };
+    c3_chart_internal_fn.filterRemoveNull = function (data) {
+        return data.filter(function (d) { return isValue(d.value); });
+    };
+    c3_chart_internal_fn.filterByXDomain = function (targets, xDomain) {
+        return targets.map(function (t) {
+            return {
+                id: t.id,
+                id_org: t.id_org,
+                values: t.values.filter(function (v) {
+                    return xDomain[0] <= v.x && v.x <= xDomain[1];
+                })
+            };
+        });
+    };
+    c3_chart_internal_fn.hasDataLabel = function () {
+        var config = this.config;
+        if (typeof config.data_labels === 'boolean' && config.data_labels) {
+            return true;
+        } else if (typeof config.data_labels === 'object' && notEmpty(config.data_labels)) {
+            return true;
+        }
+        return false;
+    };
+    c3_chart_internal_fn.getDataLabelLength = function (min, max, axisId, key) {
+        var $$ = this,
+            lengths = [0, 0], paddingCoef = 1.3;
+        $$.selectChart.select('svg').selectAll('.dummy')
+            .data([min, max])
+            .enter().append('text')
+            .text(function (d) { return $$.formatByAxisId(axisId)(d); })
+            .each(function (d, i) {
+                lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
+            })
+            .remove();
+        return lengths;
+    };
+    c3_chart_internal_fn.isNoneArc = function (d) {
+        return this.hasTarget(this.data.targets, d.id);
+    },
+    c3_chart_internal_fn.isArc = function (d) {
+        return 'data' in d && this.hasTarget(this.data.targets, d.data.id);
+    };
+    c3_chart_internal_fn.findSameXOfValues = function (values, index) {
+        var i, targetX = values[index].x, sames = [];
+        for (i = index - 1; i >= 0; i--) {
+            if (targetX !== values[i].x) { break; }
+            sames.push(values[i]);
+        }
+        for (i = index; i < values.length; i++) {
+            if (targetX !== values[i].x) { break; }
+            sames.push(values[i]);
+        }
+        return sames;
+    };
+
+    c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
+        var $$ = this, candidates;
+
+        // map to array of closest points of each target
+        candidates = targets.map(function (target) {
+            return $$.findClosest(target.values, pos);
+        });
+
+        // decide closest point and return
+        return $$.findClosest(candidates, pos);
+    };
+    c3_chart_internal_fn.findClosest = function (values, pos) {
+        var $$ = this, minDist = 100, closest;
+
+        // find mouseovering bar
+        values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
+            var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
+            if (!closest && $$.isWithinBar(shape)) {
+                closest = v;
+            }
+        });
+
+        // find closest point from non-bar
+        values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
+            var d = $$.dist(v, pos);
+            if (d < minDist) {
+                minDist = d;
+                closest = v;
+            }
+        });
+
+        return closest;
+    };
+    c3_chart_internal_fn.dist = function (data, pos) {
+        var $$ = this, config = $$.config,
+            xIndex = config.axis_rotated ? 1 : 0,
+            yIndex = config.axis_rotated ? 0 : 1,
+            y = $$.circleY(data, data.index),
+            x = $$.x(data.x);
+        return Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2);
+    };
+    c3_chart_internal_fn.convertValuesToStep = function (values) {
+        var converted = [].concat(values), i;
+
+        if (!this.isCategorized()) {
+            return values;
+        }
+
+        for (i = values.length + 1; 0 < i; i--) {
+            converted[i] = converted[i - 1];
+        }
+
+        converted[0] = {
+            x: converted[0].x - 1,
+            value: converted[0].value,
+            id: converted[0].id
+        };
+        converted[values.length + 1] = {
+            x: converted[values.length].x + 1,
+            value: converted[values.length].value,
+            id: converted[values.length].id
+        };
+
+        return converted;
+    };
+    c3_chart_internal_fn.updateDataAttributes = function (name, attrs) {
+        var $$ = this, config = $$.config, current = config['data_' + name];
+        if (typeof attrs === 'undefined') { return current; }
+        Object.keys(attrs).forEach(function (id) {
+            current[id] = attrs[id];
+        });
+        $$.redraw({withLegend: true});
+        return current;
+    };
+
+    c3_chart_internal_fn.convertUrlToData = function (url, mimeType, keys, done) {
+        var $$ = this, type = mimeType ? mimeType : 'csv';
+        $$.d3.xhr(url, function (error, data) {
+            var d;
+            if (type === 'json') {
+                d = $$.convertJsonToData(JSON.parse(data.response), keys);
+            } else if (type === 'tsv') {
+                d = $$.convertTsvToData(data.response);
+            } else {
+                d = $$.convertCsvToData(data.response);
+            }
+            done.call($$, d);
+        });
+    };
+    c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
+        var rows = parser.parseRows(xsv), d;
+        if (rows.length === 1) {
+            d = [{}];
+            rows[0].forEach(function (id) {
+                d[0][id] = null;
+            });
+        } else {
+            d = parser.parse(xsv);
+        }
+        return d;
+    };
+    c3_chart_internal_fn.convertCsvToData = function (csv) {
+        return this.convertXsvToData(csv, this.d3.csv);
+    };
+    c3_chart_internal_fn.convertTsvToData = function (tsv) {
+        return this.convertXsvToData(tsv, this.d3.tsv);
+    };
+    c3_chart_internal_fn.convertJsonToData = function (json, keys) {
+        var $$ = this,
+            new_rows = [], targetKeys, data;
+        if (keys) { // when keys specified, json would be an array that includes objects
+            targetKeys = keys.value;
+            if (keys.x) {
+                targetKeys.push(keys.x);
+                $$.config.data_x = keys.x;
+            }
+            new_rows.push(targetKeys);
+            json.forEach(function (o) {
+                var new_row = [];
+                targetKeys.forEach(function (key) {
+                    // convert undefined to null because undefined data will be removed in convertDataToTargets()
+                    var v = isUndefined(o[key]) ? null : o[key];
+                    new_row.push(v);
+                });
+                new_rows.push(new_row);
+            });
+            data = $$.convertRowsToData(new_rows);
+        } else {
+            Object.keys(json).forEach(function (key) {
+                new_rows.push([key].concat(json[key]));
+            });
+            data = $$.convertColumnsToData(new_rows);
+        }
+        return data;
+    };
+    c3_chart_internal_fn.convertRowsToData = function (rows) {
+        var keys = rows[0], new_row = {}, new_rows = [], i, j;
+        for (i = 1; i < rows.length; i++) {
+            new_row = {};
+            for (j = 0; j < rows[i].length; j++) {
+                if (isUndefined(rows[i][j])) {
+                    throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
+                }
+                new_row[keys[j]] = rows[i][j];
+            }
+            new_rows.push(new_row);
+        }
+        return new_rows;
+    };
+    c3_chart_internal_fn.convertColumnsToData = function (columns) {
+        var new_rows = [], i, j, key;
+        for (i = 0; i < columns.length; i++) {
+            key = columns[i][0];
+            for (j = 1; j < columns[i].length; j++) {
+                if (isUndefined(new_rows[j - 1])) {
+                    new_rows[j - 1] = {};
+                }
+                if (isUndefined(columns[i][j])) {
+                    throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
+                }
+                new_rows[j - 1][key] = columns[i][j];
+            }
+        }
+        return new_rows;
+    };
+    c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
+        var $$ = this, config = $$.config,
+            ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
+            xs = $$.d3.keys(data[0]).filter($$.isX, $$),
+            targets;
+
+        // save x for update data by load when custom x and c3.x API
+        ids.forEach(function (id) {
+            var xKey = $$.getXKey(id);
+
+            if ($$.isCustomX() || $$.isTimeSeries()) {
+                // if included in input data
+                if (xs.indexOf(xKey) >= 0) {
+                    $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
+                        data.map(function (d) { return d[xKey]; })
+                            .filter(isValue)
+                            .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
+                    );
+                }
+                // if not included in input data, find from preloaded data of other id's x
+                else if (config.data_x) {
+                    $$.data.xs[id] = $$.getOtherTargetXs();
+                }
+                // if not included in input data, find from preloaded data
+                else if (notEmpty(config.data_xs)) {
+                    $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
+                }
+                // MEMO: if no x included, use same x of current will be used
+            } else {
+                $$.data.xs[id] = data.map(function (d, i) { return i; });
+            }
+        });
+
+
+        // check x is defined
+        ids.forEach(function (id) {
+            if (!$$.data.xs[id]) {
+                throw new Error('x is not defined for id = "' + id + '".');
+            }
+        });
+
+        // convert to target
+        targets = ids.map(function (id, index) {
+            var convertedId = config.data_idConverter(id);
+            return {
+                id: convertedId,
+                id_org: id,
+                values: data.map(function (d, i) {
+                    var xKey = $$.getXKey(id), rawX = d[xKey], x = $$.generateTargetX(rawX, id, i);
+                    // use x as categories if custom x and categorized
+                    if ($$.isCustomX() && $$.isCategorized() && index === 0 && rawX) {
+                        if (i === 0) { config.axis_x_categories = []; }
+                        config.axis_x_categories.push(rawX);
+                    }
+                    // mark as x = undefined if value is undefined and filter to remove after mapped
+                    if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
+                        x = undefined;
+                    }
+                    return {x: x, value: d[id] !== null && !isNaN(d[id]) ? +d[id] : null, id: convertedId};
+                }).filter(function (v) { return isDefined(v.x); })
+            };
+        });
+
+        // finish targets
+        targets.forEach(function (t) {
+            var i;
+            // sort values by its x
+            if (config.data_xSort) {
+                t.values = t.values.sort(function (v1, v2) {
+                    var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
+                        x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
+                    return x1 - x2;
+                });
+            }
+            // indexing each value
+            i = 0;
+            t.values.forEach(function (v) {
+                v.index = i++;
+            });
+            // this needs to be sorted because its index and value.index is identical
+            $$.data.xs[t.id].sort(function (v1, v2) {
+                return v1 - v2;
+            });
+        });
+
+        // set target types
+        if (config.data_type) {
+            $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
+        }
+
+        // cache as original id keyed
+        targets.forEach(function (d) {
+            $$.addCache(d.id_org, d);
+        });
+
+        return targets;
+    };
+
+    c3_chart_internal_fn.load = function (targets, args) {
+        var $$ = this;
+        if (targets) {
+            // filter loading targets if needed
+            if (args.filter) {
+                targets = targets.filter(args.filter);
+            }
+            // set type if args.types || args.type specified
+            if (args.type || args.types) {
+                targets.forEach(function (t) {
+                    $$.setTargetType(t.id, args.types ? args.types[t.id] : args.type);
+                });
+            }
+            // Update/Add data
+            $$.data.targets.forEach(function (d) {
+                for (var i = 0; i < targets.length; i++) {
+                    if (d.id === targets[i].id) {
+                        d.values = targets[i].values;
+                        targets.splice(i, 1);
+                        break;
+                    }
+                }
+            });
+            $$.data.targets = $$.data.targets.concat(targets); // add remained
+        }
+
+        // Set targets
+        $$.updateTargets($$.data.targets);
+
+        // Redraw with new targets
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+
+        if (args.done) { args.done(); }
+    };
+    c3_chart_internal_fn.loadFromArgs = function (args) {
+        var $$ = this;
+        if (args.data) {
+            $$.load($$.convertDataToTargets(args.data), args);
+        }
+        else if (args.url) {
+            $$.convertUrlToData(args.url, args.mimeType, args.keys, function (data) {
+                $$.load($$.convertDataToTargets(data), args);
+            });
+        }
+        else if (args.json) {
+            $$.load($$.convertDataToTargets($$.convertJsonToData(args.json, args.keys)), args);
+        }
+        else if (args.rows) {
+            $$.load($$.convertDataToTargets($$.convertRowsToData(args.rows)), args);
+        }
+        else if (args.columns) {
+            $$.load($$.convertDataToTargets($$.convertColumnsToData(args.columns)), args);
+        }
+        else {
+            $$.load(null, args);
+        }
+    };
+    c3_chart_internal_fn.unload = function (targetIds, done) {
+        var $$ = this;
+        if (!done) {
+            done = function () {};
+        }
+        // filter existing target
+        targetIds = targetIds.filter(function (id) { return $$.hasTarget($$.data.targets, id); });
+        // If no target, call done and return
+        if (!targetIds || targetIds.length === 0) {
+            done();
+            return;
+        }
+        $$.svg.selectAll(targetIds.map(function (id) { return $$.selectorTarget(id); }))
+            .transition()
+            .style('opacity', 0)
+            .remove()
+            .call($$.endall, done);
+        targetIds.forEach(function (id) {
+            // Reset fadein for future load
+            $$.withoutFadeIn[id] = false;
+            // Remove target's elements
+            if ($$.legend) {
+                $$.legend.selectAll('.' + CLASS.legendItem + $$.getTargetSelectorSuffix(id)).remove();
+            }
+            // Remove target
+            $$.data.targets = $$.data.targets.filter(function (t) {
+                return t.id !== id;
+            });
+        });
+    };
+
+    c3_chart_internal_fn.categoryName = function (i) {
+        var config = this.config;
+        return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
+    };
+
+    c3_chart_internal_fn.initEventRect = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.eventRects)
+            .style('fill-opacity', 0);
+    };
+    c3_chart_internal_fn.redrawEventRect = function () {
+        var $$ = this, config = $$.config,
+            eventRectUpdate, maxDataCountTarget,
+            isMultipleX = $$.isMultipleX();
+
+        // rects for mouseover
+        var eventRects = $$.main.select('.' + CLASS.eventRects)
+                .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null)
+                .classed(CLASS.eventRectsMultiple, isMultipleX)
+                .classed(CLASS.eventRectsSingle, !isMultipleX);
+
+        // clear old rects
+        eventRects.selectAll('.' + CLASS.eventRect).remove();
+
+        // open as public variable
+        $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+
+        if (isMultipleX) {
+            eventRectUpdate = $$.eventRect.data([0]);
+            // enter : only one rect will be added
+            $$.generateEventRectsForMultipleXs(eventRectUpdate.enter());
+            // update
+            $$.updateEventRect(eventRectUpdate);
+            // exit : not needed because always only one rect exists
+        }
+        else {
+            // Set data and update $$.eventRect
+            maxDataCountTarget = $$.getMaxDataCountTarget($$.data.targets);
+            eventRects.datum(maxDataCountTarget ? maxDataCountTarget.values : []);
+            $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+            eventRectUpdate = $$.eventRect.data(function (d) { return d; });
+            // enter
+            $$.generateEventRectsForSingleX(eventRectUpdate.enter());
+            // update
+            $$.updateEventRect(eventRectUpdate);
+            // exit
+            eventRectUpdate.exit().remove();
+        }
+    };
+    c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
+        var $$ = this, config = $$.config,
+            x, y, w, h, rectW, rectX;
+
+        // set update selection if null
+        eventRectUpdate = eventRectUpdate || $$.eventRect.data(function (d) { return d; });
+
+        if ($$.isMultipleX()) {
+            // TODO: rotated not supported yet
+            x = 0;
+            y = 0;
+            w = $$.width;
+            h = $$.height;
+        }
+        else {
+            if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
+
+                // update index for x that is used by prevX and nextX
+                $$.updateXs();
+
+                rectW = function (d) {
+                    var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
+
+                    // if there this is a single data point make the eventRect full width (or height)
+                    if (prevX === null && nextX === null) {
+                        return config.axis_rotated ? $$.height : $$.width;
+                    }
+
+                    if (prevX === null) { prevX = $$.x.domain()[0]; }
+                    if (nextX === null) { nextX = $$.x.domain()[1]; }
+
+                    return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
+                };
+                rectX = function (d) {
+                    var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
+                        thisX = $$.data.xs[d.id][d.index];
+
+                    // if there this is a single data point position the eventRect at 0
+                    if (prevX === null && nextX === null) {
+                        return 0;
+                    }
+
+                    if (prevX === null) { prevX = $$.x.domain()[0]; }
+
+                    return ($$.x(thisX) + $$.x(prevX)) / 2;
+                };
+            } else {
+                rectW = $$.getEventRectWidth();
+                rectX = function (d) {
+                    return $$.x(d.x) - (rectW / 2);
+                };
+            }
+            x = config.axis_rotated ? 0 : rectX;
+            y = config.axis_rotated ? rectX : 0;
+            w = config.axis_rotated ? $$.width : rectW;
+            h = config.axis_rotated ? rectW : $$.height;
+        }
+
+<<<<<<< HEAD
+        function getPathBox(path) {
+            var box = path.getBoundingClientRect();
+
+            if (path.pathSegList.length >= 2) {
+                var items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
+                    minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
+                return {x: minX, y: minY, width: box.width, height: box.height};
+            } else {
+                //Some sort of fallback
+                return {x: 0, y: 0, width: 0, height: 0};
+            }
+        }
+=======
+        eventRectUpdate
+            .attr('class', $$.classEvent.bind($$))
+            .attr("x", x)
+            .attr("y", y)
+            .attr("width", w)
+            .attr("height", h);
+    };
+    c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        eventRectEnter.append("rect")
+            .attr("class", $$.classEvent.bind($$))
+            .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
+            .on('mouseover', function (d) {
+                var index = d.index, selectedData, newData;
+
+                if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+                if ($$.hasArcType()) { return; }
+
+                selectedData = $$.data.targets.map(function (t) {
+                    return $$.addName($$.getValueOnIndex(t.values, index));
+                });
+>>>>>>> upstream/master
+
+                // Sort selectedData as names order
+                newData = [];
+                Object.keys(config.data_names).forEach(function (id) {
+                    for (var j = 0; j < selectedData.length; j++) {
+                        if (selectedData[j] && selectedData[j].id === id) {
+                            newData.push(selectedData[j]);
+                            selectedData.shift(j);
+                            break;
+                        }
+                    }
+                });
+                selectedData = newData.concat(selectedData); // Add remained
+
+                // Expand shapes for selection
+                if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
+                $$.expandBars(index, null, true);
+
+                // Call event handler
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    config.data_onmouseover.call($$.api, d);
+                });
+            })
+            .on('mouseout', function (d) {
+                var index = d.index;
+                if ($$.hasArcType()) { return; }
+                $$.hideXGridFocus();
+                $$.hideTooltip();
+                // Undo expanded shapes
+                $$.unexpandCircles();
+                $$.unexpandBars();
+                // Call event handler
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    config.data_onmouseout.call($$.api, d);
+                });
+            })
+            .on('mousemove', function (d) {
+                var selectedData, index = d.index,
+                    eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
+
+                if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+                if ($$.hasArcType()) { return; }
+
+                if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                    index -= 1;
+                }
+
+                // Show tooltip
+                selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
+                    return $$.addName($$.getValueOnIndex(t.values, index));
+                });
+
+                if (config.tooltip_grouped) {
+                    $$.showTooltip(selectedData, d3.mouse(this));
+                    $$.showXGridFocus(selectedData);
+                }
+
+                if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) {
+                    return;
+                }
+
+                $$.main.selectAll('.' + CLASS.shape + '-' + index)
+                    .each(function () {
+                        d3.select(this).classed(CLASS.EXPANDED, true);
+                        if (config.data_selection_enabled) {
+                            eventRect.style('cursor', config.data_selection_grouped ? 'pointer' : null);
+                        }
+                        if (!config.tooltip_grouped) {
+                            $$.hideXGridFocus();
+                            $$.hideTooltip();
+                            if (!config.data_selection_grouped) {
+                                $$.unexpandCircles(index);
+                                $$.unexpandBars(index);
+                            }
+                        }
+                    })
+                    .filter(function (d) {
+                        return $$.isWithinShape(this, d);
+                    })
+                    .each(function (d) {
+                        if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
+                            eventRect.style('cursor', 'pointer');
+                        }
+                        if (!config.tooltip_grouped) {
+                            $$.showTooltip([d], d3.mouse(this));
+                            $$.showXGridFocus([d]);
+                            if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
+                            $$.expandBars(index, d.id, true);
+                        }
+                    });
+            })
+            .on('click', function (d) {
+                var index = d.index;
+                if ($$.hasArcType() || !$$.toggleShape) { return; }
+                if ($$.cancelClick) {
+                    $$.cancelClick = false;
+                    return;
+                }
+                if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                    index -= 1;
+                }
+                $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                    if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
+                        $$.toggleShape(this, d, index);
+                        $$.config.data_onclick.call($$.api, d, this);
+                    }
+                });
+            })
+            .call(
+                d3.behavior.drag().origin(Object)
+                    .on('drag', function () { $$.drag(d3.mouse(this)); })
+                    .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                    .on('dragend', function () { $$.dragend(); })
+            );
+    };
+
+    c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+
+        function mouseout() {
+            $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
+            $$.hideXGridFocus();
+            $$.hideTooltip();
+            $$.unexpandCircles();
+            $$.unexpandBars();
+        }
+
+        eventRectEnter.append('rect')
+            .attr('x', 0)
+            .attr('y', 0)
+            .attr('width', $$.width)
+            .attr('height', $$.height)
+            .attr('class', CLASS.eventRect)
+            .on('mouseout', function () {
+                if ($$.hasArcType()) { return; }
+                mouseout();
+            })
+            .on('mousemove', function () {
+                var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+                var mouse, closest, sameXData, selectedData;
+
+                if ($$.dragging) { return; } // do nothing when dragging
+                if ($$.hasArcType(targetsToShow)) { return; }
+
+                mouse = d3.mouse(this);
+                closest = $$.findClosestFromTargets(targetsToShow, mouse);
+
+                if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
+                    config.data_onmouseout.call($$.api, $$.mouseover);
+                    $$.mouseover = undefined;
+                }
+
+                if (! closest) {
+                    mouseout();
+                    return;
+                }
+
+                if ($$.isScatterType(closest) || !config.tooltip_grouped) {
+                    sameXData = [closest];
+                } else {
+                    sameXData = $$.filterByX(targetsToShow, closest.x);
+                }
+
+                // show tooltip when cursor is close to some point
+                selectedData = sameXData.map(function (d) {
+                    return $$.addName(d);
+                });
+                $$.showTooltip(selectedData, mouse);
+
+                // expand points
+                if (config.point_focus_expand_enabled) {
+                    $$.expandCircles(closest.index, closest.id, true);
+                }
+                $$.expandBars(closest.index, closest.id, true);
+
+                // Show xgrid focus line
+                $$.showXGridFocus(selectedData);
+
+                // Show cursor as pointer if point is close to mouse position
+                if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                    $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
+                    if (!$$.mouseover) {
+                        config.data_onmouseover.call($$.api, closest);
+                        $$.mouseover = closest;
+                    }
+                }
+            })
+            .on('click', function () {
+                var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+                var mouse, closest;
+
+                if ($$.hasArcType(targetsToShow)) { return; }
+
+                mouse = d3.mouse(this);
+                closest = $$.findClosestFromTargets(targetsToShow, mouse);
+
+                if (! closest) { return; }
+
+                // select if selection enabled
+                if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                    $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
+                        if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
+                            $$.toggleShape(this, closest, closest.index);
+                            $$.config.data_onclick.call($$.api, closest, this);
+                        }
+                    });
+                }
+            })
+            .call(
+                d3.behavior.drag().origin(Object)
+                    .on('drag', function () { $$.drag(d3.mouse(this)); })
+                    .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                    .on('dragend', function () { $$.dragend(); })
+            );
+    };
+    c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
+        var $$ = this,
+            selector = '.' + CLASS.eventRect + (!$$.isMultipleX() ? '-' + index : ''),
+            eventRect = $$.main.select(selector).node(),
+            box = eventRect.getBoundingClientRect(),
+            x = box.left + (mouse ? mouse[0] : 0),
+            y = box.top + (mouse ? mouse[1] : 0),
+            event = document.createEvent("MouseEvents");
+
+        event.initMouseEvent(type, true, true, window, 0, x, y, x, y,
+                             false, false, false, false, 0, null);
+        eventRect.dispatchEvent(event);
+    };
+
+    c3_chart_internal_fn.getCurrentWidth = function () {
+        var $$ = this, config = $$.config;
+        return config.size_width ? config.size_width : $$.getParentWidth();
+    };
+    c3_chart_internal_fn.getCurrentHeight = function () {
+        var $$ = this, config = $$.config,
+            h = config.size_height ? config.size_height : $$.getParentHeight();
+        return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
+    };
+    c3_chart_internal_fn.getCurrentPaddingTop = function () {
+        var config = this.config;
+        return isValue(config.padding_top) ? config.padding_top : 0;
+    };
+    c3_chart_internal_fn.getCurrentPaddingBottom = function () {
+        var config = this.config;
+        return isValue(config.padding_bottom) ? config.padding_bottom : 0;
+    };
+    c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
+        var $$ = this, config = $$.config;
+        if (isValue(config.padding_left)) {
+            return config.padding_left;
+        } else if (config.axis_rotated) {
+            return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
+        } else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
+            return $$.getYAxisLabelPosition().isOuter ? 30 : 1;
+        } else {
+            return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
+        }
+    };
+    c3_chart_internal_fn.getCurrentPaddingRight = function () {
+        var $$ = this, config = $$.config,
+            defaultPadding = 10, legendWidthOnRight = $$.isLegendRight ? $$.getLegendWidth() + 20 : 0;
+        if (isValue(config.padding_right)) {
+            return config.padding_right + 1; // 1 is needed not to hide tick line
+        } else if (config.axis_rotated) {
+            return defaultPadding + legendWidthOnRight;
+        } else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
+            return defaultPadding + legendWidthOnRight + ($$.getY2AxisLabelPosition().isOuter ? 20 : 0);
+        } else {
+            return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
+        }
+    };
+
+    c3_chart_internal_fn.getParentRectValue = function (key) {
+        var parent = this.selectChart.node(), v;
+        while (parent && parent.tagName !== 'BODY') {
+            v = parent.getBoundingClientRect()[key];
+            if (v) {
+                break;
+            }
+            parent = parent.parentNode;
+        }
+        return v;
+    };
+    c3_chart_internal_fn.getParentWidth = function () {
+        return this.getParentRectValue('width');
+    };
+    c3_chart_internal_fn.getParentHeight = function () {
+        var h = this.selectChart.style('height');
+        return h.indexOf('px') > 0 ? +h.replace('px', '') : 0;
+    };
+
+
+    c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
+        var $$ = this, config = $$.config,
+            leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
+            leftAxis = $$.main.select('.' + leftAxisClass).node(),
+            svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
+            chartRect = $$.selectChart.node().getBoundingClientRect(),
+            hasArc = $$.hasArcType(),
+            svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
+        return svgLeft > 0 ? svgLeft : 0;
+    };
+
+
+    c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
+        var $$ = this, position = $$.getAxisLabelPositionById(id);
+        return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
+    };
+    c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
+        var $$ = this, config = $$.config, h = 30;
+        if (axisId === 'x' && !config.axis_x_show) { return 8; }
+        if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
+        if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
+        if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
+        // Calculate x axis height when tick rotated
+        if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
+            h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
+        }
+        return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
+    };
+
+    c3_chart_internal_fn.getEventRectWidth = function () {
+        var $$ = this;
+        var target = $$.getMaxDataCountTarget($$.data.targets),
+            firstData, lastData, base, maxDataCount, ratio, w;
+        if (!target) {
+            return 0;
+        }
+        firstData = target.values[0], lastData = target.values[target.values.length - 1];
+        base = $$.x(lastData.x) - $$.x(firstData.x);
+        if (base === 0) {
+            return $$.config.axis_rotated ? $$.height : $$.width;
+        }
+        maxDataCount = $$.getMaxDataCount();
+        ratio = ($$.hasType('bar') ? (maxDataCount - ($$.isCategorized() ? 0.25 : 1)) / maxDataCount : 1);
+        w = maxDataCount > 1 ? (base * ratio) / (maxDataCount - 1) : base;
+        return w < 1 ? 1 : w;
+    };
+
+    c3_chart_internal_fn.getShapeIndices = function (typeFilter) {
+        var $$ = this, config = $$.config,
+            indices = {}, i = 0, j, k;
+        $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)).forEach(function (d) {
+            for (j = 0; j < config.data_groups.length; j++) {
+                if (config.data_groups[j].indexOf(d.id) < 0) { continue; }
+                for (k = 0; k < config.data_groups[j].length; k++) {
+                    if (config.data_groups[j][k] in indices) {
+                        indices[d.id] = indices[config.data_groups[j][k]];
+                        break;
+                    }
+                }
+            }
+            if (isUndefined(indices[d.id])) { indices[d.id] = i++; }
+        });
+        indices.__max__ = i - 1;
+        return indices;
+    };
+    c3_chart_internal_fn.getShapeX = function (offset, targetsNum, indices, isSub) {
+        var $$ = this, scale = isSub ? $$.subX : $$.x;
+        return function (d) {
+            var index = d.id in indices ? indices[d.id] : 0;
+            return d.x || d.x === 0 ? scale(d.x) - offset * (targetsNum / 2 - index) : 0;
+        };
+    };
+    c3_chart_internal_fn.getShapeY = function (isSub) {
+        var $$ = this;
+        return function (d) {
+            var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id);
+            return scale(d.value);
+        };
+    };
+    c3_chart_internal_fn.getShapeOffset = function (typeFilter, indices, isSub) {
+        var $$ = this,
+            targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))),
+            targetIds = targets.map(function (t) { return t.id; });
+        return function (d, i) {
+            var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
+                y0 = scale(0), offset = y0;
+            targets.forEach(function (t) {
+                var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
+                if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
+                if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
+                    if (values[i].value * d.value >= 0) {
+                        offset += scale(values[i].value) - y0;
+                    }
+                }
+            });
+            return offset;
+        };
+    };
+    c3_chart_internal_fn.isWithinShape = function (that, d) {
+        var $$ = this,
+            shape = $$.d3.select(that), isWithin;
+        if (!$$.isTargetToShow(d.id)) {
+            isWithin = false;
+        }
+        else if (that.nodeName === 'circle') {
+            isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
+        }
+        else if (that.nodeName === 'path') {
+            isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true;
+        }
+        return isWithin;
+    };
+
+
+    c3_chart_internal_fn.getInterpolate = function (d) {
+        var $$ = this;
+        return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? $$.config.line_step_type : "linear";
+    };
+
+    c3_chart_internal_fn.initLine = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartLines);
+    };
+    c3_chart_internal_fn.updateTargetsForLine = function (targets) {
+        var $$ = this, config = $$.config,
+            mainLineUpdate, mainLineEnter,
+            classChartLine = $$.classChartLine.bind($$),
+            classLines = $$.classLines.bind($$),
+            classAreas = $$.classAreas.bind($$),
+            classCircles = $$.classCircles.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainLineUpdate = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+            .data(targets)
+            .attr('class', function (d) { return classChartLine(d) + classFocus(d); });
+        mainLineEnter = mainLineUpdate.enter().append('g')
+            .attr('class', classChartLine)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        // Lines for each data
+        mainLineEnter.append('g')
+            .attr("class", classLines);
+        // Areas
+        mainLineEnter.append('g')
+            .attr('class', classAreas);
+        // Circles for each data point on lines
+        mainLineEnter.append('g')
+            .attr("class", function (d) { return $$.generateClass(CLASS.selectedCircles, d.id); });
+        mainLineEnter.append('g')
+            .attr("class", classCircles)
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
+        // Update date for selected circles
+        targets.forEach(function (t) {
+            $$.main.selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d) {
+                d.value = t.values[d.index].value;
+            });
+        });
+        // MEMO: can not keep same color...
+        //mainLineUpdate.exit().remove();
+    };
+    c3_chart_internal_fn.redrawLine = function (durationForExit) {
+        var $$ = this;
+        $$.mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+            .data($$.lineData.bind($$));
+        $$.mainLine.enter().append('path')
+            .attr('class', $$.classLine.bind($$))
+            .style("stroke", $$.color);
+        $$.mainLine
+            .style("opacity", $$.initialOpacity.bind($$))
+            .style('shape-rendering', function (d) { return $$.isStepType(d) ? 'crispEdges' : ''; })
+            .attr('transform', null);
+        $$.mainLine.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForLine = function (transitions, drawLine) {
+        var $$ = this;
+        transitions.push($$.mainLine.transition()
+                         .attr("d", drawLine)
+                         .style("stroke", $$.color)
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
+        var $$ = this, config = $$.config,
+            line = $$.d3.svg.line(),
+            getPoints = $$.generateGetLinePoints(lineIndices, isSub),
+            yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+            xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+            yValue = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
+            };
+
+        line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
+        if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); }
+        return function (d) {
+            var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+                x = isSub ? $$.x : $$.subX, y = yScaleGetter.call($$, d.id), x0 = 0, y0 = 0, path;
+            if ($$.isLineType(d)) {
+                if (config.data_regions[d.id]) {
+                    path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
+                } else {
+                    if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+                    path = line.interpolate($$.getInterpolate(d))(values);
+                }
+            } else {
+                if (values[0]) {
+                    x0 = x(values[0].x);
+                    y0 = y(values[0].value);
+                }
+                path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+            }
+            return path ? path : "M 0 0";
+        };
+    };
+    c3_chart_internal_fn.generateGetLinePoints = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
+        var $$ = this, config = $$.config,
+            lineTargetsNum = lineIndices.__max__ + 1,
+            x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
+            y = $$.getShapeY(!!isSub),
+            lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = lineOffset(d, i) || y0, // offset is for stacked area chart
+                posX = x(d), posY = y(d);
+            // fix posY not to overflow opposite quadrant
+            if (config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 1 point that marks the line position
+            return [
+                [posX, posY - (y0 - offset)],
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, posY - (y0 - offset)]  // needed for compatibility
+            ];
+        };
+    };
+
+
+    c3_chart_internal_fn.lineWithRegions = function (d, x, y, _regions) {
+        var $$ = this, config = $$.config,
+            prev = -1, i, j,
+            s = "M", sWithRegion,
+            xp, yp, dx, dy, dd, diff, diffx2,
+            xValue, yValue,
+            regions = [];
+
+        function isWithinRegions(x, regions) {
+            var i;
+            for (i = 0; i < regions.length; i++) {
+                if (regions[i].start < x && x <= regions[i].end) { return true; }
+            }
+            return false;
+        }
+
+        // Check start/end of regions
+        if (isDefined(_regions)) {
+            for (i = 0; i < _regions.length; i++) {
+                regions[i] = {};
+                if (isUndefined(_regions[i].start)) {
+                    regions[i].start = d[0].x;
+                } else {
+                    regions[i].start = $$.isTimeSeries() ? $$.parseDate(_regions[i].start) : _regions[i].start;
+                }
+                if (isUndefined(_regions[i].end)) {
+                    regions[i].end = d[d.length - 1].x;
+                } else {
+                    regions[i].end = $$.isTimeSeries() ? $$.parseDate(_regions[i].end) : _regions[i].end;
+                }
+            }
+        }
+
+        // Set scales
+        xValue = config.axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); };
+        yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
+
+        // Define svg generator function for region
+        if ($$.isTimeSeries()) {
+            sWithRegion = function (d0, d1, j, diff) {
+                var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
+                    xv0 = new Date(x0 + x_diff * j),
+                    xv1 = new Date(x0 + x_diff * (j + diff));
+                return "M" + x(xv0) + " " + y(yp(j)) + " " + x(xv1) + " " + y(yp(j + diff));
+            };
+        } else {
+            sWithRegion = function (d0, d1, j, diff) {
+                return "M" + x(xp(j), true) + " " + y(yp(j)) + " " + x(xp(j + diff), true) + " " + y(yp(j + diff));
+            };
+        }
+
+        // Generate
+        for (i = 0; i < d.length; i++) {
+
+            // Draw as normal
+            if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) {
+                s += " " + xValue(d[i]) + " " + yValue(d[i]);
+            }
+            // Draw with region // TODO: Fix for horizotal charts
+            else {
+                xp = $$.getScale(d[i - 1].x, d[i].x, $$.isTimeSeries());
+                yp = $$.getScale(d[i - 1].value, d[i].value);
+
+                dx = x(d[i].x) - x(d[i - 1].x);
+                dy = y(d[i].value) - y(d[i - 1].value);
+                dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
+                diff = 2 / dd;
+                diffx2 = diff * 2;
+
+                for (j = diff; j <= 1; j += diffx2) {
+                    s += sWithRegion(d[i - 1], d[i], j, diff);
+                }
+            }
+            prev = d[i].x;
+        }
+
+        return s;
+    };
+
+
+    c3_chart_internal_fn.redrawArea = function (durationForExit) {
+        var $$ = this, d3 = $$.d3;
+        $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+            .data($$.lineData.bind($$));
+        $$.mainArea.enter().append('path')
+            .attr("class", $$.classArea.bind($$))
+            .style("fill", $$.color)
+            .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+        $$.mainArea
+            .style("opacity", $$.orgAreaOpacity);
+        $$.mainArea.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForArea = function (transitions, drawArea) {
+        var $$ = this;
+        transitions.push($$.mainArea.transition()
+                         .attr("d", drawArea)
+                         .style("fill", $$.color)
+                         .style("opacity", $$.orgAreaOpacity));
+    };
+    c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
+        var $$ = this, config = $$.config, area = $$.d3.svg.area(),
+            getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
+            yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+            xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+            value0 = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
+            },
+            value1 = function (d, i) {
+                return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
+            };
+
+        area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
+        if (!config.line_connectNull) {
+            area = area.defined(function (d) { return d.value !== null; });
+        }
+
+        return function (d) {
+            var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+                x0 = 0, y0 = 0, path;
+            if ($$.isAreaType(d)) {
+                if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+                path = area.interpolate($$.getInterpolate(d))(values);
+            } else {
+                if (values[0]) {
+                    x0 = $$.x(values[0].x);
+                    y0 = $$.getYScale(d.id)(values[0].value);
+                }
+                path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+            }
+            return path ? path : "M 0 0";
+        };
+    };
+
+    c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
+        var $$ = this, config = $$.config,
+            areaTargetsNum = areaIndices.__max__ + 1,
+            x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
+            y = $$.getShapeY(!!isSub),
+            areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = areaOffset(d, i) || y0, // offset is for stacked area chart
+                posX = x(d), posY = y(d);
+            // fix posY not to overflow opposite quadrant
+            if (config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 1 point that marks the area position
+            return [
+                [posX, offset],
+                [posX, posY - (y0 - offset)],
+                [posX, posY - (y0 - offset)], // needed for compatibility
+                [posX, offset] // needed for compatibility
+            ];
+        };
+    };
+
+
+    c3_chart_internal_fn.redrawCircle = function () {
+        var $$ = this;
+        $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
+            .data($$.lineOrScatterData.bind($$));
+        $$.mainCircle.enter().append("circle")
+            .attr("class", $$.classCircle.bind($$))
+            .attr("r", $$.pointR.bind($$))
+            .style("fill", $$.color);
+        $$.mainCircle
+            .style("opacity", $$.initialOpacityForCircle.bind($$));
+        $$.mainCircle.exit().remove();
+    };
+    c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
+        var $$ = this;
+        transitions.push($$.mainCircle.transition()
+                         .style('opacity', $$.opacityForCircle.bind($$))
+                         .style("fill", $$.color)
+                         .attr("cx", cx)
+                         .attr("cy", cy));
+        transitions.push($$.main.selectAll('.' + CLASS.selectedCircle).transition()
+                         .attr("cx", cx)
+                         .attr("cy", cy));
+    };
+    c3_chart_internal_fn.circleX = function (d) {
+        return d.x || d.x === 0 ? this.x(d.x) : null;
+    };
+    c3_chart_internal_fn.updateCircleY = function () {
+        var $$ = this, lineIndices, getPoints;
+        if ($$.config.data_groups.length > 0) {
+            lineIndices = $$.getShapeIndices($$.isLineType),
+            getPoints = $$.generateGetLinePoints(lineIndices);
+            $$.circleY = function (d, i) {
+                return getPoints(d, i)[0][1];
+            };
+        } else {
+            $$.circleY = function (d) {
+                return $$.getYScale(d.id)(d.value);
+            };
+        }
+    };
+    c3_chart_internal_fn.getCircles = function (i, id) {
+        var $$ = this;
+        return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
+    };
+    c3_chart_internal_fn.expandCircles = function (i, id, reset) {
+        var $$ = this,
+            r = $$.pointExpandedR.bind($$);
+        if (reset) { $$.unexpandCircles(); }
+        $$.getCircles(i, id)
+            .classed(CLASS.EXPANDED, true)
+            .attr('r', r);
+    };
+    c3_chart_internal_fn.unexpandCircles = function (i) {
+        var $$ = this,
+            r = $$.pointR.bind($$);
+        $$.getCircles(i)
+            .filter(function () { return $$.d3.select(this).classed(CLASS.EXPANDED); })
+            .classed(CLASS.EXPANDED, false)
+            .attr('r', r);
+    };
+    c3_chart_internal_fn.pointR = function (d) {
+        var $$ = this, config = $$.config;
+        return $$.isStepType(d) ? 0 : (isFunction(config.point_r) ? config.point_r(d) : config.point_r);
+    };
+    c3_chart_internal_fn.pointExpandedR = function (d) {
+        var $$ = this, config = $$.config;
+        return config.point_focus_expand_enabled ? (config.point_focus_expand_r ? config.point_focus_expand_r : $$.pointR(d) * 1.75) : $$.pointR(d);
+    };
+    c3_chart_internal_fn.pointSelectR = function (d) {
+        var $$ = this, config = $$.config;
+        return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
+    };
+    c3_chart_internal_fn.isWithinCircle = function (that, r) {
+        var d3 = this.d3,
+            mouse = d3.mouse(that), d3_this = d3.select(that),
+            cx = +d3_this.attr("cx"), cy = +d3_this.attr("cy");
+        return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
+    };
+    c3_chart_internal_fn.isWithinStep = function (that, y) {
+        return Math.abs(y - this.d3.mouse(that)[1]) < 30;
+    };
+
+    c3_chart_internal_fn.initBar = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartBars);
+    };
+    c3_chart_internal_fn.updateTargetsForBar = function (targets) {
+        var $$ = this, config = $$.config,
+            mainBarUpdate, mainBarEnter,
+            classChartBar = $$.classChartBar.bind($$),
+            classBars = $$.classBars.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainBarUpdate = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+            .data(targets)
+            .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
+        mainBarEnter = mainBarUpdate.enter().append('g')
+            .attr('class', classChartBar)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        // Bars for each data
+        mainBarEnter.append('g')
+            .attr("class", classBars)
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
+
+    };
+    c3_chart_internal_fn.redrawBar = function (durationForExit) {
+        var $$ = this,
+            barData = $$.barData.bind($$),
+            classBar = $$.classBar.bind($$),
+            initialOpacity = $$.initialOpacity.bind($$),
+            color = function (d) { return $$.color(d.id); };
+        $$.mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+            .data(barData);
+        $$.mainBar.enter().append('path')
+            .attr("class", classBar)
+            .style("stroke", color)
+            .style("fill", color);
+        $$.mainBar
+            .style("opacity", initialOpacity);
+        $$.mainBar.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForBar = function (transitions, drawBar) {
+        var $$ = this;
+        transitions.push($$.mainBar.transition()
+                         .attr('d', drawBar)
+                         .style("fill", $$.color)
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
+        var $$ = this, config = $$.config,
+            w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
+        return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
+    };
+    c3_chart_internal_fn.getBars = function (i, id) {
+        var $$ = this;
+        return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
+    };
+    c3_chart_internal_fn.expandBars = function (i, id, reset) {
+        var $$ = this;
+        if (reset) { $$.unexpandBars(); }
+        $$.getBars(i, id).classed(CLASS.EXPANDED, true);
+    };
+    c3_chart_internal_fn.unexpandBars = function (i) {
+        var $$ = this;
+        $$.getBars(i).classed(CLASS.EXPANDED, false);
+    };
+    c3_chart_internal_fn.generateDrawBar = function (barIndices, isSub) {
+        var $$ = this, config = $$.config,
+            getPoints = $$.generateGetBarPoints(barIndices, isSub);
+        return function (d, i) {
+            // 4 points that make a bar
+            var points = getPoints(d, i);
+
+            // switch points if axis is rotated, not applicable for sub chart
+            var indexX = config.axis_rotated ? 1 : 0;
+            var indexY = config.axis_rotated ? 0 : 1;
+
+            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';
+
+            return path;
+        };
+    };
+    c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
+        var $$ = this,
+            axis = isSub ? $$.subXAxis : $$.xAxis,
+            barTargetsNum = barIndices.__max__ + 1,
+            barW = $$.getBarW(axis, barTargetsNum),
+            barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
+            barY = $$.getShapeY(!!isSub),
+            barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
+            yScale = isSub ? $$.getSubYScale : $$.getYScale;
+        return function (d, i) {
+            var y0 = yScale.call($$, d.id)(0),
+                offset = barOffset(d, i) || y0, // offset is for stacked bar chart
+                posX = barX(d), posY = barY(d);
+            // fix posY not to overflow opposite quadrant
+            if ($$.config.axis_rotated) {
+                if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+            }
+            // 4 points that make a bar
+            return [
+                [posX, offset],
+                [posX, posY - (y0 - offset)],
+                [posX + barW, posY - (y0 - offset)],
+                [posX + barW, offset]
+            ];
+        };
+    };
+    c3_chart_internal_fn.isWithinBar = function (that) {
+        var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
+            seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
+            x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
+            w = box.width, h = box.height, offset = 2,
+            sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
+        return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
+    };
+
+    c3_chart_internal_fn.initText = function () {
+        var $$ = this;
+        $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartTexts);
+        $$.mainText = $$.d3.selectAll([]);
+    };
+    c3_chart_internal_fn.updateTargetsForText = function (targets) {
+        var $$ = this, mainTextUpdate, mainTextEnter,
+            classChartText = $$.classChartText.bind($$),
+            classTexts = $$.classTexts.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainTextUpdate = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
+            .data(targets)
+            .attr('class', function (d) { return classChartText(d) + classFocus(d); });
+        mainTextEnter = mainTextUpdate.enter().append('g')
+            .attr('class', classChartText)
+            .style('opacity', 0)
+            .style("pointer-events", "none");
+        mainTextEnter.append('g')
+            .attr('class', classTexts);
+    };
+    c3_chart_internal_fn.redrawText = function (durationForExit) {
+        var $$ = this, config = $$.config,
+            barOrLineData = $$.barOrLineData.bind($$),
+            classText = $$.classText.bind($$);
+        $$.mainText = $$.main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text)
+            .data(barOrLineData);
+        $$.mainText.enter().append('text')
+            .attr("class", classText)
+            .attr('text-anchor', function (d) { return config.axis_rotated ? (d.value < 0 ? 'end' : 'start') : 'middle'; })
+            .style("stroke", 'none')
+            .style("fill", function (d) { return $$.color(d); })
+            .style("fill-opacity", 0);
+        $$.mainText
+            .text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
+        $$.mainText.exit()
+            .transition().duration(durationForExit)
+            .style('fill-opacity', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForText = function (transitions, xForText, yForText, forFlow) {
+        var $$ = this,
+            opacityForText = forFlow ? 0 : $$.opacityForText.bind($$);
+        transitions.push($$.mainText.transition()
+                         .attr('x', xForText)
+                         .attr('y', yForText)
+                         .style("fill", $$.color)
+                         .style("fill-opacity", opacityForText));
+    };
+    c3_chart_internal_fn.getTextRect = function (text, cls) {
+        var body = this.d3.select('body').classed('c3', true),
+            svg = body.append("svg").style('visibility', 'hidden'), rect;
+        svg.selectAll('.dummy')
+            .data([text])
+          .enter().append('text')
+            .classed(cls ? cls : "", true)
+            .text(text)
+          .each(function () { rect = this.getBoundingClientRect(); });
+        svg.remove();
+        body.classed('c3', false);
+        return rect;
+    };
+    c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
+        var $$ = this,
+            getAreaPoints = $$.generateGetAreaPoints(barIndices, false),
+            getBarPoints = $$.generateGetBarPoints(barIndices, false),
+            getLinePoints = $$.generateGetLinePoints(lineIndices, false),
+            getter = forX ? $$.getXForText : $$.getYForText;
+        return function (d, i) {
+            var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
+            return getter.call($$, getPoints(d, i), d, this);
+        };
+    };
+    c3_chart_internal_fn.getXForText = function (points, d, textElement) {
+        var $$ = this,
+            box = textElement.getBoundingClientRect(), xPos, padding;
+        if ($$.config.axis_rotated) {
+            padding = $$.isBarType(d) ? 4 : 6;
+            xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
+        } else {
+            xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
+        }
+        return d.value !== null ? xPos : xPos > $$.width ? $$.width - box.width : xPos;
+    };
+    c3_chart_internal_fn.getYForText = function (points, d, textElement) {
+        var $$ = this,
+            box = textElement.getBoundingClientRect(), yPos;
+        if ($$.config.axis_rotated) {
+            yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
+        } else {
+            yPos = points[2][1] + (d.value < 0 ? box.height : $$.isBarType(d) ? -3 : -6);
+        }
+        return d.value !== null ? yPos : yPos < box.height ? box.height : yPos;
+    };
+
+    c3_chart_internal_fn.setTargetType = function (targetIds, type) {
+        var $$ = this, config = $$.config;
+        $$.mapToTargetIds(targetIds).forEach(function (id) {
+            $$.withoutFadeIn[id] = (type === config.data_types[id]);
+            config.data_types[id] = type;
+        });
+        if (!targetIds) {
+            config.data_type = type;
+        }
+    };
+    c3_chart_internal_fn.hasType = function (type, targets) {
+        var $$ = this, types = $$.config.data_types, has = false;
+        targets = targets || $$.data.targets;
+        if (targets && targets.length) {
+            targets.forEach(function (target) {
+                var t = types[target.id];
+                if ((t && t.indexOf(type) >= 0) || (!t && type === 'line')) {
+                    has = true;
+                }
+<<<<<<< HEAD
+                tooltip.html(__tooltip_contents(c3.data.targets.map(function (d) {
+                    return addName(d.values[__tooltip_init_x]);
+                }), getXAxisTickFormat(), getYFormat(hasArcType(c3.data.targets)), color));
+                tooltip.style("top", __tooltip_init_position.top)
+                       .style("left", __tooltip_init_position.left)
+                       .style("display", "block");
+            }
+=======
+            });
+        } else if (Object.keys(types).length) {
+            Object.keys(types).forEach(function (id) {
+                if (types[id] === type) { has = true; }
+            });
+        } else {
+            has = $$.config.data_type === type;
+>>>>>>> upstream/master
+        }
+        return has;
+    };
+    c3_chart_internal_fn.hasArcType = function (targets) {
+        return this.hasType('pie', targets) || this.hasType('donut', targets) || this.hasType('gauge', targets);
+    };
+    c3_chart_internal_fn.isLineType = function (d) {
+        var config = this.config, id = isString(d) ? d : d.id;
+        return !config.data_types[id] || ['line', 'spline', 'area', 'area-spline', 'step', 'area-step'].indexOf(config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isStepType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['step', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isSplineType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['spline', 'area-spline'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isAreaType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return ['area', 'area-spline', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+    };
+    c3_chart_internal_fn.isBarType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'bar';
+    };
+    c3_chart_internal_fn.isScatterType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'scatter';
+    };
+    c3_chart_internal_fn.isPieType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'pie';
+    };
+    c3_chart_internal_fn.isGaugeType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'gauge';
+    };
+    c3_chart_internal_fn.isDonutType = function (d) {
+        var id = isString(d) ? d : d.id;
+        return this.config.data_types[id] === 'donut';
+    };
+    c3_chart_internal_fn.isArcType = function (d) {
+        return this.isPieType(d) || this.isDonutType(d) || this.isGaugeType(d);
+    };
+    c3_chart_internal_fn.lineData = function (d) {
+        return this.isLineType(d) ? [d] : [];
+    };
+    c3_chart_internal_fn.arcData = function (d) {
+        return this.isArcType(d.data) ? [d] : [];
+    };
+    /* not used
+     function scatterData(d) {
+     return isScatterType(d) ? d.values : [];
+     }
+     */
+    c3_chart_internal_fn.barData = function (d) {
+        return this.isBarType(d) ? d.values : [];
+    };
+    c3_chart_internal_fn.lineOrScatterData = function (d) {
+        return this.isLineType(d) || this.isScatterType(d) ? d.values : [];
+    };
+    c3_chart_internal_fn.barOrLineData = function (d) {
+        return this.isBarType(d) || this.isLineType(d) ? d.values : [];
+    };
+
+    c3_chart_internal_fn.initGrid = function () {
+        var $$ = this, config = $$.config, d3 = $$.d3;
+        $$.grid = $$.main.append('g')
+            .attr("clip-path", $$.clipPathForGrid)
+            .attr('class', CLASS.grid);
+        if (config.grid_x_show) {
+            $$.grid.append("g").attr("class", CLASS.xgrids);
+        }
+        if (config.grid_y_show) {
+            $$.grid.append('g').attr('class', CLASS.ygrids);
+        }
+        if (config.grid_focus_show) {
+            $$.grid.append('g')
+                .attr("class", CLASS.xgridFocus)
+                .append('line')
+                .attr('class', CLASS.xgridFocus);
+        }
+        $$.xgrid = d3.selectAll([]);
+        if (!config.grid_lines_front) { $$.initGridLines(); }
+    };
+    c3_chart_internal_fn.initGridLines = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.gridLines = $$.main.append('g')
+            .attr("clip-path", $$.clipPathForGrid)
+            .attr('class', CLASS.grid + ' ' + CLASS.gridLines);
+        $$.gridLines.append('g').attr("class", CLASS.xgridLines);
+        $$.gridLines.append('g').attr('class', CLASS.ygridLines);
+        $$.xgridLines = d3.selectAll([]);
+    };
+    c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
+        var $$ = this, config = $$.config, d3 = $$.d3,
+            xgridData = $$.generateGridData(config.grid_x_type, $$.x),
+            tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0;
+
+        $$.xgridAttr = config.axis_rotated ? {
+            'x1': 0,
+            'x2': $$.width,
+            'y1': function (d) { return $$.x(d) - tickOffset; },
+            'y2': function (d) { return $$.x(d) - tickOffset; }
+        } : {
+            'x1': function (d) { return $$.x(d) + tickOffset; },
+            'x2': function (d) { return $$.x(d) + tickOffset; },
+            'y1': 0,
+            'y2': $$.height
+        };
+
+        $$.xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid)
+            .data(xgridData);
+        $$.xgrid.enter().append('line').attr("class", CLASS.xgrid);
+        if (!withoutUpdate) {
+            $$.xgrid.attr($$.xgridAttr)
+                .style("opacity", function () { return +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1') === (config.axis_rotated ? $$.height : 0) ? 0 : 1; });
+        }
+        $$.xgrid.exit().remove();
+    };
+
+    c3_chart_internal_fn.updateYGrid = function () {
+        var $$ = this, config = $$.config,
+            gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
+        $$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
+            .data(gridValues);
+        $$.ygrid.enter().append('line')
+            .attr('class', CLASS.ygrid);
+        $$.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);
+        $$.ygrid.exit().remove();
+        $$.smoothLines($$.ygrid, 'grid');
+    };
+
+
+    c3_chart_internal_fn.redrawGrid = function (duration) {
+        var $$ = this, main = $$.main, config = $$.config,
+            xgridLine, ygridLine, yv;
+
+        // hide if arc type
+        $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+        main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+        if (config.grid_x_show) {
+            $$.updateXGrid();
+        }
+        $$.xgridLines = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine)
+            .data(config.grid_x_lines);
+        // enter
+        xgridLine = $$.xgridLines.enter().append('g')
+            .attr("class", function (d) { return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : ''); });
+        xgridLine.append('line')
+            .style("opacity", 0);
+        xgridLine.append('text')
+            .attr("text-anchor", "end")
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+            .attr('dy', -5)
+            .style("opacity", 0);
+        // udpate
+        // done in d3.transition() of the end of this function
+        // exit
+        $$.xgridLines.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+
+        // Y-Grid
+        if (config.grid_y_show) {
+            $$.updateYGrid();
+        }
+        $$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
+            .data(config.grid_y_lines);
+        // enter
+        ygridLine = $$.ygridLines.enter().append('g')
+            .attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
+        ygridLine.append('line')
+            .style("opacity", 0);
+        ygridLine.append('text')
+            .attr("text-anchor", "end")
+            .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+            .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+            .attr('dy', -5)
+            .style("opacity", 0);
+        // update
+        yv = $$.yv.bind($$);
+        $$.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);
+        $$.ygridLines.select('text')
+          .transition().duration(duration)
+            .attr("x", config.axis_rotated ? 0 : $$.width)
+            .attr("y", yv)
+            .text(function (d) { return d.text; })
+            .style("opacity", 1);
+        // exit
+        $$.ygridLines.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForGrid = function (transitions) {
+        var $$ = this, config = $$.config, xv = $$.xv.bind($$);
+        transitions.push($$.xgridLines.select('line').transition()
+                         .attr("x1", config.axis_rotated ? 0 : xv)
+                         .attr("x2", config.axis_rotated ? $$.width : xv)
+                         .attr("y1", config.axis_rotated ? xv : $$.margin.top)
+                         .attr("y2", config.axis_rotated ? xv : $$.height)
+                         .style("opacity", 1));
+        transitions.push($$.xgridLines.select('text').transition()
+                         .attr("x", config.axis_rotated ? $$.width : 0)
+                         .attr("y", xv)
+                         .text(function (d) { return d.text; })
+                         .style("opacity", 1));
+    };
+    c3_chart_internal_fn.showXGridFocus = function (selectedData) {
+        var $$ = this, config = $$.config,
+            dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
+            focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
+            xx = $$.xx.bind($$);
+        if (! config.tooltip_show) { return; }
+        // Hide when scatter plot exists
+        if ($$.hasType('scatter') || $$.hasArcType()) { return; }
+        focusEl
+            .style("visibility", "visible")
+            .data([dataToShow[0]])
+            .attr(config.axis_rotated ? 'y1' : 'x1', xx)
+            .attr(config.axis_rotated ? 'y2' : 'x2', xx);
+        $$.smoothLines(focusEl, 'grid');
+    };
+    c3_chart_internal_fn.hideXGridFocus = function () {
+        this.main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+    };
+    c3_chart_internal_fn.updateXgridFocus = function () {
+        var $$ = this, config = $$.config;
+        $$.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);
+    };
+    c3_chart_internal_fn.generateGridData = function (type, scale) {
+        var $$ = this,
+            gridData = [], xDomain, firstYear, lastYear, i,
+            tickNum = $$.main.select("." + CLASS.axisX).selectAll('.tick').size();
+        if (type === 'year') {
+            xDomain = $$.getXDomain();
+            firstYear = xDomain[0].getFullYear();
+            lastYear = xDomain[1].getFullYear();
+            for (i = firstYear; i <= lastYear; i++) {
+                gridData.push(new Date(i + '-01-01 00:00:00'));
+            }
+        } else {
+            gridData = scale.ticks(10);
+            if (gridData.length > tickNum) { // use only int
+                gridData = gridData.filter(function (d) { return ("" + d).indexOf('.') < 0; });
+            }
+        }
+        return gridData;
+    };
+    c3_chart_internal_fn.getGridFilterToRemove = function (params) {
+        return params ? function (line) {
+            var found = false;
+            [].concat(params).forEach(function (param) {
+                if ((('value' in param && line.value === param.value) || ('class' in param && line['class'] === param['class']))) {
+                    found = true;
+                }
+            });
+            return found;
+        } : function () { return true; };
+    };
+    c3_chart_internal_fn.removeGridLines = function (params, forX) {
+        var $$ = this, config = $$.config,
+            toRemove = $$.getGridFilterToRemove(params),
+            toShow = function (line) { return !toRemove(line); },
+            classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
+            classLine = forX ? CLASS.xgridLine : CLASS.ygridLine;
+        $$.main.select('.' + classLines).selectAll('.' + classLine).filter(toRemove)
+            .transition().duration(config.transition_duration)
+            .style('opacity', 0).remove();
+        if (forX) {
+            config.grid_x_lines = config.grid_x_lines.filter(toShow);
+        } else {
+            config.grid_y_lines = config.grid_y_lines.filter(toShow);
+        }
+    };
+
+    c3_chart_internal_fn.initTooltip = function () {
+        var $$ = this, config = $$.config, i;
+        $$.tooltip = $$.selectChart
+            .style("position", "relative")
+          .append("div")
+            .attr('class', CLASS.tooltipContainer)
+            .style("position", "absolute")
+            .style("pointer-events", "none")
+            .style("display", "none");
+        // Show tooltip if needed
+        if (config.tooltip_init_show) {
+            if ($$.isTimeSeries() && isString(config.tooltip_init_x)) {
+                config.tooltip_init_x = $$.parseDate(config.tooltip_init_x);
+                for (i = 0; i < $$.data.targets[0].values.length; i++) {
+                    if (($$.data.targets[0].values[i].x - config.tooltip_init_x) === 0) { break; }
+                }
+                config.tooltip_init_x = i;
+            }
+            $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
+                return $$.addName(d.values[config.tooltip_init_x]);
+            }), $$.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
+            $$.tooltip.style("top", config.tooltip_init_position.top)
+                .style("left", config.tooltip_init_position.left)
+                .style("display", "block");
+        }
+    };
+    c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
+        var $$ = this, config = $$.config,
+            titleFormat = config.tooltip_format_title || defaultTitleFormat,
+            nameFormat = config.tooltip_format_name || function (name) { return name; },
+            valueFormat = config.tooltip_format_value || defaultValueFormat,
+            text, i, title, value, name, bgcolor;
+        for (i = 0; i < d.length; i++) {
+            if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
+
+            if (! text) {
+                title = titleFormat ? titleFormat(d[i].x) : d[i].x;
+                text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
+            }
+
+            name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
+            value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
+            bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
+
+            text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
+            text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
+            text += "<td class='value'>" + value + "</td>";
+            text += "</tr>";
+        }
+        return text + "</table>";
+    };
+    c3_chart_internal_fn.showTooltip = function (selectedData, mouse) {
+        var $$ = this, config = $$.config;
+        var tWidth, tHeight, svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
+        var forArc = $$.hasArcType(),
+            dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
+        if (dataToShow.length === 0 || !config.tooltip_show) {
+            return;
+        }
+        $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
+
+        // Get tooltip dimensions
+        tWidth = $$.tooltip.property('offsetWidth');
+        tHeight = $$.tooltip.property('offsetHeight');
+        // Determin tooltip position
+        if (forArc) {
+            tooltipLeft = ($$.width / 2) + mouse[0];
+            tooltipTop = ($$.height / 2) + mouse[1] + 20;
+        } else {
+            svgLeft = $$.getSvgLeft(true);
+            if (config.axis_rotated) {
+                tooltipLeft = svgLeft + mouse[0] + 100;
+                tooltipRight = tooltipLeft + tWidth;
+                chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
+                tooltipTop = $$.x(dataToShow[0].x) + 20;
+            } else {
+                tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
+                tooltipRight = tooltipLeft + tWidth;
+                chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
+                tooltipTop = mouse[1] + 15;
+            }
+
+            if (tooltipRight > chartRight) {
+                tooltipLeft -= tooltipRight - chartRight;
+            }
+            if (tooltipTop + tHeight > $$.currentHeight) {
+                tooltipTop -= tHeight + 30;
+            }
+        }
+        if (tooltipTop < 0) {
+            tooltipTop = 0;
+        }
+        // Set tooltip
+        $$.tooltip
+            .style("top", tooltipTop + "px")
+            .style("left", tooltipLeft + 'px');
+    };
+    c3_chart_internal_fn.hideTooltip = function () {
+        this.tooltip.style("display", "none");
+    };
+
+    c3_chart_internal_fn.initLegend = function () {
+        var $$ = this;
+        $$.legendHasRendered = false;
+        $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
+        if (!$$.config.legend_show) {
+            $$.legend.style('visibility', 'hidden');
+            $$.hiddenLegendIds = $$.mapToIds($$.data.targets);
+            return;
+        }
+        // MEMO: call here to update legend box and tranlate for all
+        // MEMO: translate will be upated by this, so transform not needed in updateLegend()
+        $$.updateLegendWithDefaults();
+    };
+    c3_chart_internal_fn.updateLegendWithDefaults = function () {
+        var $$ = this;
+        $$.updateLegend($$.mapToIds($$.data.targets), {withTransform: false, withTransitionForTransform: false, withTransition: false});
+    };
+    c3_chart_internal_fn.updateSizeForLegend = function (legendHeight, legendWidth) {
+        var $$ = this, config = $$.config, insetLegendPosition = {
+            top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
+            left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
+        };
+
+        $$.margin3 = {
+            top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
+            right: NaN,
+            bottom: 0,
+            left: $$.isLegendRight ? $$.currentWidth - legendWidth : $$.isLegendInset ? insetLegendPosition.left : 0
+        };
+    };
+    c3_chart_internal_fn.transformLegend = function (withTransition) {
+        var $$ = this;
+        (withTransition ? $$.legend.transition() : $$.legend).attr("transform", $$.getTranslate('legend'));
+    };
+    c3_chart_internal_fn.updateLegendStep = function (step) {
+        this.legendStep = step;
+    };
+    c3_chart_internal_fn.updateLegendItemWidth = function (w) {
+        this.legendItemWidth = w;
+    };
+    c3_chart_internal_fn.updateLegendItemHeight = function (h) {
+        this.legendItemHeight = h;
+    };
+    c3_chart_internal_fn.getLegendWidth = function () {
+        var $$ = this;
+        return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
+    };
+    c3_chart_internal_fn.getLegendHeight = function () {
+        var $$ = this, h = 0;
+        if ($$.config.legend_show) {
+            if ($$.isLegendRight) {
+                h = $$.currentHeight;
+            } else {
+                h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
+            }
+        }
+        return h;
+    };
+    c3_chart_internal_fn.opacityForLegend = function (legendItem) {
+        return legendItem.classed(CLASS.legendItemHidden) ? null : 1;
+    };
+    c3_chart_internal_fn.opacityForUnfocusedLegend = function (legendItem) {
+        return legendItem.classed(CLASS.legendItemHidden) ? null : 0.3;
+    };
+    c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
+        var $$ = this;
+        targetIds = $$.mapToTargetIds(targetIds);
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .filter(function (id) { return targetIds.indexOf(id) >= 0; })
+            .classed(CLASS.legendItemFocused, focus)
+          .transition().duration(100)
+            .style('opacity', function () {
+                var opacity = focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
+                return opacity.call($$, $$.d3.select(this));
+            });
+    };
+    c3_chart_internal_fn.revertLegend = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .classed(CLASS.legendItemFocused, false)
+            .transition().duration(100)
+            .style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
+    };
+    c3_chart_internal_fn.showLegend = function (targetIds) {
+        var $$ = this, config = $$.config;
+        if (!config.legend_show) {
+            config.legend_show = true;
+            $$.legend.style('visibility', 'visible');
+            if (!$$.legendHasRendered) {
+                $$.updateLegendWithDefaults();
+            }
+        }
+        $$.removeHiddenLegendIds(targetIds);
+        $$.legend.selectAll($$.selectorLegends(targetIds))
+            .style('visibility', 'visible')
+            .transition()
+            .style('opacity', function () { return $$.opacityForLegend($$.d3.select(this)); });
+    };
+    c3_chart_internal_fn.hideLegend = function (targetIds) {
+        var $$ = this, config = $$.config;
+        if (config.legend_show && isEmpty(targetIds)) {
+            config.legend_show = false;
+            $$.legend.style('visibility', 'hidden');
+        }
+        $$.addHiddenLegendIds(targetIds);
+        $$.legend.selectAll($$.selectorLegends(targetIds))
+            .style('opacity', 0)
+            .style('visibility', 'hidden');
+    };
+    var legendItemTextBox = {};
+    c3_chart_internal_fn.clearLegendItemTextBoxCache = function () {
+        legendItemTextBox = {};
+    };
+    c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
+        var $$ = this, config = $$.config;
+        var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
+        var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
+        var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
+        var withTransition, withTransitionForTransform;
+        var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
+        var texts, rects, tiles, background;
+
+        options = options || {};
+        withTransition = getOption(options, "withTransition", true);
+        withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
+
+        function getTextBox(textElement, id) {
+            if (!legendItemTextBox[id]) {
+                legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
+            }
+            return legendItemTextBox[id];
+        }
+
+        function updatePositions(textElement, id, index) {
+            var reset = index === 0, isLast = index === targetIds.length - 1,
+                box = getTextBox(textElement, id),
+                itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
+                itemHeight = box.height + paddingTop,
+                itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
+                areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
+                margin, maxLength;
+
+            // MEMO: care about condifion of step, totalLength
+            function updateValues(id, withoutStep) {
+                if (!withoutStep) {
+                    margin = (areaLength - totalLength - itemLength) / 2;
+                    if (margin < posMin) {
+                        margin = (areaLength - itemLength) / 2;
+                        totalLength = 0;
+                        step++;
+                    }
+                }
+                steps[id] = step;
+                margins[step] = $$.isLegendInset ? 10 : margin;
+                offsets[id] = totalLength;
+                totalLength += itemLength;
+            }
+
+            if (reset) {
+                totalLength = 0;
+                step = 0;
+                maxWidth = 0;
+                maxHeight = 0;
+            }
+
+            if (config.legend_show && !$$.isLegendToShow(id)) {
+                widths[id] = heights[id] = steps[id] = offsets[id] = 0;
+                return;
+            }
+
+            widths[id] = itemWidth;
+            heights[id] = itemHeight;
+
+            if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; }
+            if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; }
+            maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth;
+
+            if (config.legend_equally) {
+                Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; });
+                Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; });
+                margin = (areaLength - maxLength * targetIds.length) / 2;
+                if (margin < posMin) {
+                    totalLength = 0;
+                    step = 0;
+                    targetIds.forEach(function (id) { updateValues(id); });
+                }
+                else {
+                    updateValues(id, true);
+                }
+            } else {
+                updateValues(id);
+            }
+        }
+
+        if ($$.isLegendInset) {
+            step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
+            $$.updateLegendStep(step);
+        }
+
+        if ($$.isLegendRight) {
+            xForLegend = function (id) { return maxWidth * steps[id]; };
+            yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+        } else if ($$.isLegendInset) {
+            xForLegend = function (id) { return maxWidth * steps[id] + 10; };
+            yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+        } else {
+            xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+            yForLegend = function (id) { return maxHeight * steps[id]; };
+        }
+        xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
+        yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
+        xForLegendRect = function (id, i) { return xForLegend(id, i); };
+        yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
+
+        // Define g for legend area
+        l = $$.legend.selectAll('.' + CLASS.legendItem)
+            .data(targetIds)
+            .enter().append('g')
+            .attr('class', function (id) { return $$.generateClass(CLASS.legendItem, id); })
+            .style('visibility', function (id) { return $$.isLegendToShow(id) ? 'visible' : 'hidden'; })
+            .style('cursor', 'pointer')
+            .on('click', function (id) {
+                if (config.legend_item_onclick) {
+                    config.legend_item_onclick.call($$, id);
+                } else {
+                    if ($$.d3.event.altKey) {
+                        $$.api.hide();
+                        $$.api.show(id);
+                    } else {
+                        $$.api.toggle(id);
+                        $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
+                    }
+                }
+            })
+            .on('mouseover', function (id) {
+                $$.d3.select(this).classed(CLASS.legendItemFocused, true);
+                if (!$$.transiting && $$.isTargetToShow(id)) {
+                    $$.api.focus(id);
+                }
+                if (config.legend_item_onmouseover) {
+                    config.legend_item_onmouseover.call($$, id);
+                }
+            })
+            .on('mouseout', function (id) {
+                $$.d3.select(this).classed(CLASS.legendItemFocused, false);
+                $$.api.revert();
+                if (config.legend_item_onmouseout) {
+                    config.legend_item_onmouseout.call($$, id);
+                }
+            });
+        l.append('text')
+            .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
+            .each(function (id, i) { updatePositions(this, id, i); })
+            .style("pointer-events", "none")
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
+        l.append('rect')
+            .attr("class", CLASS.legendItemEvent)
+            .style('fill-opacity', 0)
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
+        l.append('rect')
+            .attr("class", CLASS.legendItemTile)
+            .style("pointer-events", "none")
+            .style('fill', $$.color)
+            .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+            .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
+            .attr('width', 10)
+            .attr('height', 10);
+
+        // Set background for inset legend
+        background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
+        if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
+            background = $$.legend.insert('g', '.' + CLASS.legendItem)
+                .attr("class", CLASS.legendBackground)
+                .append('rect');
+        }
+
+        texts = $$.legend.selectAll('text')
+            .data(targetIds)
+            .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update
+            .each(function (id, i) { updatePositions(this, id, i); });
+        (withTransition ? texts.transition() : texts)
+            .attr('x', xForLegendText)
+            .attr('y', yForLegendText);
+
+        rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent)
+            .data(targetIds);
+        (withTransition ? rects.transition() : rects)
+            .attr('width', function (id) { return widths[id]; })
+            .attr('height', function (id) { return heights[id]; })
+            .attr('x', xForLegendRect)
+            .attr('y', yForLegendRect);
+
+        tiles = $$.legend.selectAll('rect.' + CLASS.legendItemTile)
+            .data(targetIds);
+        (withTransition ? tiles.transition() : tiles)
+            .style('fill', $$.color)
+            .attr('x', xForLegend)
+            .attr('y', yForLegend);
+
+        if (background) {
+            (withTransition ? background.transition() : background)
+                .attr('height', $$.getLegendHeight() - 12)
+                .attr('width', maxWidth * (step + 1) + 10);
+        }
+
+        // toggle legend state
+        $$.legend.selectAll('.' + CLASS.legendItem)
+            .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
+            .transition()
+            .style('opacity', function (id) {
+                var This = $$.d3.select(this);
+                if ($$.isTargetToShow(id)) {
+                    return !hasFocused || This.classed(CLASS.legendItemFocused) ? $$.opacityForLegend(This) : $$.opacityForUnfocusedLegend(This);
+                } else {
+                    return null; // c3-legend-item-hidden will be applied
+                }
+            });
+
+        // Update all to reflect change of legend
+        $$.updateLegendItemWidth(maxWidth);
+        $$.updateLegendItemHeight(maxHeight);
+        $$.updateLegendStep(step);
+        // Update size and scale
+        $$.updateSizes();
+        $$.updateScales();
+        $$.updateSvgSize();
+        // Update g positions
+        $$.transformAll(withTransitionForTransform, transitions);
+        $$.legendHasRendered = true;
+    };
+
+    c3_chart_internal_fn.initAxis = function () {
+        var $$ = this, config = $$.config, main = $$.main;
+        $$.axes.x = main.append("g")
+            .attr("class", CLASS.axis + ' ' + CLASS.axisX)
+            .attr("clip-path", $$.clipPathForXAxis)
+            .attr("transform", $$.getTranslate('x'))
+            .style("visibility", config.axis_x_show ? 'visible' : 'hidden');
+        $$.axes.x.append("text")
+            .attr("class", CLASS.axisXLabel)
+            .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+            .style("text-anchor", $$.textAnchorForXAxisLabel.bind($$));
+
+        $$.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');
+        $$.axes.y.append("text")
+            .attr("class", CLASS.axisYLabel)
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .style("text-anchor", $$.textAnchorForYAxisLabel.bind($$));
+
+        $$.axes.y2 = main.append("g")
+            .attr("class", CLASS.axis + ' ' + CLASS.axisY2)
+            // clip-path?
+            .attr("transform", $$.getTranslate('y2'))
+            .style("visibility", config.axis_y2_show ? 'visible' : 'hidden');
+        $$.axes.y2.append("text")
+            .attr("class", CLASS.axisY2Label)
+            .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+            .style("text-anchor", $$.textAnchorForY2AxisLabel.bind($$));
+    };
+    c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+        var $$ = this, config = $$.config,
+            axisParams = {
+                isCategory: $$.isCategorized(),
+                withOuterTick: withOuterTick,
+                tickMultiline: config.axis_x_tick_multiline,
+                tickWidth: config.axis_x_tick_width
+            },
+            axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
+
+        if ($$.isTimeSeries() && tickValues) {
+            tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
+        }
+
+        // Set tick
+        axis.tickFormat(tickFormat).tickValues(tickValues);
+        if ($$.isCategorized()) {
+            axis.tickCentered(config.axis_x_tick_centered);
+            if (isEmpty(config.axis_x_tick_culling)) {
+                config.axis_x_tick_culling = false;
+            }
+        } else {
+            // TODO: move this to c3_axis
+            axis.tickOffset = function () {
+                var scale = this.scale(),
+                    edgeX = $$.getEdgeX($$.data.targets), diff = scale(edgeX[1]) - scale(edgeX[0]),
+                    base = diff ? diff : (config.axis_rotated ? $$.height : $$.width);
+                return (base / $$.getMaxDataCount()) / 2;
+            };
+        }
+
+        return axis;
+    };
+    c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+        var axisParams = {withOuterTick: withOuterTick},
+            axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
+        if (this.isTimeSeriesY()) {
+            axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
+        } else {
+            axis.tickValues(tickValues);
+        }
+        return axis;
+    };
+    c3_chart_internal_fn.getAxisId = function (id) {
+        var config = this.config;
+        return id in config.data_axes ? config.data_axes[id] : 'y';
+    };
+    c3_chart_internal_fn.getXAxisTickFormat = function () {
+        var $$ = this, config = $$.config,
+            format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
+        if (config.axis_x_tick_format) {
+            if (isFunction(config.axis_x_tick_format)) {
+                format = config.axis_x_tick_format;
+            } else if ($$.isTimeSeries()) {
+                format = function (date) {
+                    return date ? $$.axisTimeFormat(config.axis_x_tick_format)(date) : "";
+                };
+            }
+        }
+        return isFunction(format) ? function (v) { return format.call($$, v); } : format;
+    };
+    c3_chart_internal_fn.getAxisTickValues = function (tickValues, axis) {
+        return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
+    };
+    c3_chart_internal_fn.getXAxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_x_tick_values, this.xAxis);
+    };
+    c3_chart_internal_fn.getYAxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_y_tick_values, this.yAxis);
+    };
+    c3_chart_internal_fn.getY2AxisTickValues = function () {
+        return this.getAxisTickValues(this.config.axis_y2_tick_values, this.y2Axis);
+    };
+    c3_chart_internal_fn.getAxisLabelOptionByAxisId = function (axisId) {
+        var $$ = this, config = $$.config, option;
+        if (axisId === 'y') {
+            option = config.axis_y_label;
+        } else if (axisId === 'y2') {
+            option = config.axis_y2_label;
+        } else if (axisId === 'x') {
+            option = config.axis_x_label;
+        }
+        return option;
+    };
+    c3_chart_internal_fn.getAxisLabelText = function (axisId) {
+        var option = this.getAxisLabelOptionByAxisId(axisId);
+        return isString(option) ? option : option ? option.text : null;
+    };
+    c3_chart_internal_fn.setAxisLabelText = function (axisId, text) {
+        var $$ = this, config = $$.config,
+            option = $$.getAxisLabelOptionByAxisId(axisId);
+        if (isString(option)) {
+            if (axisId === 'y') {
+                config.axis_y_label = text;
+            } else if (axisId === 'y2') {
+                config.axis_y2_label = text;
+            } else if (axisId === 'x') {
+                config.axis_x_label = text;
+            }
+        } else if (option) {
+            option.text = text;
+        }
+    };
+    c3_chart_internal_fn.getAxisLabelPosition = function (axisId, defaultPosition) {
+        var option = this.getAxisLabelOptionByAxisId(axisId),
+            position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
+        return {
+            isInner: position.indexOf('inner') >= 0,
+            isOuter: position.indexOf('outer') >= 0,
+            isLeft: position.indexOf('left') >= 0,
+            isCenter: position.indexOf('center') >= 0,
+            isRight: position.indexOf('right') >= 0,
+            isTop: position.indexOf('top') >= 0,
+            isMiddle: position.indexOf('middle') >= 0,
+            isBottom: position.indexOf('bottom') >= 0
+        };
+    };
+    c3_chart_internal_fn.getXAxisLabelPosition = function () {
+        return this.getAxisLabelPosition('x', this.config.axis_rotated ? 'inner-top' : 'inner-right');
+    };
+    c3_chart_internal_fn.getYAxisLabelPosition = function () {
+        return this.getAxisLabelPosition('y', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+    };
+    c3_chart_internal_fn.getY2AxisLabelPosition = function () {
+        return this.getAxisLabelPosition('y2', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+    };
+    c3_chart_internal_fn.getAxisLabelPositionById = function (id) {
+        return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
+    };
+    c3_chart_internal_fn.textForXAxisLabel = function () {
+        return this.getAxisLabelText('x');
+    };
+    c3_chart_internal_fn.textForYAxisLabel = function () {
+        return this.getAxisLabelText('y');
+    };
+    c3_chart_internal_fn.textForY2AxisLabel = function () {
+        return this.getAxisLabelText('y2');
+    };
+    c3_chart_internal_fn.xForAxisLabel = function (forHorizontal, position) {
+        var $$ = this;
+        if (forHorizontal) {
+            return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
+        } else {
+            return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
+        }
+    };
+    c3_chart_internal_fn.dxForAxisLabel = function (forHorizontal, position) {
+        if (forHorizontal) {
+            return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
+        } else {
+            return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
+        }
+    };
+    c3_chart_internal_fn.textAnchorForAxisLabel = function (forHorizontal, position) {
+        if (forHorizontal) {
+            return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
+        } else {
+            return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
+        }
+    };
+    c3_chart_internal_fn.xForXAxisLabel = function () {
+        return this.xForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.xForYAxisLabel = function () {
+        return this.xForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.xForY2AxisLabel = function () {
+        return this.xForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForXAxisLabel = function () {
+        return this.dxForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForYAxisLabel = function () {
+        return this.dxForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.dxForY2AxisLabel = function () {
+        return this.dxForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+    };
+    c3_chart_internal_fn.dyForXAxisLabel = function () {
+        var $$ = this, config = $$.config,
+            position = $$.getXAxisLabelPosition();
+        if (config.axis_rotated) {
+            return position.isInner ? "1.2em" : -25 - $$.getMaxTickWidth('x');
+        } else {
+            return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
+        }
+    };
+    c3_chart_internal_fn.dyForYAxisLabel = function () {
+        var $$ = this,
+            position = $$.getYAxisLabelPosition();
+        if ($$.config.axis_rotated) {
+            return position.isInner ? "-0.5em" : "3em";
+        } else {
+            return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : ($$.getMaxTickWidth('y') + 10));
+        }
+    };
+    c3_chart_internal_fn.dyForY2AxisLabel = function () {
+        var $$ = this,
+            position = $$.getY2AxisLabelPosition();
+        if ($$.config.axis_rotated) {
+            return position.isInner ? "1.2em" : "-2.2em";
+        } else {
+            return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth('y2') + 15));
+        }
+    };
+    c3_chart_internal_fn.textAnchorForXAxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel(!$$.config.axis_rotated, $$.getXAxisLabelPosition());
+    };
+    c3_chart_internal_fn.textAnchorForYAxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getYAxisLabelPosition());
+    };
+    c3_chart_internal_fn.textAnchorForY2AxisLabel = function () {
+        var $$ = this;
+        return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getY2AxisLabelPosition());
+    };
+
+    c3_chart_internal_fn.xForRotatedTickText = function (r) {
+        return 8 * Math.sin(Math.PI * (r / 180));
+    };
+    c3_chart_internal_fn.yForRotatedTickText = function (r) {
+        return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
+    };
+    c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
+        axis.selectAll('.tick text')
+            .style("text-anchor", rotate > 0 ? "start" : "end");
+        transition.selectAll('.tick text')
+            .attr("y", this.yForRotatedTickText(rotate))
+            .attr("transform", "rotate(" + rotate + ")")
+          .selectAll('tspan')
+            .attr('dx', this.xForRotatedTickText(rotate));
+    };
+
+    c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
+        var $$ = this, config = $$.config,
+            maxWidth = 0, targetsToShow, scale, axis;
+        if (withoutRecompute && $$.currentMaxTickWidths[id]) {
+            return $$.currentMaxTickWidths[id];
+        }
+        if ($$.svg) {
+            targetsToShow = $$.filterTargetsToShow($$.data.targets);
+            if (id === 'y') {
+                scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
+                axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
+            } else if (id === 'y2') {
+                scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
+                axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
+            } else {
+                scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
+                axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
+            }
+            $$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
+                $$.d3.select(this).selectAll('text tspan').each(function () {
+                    var box = this.getBoundingClientRect();
+                    if (box.left > 0 && maxWidth < box.width) { maxWidth = box.width; }
+                });
+            }).remove();
+        }
+        $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
+        return $$.currentMaxTickWidths[id];
+    };
+
+    c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
+        var $$ = this;
+        var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
+            axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
+            axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
+        (withTransition ? axisXLabel.transition() : axisXLabel)
+            .attr("x", $$.xForXAxisLabel.bind($$))
+            .attr("dx", $$.dxForXAxisLabel.bind($$))
+            .attr("dy", $$.dyForXAxisLabel.bind($$))
+            .text($$.textForXAxisLabel.bind($$));
+        (withTransition ? axisYLabel.transition() : axisYLabel)
+            .attr("x", $$.xForYAxisLabel.bind($$))
+            .attr("dx", $$.dxForYAxisLabel.bind($$))
+            .attr("dy", $$.dyForYAxisLabel.bind($$))
+            .text($$.textForYAxisLabel.bind($$));
+        (withTransition ? axisY2Label.transition() : axisY2Label)
+            .attr("x", $$.xForY2AxisLabel.bind($$))
+            .attr("dx", $$.dxForY2AxisLabel.bind($$))
+            .attr("dy", $$.dyForY2AxisLabel.bind($$))
+            .text($$.textForY2AxisLabel.bind($$));
+    };
+
+    c3_chart_internal_fn.getAxisPadding = function (padding, key, defaultValue, all) {
+        var ratio = padding.unit === 'ratio' ? all : 1;
+        return isValue(padding[key]) ? padding[key] * ratio : defaultValue;
+    };
+
+    c3_chart_internal_fn.generateTickValues = function (values, tickCount, forTimeSeries) {
+        var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
+        if (tickCount) {
+            targetCount = isFunction(tickCount) ? tickCount() : tickCount;
+            // compute ticks according to tickCount
+            if (targetCount === 1) {
+                tickValues = [values[0]];
+            } else if (targetCount === 2) {
+                tickValues = [values[0], values[values.length - 1]];
+            } else if (targetCount > 2) {
+                count = targetCount - 2;
+                start = values[0];
+                end = values[values.length - 1];
+                interval = (end - start) / (count + 1);
+                // re-construct unique values
+                tickValues = [start];
+                for (i = 0; i < count; i++) {
+                    tickValue = +start + interval * (i + 1);
+                    tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
+                }
+                tickValues.push(end);
+            }
+        }
+        if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
+        return tickValues;
+    };
+    c3_chart_internal_fn.generateAxisTransitions = function (duration) {
+        var $$ = this, axes = $$.axes;
+        return {
+            axisX: duration ? axes.x.transition().duration(duration) : axes.x,
+            axisY: duration ? axes.y.transition().duration(duration) : axes.y,
+            axisY2: duration ? axes.y2.transition().duration(duration) : axes.y2,
+            axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
+        };
+    };
+    c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
+        var $$ = this, config = $$.config;
+        $$.axes.x.style("opacity", isHidden ? 0 : 1);
+        $$.axes.y.style("opacity", isHidden ? 0 : 1);
+        $$.axes.y2.style("opacity", isHidden ? 0 : 1);
+        $$.axes.subx.style("opacity", isHidden ? 0 : 1);
+        transitions.axisX.call($$.xAxis);
+        transitions.axisY.call($$.yAxis);
+        transitions.axisY2.call($$.y2Axis);
+        transitions.axisSubX.call($$.subXAxis);
+        // rotate tick text if needed
+        if (!config.axis_rotated && config.axis_x_tick_rotate) {
+            $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
+            $$.rotateTickText($$.axes.subx, transitions.axisSubX, config.axis_x_tick_rotate);
+        }
+    };
+
+    c3_chart_internal_fn.getClipPath = function (id) {
+        var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
+        return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
+    };
+    c3_chart_internal_fn.appendClip = function (parent, id) {
+        return parent.append("clipPath").attr("id", id).append("rect");
+    };
+    c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
+        // axis line width + padding for left
+        var left = Math.max(30, this.margin.left);
+        return forHorizontal ? -(1 + left) : -(left - 1);
+    };
+    c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
+        return forHorizontal ? -20 : -this.margin.top;
+    };
+    c3_chart_internal_fn.getXAxisClipX = function () {
+        var $$ = this;
+        return $$.getAxisClipX(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getXAxisClipY = function () {
+        var $$ = this;
+        return $$.getAxisClipY(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipX = function () {
+        var $$ = this;
+        return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipY = function () {
+        var $$ = this;
+        return $$.getAxisClipY($$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
+        var $$ = this,
+            left = Math.max(30, $$.margin.left),
+            right = Math.max(30, $$.margin.right);
+        // width + axis line width + padding for left/right
+        return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
+    };
+    c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
+        return (forHorizontal ? this.margin.bottom : (this.margin.top + this.height)) + 8;
+    };
+    c3_chart_internal_fn.getXAxisClipWidth = function () {
+        var $$ = this;
+        return $$.getAxisClipWidth(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getXAxisClipHeight = function () {
+        var $$ = this;
+        return $$.getAxisClipHeight(!$$.config.axis_rotated);
+    };
+    c3_chart_internal_fn.getYAxisClipWidth = function () {
+        var $$ = this;
+        return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
+    };
+    c3_chart_internal_fn.getYAxisClipHeight = function () {
+        var $$ = this;
+        return $$.getAxisClipHeight($$.config.axis_rotated);
+    };
+
+    c3_chart_internal_fn.initPie = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config;
+        $$.pie = d3.layout.pie().value(function (d) {
+            return d.values.reduce(function (a, b) { return a + b.value; }, 0);
+        });
+        if (!config.data_order) {
+            $$.pie.sort(null);
+        }
+    };
+
+    c3_chart_internal_fn.updateRadius = function () {
+        var $$ = this, config = $$.config,
+            w = config.gauge_width || config.donut_width;
+        $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2;
+        $$.radius = $$.radiusExpanded * 0.95;
+        $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
+        $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
+    };
+
+    c3_chart_internal_fn.updateArc = function () {
+        var $$ = this;
+        $$.svgArc = $$.getSvgArc();
+        $$.svgArcExpanded = $$.getSvgArcExpanded();
+        $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
+    };
+
+    c3_chart_internal_fn.updateAngle = function (d) {
+        var $$ = this, config = $$.config,
+            found = false, index = 0,
+            gMin = config.gauge_min, gMax = config.gauge_max, gTic, gValue;
+        $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
+            if (! found && t.data.id === d.data.id) {
+                found = true;
+                d = t;
+                d.index = index;
+            }
+            index++;
+        });
+        if (isNaN(d.endAngle)) {
+            d.endAngle = d.startAngle;
+        }
+        if ($$.isGaugeType(d.data)) {
+            gTic = (Math.PI) / (gMax - gMin);
+            gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
+            d.startAngle = -1 * (Math.PI / 2);
+            d.endAngle = d.startAngle + gTic * gValue;
+        }
+        return found ? d : null;
+    };
+
+    c3_chart_internal_fn.getSvgArc = function () {
+        var $$ = this,
+            arc = $$.d3.svg.arc().outerRadius($$.radius).innerRadius($$.innerRadius),
+            newArc = function (d, withoutUpdate) {
+                var updated;
+                if (withoutUpdate) { return arc(d); } // for interpolate
+                updated = $$.updateAngle(d);
+                return updated ? arc(updated) : "M 0 0";
+            };
+        // TODO: extends all function
+        newArc.centroid = arc.centroid;
+        return newArc;
+    };
+
+    c3_chart_internal_fn.getSvgArcExpanded = function (rate) {
+        var $$ = this,
+            arc = $$.d3.svg.arc().outerRadius($$.radiusExpanded * (rate ? rate : 1)).innerRadius($$.innerRadius);
+        return function (d) {
+            var updated = $$.updateAngle(d);
+            return updated ? arc(updated) : "M 0 0";
+        };
+    };
+
+    c3_chart_internal_fn.getArc = function (d, withoutUpdate, force) {
+        return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
+    };
+
+
+    c3_chart_internal_fn.transformForArcLabel = function (d) {
+        var $$ = this,
+            updated = $$.updateAngle(d), c, x, y, h, ratio, translate = "";
+        if (updated && !$$.hasType('gauge')) {
+            c = this.svgArc.centroid(updated);
+            x = isNaN(c[0]) ? 0 : c[0];
+            y = isNaN(c[1]) ? 0 : c[1];
+            h = Math.sqrt(x * x + y * y);
+            // TODO: ratio should be an option?
+            ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
+            translate = "translate(" + (x * ratio) +  ',' + (y * ratio) +  ")";
+        }
+        return translate;
+    };
+
+    c3_chart_internal_fn.getArcRatio = function (d) {
+        var $$ = this,
+            whole = $$.hasType('gauge') ? Math.PI : (Math.PI * 2);
+        return d ? (d.endAngle - d.startAngle) / whole : null;
+    };
+
+    c3_chart_internal_fn.convertToArcData = function (d) {
+        return this.addName({
+            id: d.data.id,
+            value: d.value,
+            ratio: this.getArcRatio(d),
+            index: d.index
+        });
+    };
+
+    c3_chart_internal_fn.textForArcLabel = function (d) {
+        var $$ = this,
+            updated, value, ratio, id, format;
+        if (! $$.shouldShowArcLabel()) { return ""; }
+        updated = $$.updateAngle(d);
+        value = updated ? updated.value : null;
+        ratio = $$.getArcRatio(updated);
+        id = d.data.id;
+        if (! $$.hasType('gauge') && ! $$.meetsArcLabelThreshold(ratio)) { return ""; }
+        format = $$.getArcLabelFormat();
+        return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
+    };
+
+    c3_chart_internal_fn.expandArc = function (targetIds) {
+        var $$ = this, interval;
+
+        // MEMO: avoid to cancel transition
+        if ($$.transiting) {
+            interval = window.setInterval(function () {
+                if (!$$.transiting) {
+                    window.clearInterval(interval);
+                    if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
+                        $$.expandArc(targetIds);
+                    }
+                }
+            }, 10);
+            return;
+        }
+
+        targetIds = $$.mapToTargetIds(targetIds);
+
+        $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
+            if (! $$.shouldExpand(d.data.id)) { return; }
+            $$.d3.select(this).selectAll('path')
+                .transition().duration(50)
+                .attr("d", $$.svgArcExpanded)
+                .transition().duration(100)
+                .attr("d", $$.svgArcExpandedSub)
+                .each(function (d) {
+                    if ($$.isDonutType(d.data)) {
+                        // callback here
+                    }
+                });
+        });
+    };
+
+    c3_chart_internal_fn.unexpandArc = function (targetIds) {
+        var $$ = this;
+
+        if ($$.transiting) { return; }
+
+        targetIds = $$.mapToTargetIds(targetIds);
+
+        $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
+            .transition().duration(50)
+            .attr("d", $$.svgArc);
+        $$.svg.selectAll('.' + CLASS.arc)
+            .style("opacity", 1);
+    };
+
+    c3_chart_internal_fn.shouldExpand = function (id) {
+        var $$ = this, config = $$.config;
+        return ($$.isDonutType(id) && config.donut_expand) || ($$.isGaugeType(id) && config.gauge_expand) || ($$.isPieType(id) && config.pie_expand);
+    };
+
+    c3_chart_internal_fn.shouldShowArcLabel = function () {
+        var $$ = this, config = $$.config, shouldShow = true;
+        if ($$.hasType('donut')) {
+            shouldShow = config.donut_label_show;
+        } else if ($$.hasType('pie')) {
+            shouldShow = config.pie_label_show;
+        }
+        // when gauge, always true
+        return shouldShow;
+    };
+
+    c3_chart_internal_fn.meetsArcLabelThreshold = function (ratio) {
+        var $$ = this, config = $$.config,
+            threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
+        return ratio >= threshold;
+    };
+
+    c3_chart_internal_fn.getArcLabelFormat = function () {
+        var $$ = this, config = $$.config,
+            format = config.pie_label_format;
+        if ($$.hasType('gauge')) {
+            format = config.gauge_label_format;
+        } else if ($$.hasType('donut')) {
+            format = config.donut_label_format;
+        }
+        return format;
+    };
+
+    c3_chart_internal_fn.getArcTitle = function () {
+        var $$ = this;
+        return $$.hasType('donut') ? $$.config.donut_title : "";
+    };
+
+    c3_chart_internal_fn.updateTargetsForArc = function (targets) {
+        var $$ = this, main = $$.main,
+            mainPieUpdate, mainPieEnter,
+            classChartArc = $$.classChartArc.bind($$),
+            classArcs = $$.classArcs.bind($$),
+            classFocus = $$.classFocus.bind($$);
+        mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
+            .data($$.pie(targets))
+            .attr("class", function (d) { return classChartArc(d) + classFocus(d.data); });
+        mainPieEnter = mainPieUpdate.enter().append("g")
+            .attr("class", classChartArc);
+        mainPieEnter.append('g')
+            .attr('class', classArcs);
+        mainPieEnter.append("text")
+            .attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
+            .style("opacity", 0)
+            .style("text-anchor", "middle")
+            .style("pointer-events", "none");
+        // MEMO: can not keep same color..., but not bad to update color in redraw
+        //mainPieUpdate.exit().remove();
+    };
+
+    c3_chart_internal_fn.initArc = function () {
+        var $$ = this;
+        $$.arcs = $$.main.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartArcs)
+            .attr("transform", $$.getTranslate('arc'));
+        $$.arcs.append('text')
+            .attr('class', CLASS.chartArcsTitle)
+            .style("text-anchor", "middle")
+            .text($$.getArcTitle());
+    };
+
+    c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransform) {
+        var $$ = this, d3 = $$.d3, config = $$.config, main = $$.main,
+            mainArc;
+        mainArc = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc)
+            .data($$.arcData.bind($$));
+        mainArc.enter().append('path')
+            .attr("class", $$.classArc.bind($$))
+            .style("fill", function (d) { return $$.color(d.data); })
+            .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; })
+            .style("opacity", 0)
+            .each(function (d) {
+                if ($$.isGaugeType(d.data)) {
+                    d.startAngle = d.endAngle = -1 * (Math.PI / 2);
+                }
+                this._current = d;
+            })
+            .on('mouseover', function (d) {
+                var updated, arcData;
+                if ($$.transiting) { // skip while transiting
+                    return;
+                }
+                updated = $$.updateAngle(d);
+                arcData = $$.convertToArcData(updated);
+                // transitions
+                $$.expandArc(updated.data.id);
+                $$.api.focus(updated.data.id);
+                $$.toggleFocusLegend(updated.data.id, true);
+                $$.config.data_onmouseover(arcData, this);
+            })
+            .on('mousemove', function (d) {
+                var updated = $$.updateAngle(d),
+                    arcData = $$.convertToArcData(updated),
+                    selectedData = [arcData];
+                $$.showTooltip(selectedData, d3.mouse(this));
+            })
+            .on('mouseout', function (d) {
+                var updated, arcData;
+                if ($$.transiting) { // skip while transiting
+                    return;
+                }
+                updated = $$.updateAngle(d);
+                arcData = $$.convertToArcData(updated);
+                // transitions
+                $$.unexpandArc(updated.data.id);
+                $$.api.revert();
+                $$.revertLegend();
+                $$.hideTooltip();
+                $$.config.data_onmouseout(arcData, this);
+            })
+            .on('click', function (d, i) {
+                var updated = $$.updateAngle(d),
+                    arcData = $$.convertToArcData(updated);
+                if ($$.toggleShape) { $$.toggleShape(this, arcData, i); }
+                $$.config.data_onclick.call($$.api, arcData, this);
+            });
+        mainArc
+            .attr("transform", function (d) { return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : ""; })
+            .style("opacity", function (d) { return d === this._current ? 0 : 1; })
+            .each(function () { $$.transiting = true; })
+            .transition().duration(duration)
+            .attrTween("d", function (d) {
+                var updated = $$.updateAngle(d), interpolate;
+                if (! updated) {
+                    return function () { return "M 0 0"; };
+                }
+                //                if (this._current === d) {
+                //                    this._current = {
+                //                        startAngle: Math.PI*2,
+                //                        endAngle: Math.PI*2,
+                //                    };
+                //                }
+                if (isNaN(this._current.endAngle)) {
+                    this._current.endAngle = this._current.startAngle;
+                }
+                interpolate = d3.interpolate(this._current, updated);
+                this._current = interpolate(0);
+                return function (t) {
+                    var interpolated = interpolate(t);
+                    interpolated.data = d.data; // data.id will be updated by interporator
+                    return $$.getArc(interpolated, true);
+                };
+            })
+            .attr("transform", withTransform ? "scale(1)" : "")
+            .style("fill", function (d) {
+                return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
+            }) // Where gauge reading color would receive customization.
+            .style("opacity", 1)
+            .call($$.endall, function () {
+                $$.transiting = false;
+            });
+        mainArc.exit().transition().duration(durationForExit)
+            .style('opacity', 0)
+            .remove();
+        main.selectAll('.' + CLASS.chartArc).select('text')
+            .style("opacity", 0)
+            .attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
+            .text($$.textForArcLabel.bind($$))
+            .attr("transform", $$.transformForArcLabel.bind($$))
+            .style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
+          .transition().duration(duration)
+            .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
+        main.select('.' + CLASS.chartArcsTitle)
+            .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
+
+        if ($$.hasType('gauge')) {
+            $$.arcs.select('.' + CLASS.chartArcsBackground)
+                .attr("d", function () {
+                    var d = {
+                        data: [{value: config.gauge_max}],
+                        startAngle: -1 * (Math.PI / 2),
+                        endAngle: Math.PI / 2
+                    };
+                    return $$.getArc(d, true, true);
+                });
+            $$.arcs.select('.' + CLASS.chartArcsGaugeUnit)
+                .attr("dy", ".75em")
+                .text(config.gauge_label_show ? config.gauge_units : '');
+            $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
+                .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
+                .attr("dy", "1.2em")
+                .text(config.gauge_label_show ? config.gauge_min : '');
+            $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
+                .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
+                .attr("dy", "1.2em")
+                .text(config.gauge_label_show ? config.gauge_max : '');
+        }
+    };
+    c3_chart_internal_fn.initGauge = function () {
+        var arcs = this.arcs;
+        if (this.hasType('gauge')) {
+            arcs.append('path')
+                .attr("class", CLASS.chartArcsBackground);
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeUnit)
+                .style("text-anchor", "middle")
+                .style("pointer-events", "none");
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeMin)
+                .style("text-anchor", "middle")
+                .style("pointer-events", "none");
+            arcs.append("text")
+                .attr("class", CLASS.chartArcsGaugeMax)
+                .style("text-anchor", "middle")
+                .style("pointer-events", "none");
+        }
+    };
+    c3_chart_internal_fn.getGaugeLabelHeight = function () {
+        return this.config.gauge_label_show ? 20 : 0;
+    };
+
+    c3_chart_internal_fn.initRegion = function () {
+        var $$ = this;
+        $$.region = $$.main.append('g')
+            .attr("clip-path", $$.clipPath)
+            .attr("class", CLASS.regions);
+    };
+    c3_chart_internal_fn.redrawRegion = function (duration) {
+        var $$ = this, config = $$.config;
+
+        // hide if arc type
+        $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+        $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
+            .data(config.regions);
+        $$.mainRegion.enter().append('g')
+            .attr('class', $$.classRegion.bind($$))
+          .append('rect')
+            .style("fill-opacity", 0);
+        $$.mainRegion.exit().transition().duration(duration)
+            .style("opacity", 0)
+            .remove();
+    };
+    c3_chart_internal_fn.addTransitionForRegion = function (transitions) {
+        var $$ = this,
+            x = $$.regionX.bind($$),
+            y = $$.regionY.bind($$),
+            w = $$.regionWidth.bind($$),
+            h = $$.regionHeight.bind($$);
+        transitions.push($$.mainRegion.selectAll('rect').transition()
+                         .attr("x", x)
+                         .attr("y", y)
+                         .attr("width", w)
+                         .attr("height", h)
+                         .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; }));
+    };
+    c3_chart_internal_fn.regionX = function (d) {
+        var $$ = this, config = $$.config,
+            xPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            xPos = config.axis_rotated ? ('start' in d ? yScale(d.start) : 0) : 0;
+        } else {
+            xPos = config.axis_rotated ? 0 : ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0);
+        }
+        return xPos;
+    };
+    c3_chart_internal_fn.regionY = function (d) {
+        var $$ = this, config = $$.config,
+            yPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            yPos = config.axis_rotated ? 0 : ('end' in d ? yScale(d.end) : 0);
+        } else {
+            yPos = config.axis_rotated ? ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0) : 0;
+        }
+        return yPos;
+    };
+    c3_chart_internal_fn.regionWidth = function (d) {
+        var $$ = this, config = $$.config,
+            start = $$.regionX(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            end = config.axis_rotated ? ('end' in d ? yScale(d.end) : $$.width) : $$.width;
+        } else {
+            end = config.axis_rotated ? $$.width : ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.width);
+        }
+        return end < start ? 0 : end - start;
+    };
+    c3_chart_internal_fn.regionHeight = function (d) {
+        var $$ = this, config = $$.config,
+            start = this.regionY(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+        if (d.axis === 'y' || d.axis === 'y2') {
+            end = config.axis_rotated ? $$.height : ('start' in d ? yScale(d.start) : $$.height);
+        } else {
+            end = config.axis_rotated ? ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.height) : $$.height;
+        }
+        return end < start ? 0 : end - start;
+    };
+    c3_chart_internal_fn.isRegionOnX = function (d) {
+        return !d.axis || d.axis === 'x';
+    };
+
+    c3_chart_internal_fn.drag = function (mouse) {
+        var $$ = this, config = $$.config, main = $$.main, d3 = $$.d3;
+        var sx, sy, mx, my, minX, maxX, minY, maxY;
+
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        if (config.zoom_enabled && ! $$.zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior
+        if (!config.data_selection_multiple) { return; } // skip when single selection because drag is used for multiple selection
+
+        sx = $$.dragStart[0];
+        sy = $$.dragStart[1];
+        mx = mouse[0];
+        my = mouse[1];
+        minX = Math.min(sx, mx);
+        maxX = Math.max(sx, mx);
+        minY = (config.data_selection_grouped) ? $$.margin.top : Math.min(sy, my);
+        maxY = (config.data_selection_grouped) ? $$.height : Math.max(sy, my);
+
+        main.select('.' + CLASS.dragarea)
+            .attr('x', minX)
+            .attr('y', minY)
+            .attr('width', maxX - minX)
+            .attr('height', maxY - minY);
+        // TODO: binary search when multiple xs
+        main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape)
+            .filter(function (d) { return config.data_selection_isselectable(d); })
+            .each(function (d, i) {
+                var shape = d3.select(this),
+                    isSelected = shape.classed(CLASS.SELECTED),
+                    isIncluded = shape.classed(CLASS.INCLUDED),
+                    _x, _y, _w, _h, toggle, isWithin = false, box;
+                if (shape.classed(CLASS.circle)) {
+                    _x = shape.attr("cx") * 1;
+                    _y = shape.attr("cy") * 1;
+                    toggle = $$.togglePoint;
+                    isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
+                }
+                else if (shape.classed(CLASS.bar)) {
+                    box = getPathBox(this);
+                    _x = box.x;
+                    _y = box.y;
+                    _w = box.width;
+                    _h = box.height;
+                    toggle = $$.togglePath;
+                    isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
+                } else {
+                    // line/area selection not supported yet
+                    return;
+                }
+                if (isWithin ^ isIncluded) {
+                    shape.classed(CLASS.INCLUDED, !isIncluded);
+                    // TODO: included/unincluded callback here
+                    shape.classed(CLASS.SELECTED, !isSelected);
+                    toggle.call($$, !isSelected, shape, d, i);
+                }
+            });
+    };
+
+    c3_chart_internal_fn.dragstart = function (mouse) {
+        var $$ = this, config = $$.config;
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        $$.dragStart = mouse;
+        $$.main.select('.' + CLASS.chart).append('rect')
+            .attr('class', CLASS.dragarea)
+            .style('opacity', 0.1);
+        $$.dragging = true;
+        $$.config.data_ondragstart.call($$.api);
+    };
+
+    c3_chart_internal_fn.dragend = function () {
+        var $$ = this, config = $$.config;
+        if ($$.hasArcType()) { return; }
+        if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+        $$.main.select('.' + CLASS.dragarea)
+            .transition().duration(100)
+            .style('opacity', 0)
+            .remove();
+        $$.main.selectAll('.' + CLASS.shape)
+            .classed(CLASS.INCLUDED, false);
+        $$.dragging = false;
+        $$.config.data_ondragend.call($$.api);
+    };
+
+
+    c3_chart_internal_fn.selectPoint = function (target, d, i) {
+        var $$ = this, config = $$.config,
+            cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
+            cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
+            r = $$.pointSelectR.bind($$);
+        config.data_onselected.call($$.api, d, target.node());
+        // add selected-circle on low layer g
+        $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+            .data([d])
+            .enter().append('circle')
+            .attr("class", function () { return $$.generateClass(CLASS.selectedCircle, i); })
+            .attr("cx", cx)
+            .attr("cy", cy)
+            .attr("stroke", function () { return $$.color(d); })
+            .attr("r", function (d) { return $$.pointSelectR(d) * 1.4; })
+            .transition().duration(100)
+            .attr("r", r);
+    };
+    c3_chart_internal_fn.unselectPoint = function (target, d, i) {
+        var $$ = this;
+        $$.config.data_onunselected(d, target.node());
+        // remove selected-circle from low layer g
+        $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+            .transition().duration(100).attr('r', 0)
+            .remove();
+    };
+    c3_chart_internal_fn.togglePoint = function (selected, target, d, i) {
+        selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
+    };
+    c3_chart_internal_fn.selectPath = function (target, d) {
+        var $$ = this;
+        $$.config.data_onselected.call($$, d, target.node());
+        target.transition().duration(100)
+            .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
+    };
+    c3_chart_internal_fn.unselectPath = function (target, d) {
+        var $$ = this;
+        $$.config.data_onunselected.call($$, d, target.node());
+        target.transition().duration(100)
+            .style("fill", function () { return $$.color(d); });
+    };
+    c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
+        selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
+    };
+    c3_chart_internal_fn.getToggle = function (that, d) {
+        var $$ = this, toggle;
+        if (that.nodeName === 'circle') {
+            if ($$.isStepType(d)) {
+                // circle is hidden in step chart, so treat as within the click area
+                toggle = function () {}; // TODO: how to select step chart?
+            } else {
+                toggle = $$.togglePoint;
+            }
+        }
+        else if (that.nodeName === 'path') {
+            toggle = $$.togglePath;
+        }
+        return toggle;
+    };
+    c3_chart_internal_fn.toggleShape = function (that, d, i) {
+        var $$ = this, d3 = $$.d3, config = $$.config,
+            shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED),
+            toggle = $$.getToggle(that, d).bind($$);
+
+        if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
+            if (!config.data_selection_multiple) {
+                $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
+                    var shape = d3.select(this);
+                    if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
+                });
+            }
+            shape.classed(CLASS.SELECTED, !isSelected);
+            toggle(!isSelected, shape, d, i);
+        }
+    };
+
+    c3_chart_internal_fn.initBrush = function () {
+        var $$ = this, d3 = $$.d3;
+        $$.brush = d3.svg.brush().on("brush", function () { $$.redrawForBrush(); });
+        $$.brush.update = function () {
+            if ($$.context) { $$.context.select('.' + CLASS.brush).call(this); }
+            return this;
+        };
+        $$.brush.scale = function (scale) {
+            return $$.config.axis_rotated ? this.y(scale) : this.x(scale);
+        };
+    };
+    c3_chart_internal_fn.initSubchart = function () {
+        var $$ = this, config = $$.config,
+            context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context'));
+
+        if (!config.subchart_show) {
+            context.style('visibility', 'hidden');
+        }
+
+        // Define g for chart area
+        context.append('g')
+            .attr("clip-path", $$.clipPathForSubchart)
+            .attr('class', CLASS.chart);
+
+        // Define g for bar chart area
+        context.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartBars);
+
+        // Define g for line chart area
+        context.select('.' + CLASS.chart).append("g")
+            .attr("class", CLASS.chartLines);
+
+        // Add extent rect for Brush
+        context.append("g")
+            .attr("clip-path", $$.clipPath)
+            .attr("class", CLASS.brush)
+            .call($$.brush)
+            .selectAll("rect")
+            .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
+
+        // ATTENTION: This must be called AFTER chart added
+        // Add Axis
+        $$.axes.subx = context.append("g")
+            .attr("class", CLASS.axisX)
+            .attr("transform", $$.getTranslate('subx'))
+            .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis);
+    };
+    c3_chart_internal_fn.updateTargetsForSubchart = function (targets) {
+        var $$ = this, context = $$.context, config = $$.config,
+            contextLineEnter, contextLineUpdate, contextBarEnter, contextBarUpdate,
+            classChartBar = $$.classChartBar.bind($$),
+            classBars = $$.classBars.bind($$),
+            classChartLine = $$.classChartLine.bind($$),
+            classLines = $$.classLines.bind($$),
+            classAreas = $$.classAreas.bind($$);
+
+        if (config.subchart_show) {
+            contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+                .data(targets)
+                .attr('class', classChartBar);
+            contextBarEnter = contextBarUpdate.enter().append('g')
+                .style('opacity', 0)
+                .attr('class', classChartBar);
+            // Bars for each data
+            contextBarEnter.append('g')
+                .attr("class", classBars);
+
+            //-- Line --//
+            contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+                .data(targets)
+                .attr('class', classChartLine);
+            contextLineEnter = contextLineUpdate.enter().append('g')
+                .style('opacity', 0)
+                .attr('class', classChartLine);
+            // Lines for each data
+            contextLineEnter.append("g")
+                .attr("class", classLines);
+            // Area
+            contextLineEnter.append("g")
+                .attr("class", classAreas);
+        }
+    };
+    c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
+        var $$ = this, d3 = $$.d3, context = $$.context, config = $$.config,
+            contextLine,  contextArea, contextBar, drawAreaOnSub, drawBarOnSub, drawLineOnSub,
+            barData = $$.barData.bind($$),
+            lineData = $$.lineData.bind($$),
+            classBar = $$.classBar.bind($$),
+            classLine = $$.classLine.bind($$),
+            classArea = $$.classArea.bind($$),
+            initialOpacity = $$.initialOpacity.bind($$);
+
+        // subchart
+        if (config.subchart_show) {
+            // reflect main chart to extent on subchart if zoomed
+            if (d3.event && d3.event.type === 'zoom') {
+                $$.brush.extent($$.x.orgDomain()).update();
+            }
+            // update subchart elements if needed
+            if (withSubchart) {
+
+                // extent rect
+                if (!$$.brush.empty()) {
+                    $$.brush.extent($$.x.orgDomain()).update();
+                }
+                // setup drawer - MEMO: this must be called after axis updated
+                drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
+                drawBarOnSub = $$.generateDrawBar(barIndices, true);
+                drawLineOnSub = $$.generateDrawLine(lineIndices, true);
+                // bars
+                contextBar = context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+                    .data(barData);
+                contextBar.enter().append('path')
+                    .attr("class", classBar)
+                    .style("stroke", 'none')
+                    .style("fill", $$.color);
+                contextBar
+                    .style("opacity", initialOpacity)
+                    .transition().duration(duration)
+                    .attr('d', drawBarOnSub)
+                    .style('opacity', 1);
+                contextBar.exit().transition().duration(duration)
+                    .style('opacity', 0)
+                    .remove();
+                // lines
+                contextLine = context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+                    .data(lineData);
+                contextLine.enter().append('path')
+                    .attr('class', classLine)
+                    .style('stroke', $$.color);
+                contextLine
+                    .style("opacity", initialOpacity)
+                    .transition().duration(duration)
+                    .attr("d", drawLineOnSub)
+                    .style('opacity', 1);
+                contextLine.exit().transition().duration(duration)
+                    .style('opacity', 0)
+                    .remove();
+                // area
+                contextArea = context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+                    .data(lineData);
+                contextArea.enter().append('path')
+                    .attr("class", classArea)
+                    .style("fill", $$.color)
+                    .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+                contextArea
+                    .style("opacity", 0)
+                    .transition().duration(duration)
+                    .attr("d", drawAreaOnSub)
+                    .style("fill", $$.color)
+                    .style("opacity", $$.orgAreaOpacity);
+                contextArea.exit().transition().duration(durationForExit)
+                    .style('opacity', 0)
+                    .remove();
+            }
+        }
+    };
+    c3_chart_internal_fn.redrawForBrush = function () {
+        var $$ = this, x = $$.x;
+        $$.redraw({
+            withTransition: false,
+            withY: $$.config.zoom_rescale,
+            withSubchart: false,
+            withUpdateXDomain: true,
+            withDimension: false
+        });
+        $$.config.subchart_onbrush.call($$.api, x.orgDomain());
+    };
+    c3_chart_internal_fn.transformContext = function (withTransition, transitions) {
+        var $$ = this, subXAxis;
+        if (transitions && transitions.axisSubX) {
+            subXAxis = transitions.axisSubX;
+        } else {
+            subXAxis = $$.context.select('.' + CLASS.axisX);
+            if (withTransition) { subXAxis = subXAxis.transition(); }
+        }
+        $$.context.attr("transform", $$.getTranslate('context'));
+        subXAxis.attr("transform", $$.getTranslate('subx'));
+    };
+    c3_chart_internal_fn.getDefaultExtent = function () {
+        var $$ = this, config = $$.config,
+            extent = isFunction(config.axis_x_extent) ? config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
+        if ($$.isTimeSeries()) {
+            extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
+        }
+        return extent;
+    };
+
+    c3_chart_internal_fn.initZoom = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
+
+        $$.zoom = d3.behavior.zoom()
+            .on("zoomstart", function () {
+                startEvent = d3.event.sourceEvent;
+                $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
+                config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
+            })
+            .on("zoom", function () {
+                $$.redrawForZoom.call($$);
+            })
+            .on('zoomend', function () {
+                var event = d3.event.sourceEvent;
+                // if click, do nothing. otherwise, click interaction will be canceled.
+                if (event && startEvent.clientX === event.clientX && startEvent.clientY === event.clientY) {
+                    return;
+                }
+                $$.redrawEventRect();
+                $$.updateZoom();
+                config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
+            });
+        $$.zoom.scale = function (scale) {
+            return config.axis_rotated ? this.y(scale) : this.x(scale);
+        };
+        $$.zoom.orgScaleExtent = function () {
+            var extent = config.zoom_extent ? config.zoom_extent : [1, 10];
+            return [extent[0], Math.max($$.getMaxDataCount() / extent[1], extent[1])];
+        };
+        $$.zoom.updateScaleExtent = function () {
+            var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.orgXDomain),
+                extent = this.orgScaleExtent();
+            this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
+            return this;
+        };
+    };
+    c3_chart_internal_fn.updateZoom = function () {
+        var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
+        $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
+        $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
+    };
+    c3_chart_internal_fn.redrawForZoom = function () {
+        var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
+        if (!config.zoom_enabled) {
+            return;
+        }
+        if ($$.filterTargetsToShow($$.data.targets).length === 0) {
+            return;
+        }
+        if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) {
+            x.domain(zoom.altDomain);
+            zoom.scale(x).updateScaleExtent();
+            return;
+        }
+        if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
+            x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
+        }
+        $$.redraw({
+            withTransition: false,
+            withY: config.zoom_rescale,
+            withSubchart: false,
+            withEventRect: false,
+            withDimension: false
+        });
+        if (d3.event.sourceEvent.type === 'mousemove') {
+            $$.cancelClick = true;
+        }
+        config.zoom_onzoom.call($$.api, x.orgDomain());
+    };
+
+    c3_chart_internal_fn.generateColor = function () {
+        var $$ = this, config = $$.config, d3 = $$.d3,
+            colors = config.data_colors,
+            pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.scale.category10().range(),
+            callback = config.data_color,
+            ids = [];
+
+        return function (d) {
+            var id = d.id || d, color;
+
+            // if callback function is provided
+            if (colors[id] instanceof Function) {
+                color = colors[id](d);
+            }
+            // if specified, choose that color
+            else if (colors[id]) {
+                color = colors[id];
+            }
+            // if not specified, choose from pattern
+            else {
+                if (ids.indexOf(id) < 0) { ids.push(id); }
+                color = pattern[ids.indexOf(id) % pattern.length];
+                colors[id] = color;
+            }
+            return callback instanceof Function ? callback(color, d) : color;
+        };
+    };
+    c3_chart_internal_fn.generateLevelColor = function () {
+        var $$ = this, config = $$.config,
+            colors = config.color_pattern,
+            threshold = config.color_threshold,
+            asValue = threshold.unit === 'value',
+            values = threshold.values && threshold.values.length ? threshold.values : [],
+            max = threshold.max || 100;
+        return notEmpty(config.color_threshold) ? function (value) {
+            var i, v, color = colors[colors.length - 1];
+            for (i = 0; i < values.length; i++) {
+                v = asValue ? value : (value * 100 / max);
+                if (v < values[i]) {
+                    color = colors[i];
+                    break;
+                }
+            }
+            return color;
+        } : null;
+    };
+
+    c3_chart_internal_fn.getYFormat = function (forArc) {
+        var $$ = this,
+            formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
+            formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
+        return function (v, ratio, id) {
+            var format = $$.getAxisId(id) === 'y2' ? formatForY2 : formatForY;
+            return format.call($$, v, ratio);
+        };
+    };
+    c3_chart_internal_fn.yFormat = function (v) {
+        var $$ = this, config = $$.config,
+            format = config.axis_y_tick_format ? config.axis_y_tick_format : $$.defaultValueFormat;
+        return format(v);
+    };
+    c3_chart_internal_fn.y2Format = function (v) {
+        var $$ = this, config = $$.config,
+            format = config.axis_y2_tick_format ? config.axis_y2_tick_format : $$.defaultValueFormat;
+        return format(v);
+    };
+    c3_chart_internal_fn.defaultValueFormat = function (v) {
+        return isValue(v) ? +v : "";
+    };
+    c3_chart_internal_fn.defaultArcValueFormat = function (v, ratio) {
+        return (ratio * 100).toFixed(1) + '%';
+    };
+    c3_chart_internal_fn.formatByAxisId = function (axisId) {
+        var $$ = this, data_labels = $$.config.data_labels,
+            format = function (v) { return isValue(v) ? +v : ""; };
+        // find format according to axis id
+        if (typeof data_labels.format === 'function') {
+            format = data_labels.format;
+        } else if (typeof data_labels.format === 'object') {
+            if (data_labels.format[axisId]) {
+                format = data_labels.format[axisId];
+            }
+        }
+        return format;
+    };
+
+    c3_chart_internal_fn.hasCaches = function (ids) {
+        for (var i = 0; i < ids.length; i++) {
+            if (! (ids[i] in this.cache)) { return false; }
+        }
+        return true;
+    };
+    c3_chart_internal_fn.addCache = function (id, target) {
+        this.cache[id] = this.cloneTarget(target);
+    };
+    c3_chart_internal_fn.getCaches = function (ids) {
+        var targets = [], i;
+        for (i = 0; i < ids.length; i++) {
+            if (ids[i] in this.cache) { targets.push(this.cloneTarget(this.cache[ids[i]])); }
+        }
+        return targets;
+    };
+
+    var CLASS = c3_chart_internal_fn.CLASS = {
+        target: 'c3-target',
+        chart: 'c3-chart',
+        chartLine: 'c3-chart-line',
+        chartLines: 'c3-chart-lines',
+        chartBar: 'c3-chart-bar',
+        chartBars: 'c3-chart-bars',
+        chartText: 'c3-chart-text',
+        chartTexts: 'c3-chart-texts',
+        chartArc: 'c3-chart-arc',
+        chartArcs: 'c3-chart-arcs',
+        chartArcsTitle: 'c3-chart-arcs-title',
+        chartArcsBackground: 'c3-chart-arcs-background',
+        chartArcsGaugeUnit: 'c3-chart-arcs-gauge-unit',
+        chartArcsGaugeMax: 'c3-chart-arcs-gauge-max',
+        chartArcsGaugeMin: 'c3-chart-arcs-gauge-min',
+        selectedCircle: 'c3-selected-circle',
+        selectedCircles: 'c3-selected-circles',
+        eventRect: 'c3-event-rect',
+        eventRects: 'c3-event-rects',
+        eventRectsSingle: 'c3-event-rects-single',
+        eventRectsMultiple: 'c3-event-rects-multiple',
+        zoomRect: 'c3-zoom-rect',
+        brush: 'c3-brush',
+        focused: 'c3-focused',
+        defocused: 'c3-defocused',
+        region: 'c3-region',
+        regions: 'c3-regions',
+        tooltipContainer: 'c3-tooltip-container',
+        tooltip: 'c3-tooltip',
+        tooltipName: 'c3-tooltip-name',
+        shape: 'c3-shape',
+        shapes: 'c3-shapes',
+        line: 'c3-line',
+        lines: 'c3-lines',
+        bar: 'c3-bar',
+        bars: 'c3-bars',
+        circle: 'c3-circle',
+        circles: 'c3-circles',
+        arc: 'c3-arc',
+        arcs: 'c3-arcs',
+        area: 'c3-area',
+        areas: 'c3-areas',
+        empty: 'c3-empty',
+        text: 'c3-text',
+        texts: 'c3-texts',
+        gaugeValue: 'c3-gauge-value',
+        grid: 'c3-grid',
+        gridLines: 'c3-grid-lines',
+        xgrid: 'c3-xgrid',
+        xgrids: 'c3-xgrids',
+        xgridLine: 'c3-xgrid-line',
+        xgridLines: 'c3-xgrid-lines',
+        xgridFocus: 'c3-xgrid-focus',
+        ygrid: 'c3-ygrid',
+        ygrids: 'c3-ygrids',
+        ygridLine: 'c3-ygrid-line',
+        ygridLines: 'c3-ygrid-lines',
+        axis: 'c3-axis',
+        axisX: 'c3-axis-x',
+        axisXLabel: 'c3-axis-x-label',
+        axisY: 'c3-axis-y',
+        axisYLabel: 'c3-axis-y-label',
+        axisY2: 'c3-axis-y2',
+        axisY2Label: 'c3-axis-y2-label',
+        legendBackground: 'c3-legend-background',
+        legendItem: 'c3-legend-item',
+        legendItemEvent: 'c3-legend-item-event',
+        legendItemTile: 'c3-legend-item-tile',
+        legendItemHidden: 'c3-legend-item-hidden',
+        legendItemFocused: 'c3-legend-item-focused',
+        dragarea: 'c3-dragarea',
+        EXPANDED: '_expanded_',
+        SELECTED: '_selected_',
+        INCLUDED: '_included_'
+    };
+    c3_chart_internal_fn.generateClass = function (prefix, targetId) {
+        return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId);
+    };
+    c3_chart_internal_fn.classText = function (d) {
+        return this.generateClass(CLASS.text, d.index);
+    };
+    c3_chart_internal_fn.classTexts = function (d) {
+        return this.generateClass(CLASS.texts, d.id);
+    };
+    c3_chart_internal_fn.classShape = function (d) {
+        return this.generateClass(CLASS.shape, d.index);
+    };
+    c3_chart_internal_fn.classShapes = function (d) {
+        return this.generateClass(CLASS.shapes, d.id);
+    };
+    c3_chart_internal_fn.classLine = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.line, d.id);
+    };
+    c3_chart_internal_fn.classLines = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
+    };
+    c3_chart_internal_fn.classCircle = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
+    };
+    c3_chart_internal_fn.classCircles = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
+    };
+    c3_chart_internal_fn.classBar = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
+    };
+    c3_chart_internal_fn.classBars = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
+    };
+    c3_chart_internal_fn.classArc = function (d) {
+        return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
+    };
+    c3_chart_internal_fn.classArcs = function (d) {
+        return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
+    };
+    c3_chart_internal_fn.classArea = function (d) {
+        return this.classShape(d) + this.generateClass(CLASS.area, d.id);
+    };
+    c3_chart_internal_fn.classAreas = function (d) {
+        return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
+    };
+    c3_chart_internal_fn.classRegion = function (d, i) {
+        return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
+    };
+    c3_chart_internal_fn.classEvent = function (d) {
+        return this.generateClass(CLASS.eventRect, d.index);
+    };
+    c3_chart_internal_fn.classTarget = function (id) {
+        var $$ = this;
+        var additionalClassSuffix = $$.config.data_classes[id], additionalClass = '';
+        if (additionalClassSuffix) {
+            additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
+        }
+        return $$.generateClass(CLASS.target, id) + additionalClass;
+    };
+    c3_chart_internal_fn.classFocus = function (d) {
+        return this.classFocused(d) + this.classDefocused(d);
+    };
+    c3_chart_internal_fn.classFocused = function (d) {
+        return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
+    };
+    c3_chart_internal_fn.classDefocused = function (d) {
+        return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
+    };
+    c3_chart_internal_fn.classChartText = function (d) {
+        return CLASS.chartText + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartLine = function (d) {
+        return CLASS.chartLine + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartBar = function (d) {
+        return CLASS.chartBar + this.classTarget(d.id);
+    };
+    c3_chart_internal_fn.classChartArc = function (d) {
+        return CLASS.chartArc + this.classTarget(d.data.id);
+    };
+    c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
+        return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g, '-') : '';
+    };
+    c3_chart_internal_fn.selectorTarget = function (id, prefix) {
+        return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
+    };
+    c3_chart_internal_fn.selectorTargets = function (ids, prefix) {
+        var $$ = this;
+        ids = ids || [];
+        return ids.length ? ids.map(function (id) { return $$.selectorTarget(id, prefix); }) : null;
+    };
+    c3_chart_internal_fn.selectorLegend = function (id) {
+        return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
+    };
+    c3_chart_internal_fn.selectorLegends = function (ids) {
+        var $$ = this;
+        return ids && ids.length ? ids.map(function (id) { return $$.selectorLegend(id); }) : null;
+    };
+
+    var isValue = c3_chart_internal_fn.isValue = function (v) {
+        return v || v === 0;
+    },
+        isFunction = c3_chart_internal_fn.isFunction = function (o) {
+            return typeof o === 'function';
+        },
+        isString = c3_chart_internal_fn.isString = function (o) {
+            return typeof o === 'string';
+        },
+        isUndefined = c3_chart_internal_fn.isUndefined = function (v) {
+            return typeof v === 'undefined';
+        },
+        isDefined = c3_chart_internal_fn.isDefined = function (v) {
+            return typeof v !== 'undefined';
+        },
+        ceil10 = c3_chart_internal_fn.ceil10 = function (v) {
+            return Math.ceil(v / 10) * 10;
+        },
+        asHalfPixel = c3_chart_internal_fn.asHalfPixel = function (n) {
+            return Math.ceil(n) + 0.5;
+        },
+        diffDomain = c3_chart_internal_fn.diffDomain = function (d) {
+            return d[1] - d[0];
+        },
+        isEmpty = c3_chart_internal_fn.isEmpty = function (o) {
+            return !o || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
+        },
+        notEmpty = c3_chart_internal_fn.notEmpty = function (o) {
+            return Object.keys(o).length > 0;
+        },
+        getOption = c3_chart_internal_fn.getOption = function (options, key, defaultValue) {
+            return isDefined(options[key]) ? options[key] : defaultValue;
+        },
+        hasValue = c3_chart_internal_fn.hasValue = function (dict, value) {
+            var found = false;
+            Object.keys(dict).forEach(function (key) {
+                if (dict[key] === value) { found = true; }
+            });
+            return found;
+        },
+        getPathBox = c3_chart_internal_fn.getPathBox = function (path) {
+            var box = path.getBoundingClientRect(),
+                items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
+                minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
+            return {x: minX, y: minY, width: box.width, height: box.height};
+        };
+
+    c3_chart_fn.focus = function (targetIds) {
+        var $$ = this.internal, candidates;
+
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
+
+        this.revert();
+        this.defocus();
+        candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
+        if ($$.hasArcType()) {
+            $$.expandArc(targetIds);
+        }
+        $$.toggleFocusLegend(targetIds, true);
+
+        $$.focusedTargetIds = targetIds;
+        $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
+            return targetIds.indexOf(id) < 0;
+        });
+    };
+
+    c3_chart_fn.defocus = function (targetIds) {
+        var $$ = this.internal, candidates;
+
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
+
+        this.revert();
+        candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
+        if ($$.hasArcType()) {
+            $$.unexpandArc(targetIds);
+        }
+        $$.toggleFocusLegend(targetIds, false);
+
+        $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
+            return targetIds.indexOf(id) < 0;
+        });
+        $$.defocusedTargetIds = targetIds;
+    };
+
+    c3_chart_fn.revert = function (targetIds) {
+        var $$ = this.internal, candidates;
+
+        targetIds = $$.mapToTargetIds(targetIds);
+        candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
+
+        candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
+        if ($$.hasArcType()) {
+            $$.unexpandArc(targetIds);
+        }
+        $$.showLegend(targetIds);
+
+        $$.focusedTargetIds = [];
+        $$.defocusedTargetIds = [];
+    };
+
+    c3_chart_fn.show = function (targetIds, options) {
+        var $$ = this.internal, targets;
+
+        targetIds = $$.mapToTargetIds(targetIds);
+        options = options || {};
+
+        $$.removeHiddenTargetIds(targetIds);
+        targets = $$.svg.selectAll($$.selectorTargets(targetIds));
+
+        targets.transition()
+            .style('opacity', 1, 'important')
+            .call($$.endall, function () {
+                targets.style('opacity', null).style('opacity', 1);
+            });
+
+        if (options.withLegend) {
+            $$.showLegend(targetIds);
+        }
+
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+    };
+
+    c3_chart_fn.hide = function (targetIds, options) {
+        var $$ = this.internal, targets;
+
+        targetIds = $$.mapToTargetIds(targetIds);
+        options = options || {};
+
+        $$.addHiddenTargetIds(targetIds);
+        targets = $$.svg.selectAll($$.selectorTargets(targetIds));
+
+        targets.transition()
+            .style('opacity', 0, 'important')
+            .call($$.endall, function () {
+                targets.style('opacity', null).style('opacity', 0);
+            });
+
+        if (options.withLegend) {
+            $$.hideLegend(targetIds);
+        }
+
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+    };
+
+    c3_chart_fn.toggle = function (targetIds) {
+        var that = this, $$ = this.internal;
+        $$.mapToTargetIds(targetIds).forEach(function (targetId) {
+            $$.isTargetToShow(targetId) ? that.hide(targetId) : that.show(targetId);
+        });
+    };
+
+    c3_chart_fn.zoom = function (domain) {
+        var $$ = this.internal;
+        if (domain) {
+            if ($$.isTimeSeries()) {
+                domain = domain.map(function (x) { return $$.parseDate(x); });
+            }
+            $$.brush.extent(domain);
+            $$.redraw({withUpdateXDomain: true, withY: $$.config.zoom_rescale});
+            $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
+        }
+        return $$.brush.extent();
+    };
+    c3_chart_fn.zoom.enable = function (enabled) {
+        var $$ = this.internal;
+        $$.config.zoom_enabled = enabled;
+        $$.updateAndRedraw();
+    };
+    c3_chart_fn.unzoom = function () {
+        var $$ = this.internal;
+        $$.brush.clear().update();
+        $$.redraw({withUpdateXDomain: true});
+    };
+
+    c3_chart_fn.load = function (args) {
+        var $$ = this.internal, config = $$.config;
+        // update xs if specified
+        if (args.xs) {
+            $$.addXs(args.xs);
+        }
+        // update classes if exists
+        if ('classes' in args) {
+            Object.keys(args.classes).forEach(function (id) {
+                config.data_classes[id] = args.classes[id];
+            });
+        }
+        // update categories if exists
+        if ('categories' in args && $$.isCategorized()) {
+            config.axis_x_categories = args.categories;
+        }
+        // update axes if exists
+        if ('axes' in args) {
+            Object.keys(args.axes).forEach(function (id) {
+                config.data_axes[id] = args.axes[id];
+            });
+        }
+        // use cache if exists
+        if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
+            $$.load($$.getCaches(args.cacheIds), args.done);
+            return;
+        }
+        // unload if needed
+        if ('unload' in args) {
+            // TODO: do not unload if target will load (included in url/rows/columns)
+            $$.unload($$.mapToTargetIds((typeof args.unload === 'boolean' && args.unload) ? null : args.unload), function () {
+                $$.loadFromArgs(args);
+            });
+        } else {
+            $$.loadFromArgs(args);
+        }
+    };
+
+    c3_chart_fn.unload = function (args) {
+        var $$ = this.internal;
+        args = args || {};
+        if (args instanceof Array) {
+            args = {ids: args};
+        } else if (typeof args === 'string') {
+            args = {ids: [args]};
+        }
+        $$.unload($$.mapToTargetIds(args.ids), function () {
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+            if (args.done) { args.done(); }
+        });
+    };
+
+    c3_chart_fn.flow = function (args) {
+        var $$ = this.internal,
+            targets, data, notfoundIds = [], orgDataCount = $$.getMaxDataCount(),
+            dataCount, domain, baseTarget, baseValue, length = 0, tail = 0, diff, to;
+
+        if (args.json) {
+            data = $$.convertJsonToData(args.json, args.keys);
+        }
+        else if (args.rows) {
+            data = $$.convertRowsToData(args.rows);
+        }
+        else if (args.columns) {
+            data = $$.convertColumnsToData(args.columns);
+        }
+        else {
+            return;
+        }
+        targets = $$.convertDataToTargets(data, true);
+
+        // Update/Add data
+        $$.data.targets.forEach(function (t) {
+            var found = false, i, j;
+            for (i = 0; i < targets.length; i++) {
+                if (t.id === targets[i].id) {
+                    found = true;
+
+                    if (t.values[t.values.length - 1]) {
+                        tail = t.values[t.values.length - 1].index + 1;
+                    }
+                    length = targets[i].values.length;
+
+                    for (j = 0; j < length; j++) {
+                        targets[i].values[j].index = tail + j;
+                        if (!$$.isTimeSeries()) {
+                            targets[i].values[j].x = tail + j;
+                        }
+                    }
+                    t.values = t.values.concat(targets[i].values);
+
+                    targets.splice(i, 1);
+                    break;
+                }
+            }
+            if (!found) { notfoundIds.push(t.id); }
+        });
+
+        // Append null for not found targets
+        $$.data.targets.forEach(function (t) {
+            var i, j;
+            for (i = 0; i < notfoundIds.length; i++) {
+                if (t.id === notfoundIds[i]) {
+                    tail = t.values[t.values.length - 1].index + 1;
+                    for (j = 0; j < length; j++) {
+                        t.values.push({
+                            id: t.id,
+                            index: tail + j,
+                            x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
+                            value: null
+                        });
+                    }
+                }
+            }
+        });
+
+        // Generate null values for new target
+        if ($$.data.targets.length) {
+            targets.forEach(function (t) {
+                var i, missing = [];
+                for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
+                    missing.push({
+                        id: t.id,
+                        index: i,
+                        x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
+                        value: null
+                    });
+                }
+                t.values.forEach(function (v) {
+                    v.index += tail;
+                    if (!$$.isTimeSeries()) {
+                        v.x += tail;
+                    }
+                });
+                t.values = missing.concat(t.values);
+            });
+        }
+        $$.data.targets = $$.data.targets.concat(targets); // add remained
+
+        // check data count because behavior needs to change when it's only one
+        dataCount = $$.getMaxDataCount();
+        baseTarget = $$.data.targets[0];
+        baseValue = baseTarget.values[0];
+
+        // Update length to flow if needed
+        if (isDefined(args.to)) {
+            length = 0;
+            to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
+            baseTarget.values.forEach(function (v) {
+                if (v.x < to) { length++; }
+            });
+        } else if (isDefined(args.length)) {
+            length = args.length;
+        }
+
+        // If only one data, update the domain to flow from left edge of the chart
+        if (!orgDataCount) {
+            if ($$.isTimeSeries()) {
+                if (baseTarget.values.length > 1) {
+                    diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
+                } else {
+                    diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
+                }
+            } else {
+                diff = 1;
+            }
+            domain = [baseValue.x - diff, baseValue.x];
+            $$.updateXDomain(null, true, true, false, domain);
+        } else if (orgDataCount === 1) {
+            if ($$.isTimeSeries()) {
+                diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
+                domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
+                $$.updateXDomain(null, true, true, false, domain);
+            }
+        }
+
+        // Set targets
+        $$.updateTargets($$.data.targets);
+
+        // Redraw with new targets
+        $$.redraw({
+            flow: {
+                index: baseValue.index,
+                length: length,
+                duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
+                done: args.done,
+                orgDataCount: orgDataCount,
+            },
+            withLegend: true,
+            withTransition: orgDataCount > 1,
+            withTrimXDomain: false,
+            withUpdateXAxis: true,
+        });
+    };
+
+    c3_chart_internal_fn.generateFlow = function (args) {
+        var $$ = this, config = $$.config, d3 = $$.d3;
+
+        return function () {
+            var targets = args.targets,
+                flow = args.flow,
+                drawBar = args.drawBar,
+                drawLine = args.drawLine,
+                drawArea = args.drawArea,
+                cx = args.cx,
+                cy = args.cy,
+                xv = args.xv,
+                xForText = args.xForText,
+                yForText = args.yForText,
+                duration = args.duration;
+
+            var translateX, scaleX = 1, transform,
+                flowIndex = flow.index,
+                flowLength = flow.length,
+                flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
+                flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
+                orgDomain = $$.x.domain(), domain,
+                durationForFlow = flow.duration || duration,
+                done = flow.done || function () {},
+                wait = $$.generateWait();
+
+            var xgrid = $$.xgrid || d3.selectAll([]),
+                xgridLines = $$.xgridLines || d3.selectAll([]),
+                mainRegion = $$.mainRegion || d3.selectAll([]),
+                mainText = $$.mainText || d3.selectAll([]),
+                mainBar = $$.mainBar || d3.selectAll([]),
+                mainLine = $$.mainLine || d3.selectAll([]),
+                mainArea = $$.mainArea || d3.selectAll([]),
+                mainCircle = $$.mainCircle || d3.selectAll([]);
+
+            // set flag
+            $$.flowing = true;
+
+            // remove head data after rendered
+            $$.data.targets.forEach(function (d) {
+                d.values.splice(0, flowLength);
+            });
+
+            // update x domain to generate axis elements for flow
+            domain = $$.updateXDomain(targets, true, true);
+            // update elements related to x scale
+            if ($$.updateXGrid) { $$.updateXGrid(true); }
+
+            // generate transform to flow
+            if (!flow.orgDataCount) { // if empty
+                if ($$.data.targets[0].values.length !== 1) {
+                    translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+                } else {
+                    if ($$.isTimeSeries()) {
+                        flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
+                        flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
+                        translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
+                    } else {
+                        translateX = diffDomain(domain) / 2;
+                    }
+                }
+            } else if (flow.orgDataCount === 1 || flowStart.x === flowEnd.x) {
+                translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+            } else {
+                if ($$.isTimeSeries()) {
+                    translateX = ($$.x(orgDomain[0]) - $$.x(domain[0]));
+                } else {
+                    translateX = ($$.x(flowStart.x) - $$.x(flowEnd.x));
+                }
+            }
+            scaleX = (diffDomain(orgDomain) / diffDomain(domain));
+            transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
+
+            // hide tooltip
+            $$.hideXGridFocus();
+            $$.hideTooltip();
+
+            d3.transition().ease('linear').duration(durationForFlow).each(function () {
+                wait.add($$.axes.x.transition().call($$.xAxis));
+                wait.add(mainBar.transition().attr('transform', transform));
+                wait.add(mainLine.transition().attr('transform', transform));
+                wait.add(mainArea.transition().attr('transform', transform));
+                wait.add(mainCircle.transition().attr('transform', transform));
+                wait.add(mainText.transition().attr('transform', transform));
+                wait.add(mainRegion.filter($$.isRegionOnX).transition().attr('transform', transform));
+                wait.add(xgrid.transition().attr('transform', transform));
+                wait.add(xgridLines.transition().attr('transform', transform));
+            })
+            .call(wait, function () {
+                var i, shapes = [], texts = [], eventRects = [];
+
+                // remove flowed elements
+                if (flowLength) {
+                    for (i = 0; i < flowLength; i++) {
+                        shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
+                        texts.push('.' + CLASS.text + '-' + (flowIndex + i));
+                        eventRects.push('.' + CLASS.eventRect + '-' + (flowIndex + i));
+                    }
+                    $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
+                    $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
+                    $$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove();
+                    $$.svg.select('.' + CLASS.xgrid).remove();
+                }
+
+<<<<<<< HEAD
+            // Set targets
+            updateTargets(c3.data.targets);
+
+            // Redraw with new targets
+            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
+
+            if (typeof args.done === 'function') {
+                args.done();
+            }
+        }
+        function loadFromArgs(args) {
+            // load data
+            if ('data' in args) {
+                load(convertDataToTargets(args.data), args);
+            }
+            else if ('url' in args) {
+                d3.csv(args.url, function (error, data) {
+                    load(convertDataToTargets(data), args);
+                });
+            }
+            else if ('rows' in args) {
+                load(convertDataToTargets(convertRowsToData(args.rows)), args);
+            }
+            else if ('columns' in args) {
+                load(convertDataToTargets(convertColumnsToData(args.columns)), args);
+            }
+            else {
+                throw Error('url or rows or columns is required.');
+            }
+        }
+=======
+                // draw again for removing flowed elements and reverting attr
+                xgrid
+                    .attr('transform', null)
+                    .attr($$.xgridAttr);
+                xgridLines
+                    .attr('transform', null);
+                xgridLines.select('line')
+                    .attr("x1", config.axis_rotated ? 0 : xv)
+                    .attr("x2", config.axis_rotated ? $$.width : xv);
+                xgridLines.select('text')
+                    .attr("x", config.axis_rotated ? $$.width : 0)
+                    .attr("y", xv);
+                mainBar
+                    .attr('transform', null)
+                    .attr("d", drawBar);
+                mainLine
+                    .attr('transform', null)
+                    .attr("d", drawLine);
+                mainArea
+                    .attr('transform', null)
+                    .attr("d", drawArea);
+                mainCircle
+                    .attr('transform', null)
+                    .attr("cx", cx)
+                    .attr("cy", cy);
+                mainText
+                    .attr('transform', null)
+                    .attr('x', xForText)
+                    .attr('y', yForText)
+                    .style('fill-opacity', $$.opacityForText.bind($$));
+                mainRegion
+                    .attr('transform', null);
+                mainRegion.select('rect').filter($$.isRegionOnX)
+                    .attr("x", $$.regionX.bind($$))
+                    .attr("width", $$.regionWidth.bind($$));
+
+                if (config.interaction_enabled) {
+                    $$.redrawEventRect();
+                }
+>>>>>>> upstream/master
+
+                // callback for end of flow
+                done();
+
+                $$.flowing = false;
+            });
+        };
+    };
+
+    c3_chart_fn.selected = function (targetId) {
+        var $$ = this.internal, d3 = $$.d3;
+        return d3.merge(
+            $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
+                .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
+                .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
+        );
+    };
+    c3_chart_fn.select = function (ids, indices, resetOther) {
+        var $$ = this.internal, d3 = $$.d3, config = $$.config;
+        if (! config.data_selection_enabled) { return; }
+        $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+            var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+                toggle = $$.getToggle(this, d).bind($$),
+                isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+                isTargetIndex = !indices || indices.indexOf(i) >= 0,
+                isSelected = shape.classed(CLASS.SELECTED);
+            // line/area selection not supported yet
+            if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+                return;
+            }
+            if (isTargetId && isTargetIndex) {
+                if (config.data_selection_isselectable(d) && !isSelected) {
+                    toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
+                }
+            } else if (isDefined(resetOther) && resetOther) {
+                if (isSelected) {
+                    toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+                }
+            }
+        });
+    };
+    c3_chart_fn.unselect = function (ids, indices) {
+        var $$ = this.internal, d3 = $$.d3, config = $$.config;
+        if (! config.data_selection_enabled) { return; }
+        $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+            var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+                toggle = $$.getToggle(this, d).bind($$),
+                isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+                isTargetIndex = !indices || indices.indexOf(i) >= 0,
+                isSelected = shape.classed(CLASS.SELECTED);
+            // line/area selection not supported yet
+            if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+                return;
+            }
+            if (isTargetId && isTargetIndex) {
+                if (config.data_selection_isselectable(d)) {
+                    if (isSelected) {
+                        toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+                    }
+                }
+            }
+        });
+    };
+
+    c3_chart_fn.transform = function (type, targetIds) {
+        var $$ = this.internal,
+            options = ['pie', 'donut'].indexOf(type) >= 0 ? {withTransform: true} : null;
+        $$.transformTo(targetIds, type, options);
+    };
+
+    c3_chart_internal_fn.transformTo = function (targetIds, type, optionsForRedraw) {
+        var $$ = this,
+            withTransitionForAxis = !$$.hasArcType(),
+            options = optionsForRedraw || {withTransitionForAxis: withTransitionForAxis};
+        options.withTransitionForTransform = false;
+        $$.transiting = false;
+        $$.setTargetType(targetIds, type);
+        $$.updateAndRedraw(options);
+    };
+
+    c3_chart_fn.groups = function (groups) {
+        var $$ = this.internal, config = $$.config;
+        if (isUndefined(groups)) { return config.data_groups; }
+        config.data_groups = groups;
+        $$.redraw();
+        return config.data_groups;
+    };
+
+    c3_chart_fn.xgrids = function (grids) {
+        var $$ = this.internal, config = $$.config;
+        if (! grids) { return config.grid_x_lines; }
+        config.grid_x_lines = grids;
+        $$.redrawWithoutRescale();
+        return config.grid_x_lines;
+    };
+    c3_chart_fn.xgrids.add = function (grids) {
+        var $$ = this.internal;
+        return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
+    };
+    c3_chart_fn.xgrids.remove = function (params) { // TODO: multiple
+        var $$ = this.internal;
+        $$.removeGridLines(params, true);
+    };
+
+    c3_chart_fn.ygrids = function (grids) {
+        var $$ = this.internal, config = $$.config;
+        if (! grids) { return config.grid_y_lines; }
+        config.grid_y_lines = grids;
+        $$.redrawWithoutRescale();
+        return config.grid_y_lines;
+    };
+    c3_chart_fn.ygrids.add = function (grids) {
+        var $$ = this.internal;
+        return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
+    };
+    c3_chart_fn.ygrids.remove = function (params) { // TODO: multiple
+        var $$ = this.internal;
+        $$.removeGridLines(params, false);
+    };
+
+    c3_chart_fn.regions = function (regions) {
+        var $$ = this.internal, config = $$.config;
+        if (!regions) { return config.regions; }
+        config.regions = regions;
+        $$.redrawWithoutRescale();
+        return config.regions;
+    };
+    c3_chart_fn.regions.add = function (regions) {
+        var $$ = this.internal, config = $$.config;
+        if (!regions) { return config.regions; }
+        config.regions = config.regions.concat(regions);
+        $$.redrawWithoutRescale();
+        return config.regions;
+    };
+    c3_chart_fn.regions.remove = function (options) {
+        var $$ = this.internal, config = $$.config,
+            duration, classes, regions;
+
+        options = options || {};
+        duration = $$.getOption(options, "duration", config.transition_duration);
+        classes = $$.getOption(options, "classes", [CLASS.region]);
+
+        regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) { return '.' + c; }));
+        (duration ? regions.transition().duration(duration) : regions)
+            .style('opacity', 0)
+            .remove();
+
+        config.regions = config.regions.filter(function (region) {
+            var found = false;
+            if (!region['class']) {
+                return true;
+            }
+            region['class'].split(' ').forEach(function (c) {
+                if (classes.indexOf(c) >= 0) { found = true; }
+            });
+            return !found;
+        });
+
+        return config.regions;
+    };
+
+    c3_chart_fn.data = function (targetIds) {
+        var targets = this.internal.data.targets;
+        return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
+            return [].concat(targetIds).indexOf(t.id) >= 0;
+        });
+    };
+    c3_chart_fn.data.shown = function (targetIds) {
+        return this.internal.filterTargetsToShow(this.data(targetIds));
+    };
+    c3_chart_fn.data.values = function (targetId) {
+        var targets, values = null;
+        if (targetId) {
+            targets = this.data(targetId);
+            values = targets[0] ? targets[0].values.map(function (d) { return d.value; }) : null;
+        }
+        return values;
+    };
+    c3_chart_fn.data.names = function (names) {
+        this.internal.clearLegendItemTextBoxCache();
+        return this.internal.updateDataAttributes('names', names);
+    };
+    c3_chart_fn.data.colors = function (colors) {
+        return this.internal.updateDataAttributes('colors', colors);
+    };
+    c3_chart_fn.data.axes = function (axes) {
+        return this.internal.updateDataAttributes('axes', axes);
+    };
+
+    c3_chart_fn.category = function (i, category) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length > 1) {
+            config.axis_x_categories[i] = category;
+            $$.redraw();
+        }
+        return config.axis_x_categories[i];
+    };
+    c3_chart_fn.categories = function (categories) {
+        var $$ = this.internal, config = $$.config;
+        if (!arguments.length) { return config.axis_x_categories; }
+        config.axis_x_categories = categories;
+        $$.redraw();
+        return config.axis_x_categories;
+    };
+
+    // TODO: fix
+    c3_chart_fn.color = function (id) {
+        var $$ = this.internal;
+        return $$.color(id); // more patterns
+    };
+
+    c3_chart_fn.x = function (x) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            $$.updateTargetX($$.data.targets, x);
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        }
+        return $$.data.xs;
+    };
+    c3_chart_fn.xs = function (xs) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            $$.updateTargetXs($$.data.targets, xs);
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        }
+        return $$.data.xs;
+    };
+
+    c3_chart_fn.axis = function () {};
+    c3_chart_fn.axis.labels = function (labels) {
+        var $$ = this.internal;
+        if (arguments.length) {
+            Object.keys(labels).forEach(function (axisId) {
+                $$.setAxisLabelText(axisId, labels[axisId]);
+            });
+            $$.updateAxisLabels();
+        }
+        // TODO: return some values?
+    };
+    c3_chart_fn.axis.max = function (max) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length) {
+            if (typeof max === 'object') {
+                if (isValue(max.x)) { config.axis_x_max = max.x; }
+                if (isValue(max.y)) { config.axis_y_max = max.y; }
+                if (isValue(max.y2)) { config.axis_y2_max = max.y2; }
+            } else {
+                config.axis_y_max = config.axis_y2_max = max;
+            }
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        } else {
+            return {
+                x: config.axis_x_max,
+                y: config.axis_y_max,
+                y2: config.axis_y2_max
+            };
+        }
+    };
+    c3_chart_fn.axis.min = function (min) {
+        var $$ = this.internal, config = $$.config;
+        if (arguments.length) {
+            if (typeof min === 'object') {
+                if (isValue(min.x)) { config.axis_x_min = min.x; }
+                if (isValue(min.y)) { config.axis_y_min = min.y; }
+                if (isValue(min.y2)) { config.axis_y2_min = min.y2; }
+            } else {
+                config.axis_y_min = config.axis_y2_min = min;
+            }
+            $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+        } else {
+            return {
+                x: config.axis_x_min,
+                y: config.axis_y_min,
+                y2: config.axis_y2_min
+            };
+        }
+    };
+    c3_chart_fn.axis.range = function (range) {
+        if (arguments.length) {
+            if (isDefined(range.max)) { this.axis.max(range.max); }
+            if (isDefined(range.min)) { this.axis.min(range.min); }
+        } else {
+            return {
+                max: this.axis.max(),
+                min: this.axis.min()
+            };
+        }
+    };
+
+    c3_chart_fn.legend = function () {};
+    c3_chart_fn.legend.show = function (targetIds) {
+        var $$ = this.internal;
+        $$.showLegend($$.mapToTargetIds(targetIds));
+        $$.updateAndRedraw({withLegend: true});
+    };
+    c3_chart_fn.legend.hide = function (targetIds) {
+        var $$ = this.internal;
+        $$.hideLegend($$.mapToTargetIds(targetIds));
+        $$.updateAndRedraw({withLegend: true});
+    };
+
+    c3_chart_fn.resize = function (size) {
+        var $$ = this.internal, config = $$.config;
+        config.size_width = size ? size.width : null;
+        config.size_height = size ? size.height : null;
+        this.flush();
+    };
+
+    c3_chart_fn.flush = function () {
+        var $$ = this.internal;
+        $$.updateAndRedraw({withLegend: true, withTransition: false, withTransitionForTransform: false});
+    };
+
+<<<<<<< HEAD
+            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
+        };
+=======
+    c3_chart_fn.destroy = function () {
+        var $$ = this.internal;
+        $$.data.targets = undefined;
+        $$.data.xs = {};
+        $$.selectChart.classed('c3', false).html("");
+        window.clearInterval($$.intervalForObserveInserted);
+        window.onresize = null;
+    };
+>>>>>>> upstream/master
+
+    c3_chart_fn.tooltip = function () {};
+    c3_chart_fn.tooltip.show = function (args) {
+        var $$ = this.internal, index, mouse;
+
+        // determine mouse position on the chart
+        if (args.mouse) {
+            mouse = args.mouse;
+        }
+
+        // determine focus data
+        if (args.data) {
+            if ($$.isMultipleX()) {
+                // if multiple xs, target point will be determined by mouse
+                mouse = [$$.x(args.data.x), $$.getYScale(args.data.id)(args.data.value)];
+                index = null;
+            } else {
+                // TODO: when tooltip_grouped = false
+                index = isValue(args.data.index) ? args.data.index : $$.getIndexByX(args.data.x);
+            }
+        }
+        else if (typeof args.x !== 'undefined') {
+            index = $$.getIndexByX(args.x);
+        }
+        else if (typeof args.index !== 'undefined') {
+            index = args.index;
+        }
+
+<<<<<<< HEAD
+            redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
+        };
+=======
+        // emulate mouse events to show
+        $$.dispatchEvent('mouseover', index, mouse);
+        $$.dispatchEvent('mousemove', index, mouse);
+    };
+    c3_chart_fn.tooltip.hide = function () {
+        // TODO: get target data by checking the state of focus
+        this.internal.dispatchEvent('mouseout', 0);
+    };
+>>>>>>> upstream/master
+
+    // Features:
+    // 1. category axis
+    // 2. ceil values of translate/x/y to int for half pixel antialiasing
+    // 3. multiline tick text
+    var tickTextCharSize;
+    function c3_axis(d3, params) {
+        var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
+
+        var tickOffset = 0, tickCulling = true, tickCentered;
+
+        params = params || {};
+        outerTickSize = params.withOuterTick ? 6 : 0;
+
+        function axisX(selection, x) {
+            selection.attr("transform", function (d) {
+                return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
+            });
+        }
+        function axisY(selection, y) {
+            selection.attr("transform", function (d) {
+                return "translate(0," + Math.ceil(y(d)) + ")";
+            });
+        }
+        function scaleExtent(domain) {
+            var start = domain[0], stop = domain[domain.length - 1];
+            return start < stop ? [ start, stop ] : [ stop, start ];
+        }
+        function generateTicks(scale) {
+            var i, domain, ticks = [];
+            if (scale.ticks) {
+                return scale.ticks.apply(scale, tickArguments);
+            }
+            domain = scale.domain();
+            for (i = Math.ceil(domain[0]); i < domain[1]; i++) {
+                ticks.push(i);
+            }
+            if (ticks.length > 0 && ticks[0] > 0) {
+                ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
+            }
+            return ticks;
+        }
+        function copyScale() {
+            var newScale = scale.copy(), domain;
+            if (params.isCategory) {
+                domain = scale.domain();
+                newScale.domain([domain[0], domain[1] - 1]);
+            }
+            return newScale;
+        }
+        function textFormatted(v) {
+            return tickFormat ? tickFormat(v) : v;
+        }
+        function getSizeFor1Char(tick) {
+            if (tickTextCharSize) {
+                return tickTextCharSize;
+            }
+<<<<<<< HEAD
+        };
+
+        c3.unload = function (targetIds, done) {
+            unload(mapToTargetIds(targetIds), function () {
+                redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: __legend_show});
+            });
+        };
+
+        c3.selected = function (targetId) {
+            return d3.merge(
+                main.selectAll('.' + CLASS.shapes + getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
+                    .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
+                    .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
+            );
+        };
+
+        c3.select = function (ids, indices, resetOther) {
+            if (! __data_selection_enabled) { return; }
+            main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+                var shape = d3.select(this), id = d.data ? d.data.id : d.id, toggle = getToggle(this),
+                    isTargetId = __data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+                    isTargetIndex = !indices || indices.indexOf(i) >= 0,
+                    isSelected = shape.classed(CLASS.SELECTED);
+                if (isTargetId && isTargetIndex) {
+                    if (__data_selection_isselectable(d) && !isSelected) {
+                        toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
+                    }
+                } else if (isDefined(resetOther) && resetOther) {
+                    if (isSelected) {
+                        toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+                    }
+=======
+            var size = {
+                h: 11.5,
+                w: 5.5
+            };
+            tick.select('text').text(textFormatted).each(function (d) {
+                var box = this.getBoundingClientRect(),
+                    text = textFormatted(d),
+                    h = box.height,
+                    w = text ? (box.width / text.length) : undefined;
+                if (h && w) {
+                    size.h = h;
+                    size.w = w;
+>>>>>>> upstream/master
+                }
+            }).text('');
+            tickTextCharSize = size;
+            return size;
+        }
+        function axis(g) {
+            g.each(function () {
+                var g = d3.select(this);
+                var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale();
+
+                var ticks = tickValues ? tickValues : generateTicks(scale1),
+                    tick = g.selectAll(".tick").data(ticks, scale1),
+                    tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
+                    // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
+                    tickExit = tick.exit().remove(),
+                    tickUpdate = d3.transition(tick).style("opacity", 1),
+                    tickTransform, tickX, tickY;
+
+                var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
+                    path = g.selectAll(".domain").data([ 0 ]),
+                    pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path));
+                tickEnter.append("line");
+                tickEnter.append("text");
+
+                var lineEnter = tickEnter.select("line"),
+                    lineUpdate = tickUpdate.select("line"),
+                    textEnter = tickEnter.select("text"),
+                    textUpdate = tickUpdate.select("text");
+
+                if (params.isCategory) {
+                    tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
+                    tickX = tickCentered ? 0 : tickOffset;
+                    tickY = tickCentered ? tickOffset : 0;
+                } else {
+                    tickOffset = tickX = 0;
+                }
+
+                var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = [];
+                var tickLength = Math.max(innerTickSize, 0) + tickPadding,
+                    isVertical = orient === 'left' || orient === 'right';
+
+                // this should be called only when category axis
+                function splitTickText(d, maxWidth) {
+                    var tickText = textFormatted(d),
+                        subtext, spaceIndex, textWidth, splitted = [];
+
+                    if (Object.prototype.toString.call(tickText) === "[object Array]") {
+                        return tickText;
+                    }
+
+                    if (!maxWidth || maxWidth <= 0) {
+                        maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110;
+                    }
+
+                    function split(splitted, text) {
+                        spaceIndex = undefined;
+                        for (var i = 1; i < text.length; i++) {
+                            if (text.charAt(i) === ' ') {
+                                spaceIndex = i;
+                            }
+                            subtext = text.substr(0, i + 1);
+                            textWidth = sizeFor1Char.w * subtext.length;
+                            // if text width gets over tick width, split by space index or crrent index
+                            if (maxWidth < textWidth) {
+                                return split(
+                                    splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)),
+                                    text.slice(spaceIndex ? spaceIndex + 1 : i)
+                                );
+                            }
+                        }
+                        return splitted.concat(text);
+                    }
+
+                    return split(splitted, tickText + "");
+                }
+
+                function tspanDy(d, i) {
+                    var dy = sizeFor1Char.h;
+                    if (i === 0) {
+                        if (orient === 'left' || orient === 'right') {
+                            dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - (params.isCategory ? 2 : 3));
+                        } else {
+                            dy = ".71em";
+                        }
+                    }
+                    return dy;
+                }
+
+                function tickSize(d) {
+                    var tickPosition = scale(d) + tickOffset;
+                    return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0;
+                }
+
+                text = tick.select("text");
+                tspan = text.selectAll('tspan')
+                    .data(function (d, i) {
+                        var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
+                        counts[i] = splitted.length;
+                        return splitted.map(function (s) {
+                            return { index: i, splitted: s };
+                        });
+                    });
+                tspan.enter().append('tspan');
+                tspan.exit().remove();
+                tspan.text(function (d) { return d.splitted; });
+
+                switch (orient) {
+                case "bottom":
+                    {
+                        tickTransform = axisX;
+                        lineEnter.attr("y2", innerTickSize);
+                        textEnter.attr("y", tickLength);
+                        lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
+                        textUpdate.attr("x", 0).attr("y", tickLength);
+                        text.style("text-anchor", "middle");
+                        tspan.attr('x', 0).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+                        break;
+                    }
+                case "top":
+                    {
+                        tickTransform = axisX;
+                        lineEnter.attr("y2", -innerTickSize);
+                        textEnter.attr("y", -tickLength);
+                        lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+                        textUpdate.attr("x", 0).attr("y", -tickLength);
+                        text.style("text-anchor", "middle");
+                        tspan.attr('x', 0).attr("dy", "0em");
+                        pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+                        break;
+                    }
+                case "left":
+                    {
+                        tickTransform = axisY;
+                        lineEnter.attr("x2", -innerTickSize);
+                        textEnter.attr("x", -tickLength);
+                        lineUpdate.attr("x2", -innerTickSize).attr("y1", tickY).attr("y2", tickY);
+                        textUpdate.attr("x", -tickLength).attr("y", tickOffset);
+                        text.style("text-anchor", "end");
+                        tspan.attr('x', -tickLength).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+                        break;
+                    }
+                case "right":
+                    {
+                        tickTransform = axisY;
+                        lineEnter.attr("x2", innerTickSize);
+                        textEnter.attr("x", tickLength);
+                        lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+                        textUpdate.attr("x", tickLength).attr("y", 0);
+                        text.style("text-anchor", "start");
+                        tspan.attr('x', tickLength).attr("dy", tspanDy);
+                        pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
+                        break;
+                    }
+                }
+                if (scale1.rangeBand) {
+                    var x = scale1, dx = x.rangeBand() / 2;
+                    scale0 = scale1 = function (d) {
+                        return x(d) + dx;
+                    };
+                } else if (scale0.rangeBand) {
+                    scale0 = scale1;
+                } else {
+                    tickExit.call(tickTransform, scale1);
+                }
+                tickEnter.call(tickTransform, scale0);
+                tickUpdate.call(tickTransform, scale1);
+            });
+        }
+        axis.scale = function (x) {
+            if (!arguments.length) { return scale; }
+            scale = x;
+            return axis;
+        };
+        axis.orient = function (x) {
+            if (!arguments.length) { return orient; }
+            orient = x in {top: 1, right: 1, bottom: 1, left: 1} ? x + "" : "bottom";
+            return axis;
+        };
+        axis.tickFormat = function (format) {
+            if (!arguments.length) { return tickFormat; }
+            tickFormat = format;
+            return axis;
+        };
+        axis.tickCentered = function (isCentered) {
+            if (!arguments.length) { return tickCentered; }
+            tickCentered = isCentered;
+            return axis;
+        };
+        axis.tickOffset = function () { // This will be overwritten when normal x axis
+            return tickOffset;
+        };
+        axis.ticks = function () {
+            if (!arguments.length) { return tickArguments; }
+            tickArguments = arguments;
+            return axis;
+        };
+        axis.tickCulling = function (culling) {
+            if (!arguments.length) { return tickCulling; }
+            tickCulling = culling;
+            return axis;
+        };
+        axis.tickValues = function (x) {
+            if (typeof x === 'function') {
+                tickValues = function () {
+                    return x(scale.domain());
+                };
+            }
+            else {
+                if (!arguments.length) { return tickValues; }
+                tickValues = x;
+            }
+            return axis;
+        };
+<<<<<<< HEAD
+
+        c3.legend.show = function (targetIds) {
+            showLegend(mapToTargetIds(targetIds));
+            redraw({withLegend: __legend_show});
+        };
+        c3.legend.hide = function (targetIds) {
+            hideLegend(mapToTargetIds(targetIds));
+            redraw({withLegend: true});
+        };
+
+        c3.resize = function (size) {
+            __size_width = size ? size.width : null;
+            __size_height = size ? size.height : null;
+            updateAndRedraw({withLegend: __legend_show, withTransition: false, withTransitionForTransform: false});
+        };
+
+        c3.destroy = function () {
+            c3.data.targets = undefined;
+            c3.data.xs = {};
+            selectChart.html("");
+            window.onresize = null;
+        };
+
+        /*-- Load data and init chart with defined functions --*/
+
+        if ('url' in config.data) {
+            d3.xhr(config.data.url, function (error, data) {
+                // TODO: other mine/type
+                var rows = d3.csv.parseRows(data.response), d;
+                if (rows.length === 1) {
+                    d = [{}];
+                    rows[0].forEach(function (id) {
+                        d[0][id] = null;
+                    });
+                } else {
+                    d = d3.csv.parse(data.response);
+                }
+                init(d);
+            });
+        }
+        else if ('rows' in config.data) {
+            init(convertRowsToData(config.data.rows));
+        }
+        else if ('columns' in config.data) {
+            init(convertColumnsToData(config.data.columns));
+        }
+        else {
+            throw Error('url or rows or columns is required.');
+        }
+
+        return c3;
+    };
+
+    function isValue(v) {
+        return v || v === 0;
+    }
+    function isUndefined(v) {
+        return typeof v === 'undefined';
+    }
+    function isDefined(v) {
+        return typeof v !== 'undefined';
+=======
+        return axis;
+>>>>>>> upstream/master
+    }
+
+    if (typeof define === 'function' && define.amd) {
+        define("c3", ["d3"], c3);
+    } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
+        module.exports = c3;
+    } else {
+        window.c3 = c3;
+    }
+
+})(window);
diff --git a/c3.min.css b/c3.min.css
new file mode 100644
index 0000000..a00ad48
--- /dev/null
+++ b/c3.min.css
@@ -0,0 +1 @@
+.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
\ No newline at end of file
diff --git a/c3.min.js b/c3.min.js
index 4fe0f02..724cf3e 100644
--- a/c3.min.js
+++ b/c3.min.js
@@ -1,3 +1,5 @@
-!function(a){"use strict";function b(a){return a||0===a}function c(a){return"undefined"==typeof a}function d(a){return"undefined"!=typeof a}var e={version:"0.1.34"},f={target:"c3-target",chart:"c3-chart",chartLine:"c3-chart-line",chartLines:"c3-chart-lines",chartBar:"c3-chart-bar",chartBars:"c3-chart-bars",chartText:"c3-chart-text",chartTexts:"c3-chart-texts",chartArc:"c3-chart-arc",chartArcs:"c3-chart-arcs",chartArcsTitle:"c3-chart-arcs-title",selectedCircle:"c3-selected-circle",selectedCircles:"c3-selected-circles",eventRect:"c3-event-rect",eventRects:"c3-event-rects",eventRectsSingle:"c3-event-rects-single",eventRectsMultiple:"c3-event-rects-multiple",zoomRect:"c3-zoom-rect",brush:"c3-brush",focused:"c3-focused",region:"c3-region",regions:"c3-regions",tooltip:"c3-tooltip",tooltipName:"c3-tooltip-name",shape:"c3-shape",shapes:"c3-shapes",line:"c3-line",lines:"c3-lines",bar:"c3-bar",bars:"c3-bars",circle:"c3-circle",circles:"c3-circles",arc:"c3-arc",arcs:"c3-arcs",area:"c3-area",areas:"c3-areas",text:"c3-text",texts:"c3-texts",grid:"c3-grid",xgrid:"c3-xgrid",xgrids:"c3-xgrids",xgridLine:"c3-xgrid-line",xgridLines:"c3-xgrid-lines",xgridFocus:"c3-xgrid-focus",ygrid:"c3-ygrid",ygrids:"c3-ygrids",ygridLine:"c3-ygrid-line",ygridLines:"c3-ygrid-lines",axisX:"c3-axis-x",axisXLabel:"c3-axis-x-label",axisY:"c3-axis-y",axisYLabel:"c3-axis-y-label",axisY2:"c3-axis-y2",axisY2Label:"c3-axis-y2-label",legendItem:"c3-legend-item",legendItemEvent:"c3-legend-item-event",legendItemTile:"c3-legend-item-tile",legendItemHidden:"c3-legend-item-hidden",legendItemFocused:"c3-legend-item-focused",dragarea:"c3-dragarea",EXPANDED:"_expanded_",SELECTED:"_selected_",INCLUDED:"_included_"};e.generate=function(e){function g(a,b){if(!(a in e))throw Error(b)}function h(a,b){var c,d,f,g=e;for(c=0;c<a.length;c++){if("object"==typeof g&&!(a[c]in g))return b;if(d=c===a.length-1,f=g[a[c]],!d&&"object"!=typeof f)return b;g=f}return g}function i(a){return"url("+document.URL.split("#")[0]+"#"+a+")"}function j(a,b){var c,d,e;b&&b.axisX?c=b.axisX:(c=nj.select("."+f.axisX),a&&(c=c.transition())),b&&b.axisY?d=b.axisY:(d=nj.select("."+f.axisY),a&&(d=d.transition())),b&&b.axisY2?e=b.axisY2:(e=nj.select("."+f.axisY2),a&&(e=e.transition())),nj.attr("transform",Zi.main),c.attr("transform",Zi.x),d.attr("transform",Zi.y),e.attr("transform",Zi.y2),nj.select("."+f.chartArcs).attr("transform",Zi.arc)}function k(a,b){var c;b&&b.axisSubX?c=b.axisSubX:(c=oj.select("."+f.axisX),a&&(c=c.transition())),oj.attr("transform",Zi.context),c.attr("transform",Zi.subx)}function l(a){(a?pj.transition():pj).attr("transform",Zi.legend)}function m(a,b){j(a,b),_g&&k(a,b),l(a)}function n(){var a=Q(),b=P(),c=$i?0:a,d=ih?0:w("x"),e=_g?ah+d:0;_f=r(),ag=s(),ih?(Uf={top:w("y2"),right:u(),bottom:w("y")+c,left:e+t()},Vf={top:Uf.top,right:0/0,bottom:20+c,left:dj}):(Uf={top:4,right:u(),bottom:d+e+c,left:t()},Vf={top:ag-e-c,right:0/0,bottom:d+c,left:Uf.left}),Wf={top:$i?0:ag-a,right:0/0,bottom:0,left:$i?_f-b:0},Xf=_f-Uf.left-Uf.right,Zf=ag-Uf.top-Uf.bottom,0>Xf&&(Xf=0),0>Zf&&(Zf=0),Yf=ih?Uf.left-dj-ej:Xf,$f=ih?Zf:ag-Vf.top-Vf.bottom,0>Yf&&(Yf=0),0>$f&&($f=0),p(),$i&&he(Ff.data.targets)&&(Wf.left=Xf/2+cg)}function o(){nj.select("line."+f.xgridFocus).attr("x1",ih?0:-10).attr("x2",ih?Xf:-10).attr("y1",ih?-10:Uf.top).attr("y2",ih?-10:Zf)}function p(){cg=Zf/2,bg=.95*cg,dg=ge(Ff.data.targets)?.6*bg:0}function q(){var a=ih?f.axisX:f.axisY,b=nj.select("."+a).node(),c=b?b.getBoundingClientRect():{right:0},d=Ef.select(Hf).node().getBoundingClientRect(),e=c.right-d.left-t();return e>0?e:0}function r(){return If?If:x()}function s(){var a=Jf?Jf:y();return a>0?a:320}function t(){return he(Ff.data.targets)?0:Kf?Kf:ih?jh?v("x"):1:!Bh||Gh?1:v("y")}function u(){var a=1;return he(Ff.data.targets)?0:Lf?Lf:$i?P()+(Kh&&!ih?v("y2"):a):Kh?Ph||ih?a:v("y2"):a}function v(a){var b=jb(a);return b.isInner?20+Cb(a):40+Cb(a)}function w(a){return"x"!==a||jh?"x"===a&&yh?yh:"y"!==a||Bh?"y2"!==a||Kh?(jb(a).isInner?30:40)+("y2"===a?-10:0):fj:ch&&!$i?10:1:0}function x(){return+Ef.select(Hf).style("width").replace("px","")}function y(){return+Ef.select(Hf).style("height").replace("px","")}function z(a){return a?-5:-(Uf.left-1)}function A(a){return a?-20:-4}function B(){return z(!ih)}function C(){return A(!ih)}function D(){return z(ih)}function E(){return A(ih)}function F(a){return a?Xf+2+4:Uf.left+20}function G(a){return a?(yh?yh:0)+80:Zf+8}function H(){return F(!ih)}function I(){return G(!ih)}function J(){return F(ih)}function K(){return G(ih)}function L(){var a,b,c,d,e,f=Ac(Ff.data.targets);return f?(a=f.values[0],b=f.values[f.values.length-1],c=qg(b.x)-qg(a.x),0===c?ih?Zf:Xf:(d=zc(),e=de(Ff.data.targets)?(d-(Ii?.25:1))/d:1,d>1?c*e/(d-1):c)):0}function M(a){_i=a}function N(a){aj=a}function O(a){bj=a}function P(){return ch?$i?aj*(_i+1):_f:0}function Q(){return ch?$i?ag:bj*(_i+1):0}function R(){var a,b,c=!qg;ig=ih?1:0,jg=ih?Zf:Xf,kg=ih?0:Zf,lg=ih?Xf:1,mg=ig,ng=jg,og=ih?0:$f,pg=ih?Yf:1,qg=T(ig,jg,c?void 0:qg.domain(),function(){return wg.tickOffset()}),rg=U(kg,lg,c?void 0:rg.domain()),sg=U(kg,lg,c?void 0:sg.domain()),tg=T(ig,jg,sj,function(a){return a%1?0:zg.tickOffset()}),ug=U(og,pg,c?void 0:ug.domain()),vg=U(og,pg,c?void 0:vg.domain()),a=$(),b=th?th:c?void 0:wg.tickValues(),wg=X(qg,Vi,a,b),zg=X(tg,Yi,a,b),xg=Y(rg,Wi,Hh,Jh),yg=Y(sg,Xi,Qh,Sh),c||(gj.scale(tg),Mf&&kj.scale(qg)),S()}function S(){eg=Gb(),fg=Hb(),gg=Hb(.98)}function T(a,b,d,e){var f=(Hi?Ef.time.scale():Ef.scale.linear()).range([a,b]);if(f.orgDomain=function(){return f.domain()},d&&f.domain(d),c(e)&&(e=function(){return 0}),Ii){var g,h=f;f=function(a){return h(a)+e(a)};for(g in h)f[g]=h[g];f.orgDomain=function(){return h.domain()},f.domain=function(a){return arguments.length?(h.domain(a),f):(a=h.domain(),[a[0],a[1]+1])}}return f}function U(a,b,c){var d=Ef.scale.linear().range([a,b]);return c&&d.domain(c),d}function V(a){return"y2"===Z(a)?sg:rg}function W(a){return"y2"===Z(a)?vg:ug}function X(a,b,c,d){var e=(Ii?Eb():Ef.svg.axis()).scale(a).orient(b);return e.tickFormat(c).tickValues(d),Ii?(e.tickCentered(nh),Ae(ph)&&(ph=!1)):e.tickOffset=function(){var a=Bc(Ff.data.targets),b=qg(a[1])-qg(a[0]),c=b?b:ih?Zf:Xf;return c/zc()/2},Ii&&e.categories(mh),e}function Y(a,b,c,d){return Ef.svg.axis().scale(a).orient(b).tickFormat(c).ticks(d).outerTickSize(0)}function Z(a){return a in Hg?Hg[a]:"y"}function $(){var a=Hi?Si:Ii?Tc:function(a){return 0>a?a.toFixed(0):a};return oh&&("function"==typeof oh?a=oh:Hi&&(a=function(a){return a?Ri(oh)(a):""})),a}function _(a){var b;return"y"===a?b=Fh:"y2"===a?b=Oh:"x"===a&&(b=Ah),b}function ab(a){var b=_(a);return"string"==typeof b?b:b?b.text:null}function bb(a,b){var c=_(a);"string"==typeof c?"y"===a?Fh=b:"y2"===a?Oh=b:"x"===a&&(Ah=b):c&&(c.text=b)}function cb(a){return 10*Math.sin(Math.PI*(a/180))}function db(a){return 11.5-2.5*(a/15)}function eb(a,b,c){a.selectAll(".tick text").style("text-anchor","start"),b.selectAll(".tick text").attr("y",db(c)).attr("x",cb(c)).attr("transform","rotate("+c+")")}function fb(a,b){var c=_(a),d=c&&"object"==typeof c&&c.position?c.position:b;return{isInner:d.indexOf("inner")>=0,isOuter:d.indexOf("outer")>=0,isLeft:d.indexOf("left")>=0,isCenter:d.indexOf("center")>=0,isRight:d.indexOf("right")>=0,isTop:d.indexOf("top")>=0,isMiddle:d.indexOf("middle")>=0,isBottom:d.indexOf("bottom")>=0}}function gb(){return fb("x",ih?"inner-top":"inner-right")}function hb(){return fb("y",ih?"inner-right":"inner-top")}function ib(){return fb("y2",ih?"inner-right":"inner-top")}function jb(a){return"y2"===a?ib():"y"===a?hb():gb()}function kb(){return ab("x")}function lb(){return ab("y")}function mb(){return ab("y2")}function nb(a,b){return a?b.isLeft?0:b.isCenter?Xf/2:Xf:b.isBottom?-Zf:b.isMiddle?-Zf/2:0}function ob(a,b){return a?b.isLeft?"0.5em":b.isRight?"-0.5em":"0":b.isTop?"-0.5em":b.isBottom?"0.5em":"0"}function pb(a,b){return a?b.isLeft?"start":b.isCenter?"middle":"end":b.isBottom?"start":b.isMiddle?"middle":"end"}function qb(){return nb(!ih,gb())}function rb(){return nb(ih,hb())}function sb(){return nb(ih,ib())}function tb(){return ob(!ih,gb())}function ub(){return ob(ih,hb())}function vb(){return ob(ih,ib())}function wb(){var a=gb();return ih?a.isInner?"1.2em":-25-Cb("x"):a.isInner?"-0.5em":yh?yh-10:"3em"}function xb(){var a=hb();return ih?a.isInner?"-0.5em":"3em":a.isInner?"1.2em":-20-Cb("y")}function yb(){var a=ib();return ih?a.isInner?"1.2em":"-2.2em":a.isInner?"-0.5em":30+Cb("y2")}function zb(){return pb(!ih,gb())}function Ab(){return pb(ih,hb())}function Bb(){return pb(ih,ib())}function Cb(a){var b=0,c="x"===a?f.axisX:"y"===a?f.axisY:f.axisY2;return Ef.selectAll("."+c+" .tick text").each(function(){var a=this.getBoundingClientRect();b<a.width&&(b=a.width)}),0>b?0:b}function Db(){nj.select("."+f.axisX+" ."+f.axisXLabel).transition().attr("x",qb).attr("dx",tb).attr("dy",wb).text(kb),nj.select("."+f.axisY+" ."+f.axisYLabel).transition().attr("x",rb).attr("dx",ub).attr("dy",xb).attr("dy",xb).text(lb),nj.select("."+f.axisY2+" ."+f.axisY2Label).transition().attr("x",sb).attr("dx",vb).attr("dy",yb).text(mb)}function Eb(){function a(a,b){a.attr("transform",function(a){return"translate("+(b(a)+p)+", 0)"})}function b(a,b){a.attr("transform",function(a){return"translate(0,"+b(a)+")"})}function c(a){var b=a[0],c=a[a.length-1];return c>b?[b,c]:[c,b]}function d(a){for(var b=[],c=Math.ceil(a[0]);c<a[1];c++)b.push(c);return b.length>0&&b[0]>0&&b.unshift(b[0]-(b[1]-b[0])),b}function e(a){return a<s.length?s[a]:a}function f(a){var b=e(a);return q?q(b):b}function g(){var a=i.copy(),b=i.domain();return a.domain([b[0],b[1]-1]),a}function h(e){e.each(function(){var e,h,o,q,r,s,t,u,v=Ef.select(this),w=g(),x=this.__chart__||w,y=v.selectAll(".tick.major").data(d(w.domain()),String),z=y.enter().insert("g","path").attr("class","tick major").style("opacity",1e-6),A=Ef.transition(y.exit()).style("opacity",1e-6).remove(),B=Ef.transition(y).style("opacity",1),C=i.rangeExtent?i.rangeExtent():c(i.range()),D=v.selectAll(".domain").data([0]);switch(D.enter().append("path").attr("class","domain"),o=Ef.transition(D),z.append("line"),z.append("text"),q=z.select("line"),r=B.select("line"),s=y.select("text"),t=z.select("text"),u=B.select("text"),p=(w(1)-w(0))/2,h=n?0:p,this.__chart__=w,j){case"bottom":e=a,q.attr("y2",k),t.attr("y",Math.max(k,0)+m),r.attr("x1",h).attr("x2",h).attr("y2",k),u.attr("x",0).attr("y",Math.max(k,0)+m),s.attr("dy",".71em").style("text-anchor","middle"),s.text(f),o.attr("d","M"+C[0]+","+l+"V0H"+C[1]+"V"+l);break;case"left":e=b,q.attr("x2",-k),t.attr("x",-(Math.max(k,0)+m)),r.attr("x2",-k).attr("y2",0),u.attr("x",-(Math.max(k,0)+m)).attr("y",p),s.attr("dy",".32em").style("text-anchor","end"),s.text(f),o.attr("d","M"+-l+","+C[0]+"H0V"+C[1]+"H"+-l)}if(i.ticks)z.call(e,x),B.call(e,w),A.call(e,w);else{var E=w.rangeBand()/2,F=function(a){return w(a)+E};z.call(e,F),B.call(e,F)}})}var i=Ef.scale.linear(),j="bottom",k=6,l=6,m=3,n=!1,o=10,p=0,q=null,r=!0,s=[];return h.scale=function(a){return arguments.length?(i=a,h):i},h.orient=function(a){return arguments.length?(j=a in{top:1,right:1,bottom:1,left:1}?a+"":"bottom",h):j},h.categories=function(a){return arguments.length?(s=a,h):s},h.tickCentered=function(a){return arguments.length?(n=a,h):n},h.tickFormat=function(a){return arguments.length?(q=a,h):q},h.tickOffset=function(){return p},h.ticks=function(a){return arguments.length?(o=a,h):o},h.tickCulling=function(a){return arguments.length?(r=a,h):r},h.tickValues=function(){},h}function Fb(a){var b=!1;return hg(Ic(Ff.data.targets)).forEach(function(c){return b||c.data.id!==a.data.id?void 0:(b=!0,void(a=c))}),b?a:null}function Gb(){var a=Ef.svg.arc().outerRadius(bg).innerRadius(dg),b=function(b,c){var d;return c?a(b):(d=Fb(b),d?a(d):"M 0 0")};return b.centroid=a.centroid,b}function Hb(a){var b=Ef.svg.arc().outerRadius(cg*(a?a:1)).innerRadius(dg);return function(a){var c=Fb(a);return c?b(c):"M 0 0"}}function Ib(a,b){return oe(a.data)?eg(a,b):"M 0 0"}function Jb(a){var b,c,d,e,f=Fb(a),g="";return f&&(b=eg.centroid(f),c=b[0],d=b[1],e=Math.sqrt(c*c+d*d),g="translate("+c/e*bg*.8+","+d/e*bg*.8+")"),g}function Kb(a){return a?(a.endAngle-a.startAngle)/(2*Math.PI):null}function Lb(a){return pc({id:a.data.id,value:a.value,ratio:Kb(a)})}function Mb(a){var b,c,d,e;return Pb()?(b=Fb(a),c=b?b.value:null,d=Kb(b),e=Qb(),e?e(c,d):Dd(c,d)):""}function Nb(a,b){var c=lj.selectAll("."+f.chartArc+pd(a)),d=lj.selectAll("."+f.arc).filter(function(b){return b.data.id!==a});ue(a)&&c.selectAll("path").transition().duration(50).attr("d",fg).transition().duration(100).attr("d",gg).each(function(a){ne(a.data)}),b||d.style("opacity",.3)}function Ob(a){var b=lj.selectAll("."+f.chartArc+pd(a));b.selectAll("path").transition().duration(50).attr("d",eg),lj.selectAll("."+f.arc).style("opacity",1)}function Pb(){return ge(Ff.data.targets)?mi:gi}function Qb(){return ge(Ff.data.targets)?ni:hi}function Rb(){return ge(Ff.data.targets)?pi:""}function Sb(){var a=ge(Ff.data.targets)?qi:ji;return"function"==typeof a?a:function(){}}function Tb(){var a=ge(Ff.data.targets)?ri:ki;return"function"==typeof a?a:function(){}}function Ub(){var a=ge(Ff.data.targets)?si:li;return"function"==typeof a?a:function(){}}function Vb(a){var b,c,d,e,f,g,h=Cc(a),i=Pc(a);if(Gg.length>0)for(g=Rc(a),b=0;b<Gg.length;b++)if(e=Gg[b].filter(function(a){return h.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&i[d]&&i[d].forEach(function(a,b){i[d][b]=0>a?a:0}),c=1;c<e.length;c++)f=e[c],i[f]&&i[f].forEach(function(a,b){Z(f)!==Z(d)||!i[d]||g&&+a>0||(i[d][b]+=+a)});return Ef.min(Object.keys(i).map(function(a){return Ef.min(i[a])}))}function Wb(a){var b,c,d,e,f,g,h=Cc(a),i=Pc(a);if(Gg.length>0)for(g=Sc(a),b=0;b<Gg.length;b++)if(e=Gg[b].filter(function(a){return h.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&i[d]&&i[d].forEach(function(a,b){i[d][b]=a>0?a:0}),c=1;c<e.length;c++)f=e[c],i[f]&&i[f].forEach(function(a,b){Z(f)!==Z(d)||!i[d]||g&&0>+a||(i[d][b]+=+a)});return Ef.max(Object.keys(i).map(function(a){return Ef.max(i[a])}))}function Xb(a,c){var d,e,f,g,h,i,j,k,l=a.filter(function(a){return Z(a.id)===c}),m="y2"===c?Mh:Dh,n="y2"===c?Lh:Ch,o=b(m)?m:Vb(l),p=b(n)?n:Wb(l),q="y2"===c?Nh:Eh,r=xd()&&ih;return 0===l.length?"y2"===c?sg.domain():rg.domain():(o===p&&(0>o?p=0:o=0),d=Math.abs(p-o),e=f=g=r?0:.1*d,q&&(h=Math.max(Math.abs(o),Math.abs(p)),p=h-q,o=q-h),r&&(i=yd(o,p),j=ac(rg.range()),k=[i[0]/j,i[1]/j],f+=d*(k[1]/(1-k[0]-k[1])),g+=d*(k[0]/(1-k[0]-k[1]))),"y"===c&&Ih&&(f=b(Ih.top)?Ih.top:e,g=b(Ih.bottom)?Ih.bottom:e),"y2"===c&&Rh&&(f=b(Rh.top)?Rh.top:e,g=b(Rh.bottom)?Rh.bottom:e),de(l)&&!Rc(l)&&(g=o),[o-g,p+f])}function Yb(a){return wh?Hi?we(wh):wh:Ef.min(a,function(a){return Ef.min(a.values,function(a){return a.x})})}function Zb(a){return vh?Hi?we(vh):vh:Ef.max(a,function(a){return Ef.max(a.values,function(a){return a.x})})}function $b(a){var c,d,e,f,g=Bc(a),h=g[1]-g[0];return Ii?d=0:de(a)?(c=zc(),d=c>1?h/(c-1)/2:.5):d=.01*h,"object"==typeof xh&&Be(xh)?(e=b(xh.left)?xh.left:d,f=b(xh.right)?xh.right:d):e=f="number"==typeof xh?xh:d,{left:e,right:f}}function _b(a){var b=[Yb(a),Zb(a)],c=b[0],d=b[1],e=$b(a),f=0,g=0;return c-d===0&&(c=Hi?new Date(.5*c.getTime()):-.5,d=Hi?new Date(1.5*d.getTime()):.5),(c||0===c)&&(f=Hi?new Date(c.getTime()-e.left):c-e.left),(d||0===d)&&(g=Hi?new Date(d.getTime()+e.right):d+e.right),[f,g]}function ac(a){return a[1]-a[0]}function bc(a){for(var b=0;b<a.length;b++)if(!(a[b]in Gf))return!1;return!0}function cc(a,b){Gf[a]=wc(b)}function dc(a){for(var b=[],c=0;c<a.length;c++)a[c]in Gf&&b.push(wc(Gf[a[c]]));return b}function ec(a){var b,c="y"===a.axis?rg:sg;return b="y"===a.axis||"y2"===a.axis?ih?"start"in a?c(a.start):0:0:ih?0:"start"in a?qg(Hi?we(a.start):a.start):0}function fc(a){var b,c="y"===a.axis?rg:sg;return b="y"===a.axis||"y2"===a.axis?ih?0:"end"in a?c(a.end):0:ih?"start"in a?qg(Hi?we(a.start):a.start):0:0}function gc(a){var b,c=ec(a),d="y"===a.axis?rg:sg;return b="y"===a.axis||"y2"===a.axis?ih?"end"in a?d(a.end):Xf:Xf:ih?Xf:"end"in a?qg(Hi?we(a.end):a.end):Xf,c>b?0:b-c}function hc(a){var b,c=fc(a),d="y"===a.axis?rg:sg;return b="y"===a.axis||"y2"===a.axis?ih?Zf:"start"in a?d(a.start):Zf:ih?"end"in a?qg(Hi?we(a.end):a.end):Zf:Zf,c>b?0:b-c}function ic(a){return Ag&&a===Ag||Be(Bg)&&Ce(Bg,a)}function jc(a){return!ic(a)}function kc(a){return Ag?Ag:Be(Bg)?Bg[a]:null}function lc(a,b){var c,d=b&&Be(b)?Cc(b):[];return d.forEach(function(b){kc(b)===a&&(c=Ff.data.xs[b])}),c}function mc(a,b){return a in Ff.data.xs&&Ff.data.xs[a]&&Ff.data.xs[a][b]?Ff.data.xs[a][b]:b}function nc(a){Object.keys(a).forEach(function(b){Bg[b]=a[b]})}function oc(a){return 1===Ef.set(Object.keys(a).map(function(b){return a[b]})).size()}function pc(a){var b;return a&&(b=Eg[a.id],a.name=b?b:a.id),a}function qc(a,b){a.forEach(function(a){a.values.forEach(function(c,d){c.x=sc(b[d],a.id,d)}),Ff.data.xs[a.id]=b})}function rc(a,b){a.forEach(function(a){b[a.id]&&qc([a],b[a.id])})}function sc(a,c,d){var e;return e=Hi?a?a instanceof Date?a:we(a):we(mc(c,d)):Ji&&!Ii?b(a)?+a:mc(c,d):d}function tc(a){var b,c,d=a[0],e={},f=[];for(b=1;b<a.length;b++){for(e={},c=0;c<a[b].length;c++)e[d[c]]=a[b][c];f.push(e)}return f}function uc(a){var b,d,e,f=[];for(b=0;b<a.length;b++)for(e=a[b][0],d=1;d<a[b].length;d++)c(f[d-1])&&(f[d-1]={}),f[d-1][e]=a[b][d];return f}function vc(a){var c,d=Ef.keys(a[0]).filter(jc),e=Ef.keys(a[0]).filter(ic);return d.forEach(function(c){var d,f=kc(c);Ji||Hi?e.indexOf(f)>=0?Ff.data.xs[c]=a.map(function(a){return a[f]}).filter(b):Ag?(d=Object.keys(Ff.data.xs),Ff.data.xs[c]=d.length>0?Ff.data.xs[d[0]]:void 0):Be(Bg)&&(Ff.data.xs[c]=lc(f,Ff.data.targets)):Ff.data.xs[c]=a.map(function(a,b){return b})}),d.forEach(function(a){if(!Ff.data.xs[a])throw new Error('x is not defined for id = "'+a+'".')}),c=d.map(function(b,c){var d=Dg(b);return{id:d,id_org:b,values:a.map(function(a,e){var f=kc(b),g=a[f],h=sc(g,b,e);return Ji&&Ii&&0===c&&g&&(0===e&&(mh=[]),mh.push(g)),("undefined"==typeof a[b]||Ff.data.xs[b].length<=e)&&(h=void 0),{x:h,value:null===a[b]||isNaN(a[b])?null:+a[b],id:d}}).filter(function(a){return"undefined"!=typeof a.x})}}),c.forEach(function(a){var b;a.values=a.values.sort(function(a,b){var c=a.x||0===a.x?a.x:1/0,d=b.x||0===b.x?b.x:1/0;return c-d}),b=0,a.values.forEach(function(a){a.index=b++})}),Ig&&be(Cc(c).filter(function(a){return!(a in Jg)}),Ig),c.forEach(function(a){cc(a.id_org,a)}),c}function wc(a){return{id:a.id,id_org:a.id_org,values:a.values.map(function(a){return{x:a.x,value:a.value,id:a.id}})}}function xc(a){return a>0&&Ff.data.targets[0].values[a-1]?Ff.data.targets[0].values[a-1].x:void 0}function yc(a){return a<zc()-1?Ff.data.targets[0].values[a+1].x:void 0}function zc(){return Ef.max(Ff.data.targets,function(a){return a.values.length})}function Ac(a){var b,c=a.length,d=0;return c>1?a.forEach(function(a){a.values.length>d&&(b=a,d=a.values.length)}):b=c?a[0]:null,b}function Bc(a){var b,c,d=Ac(a);return d?(b=d.values[0],c=d.values[d.values.length-1],[b.x,c.x]):[0,0]}function Cc(a){return a.map(function(a){return a.id})}function Dc(a){return a?"string"==typeof a?[a]:a:Cc(Ff.data.targets)}function Ec(a,b){var c,d=Cc(a);for(c=0;c<d.length;c++)if(d[c]===b)return!0;return!1}function Fc(a){return d(a)?Ff.data.targets.filter(a):Ff.data.targets}function Gc(a){return Ti.indexOf(a)<0}function Hc(a){return Ui.indexOf(a)<0}function Ic(a){return a.filter(function(a){return Gc(a.id)})}function Jc(a){var b=Ef.set(Ef.merge(a.map(function(a){return a.values.map(function(a){return a.x})}))).values();return b.map(Hi?function(a){return new Date(a)}:function(a){return+a})}function Kc(a,b){var c,d,e,f,g,h,i,j=a;if(b)if(c="function"==typeof b?b():b,1===c)j=[a[0]];else if(2===c)j=[a[0],a[a.length-1]];else if(c>2){for(f=c-2,d=a[0],e=a[a.length-1],g=(e-d)/(f+1),j=[d],h=0;f>h;h++)i=+d+g*(h+1),j.push(Hi?new Date(i):i);j.push(e)}return Hi||(j=j.sort(function(a,b){return a-b})),j}function Lc(a){Ti=Ti.concat(a)}function Mc(a){Ti=Ti.filter(function(b){return a.indexOf(b)<0})}function Nc(a){Ui=Ui.concat(a)}function Oc(a){Ui=Ui.filter(function(b){return a.indexOf(b)<0})}function Pc(a){var b={};return a.forEach(function(a){b[a.id]=[],a.values.forEach(function(c){b[a.id].push(c.value)})}),b}function Qc(a,b){var c,d,e,f=Object.keys(a);for(c=0;c<f.length;c++)for(e=a[f[c]].values,d=0;d<e.length;d++)if(b(e[d].value))return!0;return!1}function Rc(a){return Qc(a,function(a){return 0>a})}function Sc(a){return Qc(a,function(a){return a>0})}function Tc(a){return a<mh.length?mh[a]:a}function Uc(a,b){return" "+a+" "+a+od(b)}function Vc(a){return Uc(f.text,a.id)}function Wc(a){return Uc(f.texts,a.id)}function Xc(a,b){return Uc(f.shape,b)}function Yc(a){return Uc(f.shapes,a.id)}function Zc(a){return Xc(a)+Uc(f.line,a.id)}function $c(a){return Yc(a)+Uc(f.lines,a.id)}function _c(a,b){return Xc(a,b)+Uc(f.circle,b)}function ad(a){return Yc(a)+Uc(f.circles,a.id)}function bd(a,b){return Xc(a,b)+Uc(f.bar,b)}function cd(a){return Yc(a)+Uc(f.bars,a.id)}function dd(a){return Xc(a.data)+Uc(f.arc,a.data.id)}function ed(a){return Yc(a.data)+Uc(f.arcs,a.data.id)}function fd(a){return Xc(a)+Uc(f.area,a.id)}function gd(a){return Yc(a)+Uc(f.areas,a.id)}function hd(a,b){return Uc(f.region,b)+" "+("class"in a?a.class:"")}function id(a,b){return Uc(f.eventRect,b)}function jd(a){var b=Fg[a],c="";return b&&(c=" "+f.target+"-"+b),Uc(f.target,a)+c}function kd(a){return f.chartText+jd(a.id)}function ld(a){return f.chartLine+jd(a.id)}function md(a){return f.chartBar+jd(a.id)}function nd(a){return f.chartArc+jd(a.data.id)}function od(a){return a||0===a?"-"+(a.replace?a.replace(/([^a-zA-Z0-9-_])/g,"-"):a):""}function pd(a){return"."+f.target+od(a)}function qd(a){return a.length?a.map(function(a){return pd(a)}):null}function rd(a){return"."+f.legendItem+od(a)}function sd(a){return a.length?a.map(function(a){return rd(a)}):null}function td(a){return null!==a.value&&uj[a.id]?1:0}function ud(a){var b=wd(a);return td(a)*b}function vd(a){return b(a.value)?le(a)?.5:1:0}function wd(){return xd()?1:0}function xd(){return"boolean"==typeof Kg&&Kg?!0:"object"==typeof Kg&&Be(Kg)?!0:!1}function yd(a,b){var c=[],d=1.3;return rj.select("svg").selectAll(".dummy").data([a,b]).enter().append("text").text(function(a){return a}).each(function(a,b){c[b]=this.getBoundingClientRect().width*d}).remove(),c}function zd(a){var b=a?Dd:Ad,c=a?Dd:Bd;return function(a,d,e){var f="y2"===Z(e)?c:b;return f(a,d)}}function Ad(a){var b=Hh?Hh:Cd;return b(a)}function Bd(a){var b=Qh?Qh:Cd;return b(a)}function Cd(a){return b(a)?+a:""}function Dd(a,b){return(100*b).toFixed(1)+"%"}function Ed(a){var c=function(a){return b(a)?+a:""},d=Z(a),e=c;return"function"==typeof Kg.format?e=Kg.format:"object"==typeof Kg.format&&"function"==typeof Kg.format[d]&&(e=Kg.format[d]),e}function Fd(a){return a?qg(a.x):null}function Gd(a){return qg(Hi?we(a.value):a.value)}function Hd(a){var b=a.axis&&"y2"===a.axis?sg:rg;return b(a.value)}function Id(a){return tg(a.x)}function Jd(a,b){var c,d=a[b].x,e=[];for(c=b-1;c>=0&&d===a[c].x;c--)e.push(a[c]);for(c=b;c<a.length&&d===a[c].x;c++)e.push(a[c]);return e}function Kd(a,b,c,d){var e,f=c?c:0,g=d?d:a.length-1,h=Math.floor((g-f)/2)+f,i=a[h],j=qg(i.x)-b[ih?1:0];return j>0?g=h:f=h,g-f===1||0===f&&0===g?(e=[],(a[f].x||0===a[f].x)&&(e=e.concat(Jd(a,f))),(a[g].x||0===a[g].x)&&(e=e.concat(Jd(a,g))),Md(e,b)):Kd(a,b,f,g)}function Ld(a,b){var c;return c=a.map(function(a){return Kd(a.values,b)}),Md(c,b)}function Md(a,b){var c,d;return a.forEach(function(a){var e=De(a,b);(c>e||!c)&&(c=e,d=a)}),d}function Nd(a,b){return Ef.merge(a.map(function(a){return a.values})).filter(function(a){return a.x-b===0})}function Od(a){var b=a.getBoundingClientRect(),c=[a.pathSegList.getItem(0),a.pathSegList.getItem(1)],d=c[0].x,e=Math.min(c[0].y,c[1].y);return{x:d,y:e,width:b.width,height:b.height}}function Pd(){return Lg&&"desc"===Lg.toLowerCase()}function Qd(){return Lg&&"asc"===Lg.toLowerCase()}function Rd(a){var b=Qd(),c=Pd();return b||c?a.sort(function(a,c){var d=function(a,b){return a+Math.abs(b.value)},e=a.values.reduce(d,0),f=c.values.reduce(d,0);return b?f-e:e-f}):"function"==typeof Lg&&a.sort(Lg),a}function Sd(a,c){var d,e,f,g,h,i,j,k=he(Ff.data.targets),l=a.filter(function(a){return a&&b(a.value)});0!==l.length&&ui&&(qj.html(xi(a,$(),zd(k),Qi)).style("display","block"),d=qj.property("offsetWidth"),e=qj.property("offsetHeight"),k?(g=Xf/2+c[0],i=Zf/2+c[1]+20):(ih?(f=q(),g=f+c[0]+100,h=g+d,j=r()-u(),i=qg(l[0].x)+20):(f=q(),g=f+t()+qg(l[0].x)+20,h=g+d,j=f+r()-u(),i=c[1]+15),h>j&&(g-=d+60),i+e>s()&&(i-=e+30)),qj.style("top",i+"px").style("left",g+"px"))}function Td(){qj.style("display","none")}function Ud(a){var c=a.filter(function(a){return a&&b(a.value)});ui&&(ee(Ff.data.targets)||he(Ff.data.targets)||nj.selectAll("line."+f.xgridFocus).style("visibility","visible").data([c[0]]).attr(ih?"y1":"x1",Fd).attr(ih?"y2":"x2",Fd))}function Vd(){nj.select("line."+f.xgridFocus).style("visibility","hidden")}function Wd(a){return a.x||0===a.x?qg(a.x):null}function Xd(a){return V(a.id)(a.value)}function Yd(){var a,b,d={},e=0;return Ic(Fc(ke)).forEach(function(f){for(a=0;a<Gg.length;a++)if(!(Gg[a].indexOf(f.id)<0))for(b=0;b<Gg[a].length;b++)if(Gg[a][b]in d){d[f.id]=d[Gg[a][b]];break}c(d[f.id])&&(d[f.id]=e++)}),d.__max__=e-1,d}function Zd(a,b,c,d){var e=d?tg:qg;return function(d){var f=d.id in c?c[d.id]:0;return d.x||0===d.x?e(d.x)-a*(b/2-f):0}}function $d(a){return function(b){var c=a?W(b.id):V(b.id);return c(b.value)}}function _d(a,b){var c=Rd(Ic(Fc(ke))),d=c.map(function(a){return a.id});return function(e,f){var g=b?W(e.id):V(e.id),h=g(0),i=h;return c.forEach(function(b){b.id!==e.id&&a[b.id]===a[e.id]&&d.indexOf(b.id)<d.indexOf(e.id)&&b.values[f].value*e.value>0&&(i+=g(b.values[f].value)-h)}),i}}function ae(a,b){return"number"==typeof ei?ei:b?2*a.tickOffset()*fi/b:0}function be(a,b){Dc(a).forEach(function(a){uj[a]=b===Jg[a],Jg[a]=b})}function ce(a,b){var c=!1;return a.forEach(function(a){Jg[a.id]===b&&(c=!0),a.id in Jg||"line"!==b||(c=!0)}),c}function de(a){return ce(a,"bar")}function ee(a){return ce(a,"scatter")}function fe(a){return ce(a,"pie")}function ge(a){return ce(a,"donut")}function he(a){return fe(a)||ge(a)}function ie(a){var b="string"==typeof a?a:a.id;return!(b in Jg)||"line"===Jg[b]||"spline"===Jg[b]||"area"===Jg[b]||"area-spline"===Jg[b]}function je(a){var b="string"==typeof a?a:a.id;return"spline"===Jg[b]||"area-spline"===Jg[b]}function ke(a){var b="string"==typeof a?a:a.id;return"bar"===Jg[b]}function le(a){var b="string"==typeof a?a:a.id;return"scatter"===Jg[b]}function me(a){var b="string"==typeof a?a:a.id;return"pie"===Jg[b]}function ne(a){var b="string"==typeof a?a:a.id;return"donut"===Jg[b]}function oe(a){return me(a)||ne(a)}function pe(a){return ie(a)?[a]:[]}function qe(a){return oe(a.data)?[a]:[]}function re(a){return ke(a)?a.values:[]}function se(a){return ie(a)||le(a)?a.values:[]}function te(a){return ke(a)||ie(a)?a.values:[]}function ue(a){return ne(a)&&oi||me(a)&&ii}function ve(a,b,c){var d=[];return function(e){var f,g=e.id||e;return a[g]instanceof Function?f=a[g](e):g in a?f=a[g]:(d.indexOf(g)<0&&d.push(g),f=b[d.indexOf(g)%b.length]),c instanceof Function?c(f,e):f}}function we(b){var c;try{c=Cg?Ef.time.format(Cg).parse(b):new Date(b)}catch(d){a.console.error("Failed to parse x '"+b+"' to Date with format "+Cg)}return c}function xe(a,b){var c=Ef.mouse(a),d=Ef.select(a),e=1*d.attr("cx"),f=1*d.attr("cy");return Math.sqrt(Math.pow(e-c[0],2)+Math.pow(f-c[1],2))<b}function ye(a){var b=Ef.mouse(a),c=a.getBoundingClientRect(),d=a.pathSegList.getItem(0),e=a.pathSegList.getItem(1),f=d.x,g=Math.min(d.y,e.y),h=c.width,i=c.height,j=2,k=f-j,l=f+h+j,m=g+i+j,n=g-j;return k<b[0]&&b[0]<l&&n<b[1]&&b[1]<m}function ze(a,b){var c;for(c=0;c<b.length;c++)if(b[c].start<a&&a<=b[c].end)return!0;return!1}function Ae(a){return!a||"string"==typeof a&&0===a.length||"object"==typeof a&&0===Object.keys(a).length}function Be(a){return Object.keys(a).length>0}function Ce(a,b){var c=!1;return Object.keys(a).forEach(function(d){a[d]===b&&(c=!0)}),c}function De(a,b){var c="y"===Z(a.id)?rg:sg,d=ih?1:0,e=ih?0:1;return Math.pow(qg(a.x)-b[d],2)+Math.pow(c(a.value)-b[e],2)}function Ee(a,b){var c=0;a.each(function(){++c}).each("end",function(){--c||b.apply(this,arguments)})}function Fe(a,b,c){Xg(b,a.node()),nj.select("."+f.selectedCircles+od(b.id)).selectAll("."+f.selectedCircle+"-"+c).data([b]).enter().append("circle").attr("class",function(){return Uc(f.selectedCircle,c)}).attr("cx",ih?Xd:Wd).attr("cy",ih?Wd:Xd).attr("stroke",function(){return Qi(b)}).attr("r",1.4*Qe(b)).transition().duration(100).attr("r",Qe)}function Ge(a,b,c){Yg(b,a.node()),nj.select("."+f.selectedCircles+od(b.id)).selectAll("."+f.selectedCircle+"-"+c).transition().duration(100).attr("r",0).remove()}function He(a,b,c,d){a?Fe(b,c,d):Ge(b,c,d)}function Ie(a,b){Xg(b,a.node()),a.transition().duration(100).style("fill",function(){return Ef.rgb(Qi(b)).brighter(.75)})}function Je(a,b){Yg(b,a.node()),a.transition().duration(100).style("fill",function(){return Qi(b)})}function Ke(a,b,c,d){a?Ie(b,c,d):Je(b,c,d)}function Le(a,b,c,d){Ke(a,b,c.data,d)}function Me(a){return"circle"===a.nodeName?He:Ef.select(a).classed(f.bar)?Ke:Le}function Ne(a){return a.filter(function(a){return b(a.value)})}function Oe(a){return Zh?"function"==typeof $h?$h(a):$h:0}function Pe(a){return ai?bi?bi:1.75*Oe(a):Oe(a)}function Qe(a){return ci?ci:4*Oe(a)}function Re(a,c){return(c?nj.selectAll("."+f.circles+od(c)):nj).selectAll("."+f.circle+(b(a)?"-"+a:""))}function Se(a,b){Re(a,b).classed(f.EXPANDED,!0).attr("r",Pe)}function Te(a){Re(a).filter(function(){return Ef.select(this).classed(f.EXPANDED)}).classed(f.EXPANDED,!1).attr("r",Oe)}function Ue(a){return nj.selectAll("."+f.bar+(b(a)?"-"+a:""))}function Ve(a){Ue(a).classed(f.EXPANDED,!0)}function We(a){Ue(a).classed(f.EXPANDED,!1)}function Xe(a,b){var c=_e(a,b);return function(a,b){var d=c(a,b),e=ih?1:0,f=ih?0:1,g="M "+d[0][e]+","+d[0][f]+" L"+d[1][e]+","+d[1][f]+" L"+d[2][e]+","+d[2][f]+" L"+d[3][e]+","+d[3][f]+" z";return g}}function Ye(a,b){var c=_e(a,!1),d=b?Ze:$e;return function(a,b){return d(c(a,b),a,this)}}function Ze(a,b){var c;return ih?(c=ke(b)?4:6,a[2][1]+c*(b.value<0?-1:1)):a[0][0]+(a[2][0]-a[0][0])/2}function $e(a,b,c){var d=c.getBoundingClientRect();return ih?(a[0][0]+a[2][0]+.6*d.height)/2:a[2][1]+(b.value<0?d.height:ke(b)?-3:-6)}function _e(a,b){var c=a.__max__+1,d=ae(wg,c),e=Zd(d,c,a,!!b),f=$d(!!b),g=_d(a,!!b),h=b?W:V;return function(a,b){var c=h(a.id)(0),i=g(a,b)||c,j=e(a),k=f(a);return ih&&(0<a.value&&c>k||a.value<0&&k>c)&&(k=c),[[j,i],[j,k-(c-i)],[j+d,k-(c-i)],[j+d,i]]}}function af(a,b,e,f){var g,h,i,j,k,l,m,n,o,p,q,r=-1,s="M",t=[];if(d(f))for(g=0;g<f.length;g++)t[g]={},t[g].start=c(f[g].start)?a[0].x:Hi?we(f[g].start):f[g].start,t[g].end=c(f[g].end)?a[a.length-1].x:Hi?we(f[g].end):f[g].end;for(p=ih?function(a){return e(a.value)}:function(a){return b(a.x)},q=ih?function(a){return b(a.x)}:function(a){return e(a.value)},i=Hi?function(a,c,d,f){var g=a.x.getTime(),h=c.x-a.x,i=new Date(g+h*d),j=new Date(g+h*(d+f));return"M"+b(i)+" "+e(k(d))+" "+b(j)+" "+e(k(d+f))}:function(a,c,d,f){return"M"+b(j(d))+" "+e(k(d))+" "+b(j(d+f))+" "+e(k(d+f))},g=0;g<a.length;g++){if(c(t)||!ze(a[g].x,t))s+=" "+p(a[g])+" "+q(a[g]);else{j=T(a[g-1].x,a[g].x),k=U(a[g-1].value,a[g].value),l=b(a[g].x)-b(a[g-1].x),m=e(a[g].value)-e(a[g-1].value),n=Math.sqrt(Math.pow(l,2)+Math.pow(m,2)),o=2/n;var u=2*o;for(h=o;1>=h;h+=u)s+=i(a[g-1],a[g],h,o)}r=a[g].x}return s}function bf(b){var c,d,e;if(rj=Ef.select(Hf),rj.empty())throw new Error('Bind element not found. Check the selector specified by "bindto" and existance of that element. Default "bindto" is "#chart".');if(rj.html("").classed("c3",!0),Ff.data.xs={},Ff.data.targets=vc(b),Pg&&Lc(Pg===!0?Cc(Ff.data.targets):Pg),n(),R(),qg.domain(Ef.extent(_b(Ff.data.targets))),rg.domain(Xb(Ff.data.targets,"y")),sg.domain(Xb(Ff.data.targets,"y2")),tg.domain(qg.domain()),ug.domain(rg.domain()),vg.domain(sg.domain()),sj=qg.domain(),gj.scale(tg),Mf&&kj.scale(qg),lj=rj.append("svg").on("mouseenter",Pf).on("mouseleave",Qf),mj=lj.append("defs"),mj.append("clipPath").attr("id",Bi).append("rect"),mj.append("clipPath").attr("id",Ci).append("rect"),mj.append("clipPath").attr("id",Di).append("rect"),nf(),nj=lj.append("g").attr("transform",Zi.main),oj=lj.append("g").attr("transform",Zi.context),pj=lj.append("g").attr("transform",Zi.legend),_g||oj.style("visibility","hidden"),ch||(pj.style("visibility","hidden"),Ui=Cc(Ff.data.targets)),qj=Ef.select(Hf).style("position","relative").append("div").style("position","absolute").style("pointer-events","none").style("z-index","10").style("display","none"),zf(Cc(Ff.data.targets),{withTransform:!1,withTransitionForTransform:!1}),d=nj.append("g").attr("clip-path",Ei).attr("class",f.grid),Th&&d.append("g").attr("class",f.xgrids),Be(Vh)&&d.append("g").attr("class",f.xgridLines),_h&&d.append("g").attr("class",f.xgridFocus).append("line").attr("class",f.xgridFocus),Wh&&d.append("g").attr("class",f.ygrids),Be(Xh)&&d.append("g").attr("class",f.ygridLines),jh&&nj.append("g").attr("class",f.axisX).attr("clip-path",Fi).attr("transform",Zi.x).append("text").attr("class",f.axisXLabel).attr("transform",ih?"rotate(-90)":"").style("text-anchor",zb),Bh&&nj.append("g").attr("class",f.axisY).attr("clip-path",Gi).attr("transform",Zi.y).append("text").attr("class",f.axisYLabel).attr("transform",ih?"":"rotate(-90)").style("text-anchor",Ab),Kh&&nj.append("g").attr("class",f.axisY2).attr("transform",Zi.y2).append("text").attr("class",f.axisY2Label).attr("transform",ih?"":"rotate(-90)").style("text-anchor",Bb),nj.append("g").attr("clip-path",Ei).attr("class",f.regions),nj.append("g").attr("clip-path",Ei).attr("class",f.chart),c=nj.select("."+f.chart).append("g").attr("class",f.eventRects).style("fill-opacity",0).style("cursor",Mf?ih?"ns-resize":"ew-resize":null),nj.select("."+f.chart).append("g").attr("class",f.chartBars),nj.select("."+f.chart).append("g").attr("class",f.chartLines),nj.select("."+f.chart).append("g").attr("class",f.chartArcs).attr("transform",Zi.arc).append("text").attr("class",f.chartArcsTitle).style("text-anchor","middle").text(Rb()),nj.select("."+f.chart).append("g").attr("class",f.chartTexts),Mf&&nj.insert("rect",Of?null:"g."+f.grid).attr("class",f.zoomRect).attr("width",Xf).attr("height",Zf).style("opacity",0).style("cursor",ih?"ns-resize":"ew-resize").call(kj).on("dblclick.zoom",null),zh&&gj.extent("function"!=typeof zh?zh:zh(_b())),oj.append("g").attr("clip-path",Ei).attr("class",f.chart),oj.select("."+f.chart).append("g").attr("class",f.chartBars),oj.select("."+f.chart).append("g").attr("class",f.chartLines),oj.append("g").attr("clip-path",Ei).attr("class",f.brush).call(gj).selectAll("rect").attr(ih?"width":"height",ih?Yf:$f),oj.append("g").attr("class",f.axisX).attr("transform",Zi.subx).attr("clip-path",ih?"":Fi),pf(Ff.data.targets),ih?nj.select("."+f.axisX).style("opacity",0).call(wg):(nj.select("."+f.axisY).style("opacity",0).call(xg),nj.select("."+f.axisY2).style("opacity",0).call(yg)),n(),R(),nf(),m(!1),jf({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransitionForAxis:!1}),yi){if(Hi&&"string"==typeof zi){for(zi=we(zi),e=0;e<Ff.data.targets[0].values.length&&Ff.data.targets[0].values[e].x-zi!==0;e++);zi=e
-}qj.html(xi(Ff.data.targets.map(function(a){return pc(a.values[zi])}),$(),zd(he(Ff.data.targets)),Qi)),qj.style("top",Ai.top).style("left",Ai.left).style("display","block")}null==a.onresize&&(a.onresize=mf()),a.onresize.add&&(a.onresize.add(Rf),a.onresize.add(function(){of({withLegend:!0,withTransition:!1,withTransitionForTransform:!1})}),a.onresize.add(Sf))}function cf(a){a.append("rect").attr("class",id).style("cursor",Qg&&Rg?"pointer":null).on("mouseover",function(a,b){if(!Li&&!he(Ff.data.targets)){var c,d,e=Ff.data.targets.map(function(a){return pc(a.values[b])});if(Object.keys(Eg).length>0){d=[];for(var g in Eg)for(c=0;c<e.length;c++)if(e[c].id===g){d.push(e[c]),e.shift(c);break}e=d.concat(e)}ai&&Se(b),Ve(b),nj.selectAll("."+f.shape+"-"+b).each(function(a){Vg(a)})}}).on("mouseout",function(a,b){he(Ff.data.targets)||(Vd(),Td(),Te(b),We(),nj.selectAll("."+f.shape+"-"+b).each(function(a){Wg(a)}))}).on("mousemove",function(a,b){var c;Li||he(Ff.data.targets)||(c=Ic(Ff.data.targets).map(function(a){return pc(a.values[b])}),Sd(c,Ef.mouse(this)),Ud(c),Qg&&(Rg||nj.selectAll("."+f.shape+"-"+b).filter(function(a){return Sg(a)}).each(function(){var a=Ef.select(this).classed(f.EXPANDED,!0);"circle"===this.nodeName&&a.attr("r",Pe),lj.select("."+f.eventRect+"-"+b).style("cursor",null)}).filter(function(a){return"circle"===this.nodeName?xe(this,Qe(a)):"path"===this.nodeName?ye(this):void 0}).each(function(){var a=Ef.select(this);a.classed(f.EXPANDED)||(a.classed(f.EXPANDED,!0),"circle"===this.nodeName&&a.attr("r",Qe)),lj.select("."+f.eventRect+"-"+b).style("cursor","pointer")})))}).on("click",function(a,b){return he(Ff.data.targets)?void 0:Mi?void(Mi=!1):void nj.selectAll("."+f.shape+"-"+b).each(function(a){ef(this,a,b)})}).call(Ef.behavior.drag().origin(Object).on("drag",function(){ff(Ef.mouse(this))}).on("dragstart",function(){gf(Ef.mouse(this))}).on("dragend",function(){hf()})).call(kj).on("dblclick.zoom",null)}function df(a){a.append("rect").attr("x",0).attr("y",0).attr("width",Xf).attr("height",Zf).attr("class",f.eventRect).on("mouseout",function(){he(Ff.data.targets)||(Vd(),Td(),Te())}).on("mousemove",function(){var a,b,c,d,e=Ic(Ff.data.targets);Li||he(e)||(a=Ef.mouse(this),b=Ld(e,a),b&&(c=le(b)?[b]:Nd(e,b.x),d=c.map(function(a){return pc(a)}),Sd(d,a),ai&&(Te(),Se(b.index,b.id)),Ud(d),De(b,a)<100?(lj.select("."+f.eventRect).style("cursor","pointer"),Ni||(Vg(b),Ni=!0)):(lj.select("."+f.eventRect).style("cursor",null),Wg(b),Ni=!1)))}).on("click",function(){var a,b,c=Ic(Ff.data.targets);he(c)||(a=Ef.mouse(this),b=Ld(c,a),b&&De(b,a)<100&&nj.select("."+f.circles+"-"+od(b.id)).select("."+f.circle+"-"+b.index).each(function(){ef(this,b,b.index)}))}).call(Ef.behavior.drag().origin(Object).on("drag",function(){ff(Ef.mouse(this))}).on("dragstart",function(){gf(Ef.mouse(this))}).on("dragend",function(){hf()})).call(kj).on("dblclick.zoom",null)}function ef(a,b,c){var d,e,g=Ef.select(a),h=g.classed(f.SELECTED);"circle"===a.nodeName?(d=xe(a,1.5*Qe(b)),e=He):"path"===a.nodeName&&(g.classed(f.bar)?(d=ye(a),e=Ke):(d=!0,e=Le)),(Rg||d)&&(Qg&&Sg(b)&&(Tg||nj.selectAll("."+f.shapes+(Rg?od(b.id):"")).selectAll("."+f.shape).each(function(a,b){var c=Ef.select(this);c.classed(f.SELECTED)&&e(!1,c.classed(f.SELECTED,!1),a,b)}),g.classed(f.SELECTED,!h),e(!h,g,b,c)),Ug(b,a))}function ff(a){var b,c,d,e,g,h,i,j;he(Ff.data.targets)||Qg&&(!Mf||kj.altDomain)&&Tg&&(b=Ki[0],c=Ki[1],d=a[0],e=a[1],g=Math.min(b,d),h=Math.max(b,d),i=Rg?Uf.top:Math.min(c,e),j=Rg?Zf:Math.max(c,e),nj.select("."+f.dragarea).attr("x",g).attr("y",i).attr("width",h-g).attr("height",j-i),nj.selectAll("."+f.shapes).selectAll("."+f.shape).filter(function(a){return Sg(a)}).each(function(a,b){var c,d,e,k,l,m,n=Ef.select(this),o=n.classed(f.SELECTED),p=n.classed(f.INCLUDED),q=!1;"circle"===this.nodeName?(c=1*n.attr("cx"),d=1*n.attr("cy"),l=He,q=c>g&&h>c&&d>i&&j>d):"path"===this.nodeName&&(m=Od(this),c=m.x,d=m.y,e=m.width,k=m.height,l=Ke,q=!(c>h||g>c+e||d>j||i>d+k)),q^p&&(n.classed(f.INCLUDED,!p),n.classed(f.SELECTED,!o),l(!o,n,a,b))}))}function gf(a){he(Ff.data.targets)||Qg&&(Ki=a,nj.select("."+f.chart).append("rect").attr("class",f.dragarea).style("opacity",.1),Li=!0,Zg())}function hf(){he(Ff.data.targets)||Qg&&(nj.select("."+f.dragarea).transition().duration(100).style("opacity",0).remove(),nj.selectAll("."+f.shape).classed(f.INCLUDED,!1),Li=!1,$g())}function jf(a){var c,e,g,h,i,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=Yd(),$=he(Ff.data.targets),_=Ic(Ff.data.targets);if(a=d(a)?a:{},E=d(a.withY)?a.withY:!0,F=d(a.withSubchart)?a.withSubchart:!0,G=d(a.withTransition)?a.withTransition:!0,J=d(a.withTransform)?a.withTransform:!1,K=d(a.withUpdateXDomain)?a.withUpdateXDomain:!1,M=d(a.withUpdateOrgXDomain)?a.withUpdateOrgXDomain:!1,N=d(a.withLegend)?a.withLegend:!1,H=d(a.withTransitionForExit)?a.withTransitionForExit:G,I=d(a.withTransitionForAxis)?a.withTransitionForAxis:G,T=G?Tf:0,U=H?T:0,V=I?T:0,c=nj.select("."+f.axisX).style("opacity",$?0:1),g=nj.select("."+f.axisY).style("opacity",$?0:1),h=nj.select("."+f.axisY2).style("opacity",$?0:1),e=oj.select("."+f.axisX).style("opacity",$?0:1),S={axisX:c.transition().duration(V),axisY:g.transition().duration(V),axisY2:h.transition().duration(V),axisSubX:e.transition().duration(V)},N&&ch&&zf(Cc(Ff.data.targets),a,S),Ii&&(0!==_.length&&M&&K||qg.domain([0,c.selectAll(".tick").size()])),_.length&&(M&&(qg.domain(Ef.extent(_b(_))),sj=qg.domain(),Mf&&kj.scale(qg).updateScaleExtent(),tg.domain(qg.domain()),gj.scale(tg)),K&&(qg.domain(gj.empty()?sj:gj.extent()),Mf&&kj.scale(qg).updateScaleExtent()),th||!sh&&!rh||(W=Kc(Jc(_),rh),wg.tickValues(W),zg.tickValues(W))),rg.domain(Xb(_,"y")),sg.domain(Xb(_,"y2")),S.axisX.call(wg),S.axisY.call(xg),S.axisY2.call(yg),S.axisSubX.call(zg),K&&_.length)if(ph&&W){for(X=1;X<W.length;X++)if(W.length/X<qh){Y=X;break}lj.selectAll("."+f.axisX+" .tick text").each(function(a){var b=W.indexOf(a);b>=0&&Ef.select(this).style("display",b%Y?"none":"block")})}else lj.selectAll("."+f.axisX+" .tick text").style("display","block");if(!ih&&uh&&eb(c,S.axisX,uh),O=Xe(Z),Q=Ye(Z,!0),R=Ye(Z,!1),Db(),ug.domain(rg.domain()),vg.domain(sg.domain()),qj.style("display","none"),o(),nj.select("line."+f.xgridFocus).style("visibility","hidden"),Th){if("year"===Uh){j=[];for(var ab=_b(),bb=ab[0].getFullYear(),cb=ab[1].getFullYear(),db=bb;cb>=db;db++)j.push(new Date(db+"-01-01 00:00:00"))}else j=qg.ticks(10);i=nj.select("."+f.xgrids).selectAll("."+f.xgrid).data(j),i.enter().append("line").attr("class",f.xgrid),i.attr("x1",ih?0:function(a){return qg(a)-wg.tickOffset()}).attr("x2",ih?Xf:function(a){return qg(a)-wg.tickOffset()}).attr("y1",ih?function(a){return qg(a)-wg.tickOffset()}:Uf.top).attr("y2",ih?function(a){return qg(a)-wg.tickOffset()}:Zf).style("opacity",function(){return+Ef.select(this).attr(ih?"y1":"x1")===(ih?Zf:0)?0:1}),i.exit().remove()}Be(Vh)&&(k=nj.select("."+f.xgridLines).selectAll("."+f.xgridLine).data(Vh),l=k.enter().append("g").attr("class",function(a){return f.xgridLine+(a.class?a.class:"")}),l.append("line").style("opacity",0),l.append("text").attr("text-anchor","end").attr("transform",ih?"":"rotate(-90)").attr("dx",ih?0:-Uf.top).attr("dy",-5).style("opacity",0),k.select("line").transition().duration(T).attr("x1",ih?0:Gd).attr("x2",ih?Xf:Gd).attr("y1",ih?Gd:Uf.top).attr("y2",ih?Gd:Zf).style("opacity",1),k.select("text").transition().duration(T).attr("x",ih?Xf:0).attr("y",Gd).text(function(a){return a.text}).style("opacity",1),k.exit().transition().duration(T).style("opacity",0).remove()),E&&Wh&&(m=nj.select("."+f.ygrids).selectAll("."+f.ygrid).data(rg.ticks(Yh)),m.enter().append("line").attr("class",f.ygrid),m.attr("x1",ih?rg:0).attr("x2",ih?rg:Xf).attr("y1",ih?0:rg).attr("y2",ih?Zf:rg),m.exit().remove()),E&&Be(Xh)&&(n=nj.select("."+f.ygridLines).selectAll("."+f.ygridLine).data(Xh),p=n.enter().append("g").attr("class",function(a){return f.ygridLine+(a.class?a.class:"")}),p.append("line").style("opacity",0),p.append("text").attr("text-anchor","end").attr("transform",ih?"rotate(-90)":"").attr("dx",ih?0:-Uf.top).attr("dy",-5).style("opacity",0),n.select("line").transition().duration(T).attr("x1",ih?Hd:0).attr("x2",ih?Hd:Xf).attr("y1",ih?0:Hd).attr("y2",ih?Zf:Hd).style("opacity",1),n.select("text").transition().duration(T).attr("x",ih?0:Xf).attr("y",Hd).text(function(a){return a.text}).style("opacity",1),n.exit().transition().duration(T).style("opacity",0).remove()),v=nj.select("."+f.regions).selectAll("rect."+f.region).data(ti),v.enter().append("rect").style("fill-opacity",0),v.attr("class",hd).attr("x",ec).attr("y",fc).attr("width",gc).attr("height",hc).transition().duration(T).style("fill-opacity",function(a){return b(a.opacity)?a.opacity:.1}),v.exit().transition().duration(T).style("fill-opacity",0).remove(),t=nj.selectAll("."+f.bars).selectAll("."+f.bar).data(re),t.enter().append("path").attr("class",bd).style("stroke","none").style("fill",Qi),t.style("opacity",td).transition().duration(T).attr("d",O).style("fill",Qi).style("opacity",1),t.exit().transition().duration(U).style("opacity",0).remove(),q=nj.selectAll("."+f.lines).selectAll("."+f.line).data(pe),q.enter().append("path").attr("class",Zc).style("stroke",Qi),q.style("opacity",td).transition().duration(T).attr("d",hj).style("opacity",1),q.exit().transition().duration(U).style("opacity",0).remove(),r=nj.selectAll("."+f.areas).selectAll("."+f.area).data(pe),r.enter().append("path").attr("class",fd).style("fill",Qi).style("opacity",function(){return tj=+Ef.select(this).style("opacity"),0}),r.style("opacity",0).transition().duration(T).attr("d",ij).style("opacity",tj),r.exit().transition().duration(U).style("opacity",0).remove(),s=nj.selectAll("."+f.circles).selectAll("."+f.circle).data(se),s.enter().append("circle").attr("class",_c).attr("r",Oe),s.style("opacity",td).transition().duration(T).style("opacity",vd).attr("cx",ih?Xd:Wd).attr("cy",ih?Wd:Xd),s.exit().remove(),w=nj.selectAll("."+f.texts).selectAll("."+f.text).data(te),w.enter().append("text").attr("class",Vc).attr("text-anchor",function(a){return ih?a.value<0?"end":"start":"middle"}).style("stroke","none").style("fill-opacity",0),w.text(function(a){return Ed(a.id)(a.value,a.id)}).style("fill-opacity",ud).transition().duration(T).attr("x",Q).attr("y",R).style("fill-opacity",wd),w.exit().transition().duration(U).style("fill-opacity",0).remove(),u=nj.selectAll("."+f.arcs).selectAll("."+f.arc).data(qe),u.enter().append("path").attr("class",dd).style("fill",function(a){return Qi(a.data)}).style("cursor",function(a){return Sg(a)?"pointer":null}).style("opacity",0).each(function(a){this._current=a}).on("mouseover",function(a,b){var c,d,e;Oi||(c=Fb(a),d=Lb(c),e=Tb(),Nb(c.data.id),vf(c.data.id,!0),e(d,b))}).on("mousemove",function(a){var b=Fb(a),c=Lb(b),d=[c];Sd(d,Ef.mouse(this))}).on("mouseout",function(a,b){var c,d,e;Oi||(c=Fb(a),d=Lb(c),e=Ub(),Ob(c.data.id),wf(),Td(),e(d,b))}).on("click",function(a,b){var c=Fb(a),d=Lb(c),e=Sb();ef(this,a,b),e(d,b)}),u.attr("transform",J?"scale(0)":"").style("opacity",function(a){return a===this._current?0:1}).each(function(){Oi=!0}).transition().duration(T).attrTween("d",function(a){var b,c=Fb(a);return c?(b=Ef.interpolate(this._current,c),this._current=b(0),function(a){return Ib(b(a),!0)}):function(){return"M 0 0"}}).attr("transform",J?"scale(1)":"").style("opacity",1).call(Ee,function(){Oi=!1}),u.exit().transition().duration(U).style("opacity",0).remove(),nj.selectAll("."+f.chartArc).select("text").attr("transform",Jb).style("opacity",0).transition().duration(T).text(Mb).style("opacity",function(a){return Gc(a.data.id)&&oe(a.data)?1:0}),nj.select("."+f.chartArcsTitle).style("opacity",ge(Ff.data.targets)?1:0),_g&&(null!==Ef.event&&"zoom"===Ef.event.type&&gj.extent(qg.orgDomain()).update(),F&&(!ih&&uh&&eb(e,S.axisSubX,uh),gj.empty()||gj.extent(qg.orgDomain()).update(),P=Xe(Z,!0),y=oj.selectAll("."+f.bars).selectAll("."+f.bar).data(re),y.enter().append("path").attr("class",bd).style("stroke","none").style("fill",Qi),y.style("opacity",td).transition().duration(T).attr("d",P).style("opacity",1),y.exit().transition().duration(T).style("opacity",0).remove(),x=oj.selectAll("."+f.lines).selectAll("."+f.line).data(pe),x.enter().append("path").attr("class",Zc).style("stroke",Qi),x.style("opacity",td).transition().duration(T).attr("d",jj).style("opacity",1),x.exit().transition().duration(T).style("opacity",0).remove())),nj.selectAll("."+f.selectedCircles).filter(function(a){return ke(a)}).selectAll("circle").remove(),nj.selectAll("."+f.selectedCircle).transition().duration(T).attr("cx",ih?Xd:Wd).attr("cy",ih?Wd:Xd),z=nj.select("."+f.eventRects),Be(Bg)&&!oc(Bg)?(z.classed(f.eventRectsMultiple)||z.classed(f.eventRectsMultiple,!0).classed(f.eventRectsSingle,!1).selectAll("."+f.eventRect).remove(),A=nj.select("."+f.eventRects).selectAll("."+f.eventRect).data([0]),df(A.enter()),A.attr("x",0).attr("y",0).attr("width",Xf).attr("height",Zf)):(z.classed(f.eventRectsSingle)||z.classed(f.eventRectsMultiple,!1).classed(f.eventRectsSingle,!0).selectAll("."+f.eventRect).remove(),Ji&&!Ii?(D=function(a,b){var c=xc(b),d=yc(b),e=Ff.data.xs[a.id][b];return(qg(d?d:e+50)-qg(c?c:e-50))/2},C=function(a,b){var c=xc(b),d=Ff.data.xs[a.id][b];return(qg(d)+qg(c?c:d-50))/2}):(D=L(),C=function(a){return qg(a.x)-D/2}),B=Ac(Ff.data.targets),nj.select("."+f.eventRects).datum(B?B.values:[]),A=nj.select("."+f.eventRects).selectAll("."+f.eventRect).data(function(a){return a}),cf(A.enter()),A.attr("class",id).attr("x",ih?0:C).attr("y",ih?C:0).attr("width",ih?Xf:D).attr("height",ih?D:Zf),A.exit().remove()),Cc(Ff.data.targets).forEach(function(a){uj[a]=!0})}function kf(){jf({withTransition:!1,withY:!1,withSubchart:!1,withUpdateXDomain:!0})}function lf(){return"mousemove"===Ef.event.sourceEvent.type&&kj.altDomain?(qg.domain(kj.altDomain),void kj.scale(qg).updateScaleExtent()):(Ii&&qg.orgDomain()[0]===sj[0]&&qg.domain([sj[0]-1e-10,qg.orgDomain()[1]]),jf({withTransition:!1,withY:!1,withSubchart:!1}),void("mousemove"===Ef.event.sourceEvent.type&&(Mi=!0)))}function mf(){function a(){b.forEach(function(a){a()})}var b=[];return a.add=function(a){b.push(a)},a}function nf(){lj.attr("width",_f).attr("height",ag),lj.select("#"+Bi).select("rect").attr("width",Xf).attr("height",Zf),lj.select("#"+Ci).select("rect").attr("x",B).attr("y",C).attr("width",H).attr("height",I),lj.select("#"+Di).select("rect").attr("x",D).attr("y",E).attr("width",J).attr("height",K),lj.select("."+f.zoomRect).attr("width",Xf).attr("height",Zf),rj.style("max-height",ag+"px")}function of(a){a=a||{},a.withTransition=d(a.withTransition)?a.withTransition:!0,a.withTransform=d(a.withTransform)?a.withTransform:!1,a.withLegend=d(a.withLegend)?a.withLegend:!1,a.withUpdateXDomain=!0,a.withUpdateOrgXDomain=!0,a.withTransitionForExit=!1,n(),R(),nf(),m(a.withTransition),jf(a)}function pf(a){var b,c,d,e,g,h,i,j,k,l,m,n;i=nj.select("."+f.chartTexts).selectAll("."+f.chartText).data(a).attr("class",kd),j=i.enter().append("g").attr("class",kd).style("opacity",0).style("pointer-events","none"),j.append("g").attr("class",Wc).style("fill",Qi),e=nj.select("."+f.chartBars).selectAll("."+f.chartBar).data(a).attr("class",md),d=e.enter().append("g").attr("class",md).style("opacity",0).style("pointer-events","none"),d.append("g").attr("class",cd).style("cursor",function(a){return Sg(a)?"pointer":null}),c=nj.select("."+f.chartLines).selectAll("."+f.chartLine).data(a).attr("class",ld),b=c.enter().append("g").attr("class",ld).style("opacity",0).style("pointer-events","none"),b.append("g").attr("class",$c),b.append("g").attr("class",gd),b.append("g").attr("class",function(a){return Uc(f.selectedCircles,a.id)}),b.append("g").attr("class",ad).style("fill",Qi).style("cursor",function(a){return Sg(a)?"pointer":null}),a.forEach(function(a){nj.selectAll("."+f.selectedCircles+od(a.id)).selectAll("."+f.selectedCircle).each(function(b,c){b.value=a.values[c].value})}),h=nj.select("."+f.chartArcs).selectAll("."+f.chartArc).data(hg(a)).attr("class",nd),g=h.enter().append("g").attr("class",nd),g.append("g").attr("class",ed),g.append("text").attr("dy",".35em").style("opacity",0).style("text-anchor","middle").style("pointer-events","none"),_g&&(n=oj.select("."+f.chartBars).selectAll("."+f.chartBar).data(a).attr("class",md),m=n.enter().append("g").style("opacity",0).attr("class",md),m.append("g").attr("class",cd),l=oj.select("."+f.chartLines).selectAll("."+f.chartLine).data(a).attr("class",ld),k=l.enter().append("g").style("opacity",0).attr("class",ld),k.append("g").attr("class",$c)),lj.selectAll("."+f.target).filter(function(a){return Gc(a.id)}).transition().duration(Tf).style("opacity",1)}function qf(a,b){(b.type||b.types)&&a.forEach(function(a){b.types?be(a.id,b.types[a.id]):be(a.id,b.type)}),Ff.data.targets.forEach(function(b){for(var c=0;c<a.length;c++)if(b.id===a[c].id){b.values=a[c].values,a.splice(c,1);break}}),Ff.data.targets=Ff.data.targets.concat(a),pf(Ff.data.targets),jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),"function"==typeof b.done&&b.done()}function rf(a){if("data"in a)qf(vc(a.data),a);else if("url"in a)Ef.csv(a.url,function(b,c){qf(vc(c),a)});else if("rows"in a)qf(vc(tc(a.rows)),a);else{if(!("columns"in a))throw Error("url or rows or columns is required.");qf(vc(uc(a.columns)),a)}}function sf(a,b){return"function"!=typeof b&&(b=function(){}),a=a.filter(function(a){return Ec(Ff.data.targets,a)}),a&&0!==a.length?(lj.selectAll(a.map(function(a){return pd(a)})).transition().style("opacity",0).remove().call(Ee,b),void a.forEach(function(a){uj[a]=!1,pj.selectAll("."+f.legendItem+od(a)).remove(),Ff.data.targets=Ff.data.targets.filter(function(b){return b.id!==a})})):void b()}function tf(a){return a.classed(f.legendItemHidden)?cj:1}function uf(a){return a.classed(f.legendItemHidden)?cj:.3}function vf(a,b){pj.selectAll("."+f.legendItem).transition().duration(100).style("opacity",function(c){var d=Ef.select(this);return a&&c!==a?b?uf(d):tf(d):b?tf(d):uf(d)})}function wf(){pj.selectAll("."+f.legendItem).transition().duration(100).style("opacity",function(){return tf(Ef.select(this))})}function xf(a){ch||(ch=!0,pj.style("visibility","visible")),Oc(a),pj.selectAll(sd(a)).style("visibility","visible").transition().style("opacity",function(){return tf(Ef.select(this))})}function yf(a){ch&&Ae(a)&&(ch=!1,pj.style("visibility","hidden")),Nc(a),pj.selectAll(sd(a)).style("opacity",0).style("visibility","hidden")}function zf(a,b,c){function e(b,c,d){function e(a,b){b||(f=(l-w-k)/2,v>f&&(f=(l-k)/2,w=0,C++)),B[a]=C,A[C]=f,x[a]=w,w+=k}var f,g,h=b.getBoundingClientRect(),i=10*Math.ceil((h.width+s)/10),j=10*Math.ceil((h.height+r)/10),k=$i?j:i,l=$i?Q():P();return d&&(w=0,C=0,t=0,u=0),ch&&!Hc(c)?void(y[c]=z[c]=B[c]=x[c]=0):(y[c]=i,z[c]=j,(!t||i>=t)&&(t=i),(!u||j>=u)&&(u=j),g=$i?u:t,void(hh?(Object.keys(y).forEach(function(a){y[a]=t}),Object.keys(z).forEach(function(a){z[a]=u}),f=(l-g*a.length)/2,v>f?(w=0,C=0,a.forEach(function(a){e(a)})):e(c,!0)):e(c)))}var g,h,i,j,k,l,o,p,q,r=4,s=26,t=0,u=0,v=10,w=0,x={},y={},z={},A=[0],B={},C=0,D=pj.selectAll("."+f.legendItemFocused).size();b=b||{},p=d(b.withTransition)?b.withTransition:!0,q=d(b.withTransitionForTransform)?b.withTransitionForTransform:!0,$i?(g=function(a){return t*(.2+B[a])},j=function(a){return A[B[a]]+x[a]}):(g=function(a){return A[B[a]]+x[a]},j=function(a){return u*(.2+B[a])}),h=function(a,b){return g(a,b)+14},k=function(a,b){return j(a,b)+9},i=function(a,b){return g(a,b)-4},l=function(a,b){return j(a,b)-7},o=pj.selectAll("."+f.legendItem).data(a).enter().append("g").attr("class",function(a){return Uc(f.legendItem,a)}).style("visibility",function(a){return Hc(a)?"visible":"hidden"}).style("cursor","pointer").on("click",function(a){"function"==typeof eh?eh(a):Ff.toggle(a)}).on("mouseover",function(a){Ef.select(this).classed(f.legendItemFocused,!0),Oi||Ff.focus(a),"function"==typeof fh&&fh(a)}).on("mouseout",function(a){Ef.select(this).classed(f.legendItemFocused,!1),Oi||Ff.revert(),"function"==typeof gh&&gh(a)}),o.append("text").text(function(a){return d(Eg[a])?Eg[a]:a}).each(function(a,b){e(this,a,0===b)}).style("pointer-events","none").attr("x",$i?h:-200).attr("y",$i?-200:k),o.append("rect").attr("class",f.legendItemEvent).style("fill-opacity",0).attr("x",$i?i:-200).attr("y",$i?-200:l).attr("width",function(a){return y[a]}).attr("height",function(a){return z[a]}),o.append("rect").attr("class",f.legendItemTile).style("pointer-events","none").style("fill",function(a){return Qi(a)}).attr("x",$i?h:-200).attr("y",$i?-200:j).attr("width",10).attr("height",10),pj.selectAll("text").data(a).text(function(a){return d(Eg[a])?Eg[a]:a}).each(function(a,b){e(this,a,0===b)}).transition().duration(p?250:0).attr("x",h).attr("y",k),pj.selectAll("rect."+f.legendItemEvent).data(a).transition().duration(p?250:0).attr("x",i).attr("y",l),pj.selectAll("rect."+f.legendItemTile).data(a).transition().duration(p?250:0).attr("x",g).attr("y",j),pj.selectAll("."+f.legendItem).classed(f.legendItemHidden,function(a){return!Gc(a)}).transition().style("opacity",function(a){var b=Ef.select(this);return Gc(a)?!D||b.classed(f.legendItemFocused)?tf(b):uf(b):cj}),N(t),O(u),M(C),n(),R(),nf(),m(q,c)}function Af(a){return Ec(Ff.data.targets,a.id)}function Bf(a){return"data"in a&&Ec(Ff.data.targets,a.data.id)}function Cf(a){var b=a&&a.value?a.value:null,c=a&&a["class"]?a["class"]:null;return b?function(a){return a.value!==b}:c?function(a){return a["class"]!==c}:function(){return!0}}function Df(a,b,c){var d=!he(Ff.data.targets);Oi=!1,be(a,b),of(c||{withTransitionForAxis:d})}var Ef=a.d3?a.d3:a.require?a.require("d3"):void 0,Ff={data:{},axis:{},legend:{}},Gf={},Hf=h(["bindto"],"#chart"),If=h(["size","width"]),Jf=h(["size","height"]),Kf=h(["padding","left"],50),Lf=h(["padding","right"]),Mf=h(["zoom","enabled"],!1),Nf=h(["zoom","extent"]),Of=h(["zoom","privileged"],!1),Pf=h(["onenter"],function(){}),Qf=h(["onleave"],function(){}),Rf=h(["onresize"],function(){}),Sf=h(["onresized"],function(){}),Tf=h(["transition","duration"],350);g("data","data is required in config");var Uf,Vf,Wf,Xf,Yf,Zf,$f,_f,ag,bg,cg,dg,eg,fg,gg,hg,ig,jg,kg,lg,mg,ng,og,pg,qg,rg,sg,tg,ug,vg,wg,xg,yg,zg,Ag=h(["data","x"]),Bg=h(["data","xs"],{}),Cg=h(["data","x_format"]),Dg=h(["data","id_converter"],function(a){return a}),Eg=h(["data","names"],{}),Fg=h(["data","classes"],{}),Gg=h(["data","groups"],[]),Hg=h(["data","axes"],{}),Ig=h(["data","type"]),Jg=h(["data","types"],{}),Kg=h(["data","labels"],{}),Lg=h(["data","order"]),Mg=h(["data","regions"],{}),Ng=h(["data","color"]),Og=h(["data","colors"],{}),Pg=h(["data","hide"],!1),Qg=h(["data","selection","enabled"],!1),Rg=h(["data","selection","grouped"],!1),Sg=h(["data","selection","isselectable"],function(){return!0}),Tg=h(["data","selection","multiple"],!0),Ug=h(["data","onclick"],function(){}),Vg=h(["data","onenter"],function(){}),Wg=h(["data","onleave"],function(){}),Xg=h(["data","onselected"],function(){}),Yg=h(["data","onunselected"],function(){}),Zg=h(["data","ondragstart"],function(){}),$g=h(["data","ondragend"],function(){}),_g=h(["subchart","show"],!1),ah=h(["subchart","size","height"],60),bh=h(["color","pattern"],[]),ch=h(["legend","show"],!0),dh=h(["legend","position"],"bottom"),eh=h(["legend","item","onclick"]),fh=h(["legend","item","onmouseover"]),gh=h(["legend","item","onmouseout"]),hh=h(["legend","equally"],!1),ih=h(["axis","rotated"],!1),jh=h(["axis","x","show"],!0),kh=h(["axis","x","type"],"indexed"),lh=h(["axis","x","localtime"],!0),mh=h(["axis","x","categories"],[]),nh=h(["axis","x","tick","centered"],!1),oh=h(["axis","x","tick","format"]),ph=h(["axis","x","tick","culling"],{}),qh=h(["axis","x","tick","culling","max"],10),rh=h(["axis","x","tick","count"]),sh=h(["axis","x","tick","fit"],!0),th=h(["axis","x","tick","values"],null),uh=h(["axis","x","tick","rotate"]),vh=h(["axis","x","max"],null),wh=h(["axis","x","min"],null),xh=h(["axis","x","padding"],{}),yh=h(["axis","x","height"]),zh=h(["axis","x","default"]),Ah=h(["axis","x","label"],{}),Bh=h(["axis","y","show"],!0),Ch=h(["axis","y","max"]),Dh=h(["axis","y","min"]),Eh=h(["axis","y","center"]),Fh=h(["axis","y","label"],{}),Gh=h(["axis","y","inner"],!1),Hh=h(["axis","y","tick","format"]),Ih=h(["axis","y","padding"]),Jh=h(["axis","y","ticks"],10),Kh=h(["axis","y2","show"],!1),Lh=h(["axis","y2","max"]),Mh=h(["axis","y2","min"]),Nh=h(["axis","y2","center"]),Oh=h(["axis","y2","label"],{}),Ph=h(["axis","y2","inner"],!1),Qh=h(["axis","y2","tick","format"]),Rh=h(["axis","y2","padding"]),Sh=h(["axis","y2","ticks"],10),Th=h(["grid","x","show"],!1),Uh=h(["grid","x","type"],"tick"),Vh=h(["grid","x","lines"],[]),Wh=h(["grid","y","show"],!1),Xh=h(["grid","y","lines"],[]),Yh=h(["grid","y","ticks"],10),Zh=h(["point","show"],!0),$h=h(["point","r"],2.5),_h=h(["point","focus","line","enabled"],!0),ai=h(["point","focus","expand","enabled"],!0),bi=h(["point","focus","expand","r"]),ci=h(["point","focus","select","r"]),di=h(["line","connect_null"],!1),ei=h(["bar","width"]),fi=h(["bar","width","ratio"],.6),gi=h(["pie","label","show"],!0),hi=h(["pie","label","format"]),ii=h(["pie","expand"],!0),ji=h(["pie","onclick"],function(){}),ki=h(["pie","onmouseover"],function(){}),li=h(["pie","onmouseout"],function(){}),mi=h(["donut","label","show"],!0),ni=h(["donut","label","format"]),oi=h(["donut","expand"],!0),pi=h(["donut","title"],""),qi=h(["donut","onclick"],function(){}),ri=h(["donut","onmouseover"],function(){}),si=h(["donut","onmouseout"],function(){}),ti=h(["regions"],[]),ui=h(["tooltip","show"],!0),vi=h(["tooltip","format","title"]),wi=h(["tooltip","format","value"]),xi=h(["tooltip","contents"],function(a,b,c,d){var e,g,h,i,j,k=vi?vi:b,l=wi?wi:c;for(g=0;g<a.length;g++)a[g]&&(a[g].value||0===a[g].value)&&(e||(h=k?k(a[g].x):a[g].x,e="<table class='"+f.tooltip+"'>"+(h||0===h?"<tr><th colspan='2'>"+h+"</th></tr>":"")),j=a[g].name,i=l(a[g].value,a[g].ratio,a[g].id,a[g].index),e+="<tr class='"+f.tooltipName+"-"+a[g].id+"'>",e+="<td class='name'><span style='background-color:"+d(a[g].id)+"'></span>"+j+"</td>",e+="<td class='value'>"+i+"</td>",e+="</tr>");return e+"</table>"}),yi=h(["tooltip","init","show"],!1),zi=h(["tooltip","init","x"],0),Ai=h(["tooltip","init","position"],{top:"0px",left:"50px"}),Bi=("string"==typeof Hf?Hf.replace("#",""):Hf.id)+"-clip",Ci=Bi+"-xaxis",Di=Bi+"-yaxis",Ei=i(Bi),Fi=i(Ci),Gi=i(Di),Hi="timeseries"===kh,Ii="categorized"===kh,Ji=!Hi&&(Ag||Be(Bg)),Ki=null,Li=!1,Mi=!1,Ni=!1,Oi=!1,Pi=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"],Qi=ve(Og,Be(bh)?bh:Pi,Ng),Ri=lh?Ef.time.format:Ef.time.format.utc,Si=function(){var a=[[Ri("%Y/%-m/%-d"),function(){return!0}],[Ri("%-m/%-d"),function(a){return a.getMonth()}],[Ri("%-m/%-d"),function(a){return 1!==a.getDate()}],[Ri("%-m/%-d"),function(a){return a.getDay()&&1!==a.getDate()}],[Ri("%I %p"),function(a){return a.getHours()}],[Ri("%I:%M"),function(a){return a.getMinutes()}],[Ri(":%S"),function(a){return a.getSeconds()}],[Ri(".%L"),function(a){return a.getMilliseconds()}]];return function(b){for(var c=a.length-1,d=a[c];!d[1](b);)d=a[--c];return d[0](b)}}(),Ti=[],Ui=[],Vi=ih?"left":"bottom",Wi=ih?Gh?"top":"bottom":Gh?"right":"left",Xi=ih?Ph?"bottom":"top":Ph?"left":"right",Yi=ih?"left":"bottom",Zi={main:function(){return"translate("+Uf.left+","+Uf.top+")"},context:function(){return"translate("+Vf.left+","+Vf.top+")"},legend:function(){return"translate("+Wf.left+","+Wf.top+")"},x:function(){return"translate(0,"+(ih?0:Zf)+")"},y:function(){return"translate(0,"+(ih?Zf:0)+")"},y2:function(){return"translate("+(ih?0:Xf)+","+(ih?1:0)+")"},subx:function(){return"translate(0,"+(ih?0:$f)+")"},arc:function(){return"translate("+Xf/2+","+Zf/2+")"}},$i="right"===dh,_i=0,aj=0,bj=0,cj=.15,dj=30,ej=ih&&!jh?0:30,fj=5;hg=Ef.layout.pie().value(function(a){return a.values.reduce(function(a,b){return a+b.value},0)});var gj,hj=function(){var a=Ef.svg.line().x(ih?function(a){return V(a.id)(a.value)}:Fd).y(ih?Fd:function(a){return V(a.id)(a.value)});return di||(a=a.defined(function(a){return null!=a.value})),function(b){var c,d,e=di?Ne(b.values):b.values;return ie(b)?(a.interpolate(je(b)?"cardinal":"linear"),Mg[b.id]?af(e,qg,V(b.id),Mg[b.id]):a(e)):(c=e[0]?qg(e[0].x):0,d=e[0]?V(b.id)(e[0].value):0,ih?"M "+d+" "+c:"M "+c+" "+d)}}(),ij=function(){var a;return a=ih?Ef.svg.area().x0(function(a){return V(a.id)(0)}).x1(function(a){return V(a.id)(a.value)}).y(Fd):Ef.svg.area().x(Fd).y0(function(a){return V(a.id)(0)}).y1(function(a){return V(a.id)(a.value)}),function(b){var c,d,e=Ne(b.values);return ce([b],"area")||ce([b],"area-spline")?(a.interpolate(je(b)?"cardinal":"linear"),a(e)):(c=e[0]?qg(e[0].x):0,d=e[0]?V(b.id)(e[0].value):0,ih?"M "+d+" "+c:"M "+c+" "+d)}}(),jj=function(){var a=Ef.svg.line().x(ih?function(a){return W(a.id)(a.value)}:Id).y(ih?Id:function(a){return W(a.id)(a.value)});return function(b){var c=Ne(b.values);return ie(b)?a(c):"M "+tg(c[0].x)+" "+W(b.id)(c[0].value)}}(),kj=function(){};gj=Ef.svg.brush().on("brush",kf),gj.update=function(){return oj&&oj.select("."+f.brush).call(this),this},gj.scale=function(a){return ih?this.y(a):this.x(a)},Mf&&(kj=Ef.behavior.zoom().on("zoomstart",function(){kj.altDomain=Ef.event.sourceEvent.altKey?qg.orgDomain():null}).on("zoom",Mf?lf:null),kj.scale=function(a){return ih?this.y(a):this.x(a)},kj.orgScaleExtent=function(){var a=Nf?Nf:[1,10];return[a[0],Math.max(zc()/a[1],a[1])]},kj.updateScaleExtent=function(){var a=ac(qg.orgDomain())/ac(sj),b=this.orgScaleExtent();return this.scaleExtent([b[0]*a,b[1]*a]),this});var lj,mj,nj,oj,pj,qj,rj,sj,tj,uj={};if(Ff.focus=function(a){function b(a){Ic(a).transition().duration(100).style("opacity",1)}var c=lj.selectAll(pd(a)),d=c.filter(Af),e=c.filter(Bf);Ff.revert(),Ff.defocus(),b(d.classed(f.focused,!0)),b(e),he(Ff.data.targets)&&Nb(a,!0),vf(a,!0)},Ff.defocus=function(a){function b(a){Ic(a).transition().duration(100).style("opacity",.3)}var c=lj.selectAll(pd(a)),d=c.filter(Af),e=c.filter(Bf);Ff.revert(),b(d.classed(f.focused,!1)),b(e),he(Ff.data.targets)&&Ob(a),vf(a,!1)},Ff.revert=function(a){function b(a){Ic(a).transition().duration(100).style("opacity",1)}var c=lj.selectAll(pd(a)),d=c.filter(Af),e=c.filter(Bf);b(d.classed(f.focused,!1)),b(e),he(Ff.data.targets)&&Ob(a),wf()},Ff.show=function(a,b){a=Dc(a),b=b||{},Mc(a),lj.selectAll(qd(a)).transition().style("opacity",1),b.withLegend&&xf(a),jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},Ff.hide=function(a,b){a=Dc(a),b=b||{},Lc(a),lj.selectAll(qd(a)).transition().style("opacity",0),b.withLegend&&yf(a),jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},Ff.toggle=function(a){Gc(a)?Ff.hide(a):Ff.show(a)},Ff.unzoom=function(){gj.clear().update(),jf({withUpdateXDomain:!0})},Ff.load=function(a){return a.xs&&nc(a.xs),"classes"in a&&Object.keys(a.classes).forEach(function(b){Fg[b]=a.classes[b]}),"categories"in a&&Ii&&(mh=a.categories,wg.categories(mh)),"cacheIds"in a&&bc(a.cacheIds)?void qf(dc(a.cacheIds),a.done):void("unload"in a?sf(Dc("boolean"==typeof a.unload&&a.unload?null:a.unload),function(){rf(a)}):rf(a))},Ff.unload=function(a,b){sf(Dc(a),function(){jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),"function"==typeof b&&b()})},Ff.selected=function(a){return Ef.merge(nj.selectAll("."+f.shapes+od(a)).selectAll("."+f.shape).filter(function(){return Ef.select(this).classed(f.SELECTED)}).map(function(a){return a.map(function(a){var b=a.__data__;return b.data?b.data:b})}))},Ff.select=function(a,b,c){Qg&&nj.selectAll("."+f.shapes).selectAll("."+f.shape).each(function(e,g){var h=Ef.select(this),i=e.data?e.data.id:e.id,j=Me(this),k=Rg||!a||a.indexOf(i)>=0,l=!b||b.indexOf(g)>=0,m=h.classed(f.SELECTED);k&&l?Sg(e)&&!m&&j(!0,h.classed(f.SELECTED,!0),e,g):d(c)&&c&&m&&j(!1,h.classed(f.SELECTED,!1),e,g)})},Ff.unselect=function(a,b){Qg&&nj.selectAll("."+f.shapes).selectAll("."+f.shape).each(function(c,d){var e=Ef.select(this),g=c.data?c.data.id:c.id,h=Me(this),i=Rg||!a||a.indexOf(g)>=0,j=!b||b.indexOf(d)>=0,k=e.classed(f.SELECTED);i&&j&&Sg(c)&&k&&h(!1,e.classed(f.SELECTED,!1),c,d)
-})},Ff.toLine=function(a){Df(a,"line")},Ff.toSpline=function(a){Df(a,"spline")},Ff.toBar=function(a){Df(a,"bar")},Ff.toScatter=function(a){Df(a,"scatter")},Ff.toArea=function(a){Df(a,"area")},Ff.toAreaSpline=function(a){Df(a,"area-spline")},Ff.toPie=function(a){Df(a,"pie",{withTransform:!0})},Ff.toDonut=function(a){Df(a,"donut",{withTransform:!0})},Ff.groups=function(a){return c(a)?Gg:(Gg=a,jf(),Gg)},Ff.xgrids=function(a){return a?(Vh=a,jf(),Vh):Vh},Ff.xgrids.add=function(a){return a?Ff.xgrids(Vh.concat(a)):void 0},Ff.xgrids.remove=function(a){var b=Cf(a);return Ff.xgrids(Vh.filter(b))},Ff.ygrids=function(a){return a?(Xh=a,jf(),Xh):Xh},Ff.ygrids.add=function(a){return a?Ff.ygrids(Xh.concat(a)):void 0},Ff.ygrids.remove=function(a){var b=Cf(a);return Ff.ygrids(Xh.filter(b))},Ff.regions=function(a){return c(a)?ti:(ti=a,jf(),ti)},Ff.regions.add=function(a){return c(a)?ti:(ti=ti.concat(a),jf(),ti)},Ff.regions.remove=function(a,c){var e=[].concat(a);return c=d(c)?c:{},e.forEach(function(a){var d=b(c.duration)?c.duration:0;lj.selectAll("."+a).transition().duration(d).style("fill-opacity",0).remove(),ti=ti.filter(function(b){return b.classes.indexOf(a)<0})}),ti},Ff.data.get=function(a){var b=Ff.data.getAsTarget(a);return d(b)?b.values.map(function(a){return a.value}):void 0},Ff.data.getAsTarget=function(a){var b=Fc(function(b){return b.id===a});return b.length>0?b[0]:void 0},Ff.data.names=function(a){return arguments.length?(Object.keys(a).forEach(function(b){Eg[b]=a[b]}),zf(Cc(Ff.data.targets),{withTransition:!0}),Eg):Eg},Ff.x=function(a){return arguments.length&&(qc(Ff.data.targets,a),jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),Ff.data.xs},Ff.xs=function(a){return arguments.length&&(rc(Ff.data.targets,a),jf({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),Ff.data.xs},Ff.axis.labels=function(a){arguments.length&&(Object.keys(a).forEach(function(b){bb(b,a[b])}),Db())},Ff.axis.max=function(a){arguments.length&&("object"==typeof a?(b(a.y)&&(Ch=+a.y),b(a.y2)&&(Lh=+a.y2)):Ch=Lh=+a,jf())},Ff.axis.min=function(a){arguments.length&&("object"==typeof a?(b(a.y)&&(Dh=+a.y),b(a.y2)&&(Mh=+a.y2)):Dh=Mh=+a,jf())},Ff.axis.range=function(a){arguments.length&&("undefined"!=typeof a.max&&Ff.axis.max(a.max),"undefined"!=typeof a.min&&Ff.axis.min(a.min))},Ff.legend.show=function(a){xf(Dc(a)),jf({withLegend:!0})},Ff.legend.hide=function(a){yf(Dc(a)),jf({withLegend:!0})},Ff.resize=function(a){If=a?a.width:null,Jf=a?a.height:null,of({withLegend:!0,withTransition:!1,withTransitionForTransform:!1})},Ff.destroy=function(){Ff.data.targets=void 0,Ff.data.xs={},rj.html(""),a.onresize=null},"url"in e.data)Ef.xhr(e.data.url,function(a,b){var c,d=Ef.csv.parseRows(b.response);1===d.length?(c=[{}],d[0].forEach(function(a){c[0][a]=null})):c=Ef.csv.parse(b.response),bf(c)});else if("rows"in e.data)bf(tc(e.data.rows));else{if(!("columns"in e.data))throw Error("url or rows or columns is required.");bf(uc(e.data.columns))}return Ff},"function"==typeof a.define&&a.define.amd?a.define("c3",["d3"],e):a.c3=e}(window);
\ No newline at end of file
+!function(a){"use strict";function b(a){var b=this.internal=new c(this);b.loadConfig(a),b.init(),function d(a,b,c){Object.keys(a).forEach(function(e){b[e]=a[e].bind(c),Object.keys(a[e]).length>0&&d(a[e],b[e],c)})}(e,this,this)}function c(b){var c=this;c.d3=a.d3?a.d3:"undefined"!=typeof require?require("d3"):void 0,c.api=b,c.config=c.getDefaultConfig(),c.data={},c.cache={},c.axes={}}function d(a,b){function c(a,b){a.attr("transform",function(a){return"translate("+Math.ceil(b(a)+t)+", 0)"})}function d(a,b){a.attr("transform",function(a){return"translate(0,"+Math.ceil(b(a))+")"})}function e(a){var b=a[0],c=a[a.length-1];return c>b?[b,c]:[c,b]}function f(a){var b,c,d=[];if(a.ticks)return a.ticks.apply(a,m);for(c=a.domain(),b=Math.ceil(c[0]);b<c[1];b++)d.push(b);return d.length>0&&d[0]>0&&d.unshift(d[0]-(d[1]-d[0])),d}function g(){var a,c=o.copy();return b.isCategory&&(a=o.domain(),c.domain([a[0],a[1]-1])),c}function h(a){return l?l(a):a}function i(a){if(w)return w;var b={h:11.5,w:5.5};return a.select("text").text(h).each(function(a){var c=this.getBoundingClientRect(),d=h(a),e=c.height,f=d?c.width/d.length:void 0;e&&f&&(b.h=e,b.w=f)}).text(""),w=b,b}function j(j){j.each(function(){function j(a,c){function d(a,b){f=void 0;for(var h=1;h<b.length;h++)if(" "===b.charAt(h)&&(f=h),e=b.substr(0,h+1),g=O.w*e.length,g>c)return d(a.concat(b.substr(0,f?f:h)),b.slice(f?f+1:h));return a.concat(b)}var e,f,g,i=h(a),j=[];return"[object Array]"===Object.prototype.toString.call(i)?i:((!c||0>=c)&&(c=R?95:b.isCategory?Math.ceil(z(A[1])-z(A[0]))-12:110),d(j,i+""))}function l(a,c){var d=O.h;return 0===c&&(d="left"===p||"right"===p?-((P[a.index]-1)*(O.h/2)-(b.isCategory?2:3)):".71em"),d}function m(a){var b=o(a)+t;return F[0]<b&&b<F[1]?q:0}var u,v,w,x=a.select(this),y=this.__chart__||o,z=this.__chart__=g(),A=s?s:f(z),B=x.selectAll(".tick").data(A,z),C=B.enter().insert("g",".domain").attr("class","tick").style("opacity",1e-6),D=B.exit().remove(),E=a.transition(B).style("opacity",1),F=o.rangeExtent?o.rangeExtent():e(o.range()),G=x.selectAll(".domain").data([0]),H=(G.enter().append("path").attr("class","domain"),a.transition(G));C.append("line"),C.append("text");var I=C.select("line"),J=E.select("line"),K=C.select("text"),L=E.select("text");b.isCategory?(t=Math.ceil((z(1)-z(0))/2),v=n?0:t,w=n?t:0):t=v=0;var M,N,O=i(x.select(".tick")),P=[],Q=Math.max(q,0)+r,R="left"===p||"right"===p;switch(M=B.select("text"),N=M.selectAll("tspan").data(function(a,c){var d=b.tickMultiline?j(a,b.tickWidth):[].concat(h(a));return P[c]=d.length,d.map(function(a){return{index:c,splitted:a}})}),N.enter().append("tspan"),N.exit().remove(),N.text(function(a){return a.splitted}),p){case"bottom":u=c,I.attr("y2",q),K.attr("y",Q),J.attr("x1",v).attr("x2",v).attr("y2",m),L.attr("x",0).attr("y",Q),M.style("text-anchor","middle"),N.attr("x",0).attr("dy",l),H.attr("d","M"+F[0]+","+k+"V0H"+F[1]+"V"+k);break;case"top":u=c,I.attr("y2",-q),K.attr("y",-Q),J.attr("x2",0).attr("y2",-q),L.attr("x",0).attr("y",-Q),M.style("text-anchor","middle"),N.attr("x",0).attr("dy","0em"),H.attr("d","M"+F[0]+","+-k+"V0H"+F[1]+"V"+-k);break;case"left":u=d,I.attr("x2",-q),K.attr("x",-Q),J.attr("x2",-q).attr("y1",w).attr("y2",w),L.attr("x",-Q).attr("y",t),M.style("text-anchor","end"),N.attr("x",-Q).attr("dy",l),H.attr("d","M"+-k+","+F[0]+"H0V"+F[1]+"H"+-k);break;case"right":u=d,I.attr("x2",q),K.attr("x",Q),J.attr("x2",q).attr("y2",0),L.attr("x",Q).attr("y",0),M.style("text-anchor","start"),N.attr("x",Q).attr("dy",l),H.attr("d","M"+k+","+F[0]+"H0V"+F[1]+"H"+k)}if(z.rangeBand){var S=z,T=S.rangeBand()/2;y=z=function(a){return S(a)+T}}else y.rangeBand?y=z:D.call(u,z);C.call(u,y),E.call(u,z)})}var k,l,m,n,o=a.scale.linear(),p="bottom",q=6,r=3,s=null,t=0,u=!0;return b=b||{},k=b.withOuterTick?6:0,j.scale=function(a){return arguments.length?(o=a,j):o},j.orient=function(a){return arguments.length?(p=a in{top:1,right:1,bottom:1,left:1}?a+"":"bottom",j):p},j.tickFormat=function(a){return arguments.length?(l=a,j):l},j.tickCentered=function(a){return arguments.length?(n=a,j):n},j.tickOffset=function(){return t},j.ticks=function(){return arguments.length?(m=arguments,j):m},j.tickCulling=function(a){return arguments.length?(u=a,j):u},j.tickValues=function(a){if("function"==typeof a)s=function(){return a(o.domain())};else{if(!arguments.length)return s;s=a}return j},j}var e,f,g={version:"0.4.6"};g.generate=function(a){return new b(a)},g.chart={fn:b.prototype,internal:{fn:c.prototype}},e=g.chart.fn,f=g.chart.internal.fn,f.init=function(){var a=this,b=a.config;if(a.initParams(),b.data_url)a.convertUrlToData(b.data_url,b.data_mimeType,b.data_keys,a.initWithData);else if(b.data_json)a.initWithData(a.convertJsonToData(b.data_json,b.data_keys));else if(b.data_rows)a.initWithData(a.convertRowsToData(b.data_rows));else{if(!b.data_columns)throw Error("url or json or rows or columns is required.");a.initWithData(a.convertColumnsToData(b.data_columns))}},f.initParams=function(){var a=this,b=a.d3,c=a.config;a.clipId="c3-"+ +new Date+"-clip",a.clipIdForXAxis=a.clipId+"-xaxis",a.clipIdForYAxis=a.clipId+"-yaxis",a.clipIdForGrid=a.clipId+"-grid",a.clipIdForSubchart=a.clipId+"-subchart",a.clipPath=a.getClipPath(a.clipId),a.clipPathForXAxis=a.getClipPath(a.clipIdForXAxis),a.clipPathForYAxis=a.getClipPath(a.clipIdForYAxis),a.clipPathForGrid=a.getClipPath(a.clipIdForGrid),a.clipPathForSubchart=a.getClipPath(a.clipIdForSubchart),a.dragStart=null,a.dragging=!1,a.flowing=!1,a.cancelClick=!1,a.mouseover=!1,a.transiting=!1,a.color=a.generateColor(),a.levelColor=a.generateLevelColor(),a.dataTimeFormat=c.data_xLocaltime?b.time.format:b.time.format.utc,a.axisTimeFormat=c.axis_x_localtime?b.time.format:b.time.format.utc,a.defaultAxisTimeFormat=a.axisTimeFormat.multi([[".%L",function(a){return a.getMilliseconds()}],[":%S",function(a){return a.getSeconds()}],["%I:%M",function(a){return a.getMinutes()}],["%I %p",function(a){return a.getHours()}],["%-m/%-d",function(a){return a.getDay()&&1!==a.getDate()}],["%-m/%-d",function(a){return 1!==a.getDate()}],["%-m/%-d",function(a){return a.getMonth()}],["%Y/%-m/%-d",function(){return!0}]]),a.hiddenTargetIds=[],a.hiddenLegendIds=[],a.focusedTargetIds=[],a.defocusedTargetIds=[],a.xOrient=c.axis_rotated?"left":"bottom",a.yOrient=c.axis_rotated?c.axis_y_inner?"top":"bottom":c.axis_y_inner?"right":"left",a.y2Orient=c.axis_rotated?c.axis_y_inner?"bottom":"top":c.axis_y_inner?"left":"right",a.subXOrient=c.axis_rotated?"left":"bottom",a.isLegendRight="right"===c.legend_position,a.isLegendInset="inset"===c.legend_position,a.isLegendTop="top-left"===c.legend_inset_anchor||"top-right"===c.legend_inset_anchor,a.isLegendLeft="top-left"===c.legend_inset_anchor||"bottom-left"===c.legend_inset_anchor,a.legendStep=0,a.legendItemWidth=0,a.legendItemHeight=0,a.currentMaxTickWidths={x:0,y:0,y2:0},a.rotated_padding_left=30,a.rotated_padding_right=c.axis_rotated&&!c.axis_x_show?0:30,a.rotated_padding_top=5,a.withoutFadeIn={},a.intervalForObserveInserted=void 0,a.axes.subx=b.selectAll([])},f.initChartElements=function(){this.initBar&&this.initBar(),this.initLine&&this.initLine(),this.initArc&&this.initArc(),this.initGauge&&this.initGauge(),this.initText&&this.initText()},f.initWithData=function(b){var c,d,e=this,f=e.d3,g=e.config,h=!0;e.initPie&&e.initPie(),e.initBrush&&e.initBrush(),e.initZoom&&e.initZoom(),e.selectChart="function"==typeof g.bindto.node?g.bindto:f.select(g.bindto),e.selectChart.empty()&&(e.selectChart=f.select(document.createElement("div")).style("opacity",0),e.observeInserted(e.selectChart),h=!1),e.selectChart.html("").classed("c3",!0),e.data.xs={},e.data.targets=e.convertDataToTargets(b),g.data_filter&&(e.data.targets=e.data.targets.filter(g.data_filter)),g.data_hide&&e.addHiddenTargetIds(g.data_hide===!0?e.mapToIds(e.data.targets):g.data_hide),g.legend_hide&&e.addHiddenLegendIds(g.legend_hide===!0?e.mapToIds(e.data.targets):g.legend_hide),e.hasType("gauge")&&(g.legend_show=!1),e.updateSizes(),e.updateScales(),e.x.domain(f.extent(e.getXDomain(e.data.targets))),e.y.domain(e.getYDomain(e.data.targets,"y")),e.y2.domain(e.getYDomain(e.data.targets,"y2")),e.subX.domain(e.x.domain()),e.subY.domain(e.y.domain()),e.subY2.domain(e.y2.domain()),e.orgXDomain=e.x.domain(),e.brush&&e.brush.scale(e.subX),g.zoom_enabled&&e.zoom.scale(e.x),e.svg=e.selectChart.append("svg").style("overflow","hidden").on("mouseenter",function(){return g.onmouseover.call(e)}).on("mouseleave",function(){return g.onmouseout.call(e)}),c=e.svg.append("defs"),e.clipChart=e.appendClip(c,e.clipId),e.clipXAxis=e.appendClip(c,e.clipIdForXAxis),e.clipYAxis=e.appendClip(c,e.clipIdForYAxis),e.clipGrid=e.appendClip(c,e.clipIdForGrid),e.clipSubchart=e.appendClip(c,e.clipIdForSubchart),e.updateSvgSize(),d=e.main=e.svg.append("g").attr("transform",e.getTranslate("main")),e.initSubchart&&e.initSubchart(),e.initTooltip&&e.initTooltip(),e.initLegend&&e.initLegend(),d.append("text").attr("class",i.text+" "+i.empty).attr("text-anchor","middle").attr("dominant-baseline","middle"),e.initRegion(),e.initGrid(),d.append("g").attr("clip-path",e.clipPath).attr("class",i.chart),g.grid_lines_front&&e.initGridLines(),e.initEventRect(),e.initChartElements(),d.insert("rect",g.zoom_privileged?null:"g."+i.regions).attr("class",i.zoomRect).attr("width",e.width).attr("height",e.height).style("opacity",0).on("dblclick.zoom",null),g.axis_x_extent&&e.brush.extent(e.getDefaultExtent()),e.initAxis(),e.updateTargets(e.data.targets),h&&(e.updateDimension(),e.config.oninit.call(e),e.redraw({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransitionForAxis:!1})),null==a.onresize&&(a.onresize=e.generateResize()),a.onresize.add&&(a.onresize.add(function(){g.onresize.call(e)}),a.onresize.add(function(){e.api.flush()}),a.onresize.add(function(){g.onresized.call(e)})),e.api.element=e.selectChart.node()},f.smoothLines=function(a,b){var c=this;"grid"===b&&a.each(function(){var a=c.d3.select(this),b=a.attr("x1"),d=a.attr("x2"),e=a.attr("y1"),f=a.attr("y2");a.attr({x1:Math.ceil(b),x2:Math.ceil(d),y1:Math.ceil(e),y2:Math.ceil(f)})})},f.updateSizes=function(){var a=this,b=a.config,c=a.legend?a.getLegendHeight():0,d=a.legend?a.getLegendWidth():0,e=a.isLegendRight||a.isLegendInset?0:c,f=a.hasArcType(),g=b.axis_rotated||f?0:a.getHorizontalAxisHeight("x"),h=b.subchart_show&&!f?b.subchart_size_height+g:0;a.currentWidth=a.getCurrentWidth(),a.currentHeight=a.getCurrentHeight(),a.margin=b.axis_rotated?{top:a.getHorizontalAxisHeight("y2")+a.getCurrentPaddingTop(),right:f?0:a.getCurrentPaddingRight(),bottom:a.getHorizontalAxisHeight("y")+e+a.getCurrentPaddingBottom(),left:h+(f?0:a.getCurrentPaddingLeft())}:{top:4+a.getCurrentPaddingTop(),right:f?0:a.getCurrentPaddingRight(),bottom:g+h+e+a.getCurrentPaddingBottom(),left:f?0:a.getCurrentPaddingLeft()},a.margin2=b.axis_rotated?{top:a.margin.top,right:0/0,bottom:20+e,left:a.rotated_padding_left}:{top:a.currentHeight-h-e,right:0/0,bottom:g+e,left:a.margin.left},a.margin3={top:0,right:0/0,bottom:0,left:0},a.updateSizeForLegend&&a.updateSizeForLegend(c,d),a.width=a.currentWidth-a.margin.left-a.margin.right,a.height=a.currentHeight-a.margin.top-a.margin.bottom,a.width<0&&(a.width=0),a.height<0&&(a.height=0),a.width2=b.axis_rotated?a.margin.left-a.rotated_padding_left-a.rotated_padding_right:a.width,a.height2=b.axis_rotated?a.height:a.currentHeight-a.margin2.top-a.margin2.bottom,a.width2<0&&(a.width2=0),a.height2<0&&(a.height2=0),a.arcWidth=a.width-(a.isLegendRight?d+10:0),a.arcHeight=a.height-(a.isLegendRight?0:10),a.hasType("gauge")&&(a.arcHeight+=a.height-a.getGaugeLabelHeight()),a.updateRadius&&a.updateRadius(),a.isLegendRight&&f&&(a.margin3.left=a.arcWidth/2+1.1*a.radiusExpanded)},f.updateTargets=function(a){var b=this,c=b.config;b.updateTargetsForText(a),b.updateTargetsForBar(a),b.updateTargetsForLine(a),b.updateTargetsForArc&&b.updateTargetsForArc(a),b.updateTargetsForSubchart&&b.updateTargetsForSubchart(a),b.svg.selectAll("."+i.target).filter(function(a){return b.isTargetToShow(a.id)}).transition().duration(c.transition_duration).style("opacity",1)},f.redraw=function(a,b){var c,d,e,f,g,h,j,k,l,m,n,o,p,q,r,s,u,v,w,x,y,z,A,B,C,D,E,F,G,H=this,I=H.main,J=H.d3,K=H.config,L=H.getShapeIndices(H.isAreaType),M=H.getShapeIndices(H.isBarType),N=H.getShapeIndices(H.isLineType),O=H.hasArcType(),P=H.filterTargetsToShow(H.data.targets),Q=H.xv.bind(H);if(a=a||{},c=t(a,"withY",!0),d=t(a,"withSubchart",!0),e=t(a,"withTransition",!0),h=t(a,"withTransform",!1),j=t(a,"withUpdateXDomain",!1),k=t(a,"withUpdateOrgXDomain",!1),l=t(a,"withTrimXDomain",!0),p=t(a,"withUpdateXAxis",j),m=t(a,"withLegend",!1),n=t(a,"withEventRect",!0),o=t(a,"withDimension",!0),f=t(a,"withTransitionForExit",e),g=t(a,"withTransitionForAxis",e),w=e?K.transition_duration:0,x=f?w:0,y=g?w:0,b=b||H.generateAxisTransitions(y),m&&K.legend_show?H.updateLegend(H.mapToIds(H.data.targets),a,b):o&&H.updateDimension(!0),H.isCategorized()&&0===P.length&&H.x.domain([0,H.axes.x.selectAll(".tick").size()]),P.length?(H.updateXDomain(P,j,k,l),K.axis_x_tick_values||(B=K.axis_x_tick_fit||K.axis_x_tick_count?H.generateTickValues(H.mapTargetsToUniqueXs(P),K.axis_x_tick_count,H.isTimeSeries()):void 0,H.xAxis.tickValues(B),H.subXAxis.tickValues(B))):(H.xAxis.tickValues([]),H.subXAxis.tickValues([])),K.zoom_rescale&&!a.flow&&(E=H.x.orgDomain()),H.y.domain(H.getYDomain(P,"y",E)),H.y2.domain(H.getYDomain(P,"y2",E)),!K.axis_y_tick_values&&K.axis_y_tick_count&&H.yAxis.tickValues(H.generateTickValues(H.y.domain(),K.axis_y_tick_count)),!K.axis_y2_tick_values&&K.axis_y2_tick_count&&H.y2Axis.tickValues(H.generateTickValues(H.y2.domain(),K.axis_y2_tick_count)),H.redrawAxis(b,O),H.updateAxisLabels(e),(j||p)&&P.length)if(K.axis_x_tick_culling&&B){for(C=1;C<B.length;C++)if(B.length/C<K.axis_x_tick_culling_max){D=C;break}H.svg.selectAll("."+i.axisX+" .tick text").each(function(a){var b=B.indexOf(a);b>=0&&J.select(this).style("display",b%D?"none":"block")})}else H.svg.selectAll("."+i.axisX+" .tick text").style("display","block");q=H.generateDrawArea?H.generateDrawArea(L,!1):void 0,r=H.generateDrawBar?H.generateDrawBar(M):void 0,s=H.generateDrawLine?H.generateDrawLine(N,!1):void 0,u=H.generateXYForText(L,M,N,!0),v=H.generateXYForText(L,M,N,!1),c&&(H.subY.domain(H.getYDomain(P,"y")),H.subY2.domain(H.getYDomain(P,"y2"))),H.tooltip.style("display","none"),H.updateXgridFocus(),I.select("text."+i.text+"."+i.empty).attr("x",H.width/2).attr("y",H.height/2).text(K.data_empty_label_text).transition().style("opacity",P.length?0:1),H.redrawGrid(w),H.redrawRegion(w),H.redrawBar(x),H.redrawLine(x),H.redrawArea(x),H.redrawCircle(),H.hasDataLabel()&&H.redrawText(x),H.redrawArc&&H.redrawArc(w,x,h),H.redrawSubchart&&H.redrawSubchart(d,b,w,x,L,M,N),I.selectAll("."+i.selectedCircles).filter(H.isBarType.bind(H)).selectAll("circle").remove(),K.interaction_enabled&&!a.flow&&n&&(H.redrawEventRect(),H.updateZoom&&H.updateZoom()),H.updateCircleY(),F=(H.config.axis_rotated?H.circleY:H.circleX).bind(H),G=(H.config.axis_rotated?H.circleX:H.circleY).bind(H),J.transition().duration(w).each(function(){var b=[];H.addTransitionForBar(b,r),H.addTransitionForLine(b,s),H.addTransitionForArea(b,q),H.addTransitionForCircle(b,F,G),H.addTransitionForText(b,u,v,a.flow),H.addTransitionForRegion(b),H.addTransitionForGrid(b),a.flow&&(z=H.generateWait(),b.forEach(function(a){z.add(a)}),A=H.generateFlow({targets:P,flow:a.flow,duration:w,drawBar:r,drawLine:s,drawArea:q,cx:F,cy:G,xv:Q,xForText:u,yForText:v}))}).call(z||function(){},A||function(){}),H.mapToIds(H.data.targets).forEach(function(a){H.withoutFadeIn[a]=!0})},f.updateAndRedraw=function(a){var b,c=this,d=c.config;a=a||{},a.withTransition=t(a,"withTransition",!0),a.withTransform=t(a,"withTransform",!1),a.withLegend=t(a,"withLegend",!1),a.withUpdateXDomain=!0,a.withUpdateOrgXDomain=!0,a.withTransitionForExit=!1,a.withTransitionForTransform=t(a,"withTransitionForTransform",a.withTransition),c.updateSizes(),a.withLegend&&d.legend_show||(b=c.generateAxisTransitions(a.withTransitionForAxis?d.transition_duration:0),c.updateScales(),c.updateSvgSize(),c.transformAll(a.withTransitionForTransform,b)),c.redraw(a,b)},f.redrawWithoutRescale=function(){this.redraw({withY:!1,withSubchart:!1,withEventRect:!1,withTransitionForAxis:!1})},f.isTimeSeries=function(){return"timeseries"===this.config.axis_x_type},f.isCategorized=function(){return this.config.axis_x_type.indexOf("categor")>=0},f.isCustomX=function(){var a=this,b=a.config;return!a.isTimeSeries()&&(b.data_x||s(b.data_xs))},f.isTimeSeriesY=function(){return"timeseries"===this.config.axis_y_type},f.getTranslate=function(a){var b,c,d=this,e=d.config;return"main"===a?(b=p(d.margin.left),c=p(d.margin.top)):"context"===a?(b=p(d.margin2.left),c=p(d.margin2.top)):"legend"===a?(b=d.margin3.left,c=d.margin3.top):"x"===a?(b=0,c=e.axis_rotated?0:d.height):"y"===a?(b=0,c=e.axis_rotated?d.height:0):"y2"===a?(b=e.axis_rotated?0:d.width,c=e.axis_rotated?1:0):"subx"===a?(b=0,c=e.axis_rotated?0:d.height2):"arc"===a&&(b=d.arcWidth/2,c=d.arcHeight/2),"translate("+b+","+c+")"},f.initialOpacity=function(a){return null!==a.value&&this.withoutFadeIn[a.id]?1:0},f.initialOpacityForCircle=function(a){return null!==a.value&&this.withoutFadeIn[a.id]?this.opacityForCircle(a):0},f.opacityForCircle=function(a){var b=this.config.point_show?1:0;return j(a.value)?this.isScatterType(a)?.5:b:0},f.opacityForText=function(){return this.hasDataLabel()?1:0},f.xx=function(a){return a?this.x(a.x):null},f.xv=function(a){var b=this;return Math.ceil(b.x(b.isTimeSeries()?b.parseDate(a.value):a.value))},f.yv=function(a){var b=this,c=a.axis&&"y2"===a.axis?b.y2:b.y;return Math.ceil(c(a.value))},f.subxx=function(a){return a?this.subX(a.x):null},f.transformMain=function(a,b){var c,d,e,f=this;b&&b.axisX?c=b.axisX:(c=f.main.select("."+i.axisX),a&&(c=c.transition())),b&&b.axisY?d=b.axisY:(d=f.main.select("."+i.axisY),a&&(d=d.transition())),b&&b.axisY2?e=b.axisY2:(e=f.main.select("."+i.axisY2),a&&(e=e.transition())),(a?f.main.transition():f.main).attr("transform",f.getTranslate("main")),c.attr("transform",f.getTranslate("x")),d.attr("transform",f.getTranslate("y")),e.attr("transform",f.getTranslate("y2")),f.main.select("."+i.chartArcs).attr("transform",f.getTranslate("arc"))},f.transformAll=function(a,b){var c=this;c.transformMain(a,b),c.config.subchart_show&&c.transformContext(a,b),c.legend&&c.transformLegend(a)},f.updateSvgSize=function(){var a=this,b=a.svg.select(".c3-brush .background");a.svg.attr("width",a.currentWidth).attr("height",a.currentHeight),a.svg.selectAll(["#"+a.clipId,"#"+a.clipIdForGrid]).select("rect").attr("width",a.width).attr("height",a.height),a.svg.select("#"+a.clipIdForXAxis).select("rect").attr("x",a.getXAxisClipX.bind(a)).attr("y",a.getXAxisClipY.bind(a)).attr("width",a.getXAxisClipWidth.bind(a)).attr("height",a.getXAxisClipHeight.bind(a)),a.svg.select("#"+a.clipIdForYAxis).select("rect").attr("x",a.getYAxisClipX.bind(a)).attr("y",a.getYAxisClipY.bind(a)).attr("width",a.getYAxisClipWidth.bind(a)).attr("height",a.getYAxisClipHeight.bind(a)),a.svg.select("#"+a.clipIdForSubchart).select("rect").attr("width",a.width).attr("height",b.size()?b.attr("height"):0),a.svg.select("."+i.zoomRect).attr("width",a.width).attr("height",a.height),a.selectChart.style("max-height",a.currentHeight+"px")},f.updateDimension=function(a){var b=this;a||(b.config.axis_rotated?(b.axes.x.call(b.xAxis),b.axes.subx.call(b.subXAxis)):(b.axes.y.call(b.yAxis),b.axes.y2.call(b.y2Axis))),b.updateSizes(),b.updateScales(),b.updateSvgSize(),b.transformAll(!1)},f.observeInserted=function(b){var c=this,d=new MutationObserver(function(e){e.forEach(function(e){"childList"===e.type&&e.previousSibling&&(d.disconnect(),c.intervalForObserveInserted=a.setInterval(function(){b.node().parentNode&&(a.clearInterval(c.intervalForObserveInserted),c.updateDimension(),c.config.oninit.call(c),c.redraw({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransition:!1,withTransitionForTransform:!1,withLegend:!0}),b.transition().style("opacity",1))},10))})});d.observe(b.node(),{attributes:!0,childList:!0,characterData:!0})},f.generateResize=function(){function a(){b.forEach(function(a){a()})}var b=[];return a.add=function(a){b.push(a)},a},f.endall=function(a,b){var c=0;a.each(function(){++c}).each("end",function(){--c||b.apply(this,arguments)})},f.generateWait=function(){var a=[],b=function(b,c){var d=setInterval(function(){var b=0;a.forEach(function(a){if(a.empty())return void(b+=1);try{a.transition()}catch(c){b+=1}}),b===a.length&&(clearInterval(d),c&&c())},10)};return b.add=function(b){a.push(b)},b},f.parseDate=function(b){var c,d=this;return c=b instanceof Date?b:"number"==typeof b?new Date(b):d.dataTimeFormat(d.config.data_xFormat).parse(b),(!c||isNaN(+c))&&a.console.error("Failed to parse x '"+b+"' to Date object"),c},f.getDefaultConfig=function(){var a={bindto:"#chart",size_width:void 0,size_height:void 0,padding_left:void 0,padding_right:void 0,padding_top:void 0,padding_bottom:void 0,zoom_enabled:!1,zoom_extent:void 0,zoom_privileged:!1,zoom_rescale:!1,zoom_onzoom:function(){},zoom_onzoomstart:function(){},zoom_onzoomend:function(){},interaction_enabled:!0,onmouseover:function(){},onmouseout:function(){},onresize:function(){},onresized:function(){},oninit:function(){},transition_duration:350,data_x:void 0,data_xs:{},data_xFormat:"%Y-%m-%d",data_xLocaltime:!0,data_xSort:!0,data_idConverter:function(a){return a},data_names:{},data_classes:{},data_groups:[],data_axes:{},data_type:void 0,data_types:{},data_labels:{},data_order:"desc",data_regions:{},data_color:void 0,data_colors:{},data_hide:!1,data_filter:void 0,data_selection_enabled:!1,data_selection_grouped:!1,data_selection_isselectable:function(){return!0},data_selection_multiple:!0,data_onclick:function(){},data_onmouseover:function(){},data_onmouseout:function(){},data_onselected:function(){},data_onunselected:function(){},data_ondragstart:function(){},data_ondragend:function(){},data_url:void 0,data_json:void 0,data_rows:void 0,data_columns:void 0,data_mimeType:void 0,data_keys:void 0,data_empty_label_text:"",subchart_show:!1,subchart_size_height:60,subchart_onbrush:function(){},color_pattern:[],color_threshold:{},legend_show:!0,legend_hide:!1,legend_position:"bottom",legend_inset_anchor:"top-left",legend_inset_x:10,legend_inset_y:0,legend_inset_step:void 0,legend_item_onclick:void 0,legend_item_onmouseover:void 0,legend_item_onmouseout:void 0,legend_equally:!1,axis_rotated:!1,axis_x_show:!0,axis_x_type:"indexed",axis_x_localtime:!0,axis_x_categories:[],axis_x_tick_centered:!1,axis_x_tick_format:void 0,axis_x_tick_culling:{},axis_x_tick_culling_max:10,axis_x_tick_count:void 0,axis_x_tick_fit:!0,axis_x_tick_values:null,axis_x_tick_rotate:0,axis_x_tick_outer:!0,axis_x_tick_multiline:!0,axis_x_tick_width:null,axis_x_max:void 0,axis_x_min:void 0,axis_x_padding:{},axis_x_height:void 0,axis_x_extent:void 0,axis_x_label:{},axis_y_show:!0,axis_y_type:void 0,axis_y_max:void 0,axis_y_min:void 0,axis_y_center:void 0,axis_y_inner:void 0,axis_y_label:{},axis_y_tick_format:void 0,axis_y_tick_outer:!0,axis_y_tick_values:null,axis_y_tick_count:void 0,axis_y_tick_time_value:void 0,axis_y_tick_time_interval:void 0,axis_y_padding:{},axis_y_default:void 0,axis_y2_show:!1,axis_y2_max:void 0,axis_y2_min:void 0,axis_y2_center:void 0,axis_y2_inner:void 0,axis_y2_label:{},axis_y2_tick_format:void 0,axis_y2_tick_outer:!0,axis_y2_tick_values:null,axis_y2_tick_count:void 0,axis_y2_padding:{},axis_y2_default:void 0,grid_x_show:!1,grid_x_type:"tick",grid_x_lines:[],grid_y_show:!1,grid_y_lines:[],grid_y_ticks:10,grid_focus_show:!0,grid_lines_front:!0,point_show:!0,point_r:2.5,point_focus_expand_enabled:!0,point_focus_expand_r:void 0,point_select_r:void 0,line_connectNull:!1,line_step_type:"step",bar_width:void 0,bar_width_ratio:.6,bar_width_max:void 0,bar_zerobased:!0,area_zerobased:!0,pie_label_show:!0,pie_label_format:void 0,pie_label_threshold:.05,pie_expand:!0,gauge_label_show:!0,gauge_label_format:void 0,gauge_expand:!0,gauge_min:0,gauge_max:100,gauge_units:void 0,gauge_width:void 0,donut_label_show:!0,donut_label_format:void 0,donut_label_threshold:.05,donut_width:void 0,donut_expand:!0,donut_title:"",regions:[],tooltip_show:!0,tooltip_grouped:!0,tooltip_format_title:void 0,tooltip_format_name:void 0,tooltip_format_value:void 0,tooltip_contents:function(a,b,c,d){return this.getTooltipContent?this.getTooltipContent(a,b,c,d):""},tooltip_init_show:!1,tooltip_init_x:0,tooltip_init_position:{top:"0px",left:"50px"}};return Object.keys(this.additionalConfig).forEach(function(b){a[b]=this.additionalConfig[b]},this),a},f.additionalConfig={},f.loadConfig=function(a){function b(){var a=d.shift();return a&&c&&"object"==typeof c&&a in c?(c=c[a],b()):a?void 0:c}var c,d,e,f=this.config;Object.keys(f).forEach(function(g){c=a,d=g.split("_"),e=b(),n(e)&&(f[g]=e)})},f.getScale=function(a,b,c){return(c?this.d3.time.scale():this.d3.scale.linear()).range([a,b])},f.getX=function(a,b,c,d){var e,f=this,g=f.getScale(a,b,f.isTimeSeries()),h=c?g.domain(c):g;f.isCategorized()?(d=d||function(){return 0},g=function(a,b){var c=h(a)+d(a);return b?c:Math.ceil(c)}):g=function(a,b){var c=h(a);return b?c:Math.ceil(c)};for(e in h)g[e]=h[e];return g.orgDomain=function(){return h.domain()},f.isCategorized()&&(g.domain=function(a){return arguments.length?(h.domain(a),g):(a=this.orgDomain(),[a[0],a[1]+1])}),g},f.getY=function(a,b,c){var d=this.getScale(a,b,this.isTimeSeriesY());return c&&d.domain(c),d},f.getYScale=function(a){return"y2"===this.getAxisId(a)?this.y2:this.y},f.getSubYScale=function(a){return"y2"===this.getAxisId(a)?this.subY2:this.subY},f.updateScales=function(){var a=this,b=a.config,c=!a.x;a.xMin=b.axis_rotated?1:0,a.xMax=b.axis_rotated?a.height:a.width,a.yMin=b.axis_rotated?0:a.height,a.yMax=b.axis_rotated?a.width:1,a.subXMin=a.xMin,a.subXMax=a.xMax,a.subYMin=b.axis_rotated?0:a.height2,a.subYMax=b.axis_rotated?a.width2:1,a.x=a.getX(a.xMin,a.xMax,c?void 0:a.x.orgDomain(),function(){return a.xAxis.tickOffset()}),a.y=a.getY(a.yMin,a.yMax,c?b.axis_y_default:a.y.domain()),a.y2=a.getY(a.yMin,a.yMax,c?b.axis_y2_default:a.y2.domain()),a.subX=a.getX(a.xMin,a.xMax,a.orgXDomain,function(b){return b%1?0:a.subXAxis.tickOffset()}),a.subY=a.getY(a.subYMin,a.subYMax,c?b.axis_y_default:a.subY.domain()),a.subY2=a.getY(a.subYMin,a.subYMax,c?b.axis_y2_default:a.subY2.domain()),a.xAxisTickFormat=a.getXAxisTickFormat(),a.xAxisTickValues=a.getXAxisTickValues(),a.yAxisTickValues=a.getYAxisTickValues(),a.y2AxisTickValues=a.getY2AxisTickValues(),a.xAxis=a.getXAxis(a.x,a.xOrient,a.xAxisTickFormat,a.xAxisTickValues,b.axis_x_tick_outer),a.subXAxis=a.getXAxis(a.subX,a.subXOrient,a.xAxisTickFormat,a.xAxisTickValues,b.axis_x_tick_outer),a.yAxis=a.getYAxis(a.y,a.yOrient,b.axis_y_tick_format,a.yAxisTickValues,b.axis_y_tick_outer),a.y2Axis=a.getYAxis(a.y2,a.y2Orient,b.axis_y2_tick_format,a.y2AxisTickValues,b.axis_y2_tick_outer),c||(a.brush&&a.brush.scale(a.subX),b.zoom_enabled&&a.zoom.scale(a.x)),a.updateArc&&a.updateArc()},f.getYDomainMin=function(a){var b,c,d,e,f,g,h=this,i=h.config,j=h.mapToIds(a),k=h.getValuesAsIdKeyed(a);if(i.data_groups.length>0)for(g=h.hasNegativeValueInTargets(a),b=0;b<i.data_groups.length;b++)if(e=i.data_groups[b].filter(function(a){return j.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&k[d]&&k[d].forEach(function(a,b){k[d][b]=0>a?a:0}),c=1;c<e.length;c++)f=e[c],k[f]&&k[f].forEach(function(a,b){h.getAxisId(f)!==h.getAxisId(d)||!k[d]||g&&+a>0||(k[d][b]+=+a)});return h.d3.min(Object.keys(k).map(function(a){return h.d3.min(k[a])}))},f.getYDomainMax=function(a){var b,c,d,e,f,g,h=this,i=h.config,j=h.mapToIds(a),k=h.getValuesAsIdKeyed(a);if(i.data_groups.length>0)for(g=h.hasPositiveValueInTargets(a),b=0;b<i.data_groups.length;b++)if(e=i.data_groups[b].filter(function(a){return j.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&k[d]&&k[d].forEach(function(a,b){k[d][b]=a>0?a:0}),c=1;c<e.length;c++)f=e[c],k[f]&&k[f].forEach(function(a,b){h.getAxisId(f)!==h.getAxisId(d)||!k[d]||g&&0>+a||(k[d][b]+=+a)});return h.d3.max(Object.keys(k).map(function(a){return h.d3.max(k[a])}))},f.getYDomain=function(a,b,c){var d,e,f,g,h,i,k,l,m,n,o=this,p=o.config,r=a.filter(function(a){return o.getAxisId(a.id)===b}),t=c?o.filterByXDomain(r,c):r,u="y2"===b?p.axis_y2_min:p.axis_y_min,v="y2"===b?p.axis_y2_max:p.axis_y_max,w=j(u)?u:o.getYDomainMin(t),x=j(v)?v:o.getYDomainMax(t),y="y2"===b?p.axis_y2_center:p.axis_y_center,z=o.hasType("bar",t)&&p.bar_zerobased||o.hasType("area",t)&&p.area_zerobased,A=o.hasDataLabel()&&p.axis_rotated,B=o.hasDataLabel()&&!p.axis_rotated;return w>x&&(j(u)?x=w+10:w=x-10),0===t.length?"y2"===b?o.y2.domain():o.y.domain():(isNaN(w)&&(w=0),isNaN(x)&&(x=w),w===x&&(0>w?x=0:w=0),m=w>=0&&x>=0,n=0>=w&&0>=x,(j(u)&&m||j(v)&&n)&&(z=!1),z&&(m&&(w=0),n&&(x=0)),d=Math.abs(x-w),e=f=g=.1*d,y&&(h=Math.max(Math.abs(w),Math.abs(x)),x=h-y,w=y-h),A?(i=o.getDataLabelLength(w,x,b,"width"),k=q(o.y.range()),l=[i[0]/k,i[1]/k],f+=d*(l[1]/(1-l[0]-l[1])),g+=d*(l[0]/(1-l[0]-l[1]))):B&&(i=o.getDataLabelLength(w,x,b,"height"),f+=i[1],g+=i[0]),"y"===b&&s(p.axis_y_padding)&&(f=o.getAxisPadding(p.axis_y_padding,"top",e,d),g=o.getAxisPadding(p.axis_y_padding,"bottom",e,d)),"y2"===b&&s(p.axis_y2_padding)&&(f=o.getAxisPadding(p.axis_y2_padding,"top",e,d),g=o.getAxisPadding(p.axis_y2_padding,"bottom",e,d)),z&&(m&&(g=w),n&&(f=-x)),[w-g,x+f])},f.getXDomainMin=function(a){var b=this,c=b.config;return n(c.axis_x_min)?b.isTimeSeries()?this.parseDate(c.axis_x_min):c.axis_x_min:b.d3.min(a,function(a){return b.d3.min(a.values,function(a){return a.x})})},f.getXDomainMax=function(a){var b=this,c=b.config;return n(c.axis_x_max)?b.isTimeSeries()?this.parseDate(c.axis_x_max):c.axis_x_max:b.d3.max(a,function(a){return b.d3.max(a.values,function(a){return a.x})})},f.getXDomainPadding=function(a){var b,c,d,e,f=this,g=f.config,h=a[1]-a[0];return f.isCategorized()?c=0:f.hasType("bar")?(b=f.getMaxDataCount(),c=b>1?h/(b-1)/2:.5):c=.01*h,"object"==typeof g.axis_x_padding&&s(g.axis_x_padding)?(d=j(g.axis_x_padding.left)?g.axis_x_padding.left:c,e=j(g.axis_x_padding.right)?g.axis_x_padding.right:c):d=e="number"==typeof g.axis_x_padding?g.axis_x_padding:c,{left:d,right:e}},f.getXDomain=function(a){var b=this,c=[b.getXDomainMin(a),b.getXDomainMax(a)],d=c[0],e=c[1],f=b.getXDomainPadding(c),g=0,h=0;return d-e!==0||b.isCategorized()||(b.isTimeSeries()?(d=new Date(.5*d.getTime()),e=new Date(1.5*e.getTime())):(d=0===d?1:.5*d,e=0===e?-1:1.5*e)),(d||0===d)&&(g=b.isTimeSeries()?new Date(d.getTime()-f.left):d-f.left),(e||0===e)&&(h=b.isTimeSeries()?new Date(e.getTime()+f.right):e+f.right),[g,h]},f.updateXDomain=function(a,b,c,d,e){var f=this,g=f.config;return c&&(f.x.domain(e?e:f.d3.extent(f.getXDomain(a))),f.orgXDomain=f.x.domain(),g.zoom_enabled&&f.zoom.scale(f.x).updateScaleExtent(),f.subX.domain(f.x.domain()),f.brush&&f.brush.scale(f.subX)),b&&(f.x.domain(e?e:!f.brush||f.brush.empty()?f.orgXDomain:f.brush.extent()),g.zoom_enabled&&f.zoom.scale(f.x).updateScaleExtent()),d&&f.x.domain(f.trimXDomain(f.x.orgDomain())),f.x.domain()},f.trimXDomain=function(a){var b=this;return a[0]<=b.orgXDomain[0]&&(a[1]=+a[1]+(b.orgXDomain[0]-a[0]),a[0]=b.orgXDomain[0]),b.orgXDomain[1]<=a[1]&&(a[0]=+a[0]-(a[1]-b.orgXDomain[1]),a[1]=b.orgXDomain[1]),a},f.isX=function(a){var b=this,c=b.config;return c.data_x&&a===c.data_x||s(c.data_xs)&&u(c.data_xs,a)},f.isNotX=function(a){return!this.isX(a)},f.getXKey=function(a){var b=this,c=b.config;return c.data_x?c.data_x:s(c.data_xs)?c.data_xs[a]:null},f.getXValuesOfXKey=function(a,b){var c,d=this,e=b&&s(b)?d.mapToIds(b):[];return e.forEach(function(b){d.getXKey(b)===a&&(c=d.data.xs[b])}),c},f.getIndexByX=function(a){var b=this,c=b.filterByX(b.data.targets,a);return c.length?c[0].index:null},f.getXValue=function(a,b){var c=this;return a in c.data.xs&&c.data.xs[a]&&j(c.data.xs[a][b])?c.data.xs[a][b]:b},f.getOtherTargetXs=function(){var a=this,b=Object.keys(a.data.xs);return b.length?a.data.xs[b[0]]:null},f.getOtherTargetX=function(a){var b=this.getOtherTargetXs();return b&&a<b.length?b[a]:null
+},f.addXs=function(a){var b=this;Object.keys(a).forEach(function(c){b.config.data_xs[c]=a[c]})},f.hasMultipleX=function(a){return this.d3.set(Object.keys(a).map(function(b){return a[b]})).size()>1},f.isMultipleX=function(){return s(this.config.data_xs)||!this.config.data_xSort||this.hasType("scatter")},f.addName=function(a){var b,c=this;return a&&(b=c.config.data_names[a.id],a.name=b?b:a.id),a},f.getValueOnIndex=function(a,b){var c=a.filter(function(a){return a.index===b});return c.length?c[0]:null},f.updateTargetX=function(a,b){var c=this;a.forEach(function(a){a.values.forEach(function(d,e){d.x=c.generateTargetX(b[e],a.id,e)}),c.data.xs[a.id]=b})},f.updateTargetXs=function(a,b){var c=this;a.forEach(function(a){b[a.id]&&c.updateTargetX([a],b[a.id])})},f.generateTargetX=function(a,b,c){var d,e=this;return d=e.isTimeSeries()?e.parseDate(a?a:e.getXValue(b,c)):e.isCustomX()&&!e.isCategorized()?j(a)?+a:e.getXValue(b,c):c},f.cloneTarget=function(a){return{id:a.id,id_org:a.id_org,values:a.values.map(function(a){return{x:a.x,value:a.value,id:a.id}})}},f.updateXs=function(){var a=this;a.data.targets.length&&(a.xs=[],a.data.targets[0].values.forEach(function(b){a.xs[b.index]=b.x}))},f.getPrevX=function(a){var b=this.xs[a-1];return"undefined"!=typeof b?b:null},f.getNextX=function(a){var b=this.xs[a+1];return"undefined"!=typeof b?b:null},f.getMaxDataCount=function(){var a=this;return a.d3.max(a.data.targets,function(a){return a.values.length})},f.getMaxDataCountTarget=function(a){var b,c=a.length,d=0;return c>1?a.forEach(function(a){a.values.length>d&&(b=a,d=a.values.length)}):b=c?a[0]:null,b},f.getEdgeX=function(a){var b=this;return a.length?[b.d3.min(a,function(a){return a.values[0].x}),b.d3.max(a,function(a){return a.values[a.values.length-1].x})]:[0,0]},f.mapToIds=function(a){return a.map(function(a){return a.id})},f.mapToTargetIds=function(a){var b=this;return a?l(a)?[a]:a:b.mapToIds(b.data.targets)},f.hasTarget=function(a,b){var c,d=this.mapToIds(a);for(c=0;c<d.length;c++)if(d[c]===b)return!0;return!1},f.isTargetToShow=function(a){return this.hiddenTargetIds.indexOf(a)<0},f.isLegendToShow=function(a){return this.hiddenLegendIds.indexOf(a)<0},f.filterTargetsToShow=function(a){var b=this;return a.filter(function(a){return b.isTargetToShow(a.id)})},f.mapTargetsToUniqueXs=function(a){var b=this,c=b.d3.set(b.d3.merge(a.map(function(a){return a.values.map(function(a){return+a.x})}))).values();return c.map(b.isTimeSeries()?function(a){return new Date(+a)}:function(a){return+a})},f.addHiddenTargetIds=function(a){this.hiddenTargetIds=this.hiddenTargetIds.concat(a)},f.removeHiddenTargetIds=function(a){this.hiddenTargetIds=this.hiddenTargetIds.filter(function(b){return a.indexOf(b)<0})},f.addHiddenLegendIds=function(a){this.hiddenLegendIds=this.hiddenLegendIds.concat(a)},f.removeHiddenLegendIds=function(a){this.hiddenLegendIds=this.hiddenLegendIds.filter(function(b){return a.indexOf(b)<0})},f.getValuesAsIdKeyed=function(a){var b={};return a.forEach(function(a){b[a.id]=[],a.values.forEach(function(c){b[a.id].push(c.value)})}),b},f.checkValueInTargets=function(a,b){var c,d,e,f=Object.keys(a);for(c=0;c<f.length;c++)for(e=a[f[c]].values,d=0;d<e.length;d++)if(b(e[d].value))return!0;return!1},f.hasNegativeValueInTargets=function(a){return this.checkValueInTargets(a,function(a){return 0>a})},f.hasPositiveValueInTargets=function(a){return this.checkValueInTargets(a,function(a){return a>0})},f.isOrderDesc=function(){var a=this.config;return"string"==typeof a.data_order&&"desc"===a.data_order.toLowerCase()},f.isOrderAsc=function(){var a=this.config;return"string"==typeof a.data_order&&"asc"===a.data_order.toLowerCase()},f.orderTargets=function(a){var b=this,c=b.config,d=b.isOrderAsc(),e=b.isOrderDesc();return d||e?a.sort(function(a,b){var c=function(a,b){return a+Math.abs(b.value)},e=a.values.reduce(c,0),f=b.values.reduce(c,0);return d?f-e:e-f}):k(c.data_order)&&a.sort(c.data_order),a},f.filterByX=function(a,b){return this.d3.merge(a.map(function(a){return a.values})).filter(function(a){return a.x-b===0})},f.filterRemoveNull=function(a){return a.filter(function(a){return j(a.value)})},f.filterByXDomain=function(a,b){return a.map(function(a){return{id:a.id,id_org:a.id_org,values:a.values.filter(function(a){return b[0]<=a.x&&a.x<=b[1]})}})},f.hasDataLabel=function(){var a=this.config;return"boolean"==typeof a.data_labels&&a.data_labels?!0:"object"==typeof a.data_labels&&s(a.data_labels)?!0:!1},f.getDataLabelLength=function(a,b,c,d){var e=this,f=[0,0],g=1.3;return e.selectChart.select("svg").selectAll(".dummy").data([a,b]).enter().append("text").text(function(a){return e.formatByAxisId(c)(a)}).each(function(a,b){f[b]=this.getBoundingClientRect()[d]*g}).remove(),f},f.isNoneArc=function(a){return this.hasTarget(this.data.targets,a.id)},f.isArc=function(a){return"data"in a&&this.hasTarget(this.data.targets,a.data.id)},f.findSameXOfValues=function(a,b){var c,d=a[b].x,e=[];for(c=b-1;c>=0&&d===a[c].x;c--)e.push(a[c]);for(c=b;c<a.length&&d===a[c].x;c++)e.push(a[c]);return e},f.findClosestFromTargets=function(a,b){var c,d=this;return c=a.map(function(a){return d.findClosest(a.values,b)}),d.findClosest(c,b)},f.findClosest=function(a,b){var c,d=this,e=100;return a.filter(function(a){return a&&d.isBarType(a.id)}).forEach(function(a){var b=d.main.select("."+i.bars+d.getTargetSelectorSuffix(a.id)+" ."+i.bar+"-"+a.index).node();!c&&d.isWithinBar(b)&&(c=a)}),a.filter(function(a){return a&&!d.isBarType(a.id)}).forEach(function(a){var f=d.dist(a,b);e>f&&(e=f,c=a)}),c},f.dist=function(a,b){var c=this,d=c.config,e=d.axis_rotated?1:0,f=d.axis_rotated?0:1,g=c.circleY(a,a.index),h=c.x(a.x);return Math.pow(h-b[e],2)+Math.pow(g-b[f],2)},f.convertValuesToStep=function(a){var b,c=[].concat(a);if(!this.isCategorized())return a;for(b=a.length+1;b>0;b--)c[b]=c[b-1];return c[0]={x:c[0].x-1,value:c[0].value,id:c[0].id},c[a.length+1]={x:c[a.length].x+1,value:c[a.length].value,id:c[a.length].id},c},f.updateDataAttributes=function(a,b){var c=this,d=c.config,e=d["data_"+a];return"undefined"==typeof b?e:(Object.keys(b).forEach(function(a){e[a]=b[a]}),c.redraw({withLegend:!0}),e)},f.convertUrlToData=function(a,b,c,d){var e=this,f=b?b:"csv";e.d3.xhr(a,function(a,b){var g;g="json"===f?e.convertJsonToData(JSON.parse(b.response),c):"tsv"===f?e.convertTsvToData(b.response):e.convertCsvToData(b.response),d.call(e,g)})},f.convertXsvToData=function(a,b){var c,d=b.parseRows(a);return 1===d.length?(c=[{}],d[0].forEach(function(a){c[0][a]=null})):c=b.parse(a),c},f.convertCsvToData=function(a){return this.convertXsvToData(a,this.d3.csv)},f.convertTsvToData=function(a){return this.convertXsvToData(a,this.d3.tsv)},f.convertJsonToData=function(a,b){var c,d,e=this,f=[];return b?(c=b.value,b.x&&(c.push(b.x),e.config.data_x=b.x),f.push(c),a.forEach(function(a){var b=[];c.forEach(function(c){var d=m(a[c])?null:a[c];b.push(d)}),f.push(b)}),d=e.convertRowsToData(f)):(Object.keys(a).forEach(function(b){f.push([b].concat(a[b]))}),d=e.convertColumnsToData(f)),d},f.convertRowsToData=function(a){var b,c,d=a[0],e={},f=[];for(b=1;b<a.length;b++){for(e={},c=0;c<a[b].length;c++){if(m(a[b][c]))throw new Error("Source data is missing a component at ("+b+","+c+")!");e[d[c]]=a[b][c]}f.push(e)}return f},f.convertColumnsToData=function(a){var b,c,d,e=[];for(b=0;b<a.length;b++)for(d=a[b][0],c=1;c<a[b].length;c++){if(m(e[c-1])&&(e[c-1]={}),m(a[b][c]))throw new Error("Source data is missing a component at ("+b+","+c+")!");e[c-1][d]=a[b][c]}return e},f.convertDataToTargets=function(a,b){var c,d=this,e=d.config,f=d.d3.keys(a[0]).filter(d.isNotX,d),g=d.d3.keys(a[0]).filter(d.isX,d);return f.forEach(function(c){var f=d.getXKey(c);d.isCustomX()||d.isTimeSeries()?g.indexOf(f)>=0?d.data.xs[c]=(b&&d.data.xs[c]?d.data.xs[c]:[]).concat(a.map(function(a){return a[f]}).filter(j).map(function(a,b){return d.generateTargetX(a,c,b)})):e.data_x?d.data.xs[c]=d.getOtherTargetXs():s(e.data_xs)&&(d.data.xs[c]=d.getXValuesOfXKey(f,d.data.targets)):d.data.xs[c]=a.map(function(a,b){return b})}),f.forEach(function(a){if(!d.data.xs[a])throw new Error('x is not defined for id = "'+a+'".')}),c=f.map(function(b,c){var f=e.data_idConverter(b);return{id:f,id_org:b,values:a.map(function(a,g){var h=d.getXKey(b),i=a[h],j=d.generateTargetX(i,b,g);return d.isCustomX()&&d.isCategorized()&&0===c&&i&&(0===g&&(e.axis_x_categories=[]),e.axis_x_categories.push(i)),(m(a[b])||d.data.xs[b].length<=g)&&(j=void 0),{x:j,value:null===a[b]||isNaN(a[b])?null:+a[b],id:f}}).filter(function(a){return n(a.x)})}}),c.forEach(function(a){var b;e.data_xSort&&(a.values=a.values.sort(function(a,b){var c=a.x||0===a.x?a.x:1/0,d=b.x||0===b.x?b.x:1/0;return c-d})),b=0,a.values.forEach(function(a){a.index=b++}),d.data.xs[a.id].sort(function(a,b){return a-b})}),e.data_type&&d.setTargetType(d.mapToIds(c).filter(function(a){return!(a in e.data_types)}),e.data_type),c.forEach(function(a){d.addCache(a.id_org,a)}),c},f.load=function(a,b){var c=this;a&&(b.filter&&(a=a.filter(b.filter)),(b.type||b.types)&&a.forEach(function(a){c.setTargetType(a.id,b.types?b.types[a.id]:b.type)}),c.data.targets.forEach(function(b){for(var c=0;c<a.length;c++)if(b.id===a[c].id){b.values=a[c].values,a.splice(c,1);break}}),c.data.targets=c.data.targets.concat(a)),c.updateTargets(c.data.targets),c.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),b.done&&b.done()},f.loadFromArgs=function(a){var b=this;a.data?b.load(b.convertDataToTargets(a.data),a):a.url?b.convertUrlToData(a.url,a.mimeType,a.keys,function(c){b.load(b.convertDataToTargets(c),a)}):a.json?b.load(b.convertDataToTargets(b.convertJsonToData(a.json,a.keys)),a):a.rows?b.load(b.convertDataToTargets(b.convertRowsToData(a.rows)),a):a.columns?b.load(b.convertDataToTargets(b.convertColumnsToData(a.columns)),a):b.load(null,a)},f.unload=function(a,b){var c=this;return b||(b=function(){}),a=a.filter(function(a){return c.hasTarget(c.data.targets,a)}),a&&0!==a.length?(c.svg.selectAll(a.map(function(a){return c.selectorTarget(a)})).transition().style("opacity",0).remove().call(c.endall,b),void a.forEach(function(a){c.withoutFadeIn[a]=!1,c.legend&&c.legend.selectAll("."+i.legendItem+c.getTargetSelectorSuffix(a)).remove(),c.data.targets=c.data.targets.filter(function(b){return b.id!==a})})):void b()},f.categoryName=function(a){var b=this.config;return a<b.axis_x_categories.length?b.axis_x_categories[a]:a},f.initEventRect=function(){var a=this;a.main.select("."+i.chart).append("g").attr("class",i.eventRects).style("fill-opacity",0)},f.redrawEventRect=function(){var a,b,c=this,d=c.config,e=c.isMultipleX(),f=c.main.select("."+i.eventRects).style("cursor",d.zoom_enabled?d.axis_rotated?"ns-resize":"ew-resize":null).classed(i.eventRectsMultiple,e).classed(i.eventRectsSingle,!e);f.selectAll("."+i.eventRect).remove(),c.eventRect=f.selectAll("."+i.eventRect),e?(a=c.eventRect.data([0]),c.generateEventRectsForMultipleXs(a.enter()),c.updateEventRect(a)):(b=c.getMaxDataCountTarget(c.data.targets),f.datum(b?b.values:[]),c.eventRect=f.selectAll("."+i.eventRect),a=c.eventRect.data(function(a){return a}),c.generateEventRectsForSingleX(a.enter()),c.updateEventRect(a),a.exit().remove())},f.updateEventRect=function(a){var b,c,d,e,f,g,h=this,i=h.config;a=a||h.eventRect.data(function(a){return a}),h.isMultipleX()?(b=0,c=0,d=h.width,e=h.height):(!h.isCustomX()&&!h.isTimeSeries()||h.isCategorized()?(f=h.getEventRectWidth(),g=function(a){return h.x(a.x)-f/2}):(h.updateXs(),f=function(a){var b=h.getPrevX(a.index),c=h.getNextX(a.index);return null===b&&null===c?i.axis_rotated?h.height:h.width:(null===b&&(b=h.x.domain()[0]),null===c&&(c=h.x.domain()[1]),Math.max(0,(h.x(c)-h.x(b))/2))},g=function(a){var b=h.getPrevX(a.index),c=h.getNextX(a.index),d=h.data.xs[a.id][a.index];return null===b&&null===c?0:(null===b&&(b=h.x.domain()[0]),(h.x(d)+h.x(b))/2)}),b=i.axis_rotated?0:g,c=i.axis_rotated?g:0,d=i.axis_rotated?h.width:f,e=i.axis_rotated?f:h.height),a.attr("class",h.classEvent.bind(h)).attr("x",b).attr("y",c).attr("width",d).attr("height",e)},f.generateEventRectsForSingleX=function(a){var b=this,c=b.d3,d=b.config;a.append("rect").attr("class",b.classEvent.bind(b)).style("cursor",d.data_selection_enabled&&d.data_selection_grouped?"pointer":null).on("mouseover",function(a){var c,e,f=a.index;b.dragging||b.flowing||b.hasArcType()||(c=b.data.targets.map(function(a){return b.addName(b.getValueOnIndex(a.values,f))}),e=[],Object.keys(d.data_names).forEach(function(a){for(var b=0;b<c.length;b++)if(c[b]&&c[b].id===a){e.push(c[b]),c.shift(b);break}}),c=e.concat(c),d.point_focus_expand_enabled&&b.expandCircles(f,null,!0),b.expandBars(f,null,!0),b.main.selectAll("."+i.shape+"-"+f).each(function(a){d.data_onmouseover.call(b.api,a)}))}).on("mouseout",function(a){var c=a.index;b.hasArcType()||(b.hideXGridFocus(),b.hideTooltip(),b.unexpandCircles(),b.unexpandBars(),b.main.selectAll("."+i.shape+"-"+c).each(function(a){d.data_onmouseout.call(b.api,a)}))}).on("mousemove",function(a){var e,f=a.index,g=b.svg.select("."+i.eventRect+"-"+f);b.dragging||b.flowing||b.hasArcType()||(b.isStepType(a)&&"step-after"===b.config.line_step_type&&c.mouse(this)[0]<b.x(b.getXValue(a.id,f))&&(f-=1),e=b.filterTargetsToShow(b.data.targets).map(function(a){return b.addName(b.getValueOnIndex(a.values,f))}),d.tooltip_grouped&&(b.showTooltip(e,c.mouse(this)),b.showXGridFocus(e)),(!d.tooltip_grouped||d.data_selection_enabled&&!d.data_selection_grouped)&&b.main.selectAll("."+i.shape+"-"+f).each(function(){c.select(this).classed(i.EXPANDED,!0),d.data_selection_enabled&&g.style("cursor",d.data_selection_grouped?"pointer":null),d.tooltip_grouped||(b.hideXGridFocus(),b.hideTooltip(),d.data_selection_grouped||(b.unexpandCircles(f),b.unexpandBars(f)))}).filter(function(a){return b.isWithinShape(this,a)}).each(function(a){d.data_selection_enabled&&(d.data_selection_grouped||d.data_selection_isselectable(a))&&g.style("cursor","pointer"),d.tooltip_grouped||(b.showTooltip([a],c.mouse(this)),b.showXGridFocus([a]),d.point_focus_expand_enabled&&b.expandCircles(f,a.id,!0),b.expandBars(f,a.id,!0))}))}).on("click",function(a){var e=a.index;if(!b.hasArcType()&&b.toggleShape){if(b.cancelClick)return void(b.cancelClick=!1);b.isStepType(a)&&"step-after"===d.line_step_type&&c.mouse(this)[0]<b.x(b.getXValue(a.id,e))&&(e-=1),b.main.selectAll("."+i.shape+"-"+e).each(function(a){(d.data_selection_grouped||b.isWithinShape(this,a))&&(b.toggleShape(this,a,e),b.config.data_onclick.call(b.api,a,this))})}}).call(c.behavior.drag().origin(Object).on("drag",function(){b.drag(c.mouse(this))}).on("dragstart",function(){b.dragstart(c.mouse(this))}).on("dragend",function(){b.dragend()}))},f.generateEventRectsForMultipleXs=function(a){function b(){c.svg.select("."+i.eventRect).style("cursor",null),c.hideXGridFocus(),c.hideTooltip(),c.unexpandCircles(),c.unexpandBars()}var c=this,d=c.d3,e=c.config;a.append("rect").attr("x",0).attr("y",0).attr("width",c.width).attr("height",c.height).attr("class",i.eventRect).on("mouseout",function(){c.hasArcType()||b()}).on("mousemove",function(){var a,f,g,h,j=c.filterTargetsToShow(c.data.targets);if(!c.dragging&&!c.hasArcType(j)){if(a=d.mouse(this),f=c.findClosestFromTargets(j,a),!c.mouseover||f&&f.id===c.mouseover.id||(e.data_onmouseout.call(c.api,c.mouseover),c.mouseover=void 0),!f)return void b();g=c.isScatterType(f)||!e.tooltip_grouped?[f]:c.filterByX(j,f.x),h=g.map(function(a){return c.addName(a)}),c.showTooltip(h,a),e.point_focus_expand_enabled&&c.expandCircles(f.index,f.id,!0),c.expandBars(f.index,f.id,!0),c.showXGridFocus(h),(c.isBarType(f.id)||c.dist(f,a)<100)&&(c.svg.select("."+i.eventRect).style("cursor","pointer"),c.mouseover||(e.data_onmouseover.call(c.api,f),c.mouseover=f))}}).on("click",function(){var a,b,f=c.filterTargetsToShow(c.data.targets);c.hasArcType(f)||(a=d.mouse(this),b=c.findClosestFromTargets(f,a),b&&(c.isBarType(b.id)||c.dist(b,a)<100)&&c.main.selectAll("."+i.shapes+c.getTargetSelectorSuffix(b.id)).select("."+i.shape+"-"+b.index).each(function(){(e.data_selection_grouped||c.isWithinShape(this,b))&&(c.toggleShape(this,b,b.index),c.config.data_onclick.call(c.api,b,this))}))}).call(d.behavior.drag().origin(Object).on("drag",function(){c.drag(d.mouse(this))}).on("dragstart",function(){c.dragstart(d.mouse(this))}).on("dragend",function(){c.dragend()}))},f.dispatchEvent=function(b,c,d){var e=this,f="."+i.eventRect+(e.isMultipleX()?"":"-"+c),g=e.main.select(f).node(),h=g.getBoundingClientRect(),j=h.left+(d?d[0]:0),k=h.top+(d?d[1]:0),l=document.createEvent("MouseEvents");l.initMouseEvent(b,!0,!0,a,0,j,k,j,k,!1,!1,!1,!1,0,null),g.dispatchEvent(l)},f.getCurrentWidth=function(){var a=this,b=a.config;return b.size_width?b.size_width:a.getParentWidth()},f.getCurrentHeight=function(){var a=this,b=a.config,c=b.size_height?b.size_height:a.getParentHeight();return c>0?c:320/(a.hasType("gauge")?2:1)},f.getCurrentPaddingTop=function(){var a=this.config;return j(a.padding_top)?a.padding_top:0},f.getCurrentPaddingBottom=function(){var a=this.config;return j(a.padding_bottom)?a.padding_bottom:0},f.getCurrentPaddingLeft=function(a){var b=this,c=b.config;return j(c.padding_left)?c.padding_left:c.axis_rotated?c.axis_x_show?Math.max(o(b.getAxisWidthByAxisId("x",a)),40):1:!c.axis_y_show||c.axis_y_inner?b.getYAxisLabelPosition().isOuter?30:1:o(b.getAxisWidthByAxisId("y",a))},f.getCurrentPaddingRight=function(){var a=this,b=a.config,c=10,d=a.isLegendRight?a.getLegendWidth()+20:0;return j(b.padding_right)?b.padding_right+1:b.axis_rotated?c+d:!b.axis_y2_show||b.axis_y2_inner?c+d+(a.getY2AxisLabelPosition().isOuter?20:0):o(a.getAxisWidthByAxisId("y2"))+d},f.getParentRectValue=function(a){for(var b,c=this.selectChart.node();c&&"BODY"!==c.tagName&&!(b=c.getBoundingClientRect()[a]);)c=c.parentNode;return b},f.getParentWidth=function(){return this.getParentRectValue("width")},f.getParentHeight=function(){var a=this.selectChart.style("height");return a.indexOf("px")>0?+a.replace("px",""):0},f.getSvgLeft=function(a){var b=this,c=b.config,d=c.axis_rotated?i.axisX:i.axisY,e=b.main.select("."+d).node(),f=e?e.getBoundingClientRect():{right:0},g=b.selectChart.node().getBoundingClientRect(),h=b.hasArcType(),j=f.right-g.left-(h?0:b.getCurrentPaddingLeft(a));return j>0?j:0},f.getAxisWidthByAxisId=function(a,b){var c=this,d=c.getAxisLabelPositionById(a);return c.getMaxTickWidth(a,b)+(d.isInner?20:40)},f.getHorizontalAxisHeight=function(a){var b=this,c=b.config,d=30;return"x"!==a||c.axis_x_show?"x"===a&&c.axis_x_height?c.axis_x_height:"y"!==a||c.axis_y_show?"y2"!==a||c.axis_y2_show?("x"===a&&!c.axis_rotated&&c.axis_x_tick_rotate&&(d=b.getMaxTickWidth(a)*Math.cos(Math.PI*(90-c.axis_x_tick_rotate)/180)),d+(b.getAxisLabelPositionById(a).isInner?0:10)+("y2"===a?-10:0)):b.rotated_padding_top:!c.legend_show||b.isLegendRight||b.isLegendInset?1:10:8},f.getEventRectWidth=function(){var a,b,c,d,e,f,g=this,h=g.getMaxDataCountTarget(g.data.targets);return h?(a=h.values[0],b=h.values[h.values.length-1],c=g.x(b.x)-g.x(a.x),0===c?g.config.axis_rotated?g.height:g.width:(d=g.getMaxDataCount(),e=g.hasType("bar")?(d-(g.isCategorized()?.25:1))/d:1,f=d>1?c*e/(d-1):c,1>f?1:f)):0},f.getShapeIndices=function(a){var b,c,d=this,e=d.config,f={},g=0;return d.filterTargetsToShow(d.data.targets.filter(a,d)).forEach(function(a){for(b=0;b<e.data_groups.length;b++)if(!(e.data_groups[b].indexOf(a.id)<0))for(c=0;c<e.data_groups[b].length;c++)if(e.data_groups[b][c]in f){f[a.id]=f[e.data_groups[b][c]];break}m(f[a.id])&&(f[a.id]=g++)}),f.__max__=g-1,f},f.getShapeX=function(a,b,c,d){var e=this,f=d?e.subX:e.x;return function(d){var e=d.id in c?c[d.id]:0;return d.x||0===d.x?f(d.x)-a*(b/2-e):0}},f.getShapeY=function(a){var b=this;return function(c){var d=a?b.getSubYScale(c.id):b.getYScale(c.id);return d(c.value)}},f.getShapeOffset=function(a,b,c){var d=this,e=d.orderTargets(d.filterTargetsToShow(d.data.targets.filter(a,d))),f=e.map(function(a){return a.id});return function(a,g){var h=c?d.getSubYScale(a.id):d.getYScale(a.id),i=h(0),j=i;return e.forEach(function(c){var e=d.isStepType(a)?d.convertValuesToStep(c.values):c.values;c.id!==a.id&&b[c.id]===b[a.id]&&f.indexOf(c.id)<f.indexOf(a.id)&&e[g].value*a.value>=0&&(j+=h(e[g].value)-i)}),j}},f.isWithinShape=function(a,b){var c,d=this,e=d.d3.select(a);return d.isTargetToShow(b.id)?"circle"===a.nodeName?c=d.isStepType(b)?d.isWithinStep(a,d.getYScale(b.id)(b.value)):d.isWithinCircle(a,1.5*d.pointSelectR(b)):"path"===a.nodeName&&(c=e.classed(i.bar)?d.isWithinBar(a):!0):c=!1,c},f.getInterpolate=function(a){var b=this;return b.isSplineType(a)?"cardinal":b.isStepType(a)?b.config.line_step_type:"linear"},f.initLine=function(){var a=this;a.main.select("."+i.chart).append("g").attr("class",i.chartLines)},f.updateTargetsForLine=function(a){var b,c,d=this,e=d.config,f=d.classChartLine.bind(d),g=d.classLines.bind(d),h=d.classAreas.bind(d),j=d.classCircles.bind(d),k=d.classFocus.bind(d);b=d.main.select("."+i.chartLines).selectAll("."+i.chartLine).data(a).attr("class",function(a){return f(a)+k(a)}),c=b.enter().append("g").attr("class",f).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",g),c.append("g").attr("class",h),c.append("g").attr("class",function(a){return d.generateClass(i.selectedCircles,a.id)}),c.append("g").attr("class",j).style("cursor",function(a){return e.data_selection_isselectable(a)?"pointer":null}),a.forEach(function(a){d.main.selectAll("."+i.selectedCircles+d.getTargetSelectorSuffix(a.id)).selectAll("."+i.selectedCircle).each(function(b){b.value=a.values[b.index].value})})},f.redrawLine=function(a){var b=this;b.mainLine=b.main.selectAll("."+i.lines).selectAll("."+i.line).data(b.lineData.bind(b)),b.mainLine.enter().append("path").attr("class",b.classLine.bind(b)).style("stroke",b.color),b.mainLine.style("opacity",b.initialOpacity.bind(b)).style("shape-rendering",function(a){return b.isStepType(a)?"crispEdges":""}).attr("transform",null),b.mainLine.exit().transition().duration(a).style("opacity",0).remove()},f.addTransitionForLine=function(a,b){var c=this;a.push(c.mainLine.transition().attr("d",b).style("stroke",c.color).style("opacity",1))},f.generateDrawLine=function(a,b){var c=this,d=c.config,e=c.d3.svg.line(),f=c.generateGetLinePoints(a,b),g=b?c.getSubYScale:c.getYScale,h=function(a){return(b?c.subxx:c.xx).call(c,a)},i=function(a,b){return d.data_groups.length>0?f(a,b)[0][1]:g.call(c,a.id)(a.value)};return e=d.axis_rotated?e.x(i).y(h):e.x(h).y(i),d.line_connectNull||(e=e.defined(function(a){return null!=a.value})),function(a){var f,h=d.line_connectNull?c.filterRemoveNull(a.values):a.values,i=b?c.x:c.subX,j=g.call(c,a.id),k=0,l=0;return c.isLineType(a)?d.data_regions[a.id]?f=c.lineWithRegions(h,i,j,d.data_regions[a.id]):(c.isStepType(a)&&(h=c.convertValuesToStep(h)),f=e.interpolate(c.getInterpolate(a))(h)):(h[0]&&(k=i(h[0].x),l=j(h[0].value)),f=d.axis_rotated?"M "+l+" "+k:"M "+k+" "+l),f?f:"M 0 0"}},f.generateGetLinePoints=function(a,b){var c=this,d=c.config,e=a.__max__+1,f=c.getShapeX(0,e,a,!!b),g=c.getShapeY(!!b),h=c.getShapeOffset(c.isLineType,a,!!b),i=b?c.getSubYScale:c.getYScale;return function(a,b){var e=i.call(c,a.id)(0),j=h(a,b)||e,k=f(a),l=g(a);return d.axis_rotated&&(0<a.value&&e>l||a.value<0&&l>e)&&(l=e),[[k,l-(e-j)],[k,l-(e-j)],[k,l-(e-j)],[k,l-(e-j)]]}},f.lineWithRegions=function(a,b,c,d){function e(a,b){var c;for(c=0;c<b.length;c++)if(b[c].start<a&&a<=b[c].end)return!0;return!1}var f,g,h,i,j,k,l,o,p,q,r,s,t=this,u=t.config,v=-1,w="M",x=[];if(n(d))for(f=0;f<d.length;f++)x[f]={},x[f].start=m(d[f].start)?a[0].x:t.isTimeSeries()?t.parseDate(d[f].start):d[f].start,x[f].end=m(d[f].end)?a[a.length-1].x:t.isTimeSeries()?t.parseDate(d[f].end):d[f].end;for(r=u.axis_rotated?function(a){return c(a.value)}:function(a){return b(a.x)},s=u.axis_rotated?function(a){return b(a.x)}:function(a){return c(a.value)},h=t.isTimeSeries()?function(a,d,e,f){var g=a.x.getTime(),h=d.x-a.x,i=new Date(g+h*e),k=new Date(g+h*(e+f));return"M"+b(i)+" "+c(j(e))+" "+b(k)+" "+c(j(e+f))}:function(a,d,e,f){return"M"+b(i(e),!0)+" "+c(j(e))+" "+b(i(e+f),!0)+" "+c(j(e+f))},f=0;f<a.length;f++){if(m(x)||!e(a[f].x,x))w+=" "+r(a[f])+" "+s(a[f]);else for(i=t.getScale(a[f-1].x,a[f].x,t.isTimeSeries()),j=t.getScale(a[f-1].value,a[f].value),k=b(a[f].x)-b(a[f-1].x),l=c(a[f].value)-c(a[f-1].value),o=Math.sqrt(Math.pow(k,2)+Math.pow(l,2)),p=2/o,q=2*p,g=p;1>=g;g+=q)w+=h(a[f-1],a[f],g,p);v=a[f].x}return w},f.redrawArea=function(a){var b=this,c=b.d3;b.mainArea=b.main.selectAll("."+i.areas).selectAll("."+i.area).data(b.lineData.bind(b)),b.mainArea.enter().append("path").attr("class",b.classArea.bind(b)).style("fill",b.color).style("opacity",function(){return b.orgAreaOpacity=+c.select(this).style("opacity"),0}),b.mainArea.style("opacity",b.orgAreaOpacity),b.mainArea.exit().transition().duration(a).style("opacity",0).remove()},f.addTransitionForArea=function(a,b){var c=this;a.push(c.mainArea.transition().attr("d",b).style("fill",c.color).style("opacity",c.orgAreaOpacity))},f.generateDrawArea=function(a,b){var c=this,d=c.config,e=c.d3.svg.area(),f=c.generateGetAreaPoints(a,b),g=b?c.getSubYScale:c.getYScale,h=function(a){return(b?c.subxx:c.xx).call(c,a)},i=function(a,b){return d.data_groups.length>0?f(a,b)[0][1]:g.call(c,a.id)(0)},j=function(a,b){return d.data_groups.length>0?f(a,b)[1][1]:g.call(c,a.id)(a.value)};return e=d.axis_rotated?e.x0(i).x1(j).y(h):e.x(h).y0(i).y1(j),d.line_connectNull||(e=e.defined(function(a){return null!==a.value})),function(a){var b,f=d.line_connectNull?c.filterRemoveNull(a.values):a.values,g=0,h=0;return c.isAreaType(a)?(c.isStepType(a)&&(f=c.convertValuesToStep(f)),b=e.interpolate(c.getInterpolate(a))(f)):(f[0]&&(g=c.x(f[0].x),h=c.getYScale(a.id)(f[0].value)),b=d.axis_rotated?"M "+h+" "+g:"M "+g+" "+h),b?b:"M 0 0"}},f.generateGetAreaPoints=function(a,b){var c=this,d=c.config,e=a.__max__+1,f=c.getShapeX(0,e,a,!!b),g=c.getShapeY(!!b),h=c.getShapeOffset(c.isAreaType,a,!!b),i=b?c.getSubYScale:c.getYScale;return function(a,b){var e=i.call(c,a.id)(0),j=h(a,b)||e,k=f(a),l=g(a);return d.axis_rotated&&(0<a.value&&e>l||a.value<0&&l>e)&&(l=e),[[k,j],[k,l-(e-j)],[k,l-(e-j)],[k,j]]}},f.redrawCircle=function(){var a=this;a.mainCircle=a.main.selectAll("."+i.circles).selectAll("."+i.circle).data(a.lineOrScatterData.bind(a)),a.mainCircle.enter().append("circle").attr("class",a.classCircle.bind(a)).attr("r",a.pointR.bind(a)).style("fill",a.color),a.mainCircle.style("opacity",a.initialOpacityForCircle.bind(a)),a.mainCircle.exit().remove()},f.addTransitionForCircle=function(a,b,c){var d=this;a.push(d.mainCircle.transition().style("opacity",d.opacityForCircle.bind(d)).style("fill",d.color).attr("cx",b).attr("cy",c)),a.push(d.main.selectAll("."+i.selectedCircle).transition().attr("cx",b).attr("cy",c))},f.circleX=function(a){return a.x||0===a.x?this.x(a.x):null},f.updateCircleY=function(){var a,b,c=this;c.config.data_groups.length>0?(a=c.getShapeIndices(c.isLineType),b=c.generateGetLinePoints(a),c.circleY=function(a,c){return b(a,c)[0][1]}):c.circleY=function(a){return c.getYScale(a.id)(a.value)}},f.getCircles=function(a,b){var c=this;return(b?c.main.selectAll("."+i.circles+c.getTargetSelectorSuffix(b)):c.main).selectAll("."+i.circle+(j(a)?"-"+a:""))},f.expandCircles=function(a,b,c){var d=this,e=d.pointExpandedR.bind(d);c&&d.unexpandCircles(),d.getCircles(a,b).classed(i.EXPANDED,!0).attr("r",e)},f.unexpandCircles=function(a){var b=this,c=b.pointR.bind(b);b.getCircles(a).filter(function(){return b.d3.select(this).classed(i.EXPANDED)}).classed(i.EXPANDED,!1).attr("r",c)},f.pointR=function(a){var b=this,c=b.config;return b.isStepType(a)?0:k(c.point_r)?c.point_r(a):c.point_r},f.pointExpandedR=function(a){var b=this,c=b.config;return c.point_focus_expand_enabled?c.point_focus_expand_r?c.point_focus_expand_r:1.75*b.pointR(a):b.pointR(a)},f.pointSelectR=function(a){var b=this,c=b.config;return c.point_select_r?c.point_select_r:4*b.pointR(a)},f.isWithinCircle=function(a,b){var c=this.d3,d=c.mouse(a),e=c.select(a),f=+e.attr("cx"),g=+e.attr("cy");return Math.sqrt(Math.pow(f-d[0],2)+Math.pow(g-d[1],2))<b},f.isWithinStep=function(a,b){return Math.abs(b-this.d3.mouse(a)[1])<30},f.initBar=function(){var a=this;a.main.select("."+i.chart).append("g").attr("class",i.chartBars)},f.updateTargetsForBar=function(a){var b,c,d=this,e=d.config,f=d.classChartBar.bind(d),g=d.classBars.bind(d),h=d.classFocus.bind(d);b=d.main.select("."+i.chartBars).selectAll("."+i.chartBar).data(a).attr("class",function(a){return f(a)+h(a)}),c=b.enter().append("g").attr("class",f).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",g).style("cursor",function(a){return e.data_selection_isselectable(a)?"pointer":null})},f.redrawBar=function(a){var b=this,c=b.barData.bind(b),d=b.classBar.bind(b),e=b.initialOpacity.bind(b),f=function(a){return b.color(a.id)};b.mainBar=b.main.selectAll("."+i.bars).selectAll("."+i.bar).data(c),b.mainBar.enter().append("path").attr("class",d).style("stroke",f).style("fill",f),b.mainBar.style("opacity",e),b.mainBar.exit().transition().duration(a).style("opacity",0).remove()},f.addTransitionForBar=function(a,b){var c=this;a.push(c.mainBar.transition().attr("d",b).style("fill",c.color).style("opacity",1))},f.getBarW=function(a,b){var c=this,d=c.config,e="number"==typeof d.bar_width?d.bar_width:b?2*a.tickOffset()*d.bar_width_ratio/b:0;return d.bar_width_max&&e>d.bar_width_max?d.bar_width_max:e},f.getBars=function(a,b){var c=this;return(b?c.main.selectAll("."+i.bars+c.getTargetSelectorSuffix(b)):c.main).selectAll("."+i.bar+(j(a)?"-"+a:""))},f.expandBars=function(a,b,c){var d=this;c&&d.unexpandBars(),d.getBars(a,b).classed(i.EXPANDED,!0)},f.unexpandBars=function(a){var b=this;b.getBars(a).classed(i.EXPANDED,!1)},f.generateDrawBar=function(a,b){var c=this,d=c.config,e=c.generateGetBarPoints(a,b);return function(a,b){var c=e(a,b),f=d.axis_rotated?1:0,g=d.axis_rotated?0:1,h="M "+c[0][f]+","+c[0][g]+" L"+c[1][f]+","+c[1][g]+" L"+c[2][f]+","+c[2][g]+" L"+c[3][f]+","+c[3][g]+" z";return h}},f.generateGetBarPoints=function(a,b){var c=this,d=b?c.subXAxis:c.xAxis,e=a.__max__+1,f=c.getBarW(d,e),g=c.getShapeX(f,e,a,!!b),h=c.getShapeY(!!b),i=c.getShapeOffset(c.isBarType,a,!!b),j=b?c.getSubYScale:c.getYScale;return function(a,b){var d=j.call(c,a.id)(0),e=i(a,b)||d,k=g(a),l=h(a);return c.config.axis_rotated&&(0<a.value&&d>l||a.value<0&&l>d)&&(l=d),[[k,e],[k,l-(d-e)],[k+f,l-(d-e)],[k+f,e]]}},f.isWithinBar=function(a){var b=this.d3.mouse(a),c=a.getBoundingClientRect(),d=a.pathSegList.getItem(0),e=a.pathSegList.getItem(1),f=Math.min(d.x,e.x),g=Math.min(d.y,e.y),h=c.width,i=c.height,j=2,k=f-j,l=f+h+j,m=g+i+j,n=g-j;return k<b[0]&&b[0]<l&&n<b[1]&&b[1]<m},f.initText=function(){var a=this;a.main.select("."+i.chart).append("g").attr("class",i.chartTexts),a.mainText=a.d3.selectAll([])},f.updateTargetsForText=function(a){var b,c,d=this,e=d.classChartText.bind(d),f=d.classTexts.bind(d),g=d.classFocus.bind(d);b=d.main.select("."+i.chartTexts).selectAll("."+i.chartText).data(a).attr("class",function(a){return e(a)+g(a)}),c=b.enter().append("g").attr("class",e).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",f)},f.redrawText=function(a){var b=this,c=b.config,d=b.barOrLineData.bind(b),e=b.classText.bind(b);b.mainText=b.main.selectAll("."+i.texts).selectAll("."+i.text).data(d),b.mainText.enter().append("text").attr("class",e).attr("text-anchor",function(a){return c.axis_rotated?a.value<0?"end":"start":"middle"}).style("stroke","none").style("fill",function(a){return b.color(a)}).style("fill-opacity",0),b.mainText.text(function(a,c,d){return b.formatByAxisId(b.getAxisId(a.id))(a.value,a.id,c,d)}),b.mainText.exit().transition().duration(a).style("fill-opacity",0).remove()},f.addTransitionForText=function(a,b,c,d){var e=this,f=d?0:e.opacityForText.bind(e);a.push(e.mainText.transition().attr("x",b).attr("y",c).style("fill",e.color).style("fill-opacity",f))},f.getTextRect=function(a,b){var c,d=this.d3.select("body").classed("c3",!0),e=d.append("svg").style("visibility","hidden");return e.selectAll(".dummy").data([a]).enter().append("text").classed(b?b:"",!0).text(a).each(function(){c=this.getBoundingClientRect()
+}),e.remove(),d.classed("c3",!1),c},f.generateXYForText=function(a,b,c,d){var e=this,f=e.generateGetAreaPoints(b,!1),g=e.generateGetBarPoints(b,!1),h=e.generateGetLinePoints(c,!1),i=d?e.getXForText:e.getYForText;return function(a,b){var c=e.isAreaType(a)?f:e.isBarType(a)?g:h;return i.call(e,c(a,b),a,this)}},f.getXForText=function(a,b,c){var d,e,f=this,g=c.getBoundingClientRect();return f.config.axis_rotated?(e=f.isBarType(b)?4:6,d=a[2][1]+e*(b.value<0?-1:1)):d=f.hasType("bar")?(a[2][0]+a[0][0])/2:a[0][0],null!==b.value?d:d>f.width?f.width-g.width:d},f.getYForText=function(a,b,c){var d,e=this,f=c.getBoundingClientRect();return d=e.config.axis_rotated?(a[0][0]+a[2][0]+.6*f.height)/2:a[2][1]+(b.value<0?f.height:e.isBarType(b)?-3:-6),null!==b.value?d:d<f.height?f.height:d},f.setTargetType=function(a,b){var c=this,d=c.config;c.mapToTargetIds(a).forEach(function(a){c.withoutFadeIn[a]=b===d.data_types[a],d.data_types[a]=b}),a||(d.data_type=b)},f.hasType=function(a,b){var c=this,d=c.config.data_types,e=!1;return b=b||c.data.targets,b&&b.length?b.forEach(function(b){var c=d[b.id];(c&&c.indexOf(a)>=0||!c&&"line"===a)&&(e=!0)}):Object.keys(d).length?Object.keys(d).forEach(function(b){d[b]===a&&(e=!0)}):e=c.config.data_type===a,e},f.hasArcType=function(a){return this.hasType("pie",a)||this.hasType("donut",a)||this.hasType("gauge",a)},f.isLineType=function(a){var b=this.config,c=l(a)?a:a.id;return!b.data_types[c]||["line","spline","area","area-spline","step","area-step"].indexOf(b.data_types[c])>=0},f.isStepType=function(a){var b=l(a)?a:a.id;return["step","area-step"].indexOf(this.config.data_types[b])>=0},f.isSplineType=function(a){var b=l(a)?a:a.id;return["spline","area-spline"].indexOf(this.config.data_types[b])>=0},f.isAreaType=function(a){var b=l(a)?a:a.id;return["area","area-spline","area-step"].indexOf(this.config.data_types[b])>=0},f.isBarType=function(a){var b=l(a)?a:a.id;return"bar"===this.config.data_types[b]},f.isScatterType=function(a){var b=l(a)?a:a.id;return"scatter"===this.config.data_types[b]},f.isPieType=function(a){var b=l(a)?a:a.id;return"pie"===this.config.data_types[b]},f.isGaugeType=function(a){var b=l(a)?a:a.id;return"gauge"===this.config.data_types[b]},f.isDonutType=function(a){var b=l(a)?a:a.id;return"donut"===this.config.data_types[b]},f.isArcType=function(a){return this.isPieType(a)||this.isDonutType(a)||this.isGaugeType(a)},f.lineData=function(a){return this.isLineType(a)?[a]:[]},f.arcData=function(a){return this.isArcType(a.data)?[a]:[]},f.barData=function(a){return this.isBarType(a)?a.values:[]},f.lineOrScatterData=function(a){return this.isLineType(a)||this.isScatterType(a)?a.values:[]},f.barOrLineData=function(a){return this.isBarType(a)||this.isLineType(a)?a.values:[]},f.initGrid=function(){var a=this,b=a.config,c=a.d3;a.grid=a.main.append("g").attr("clip-path",a.clipPathForGrid).attr("class",i.grid),b.grid_x_show&&a.grid.append("g").attr("class",i.xgrids),b.grid_y_show&&a.grid.append("g").attr("class",i.ygrids),b.grid_focus_show&&a.grid.append("g").attr("class",i.xgridFocus).append("line").attr("class",i.xgridFocus),a.xgrid=c.selectAll([]),b.grid_lines_front||a.initGridLines()},f.initGridLines=function(){var a=this,b=a.d3;a.gridLines=a.main.append("g").attr("clip-path",a.clipPathForGrid).attr("class",i.grid+" "+i.gridLines),a.gridLines.append("g").attr("class",i.xgridLines),a.gridLines.append("g").attr("class",i.ygridLines),a.xgridLines=b.selectAll([])},f.updateXGrid=function(a){var b=this,c=b.config,d=b.d3,e=b.generateGridData(c.grid_x_type,b.x),f=b.isCategorized()?b.xAxis.tickOffset():0;b.xgridAttr=c.axis_rotated?{x1:0,x2:b.width,y1:function(a){return b.x(a)-f},y2:function(a){return b.x(a)-f}}:{x1:function(a){return b.x(a)+f},x2:function(a){return b.x(a)+f},y1:0,y2:b.height},b.xgrid=b.main.select("."+i.xgrids).selectAll("."+i.xgrid).data(e),b.xgrid.enter().append("line").attr("class",i.xgrid),a||b.xgrid.attr(b.xgridAttr).style("opacity",function(){return+d.select(this).attr(c.axis_rotated?"y1":"x1")===(c.axis_rotated?b.height:0)?0:1}),b.xgrid.exit().remove()},f.updateYGrid=function(){var a=this,b=a.config,c=a.yAxis.tickValues()||a.y.ticks(b.grid_y_ticks);a.ygrid=a.main.select("."+i.ygrids).selectAll("."+i.ygrid).data(c),a.ygrid.enter().append("line").attr("class",i.ygrid),a.ygrid.attr("x1",b.axis_rotated?a.y:0).attr("x2",b.axis_rotated?a.y:a.width).attr("y1",b.axis_rotated?0:a.y).attr("y2",b.axis_rotated?a.height:a.y),a.ygrid.exit().remove(),a.smoothLines(a.ygrid,"grid")},f.redrawGrid=function(a){var b,c,d,e=this,f=e.main,g=e.config;e.grid.style("visibility",e.hasArcType()?"hidden":"visible"),f.select("line."+i.xgridFocus).style("visibility","hidden"),g.grid_x_show&&e.updateXGrid(),e.xgridLines=f.select("."+i.xgridLines).selectAll("."+i.xgridLine).data(g.grid_x_lines),b=e.xgridLines.enter().append("g").attr("class",function(a){return i.xgridLine+(a["class"]?" "+a["class"]:"")}),b.append("line").style("opacity",0),b.append("text").attr("text-anchor","end").attr("transform",g.axis_rotated?"":"rotate(-90)").attr("dx",g.axis_rotated?0:-e.margin.top).attr("dy",-5).style("opacity",0),e.xgridLines.exit().transition().duration(a).style("opacity",0).remove(),g.grid_y_show&&e.updateYGrid(),e.ygridLines=f.select("."+i.ygridLines).selectAll("."+i.ygridLine).data(g.grid_y_lines),c=e.ygridLines.enter().append("g").attr("class",function(a){return i.ygridLine+(a["class"]?" "+a["class"]:"")}),c.append("line").style("opacity",0),c.append("text").attr("text-anchor","end").attr("transform",g.axis_rotated?"rotate(-90)":"").attr("dx",g.axis_rotated?0:-e.margin.top).attr("dy",-5).style("opacity",0),d=e.yv.bind(e),e.ygridLines.select("line").transition().duration(a).attr("x1",g.axis_rotated?d:0).attr("x2",g.axis_rotated?d:e.width).attr("y1",g.axis_rotated?0:d).attr("y2",g.axis_rotated?e.height:d).style("opacity",1),e.ygridLines.select("text").transition().duration(a).attr("x",g.axis_rotated?0:e.width).attr("y",d).text(function(a){return a.text}).style("opacity",1),e.ygridLines.exit().transition().duration(a).style("opacity",0).remove()},f.addTransitionForGrid=function(a){var b=this,c=b.config,d=b.xv.bind(b);a.push(b.xgridLines.select("line").transition().attr("x1",c.axis_rotated?0:d).attr("x2",c.axis_rotated?b.width:d).attr("y1",c.axis_rotated?d:b.margin.top).attr("y2",c.axis_rotated?d:b.height).style("opacity",1)),a.push(b.xgridLines.select("text").transition().attr("x",c.axis_rotated?b.width:0).attr("y",d).text(function(a){return a.text}).style("opacity",1))},f.showXGridFocus=function(a){var b=this,c=b.config,d=a.filter(function(a){return a&&j(a.value)}),e=b.main.selectAll("line."+i.xgridFocus),f=b.xx.bind(b);c.tooltip_show&&(b.hasType("scatter")||b.hasArcType()||(e.style("visibility","visible").data([d[0]]).attr(c.axis_rotated?"y1":"x1",f).attr(c.axis_rotated?"y2":"x2",f),b.smoothLines(e,"grid")))},f.hideXGridFocus=function(){this.main.select("line."+i.xgridFocus).style("visibility","hidden")},f.updateXgridFocus=function(){var a=this,b=a.config;a.main.select("line."+i.xgridFocus).attr("x1",b.axis_rotated?0:-10).attr("x2",b.axis_rotated?a.width:-10).attr("y1",b.axis_rotated?-10:0).attr("y2",b.axis_rotated?-10:a.height)},f.generateGridData=function(a,b){var c,d,e,f,g=this,h=[],j=g.main.select("."+i.axisX).selectAll(".tick").size();if("year"===a)for(c=g.getXDomain(),d=c[0].getFullYear(),e=c[1].getFullYear(),f=d;e>=f;f++)h.push(new Date(f+"-01-01 00:00:00"));else h=b.ticks(10),h.length>j&&(h=h.filter(function(a){return(""+a).indexOf(".")<0}));return h},f.getGridFilterToRemove=function(a){return a?function(b){var c=!1;return[].concat(a).forEach(function(a){("value"in a&&b.value===a.value||"class"in a&&b["class"]===a["class"])&&(c=!0)}),c}:function(){return!0}},f.removeGridLines=function(a,b){var c=this,d=c.config,e=c.getGridFilterToRemove(a),f=function(a){return!e(a)},g=b?i.xgridLines:i.ygridLines,h=b?i.xgridLine:i.ygridLine;c.main.select("."+g).selectAll("."+h).filter(e).transition().duration(d.transition_duration).style("opacity",0).remove(),b?d.grid_x_lines=d.grid_x_lines.filter(f):d.grid_y_lines=d.grid_y_lines.filter(f)},f.initTooltip=function(){var a,b=this,c=b.config;if(b.tooltip=b.selectChart.style("position","relative").append("div").attr("class",i.tooltipContainer).style("position","absolute").style("pointer-events","none").style("display","none"),c.tooltip_init_show){if(b.isTimeSeries()&&l(c.tooltip_init_x)){for(c.tooltip_init_x=b.parseDate(c.tooltip_init_x),a=0;a<b.data.targets[0].values.length&&b.data.targets[0].values[a].x-c.tooltip_init_x!==0;a++);c.tooltip_init_x=a}b.tooltip.html(c.tooltip_contents.call(b,b.data.targets.map(function(a){return b.addName(a.values[c.tooltip_init_x])}),b.getXAxisTickFormat(),b.getYFormat(b.hasArcType()),b.color)),b.tooltip.style("top",c.tooltip_init_position.top).style("left",c.tooltip_init_position.left).style("display","block")}},f.getTooltipContent=function(a,b,c,d){var e,f,g,h,j,k,l=this,m=l.config,n=m.tooltip_format_title||b,o=m.tooltip_format_name||function(a){return a},p=m.tooltip_format_value||c;for(f=0;f<a.length;f++)a[f]&&(a[f].value||0===a[f].value)&&(e||(g=n?n(a[f].x):a[f].x,e="<table class='"+i.tooltip+"'>"+(g||0===g?"<tr><th colspan='2'>"+g+"</th></tr>":"")),j=o(a[f].name,a[f].ratio,a[f].id,a[f].index),h=p(a[f].value,a[f].ratio,a[f].id,a[f].index),k=l.levelColor?l.levelColor(a[f].value):d(a[f].id),e+="<tr class='"+i.tooltipName+"-"+a[f].id+"'>",e+="<td class='name'><span style='background-color:"+k+"'></span>"+j+"</td>",e+="<td class='value'>"+h+"</td>",e+="</tr>");return e+"</table>"},f.showTooltip=function(a,b){var c,d,e,f,g,h,i,k=this,l=k.config,m=k.hasArcType(),n=a.filter(function(a){return a&&j(a.value)});0!==n.length&&l.tooltip_show&&(k.tooltip.html(l.tooltip_contents.call(k,a,k.getXAxisTickFormat(),k.getYFormat(m),k.color)).style("display","block"),c=k.tooltip.property("offsetWidth"),d=k.tooltip.property("offsetHeight"),m?(f=k.width/2+b[0],h=k.height/2+b[1]+20):(e=k.getSvgLeft(!0),l.axis_rotated?(f=e+b[0]+100,g=f+c,i=k.currentWidth-k.getCurrentPaddingRight(),h=k.x(n[0].x)+20):(f=e+k.getCurrentPaddingLeft(!0)+k.x(n[0].x)+20,g=f+c,i=e+k.currentWidth-k.getCurrentPaddingRight(),h=b[1]+15),g>i&&(f-=g-i),h+d>k.currentHeight&&(h-=d+30)),0>h&&(h=0),k.tooltip.style("top",h+"px").style("left",f+"px"))},f.hideTooltip=function(){this.tooltip.style("display","none")},f.initLegend=function(){var a=this;return a.legendHasRendered=!1,a.legend=a.svg.append("g").attr("transform",a.getTranslate("legend")),a.config.legend_show?void a.updateLegendWithDefaults():(a.legend.style("visibility","hidden"),void(a.hiddenLegendIds=a.mapToIds(a.data.targets)))},f.updateLegendWithDefaults=function(){var a=this;a.updateLegend(a.mapToIds(a.data.targets),{withTransform:!1,withTransitionForTransform:!1,withTransition:!1})},f.updateSizeForLegend=function(a,b){var c=this,d=c.config,e={top:c.isLegendTop?c.getCurrentPaddingTop()+d.legend_inset_y+5.5:c.currentHeight-a-c.getCurrentPaddingBottom()-d.legend_inset_y,left:c.isLegendLeft?c.getCurrentPaddingLeft()+d.legend_inset_x+.5:c.currentWidth-b-c.getCurrentPaddingRight()-d.legend_inset_x+.5};c.margin3={top:c.isLegendRight?0:c.isLegendInset?e.top:c.currentHeight-a,right:0/0,bottom:0,left:c.isLegendRight?c.currentWidth-b:c.isLegendInset?e.left:0}},f.transformLegend=function(a){var b=this;(a?b.legend.transition():b.legend).attr("transform",b.getTranslate("legend"))},f.updateLegendStep=function(a){this.legendStep=a},f.updateLegendItemWidth=function(a){this.legendItemWidth=a},f.updateLegendItemHeight=function(a){this.legendItemHeight=a},f.getLegendWidth=function(){var a=this;return a.config.legend_show?a.isLegendRight||a.isLegendInset?a.legendItemWidth*(a.legendStep+1):a.currentWidth:0},f.getLegendHeight=function(){var a=this,b=0;return a.config.legend_show&&(b=a.isLegendRight?a.currentHeight:Math.max(20,a.legendItemHeight)*(a.legendStep+1)),b},f.opacityForLegend=function(a){return a.classed(i.legendItemHidden)?null:1},f.opacityForUnfocusedLegend=function(a){return a.classed(i.legendItemHidden)?null:.3},f.toggleFocusLegend=function(a,b){var c=this;a=c.mapToTargetIds(a),c.legend.selectAll("."+i.legendItem).filter(function(b){return a.indexOf(b)>=0}).classed(i.legendItemFocused,b).transition().duration(100).style("opacity",function(){var a=b?c.opacityForLegend:c.opacityForUnfocusedLegend;return a.call(c,c.d3.select(this))})},f.revertLegend=function(){var a=this,b=a.d3;a.legend.selectAll("."+i.legendItem).classed(i.legendItemFocused,!1).transition().duration(100).style("opacity",function(){return a.opacityForLegend(b.select(this))})},f.showLegend=function(a){var b=this,c=b.config;c.legend_show||(c.legend_show=!0,b.legend.style("visibility","visible"),b.legendHasRendered||b.updateLegendWithDefaults()),b.removeHiddenLegendIds(a),b.legend.selectAll(b.selectorLegends(a)).style("visibility","visible").transition().style("opacity",function(){return b.opacityForLegend(b.d3.select(this))})},f.hideLegend=function(a){var b=this,c=b.config;c.legend_show&&r(a)&&(c.legend_show=!1,b.legend.style("visibility","hidden")),b.addHiddenLegendIds(a),b.legend.selectAll(b.selectorLegends(a)).style("opacity",0).style("visibility","hidden")};var h={};f.clearLegendItemTextBoxCache=function(){h={}},f.updateLegend=function(a,b,c){function d(a,b){return h[b]||(h[b]=w.getTextRect(a.textContent,i.legendItem)),h[b]}function e(b,c,e){function f(a,b){b||(g=(o-E-n)/2,C>g&&(g=(o-n)/2,E=0,K++)),J[a]=K,I[K]=w.isLegendInset?10:g,F[a]=E,E+=n}var g,h,i=0===e,j=e===a.length-1,k=d(b,c),l=k.width+D+(!j||w.isLegendRight||w.isLegendInset?z:0),m=k.height+y,n=w.isLegendRight||w.isLegendInset?m:l,o=w.isLegendRight||w.isLegendInset?w.getLegendHeight():w.getLegendWidth();return i&&(E=0,K=0,A=0,B=0),x.legend_show&&!w.isLegendToShow(c)?void(G[c]=H[c]=J[c]=F[c]=0):(G[c]=l,H[c]=m,(!A||l>=A)&&(A=l),(!B||m>=B)&&(B=m),h=w.isLegendRight||w.isLegendInset?B:A,void(x.legend_equally?(Object.keys(G).forEach(function(a){G[a]=A}),Object.keys(H).forEach(function(a){H[a]=B}),g=(o-h*a.length)/2,C>g?(E=0,K=0,a.forEach(function(a){f(a)})):f(c,!0)):f(c)))}var f,g,j,k,l,m,o,p,q,r,s,u,v,w=this,x=w.config,y=4,z=10,A=0,B=0,C=10,D=15,E=0,F={},G={},H={},I=[0],J={},K=0,L=w.legend.selectAll("."+i.legendItemFocused).size();b=b||{},p=t(b,"withTransition",!0),q=t(b,"withTransitionForTransform",!0),w.isLegendInset&&(K=x.legend_inset_step?x.legend_inset_step:a.length,w.updateLegendStep(K)),w.isLegendRight?(f=function(a){return A*J[a]},k=function(a){return I[J[a]]+F[a]}):w.isLegendInset?(f=function(a){return A*J[a]+10},k=function(a){return I[J[a]]+F[a]}):(f=function(a){return I[J[a]]+F[a]},k=function(a){return B*J[a]}),g=function(a,b){return f(a,b)+14},l=function(a,b){return k(a,b)+9},j=function(a,b){return f(a,b)},m=function(a,b){return k(a,b)-5},o=w.legend.selectAll("."+i.legendItem).data(a).enter().append("g").attr("class",function(a){return w.generateClass(i.legendItem,a)}).style("visibility",function(a){return w.isLegendToShow(a)?"visible":"hidden"}).style("cursor","pointer").on("click",function(a){x.legend_item_onclick?x.legend_item_onclick.call(w,a):w.d3.event.altKey?(w.api.hide(),w.api.show(a)):(w.api.toggle(a),w.isTargetToShow(a)?w.api.focus(a):w.api.revert())}).on("mouseover",function(a){w.d3.select(this).classed(i.legendItemFocused,!0),!w.transiting&&w.isTargetToShow(a)&&w.api.focus(a),x.legend_item_onmouseover&&x.legend_item_onmouseover.call(w,a)}).on("mouseout",function(a){w.d3.select(this).classed(i.legendItemFocused,!1),w.api.revert(),x.legend_item_onmouseout&&x.legend_item_onmouseout.call(w,a)}),o.append("text").text(function(a){return n(x.data_names[a])?x.data_names[a]:a}).each(function(a,b){e(this,a,b)}).style("pointer-events","none").attr("x",w.isLegendRight||w.isLegendInset?g:-200).attr("y",w.isLegendRight||w.isLegendInset?-200:l),o.append("rect").attr("class",i.legendItemEvent).style("fill-opacity",0).attr("x",w.isLegendRight||w.isLegendInset?j:-200).attr("y",w.isLegendRight||w.isLegendInset?-200:m),o.append("rect").attr("class",i.legendItemTile).style("pointer-events","none").style("fill",w.color).attr("x",w.isLegendRight||w.isLegendInset?g:-200).attr("y",w.isLegendRight||w.isLegendInset?-200:k).attr("width",10).attr("height",10),v=w.legend.select("."+i.legendBackground+" rect"),w.isLegendInset&&A>0&&0===v.size()&&(v=w.legend.insert("g","."+i.legendItem).attr("class",i.legendBackground).append("rect")),r=w.legend.selectAll("text").data(a).text(function(a){return n(x.data_names[a])?x.data_names[a]:a}).each(function(a,b){e(this,a,b)}),(p?r.transition():r).attr("x",g).attr("y",l),s=w.legend.selectAll("rect."+i.legendItemEvent).data(a),(p?s.transition():s).attr("width",function(a){return G[a]}).attr("height",function(a){return H[a]}).attr("x",j).attr("y",m),u=w.legend.selectAll("rect."+i.legendItemTile).data(a),(p?u.transition():u).style("fill",w.color).attr("x",f).attr("y",k),v&&(p?v.transition():v).attr("height",w.getLegendHeight()-12).attr("width",A*(K+1)+10),w.legend.selectAll("."+i.legendItem).classed(i.legendItemHidden,function(a){return!w.isTargetToShow(a)}).transition().style("opacity",function(a){var b=w.d3.select(this);return w.isTargetToShow(a)?!L||b.classed(i.legendItemFocused)?w.opacityForLegend(b):w.opacityForUnfocusedLegend(b):null}),w.updateLegendItemWidth(A),w.updateLegendItemHeight(B),w.updateLegendStep(K),w.updateSizes(),w.updateScales(),w.updateSvgSize(),w.transformAll(q,c),w.legendHasRendered=!0},f.initAxis=function(){var a=this,b=a.config,c=a.main;a.axes.x=c.append("g").attr("class",i.axis+" "+i.axisX).attr("clip-path",a.clipPathForXAxis).attr("transform",a.getTranslate("x")).style("visibility",b.axis_x_show?"visible":"hidden"),a.axes.x.append("text").attr("class",i.axisXLabel).attr("transform",b.axis_rotated?"rotate(-90)":"").style("text-anchor",a.textAnchorForXAxisLabel.bind(a)),a.axes.y=c.append("g").attr("class",i.axis+" "+i.axisY).attr("clip-path",b.axis_y_inner?"":a.clipPathForYAxis).attr("transform",a.getTranslate("y")).style("visibility",b.axis_y_show?"visible":"hidden"),a.axes.y.append("text").attr("class",i.axisYLabel).attr("transform",b.axis_rotated?"":"rotate(-90)").style("text-anchor",a.textAnchorForYAxisLabel.bind(a)),a.axes.y2=c.append("g").attr("class",i.axis+" "+i.axisY2).attr("transform",a.getTranslate("y2")).style("visibility",b.axis_y2_show?"visible":"hidden"),a.axes.y2.append("text").attr("class",i.axisY2Label).attr("transform",b.axis_rotated?"":"rotate(-90)").style("text-anchor",a.textAnchorForY2AxisLabel.bind(a))},f.getXAxis=function(a,b,c,e,f){var g=this,h=g.config,i={isCategory:g.isCategorized(),withOuterTick:f,tickMultiline:h.axis_x_tick_multiline,tickWidth:h.axis_x_tick_width},j=d(g.d3,i).scale(a).orient(b);return g.isTimeSeries()&&e&&(e=e.map(function(a){return g.parseDate(a)})),j.tickFormat(c).tickValues(e),g.isCategorized()?(j.tickCentered(h.axis_x_tick_centered),r(h.axis_x_tick_culling)&&(h.axis_x_tick_culling=!1)):j.tickOffset=function(){var a=this.scale(),b=g.getEdgeX(g.data.targets),c=a(b[1])-a(b[0]),d=c?c:h.axis_rotated?g.height:g.width;return d/g.getMaxDataCount()/2},j},f.getYAxis=function(a,b,c,e,f){var g={withOuterTick:f},h=d(this.d3,g).scale(a).orient(b).tickFormat(c);return this.isTimeSeriesY()?h.ticks(this.d3.time[this.config.axis_y_tick_time_value],this.config.axis_y_tick_time_interval):h.tickValues(e),h},f.getAxisId=function(a){var b=this.config;return a in b.data_axes?b.data_axes[a]:"y"},f.getXAxisTickFormat=function(){var a=this,b=a.config,c=a.isTimeSeries()?a.defaultAxisTimeFormat:a.isCategorized()?a.categoryName:function(a){return 0>a?a.toFixed(0):a};return b.axis_x_tick_format&&(k(b.axis_x_tick_format)?c=b.axis_x_tick_format:a.isTimeSeries()&&(c=function(c){return c?a.axisTimeFormat(b.axis_x_tick_format)(c):""})),k(c)?function(b){return c.call(a,b)}:c},f.getAxisTickValues=function(a,b){return a?a:b?b.tickValues():void 0},f.getXAxisTickValues=function(){return this.getAxisTickValues(this.config.axis_x_tick_values,this.xAxis)},f.getYAxisTickValues=function(){return this.getAxisTickValues(this.config.axis_y_tick_values,this.yAxis)},f.getY2AxisTickValues=function(){return this.getAxisTickValues(this.config.axis_y2_tick_values,this.y2Axis)},f.getAxisLabelOptionByAxisId=function(a){var b,c=this,d=c.config;return"y"===a?b=d.axis_y_label:"y2"===a?b=d.axis_y2_label:"x"===a&&(b=d.axis_x_label),b},f.getAxisLabelText=function(a){var b=this.getAxisLabelOptionByAxisId(a);return l(b)?b:b?b.text:null},f.setAxisLabelText=function(a,b){var c=this,d=c.config,e=c.getAxisLabelOptionByAxisId(a);l(e)?"y"===a?d.axis_y_label=b:"y2"===a?d.axis_y2_label=b:"x"===a&&(d.axis_x_label=b):e&&(e.text=b)},f.getAxisLabelPosition=function(a,b){var c=this.getAxisLabelOptionByAxisId(a),d=c&&"object"==typeof c&&c.position?c.position:b;return{isInner:d.indexOf("inner")>=0,isOuter:d.indexOf("outer")>=0,isLeft:d.indexOf("left")>=0,isCenter:d.indexOf("center")>=0,isRight:d.indexOf("right")>=0,isTop:d.indexOf("top")>=0,isMiddle:d.indexOf("middle")>=0,isBottom:d.indexOf("bottom")>=0}},f.getXAxisLabelPosition=function(){return this.getAxisLabelPosition("x",this.config.axis_rotated?"inner-top":"inner-right")},f.getYAxisLabelPosition=function(){return this.getAxisLabelPosition("y",this.config.axis_rotated?"inner-right":"inner-top")},f.getY2AxisLabelPosition=function(){return this.getAxisLabelPosition("y2",this.config.axis_rotated?"inner-right":"inner-top")},f.getAxisLabelPositionById=function(a){return"y2"===a?this.getY2AxisLabelPosition():"y"===a?this.getYAxisLabelPosition():this.getXAxisLabelPosition()},f.textForXAxisLabel=function(){return this.getAxisLabelText("x")},f.textForYAxisLabel=function(){return this.getAxisLabelText("y")},f.textForY2AxisLabel=function(){return this.getAxisLabelText("y2")},f.xForAxisLabel=function(a,b){var c=this;return a?b.isLeft?0:b.isCenter?c.width/2:c.width:b.isBottom?-c.height:b.isMiddle?-c.height/2:0},f.dxForAxisLabel=function(a,b){return a?b.isLeft?"0.5em":b.isRight?"-0.5em":"0":b.isTop?"-0.5em":b.isBottom?"0.5em":"0"},f.textAnchorForAxisLabel=function(a,b){return a?b.isLeft?"start":b.isCenter?"middle":"end":b.isBottom?"start":b.isMiddle?"middle":"end"},f.xForXAxisLabel=function(){return this.xForAxisLabel(!this.config.axis_rotated,this.getXAxisLabelPosition())},f.xForYAxisLabel=function(){return this.xForAxisLabel(this.config.axis_rotated,this.getYAxisLabelPosition())},f.xForY2AxisLabel=function(){return this.xForAxisLabel(this.config.axis_rotated,this.getY2AxisLabelPosition())},f.dxForXAxisLabel=function(){return this.dxForAxisLabel(!this.config.axis_rotated,this.getXAxisLabelPosition())},f.dxForYAxisLabel=function(){return this.dxForAxisLabel(this.config.axis_rotated,this.getYAxisLabelPosition())},f.dxForY2AxisLabel=function(){return this.dxForAxisLabel(this.config.axis_rotated,this.getY2AxisLabelPosition())},f.dyForXAxisLabel=function(){var a=this,b=a.config,c=a.getXAxisLabelPosition();return b.axis_rotated?c.isInner?"1.2em":-25-a.getMaxTickWidth("x"):c.isInner?"-0.5em":b.axis_x_height?b.axis_x_height-10:"3em"},f.dyForYAxisLabel=function(){var a=this,b=a.getYAxisLabelPosition();return a.config.axis_rotated?b.isInner?"-0.5em":"3em":b.isInner?"1.2em":-10-(a.config.axis_y_inner?0:a.getMaxTickWidth("y")+10)},f.dyForY2AxisLabel=function(){var a=this,b=a.getY2AxisLabelPosition();return a.config.axis_rotated?b.isInner?"1.2em":"-2.2em":b.isInner?"-0.5em":15+(a.config.axis_y2_inner?0:this.getMaxTickWidth("y2")+15)},f.textAnchorForXAxisLabel=function(){var a=this;return a.textAnchorForAxisLabel(!a.config.axis_rotated,a.getXAxisLabelPosition())},f.textAnchorForYAxisLabel=function(){var a=this;return a.textAnchorForAxisLabel(a.config.axis_rotated,a.getYAxisLabelPosition())},f.textAnchorForY2AxisLabel=function(){var a=this;return a.textAnchorForAxisLabel(a.config.axis_rotated,a.getY2AxisLabelPosition())},f.xForRotatedTickText=function(a){return 8*Math.sin(Math.PI*(a/180))},f.yForRotatedTickText=function(a){return 11.5-2.5*(a/15)*(a>0?1:-1)},f.rotateTickText=function(a,b,c){a.selectAll(".tick text").style("text-anchor",c>0?"start":"end"),b.selectAll(".tick text").attr("y",this.yForRotatedTickText(c)).attr("transform","rotate("+c+")").selectAll("tspan").attr("dx",this.xForRotatedTickText(c))},f.getMaxTickWidth=function(a,b){var c,d,e,f=this,g=f.config,h=0;return b&&f.currentMaxTickWidths[a]?f.currentMaxTickWidths[a]:(f.svg&&(c=f.filterTargetsToShow(f.data.targets),"y"===a?(d=f.y.copy().domain(f.getYDomain(c,"y")),e=f.getYAxis(d,f.yOrient,g.axis_y_tick_format,f.yAxisTickValues)):"y2"===a?(d=f.y2.copy().domain(f.getYDomain(c,"y2")),e=f.getYAxis(d,f.y2Orient,g.axis_y2_tick_format,f.y2AxisTickValues)):(d=f.x.copy().domain(f.getXDomain(c)),e=f.getXAxis(d,f.xOrient,f.xAxisTickFormat,f.xAxisTickValues)),f.d3.select("body").append("g").style("visibility","hidden").call(e).each(function(){f.d3.select(this).selectAll("text tspan").each(function(){var a=this.getBoundingClientRect();a.left>0&&h<a.width&&(h=a.width)})}).remove()),f.currentMaxTickWidths[a]=0>=h?f.currentMaxTickWidths[a]:h,f.currentMaxTickWidths[a])},f.updateAxisLabels=function(a){var b=this,c=b.main.select("."+i.axisX+" ."+i.axisXLabel),d=b.main.select("."+i.axisY+" ."+i.axisYLabel),e=b.main.select("."+i.axisY2+" ."+i.axisY2Label);(a?c.transition():c).attr("x",b.xForXAxisLabel.bind(b)).attr("dx",b.dxForXAxisLabel.bind(b)).attr("dy",b.dyForXAxisLabel.bind(b)).text(b.textForXAxisLabel.bind(b)),(a?d.transition():d).attr("x",b.xForYAxisLabel.bind(b)).attr("dx",b.dxForYAxisLabel.bind(b)).attr("dy",b.dyForYAxisLabel.bind(b)).text(b.textForYAxisLabel.bind(b)),(a?e.transition():e).attr("x",b.xForY2AxisLabel.bind(b)).attr("dx",b.dxForY2AxisLabel.bind(b)).attr("dy",b.dyForY2AxisLabel.bind(b)).text(b.textForY2AxisLabel.bind(b))},f.getAxisPadding=function(a,b,c,d){var e="ratio"===a.unit?d:1;return j(a[b])?a[b]*e:c},f.generateTickValues=function(a,b,c){var d,e,f,g,h,i,j,l=a;if(b)if(d=k(b)?b():b,1===d)l=[a[0]];else if(2===d)l=[a[0],a[a.length-1]];else if(d>2){for(g=d-2,e=a[0],f=a[a.length-1],h=(f-e)/(g+1),l=[e],i=0;g>i;i++)j=+e+h*(i+1),l.push(c?new Date(j):j);l.push(f)}return c||(l=l.sort(function(a,b){return a-b})),l},f.generateAxisTransitions=function(a){var b=this,c=b.axes;return{axisX:a?c.x.transition().duration(a):c.x,axisY:a?c.y.transition().duration(a):c.y,axisY2:a?c.y2.transition().duration(a):c.y2,axisSubX:a?c.subx.transition().duration(a):c.subx}},f.redrawAxis=function(a,b){var c=this,d=c.config;c.axes.x.style("opacity",b?0:1),c.axes.y.style("opacity",b?0:1),c.axes.y2.style("opacity",b?0:1),c.axes.subx.style("opacity",b?0:1),a.axisX.call(c.xAxis),a.axisY.call(c.yAxis),a.axisY2.call(c.y2Axis),a.axisSubX.call(c.subXAxis),!d.axis_rotated&&d.axis_x_tick_rotate&&(c.rotateTickText(c.axes.x,a.axisX,d.axis_x_tick_rotate),c.rotateTickText(c.axes.subx,a.axisSubX,d.axis_x_tick_rotate))},f.getClipPath=function(b){var c=a.navigator.appVersion.toLowerCase().indexOf("msie 9.")>=0;return"url("+(c?"":document.URL.split("#")[0])+"#"+b+")"},f.appendClip=function(a,b){return a.append("clipPath").attr("id",b).append("rect")},f.getAxisClipX=function(a){var b=Math.max(30,this.margin.left);return a?-(1+b):-(b-1)},f.getAxisClipY=function(a){return a?-20:-this.margin.top},f.getXAxisClipX=function(){var a=this;return a.getAxisClipX(!a.config.axis_rotated)},f.getXAxisClipY=function(){var a=this;return a.getAxisClipY(!a.config.axis_rotated)},f.getYAxisClipX=function(){var a=this;return a.config.axis_y_inner?-1:a.getAxisClipX(a.config.axis_rotated)},f.getYAxisClipY=function(){var a=this;return a.getAxisClipY(a.config.axis_rotated)},f.getAxisClipWidth=function(a){var b=this,c=Math.max(30,b.margin.left),d=Math.max(30,b.margin.right);return a?b.width+2+c+d:b.margin.left+20},f.getAxisClipHeight=function(a){return(a?this.margin.bottom:this.margin.top+this.height)+8},f.getXAxisClipWidth=function(){var a=this;return a.getAxisClipWidth(!a.config.axis_rotated)},f.getXAxisClipHeight=function(){var a=this;return a.getAxisClipHeight(!a.config.axis_rotated)},f.getYAxisClipWidth=function(){var a=this;return a.getAxisClipWidth(a.config.axis_rotated)+(a.config.axis_y_inner?20:0)},f.getYAxisClipHeight=function(){var a=this;return a.getAxisClipHeight(a.config.axis_rotated)},f.initPie=function(){var a=this,b=a.d3,c=a.config;a.pie=b.layout.pie().value(function(a){return a.values.reduce(function(a,b){return a+b.value},0)}),c.data_order||a.pie.sort(null)},f.updateRadius=function(){var a=this,b=a.config,c=b.gauge_width||b.donut_width;a.radiusExpanded=Math.min(a.arcWidth,a.arcHeight)/2,a.radius=.95*a.radiusExpanded,a.innerRadiusRatio=c?(a.radius-c)/a.radius:.6,a.innerRadius=a.hasType("donut")||a.hasType("gauge")?a.radius*a.innerRadiusRatio:0},f.updateArc=function(){var a=this;a.svgArc=a.getSvgArc(),a.svgArcExpanded=a.getSvgArcExpanded(),a.svgArcExpandedSub=a.getSvgArcExpanded(.98)},f.updateAngle=function(a){var b,c,d=this,e=d.config,f=!1,g=0,h=e.gauge_min,i=e.gauge_max;return d.pie(d.filterTargetsToShow(d.data.targets)).forEach(function(b){f||b.data.id!==a.data.id||(f=!0,a=b,a.index=g),g++}),isNaN(a.endAngle)&&(a.endAngle=a.startAngle),d.isGaugeType(a.data)&&(b=Math.PI/(i-h),c=a.value<h?0:a.value<i?a.value-h:i-h,a.startAngle=-1*(Math.PI/2),a.endAngle=a.startAngle+b*c),f?a:null},f.getSvgArc=function(){var a=this,b=a.d3.svg.arc().outerRadius(a.radius).innerRadius(a.innerRadius),c=function(c,d){var e;return d?b(c):(e=a.updateAngle(c),e?b(e):"M 0 0")};return c.centroid=b.centroid,c},f.getSvgArcExpanded=function(a){var b=this,c=b.d3.svg.arc().outerRadius(b.radiusExpanded*(a?a:1)).innerRadius(b.innerRadius);return function(a){var d=b.updateAngle(a);return d?c(d):"M 0 0"}},f.getArc=function(a,b,c){return c||this.isArcType(a.data)?this.svgArc(a,b):"M 0 0"},f.transformForArcLabel=function(a){var b,c,d,e,f,g=this,h=g.updateAngle(a),i="";return h&&!g.hasType("gauge")&&(b=this.svgArc.centroid(h),c=isNaN(b[0])?0:b[0],d=isNaN(b[1])?0:b[1],e=Math.sqrt(c*c+d*d),f=g.radius&&e?(36/g.radius>.375?1.175-36/g.radius:.8)*g.radius/e:0,i="translate("+c*f+","+d*f+")"),i},f.getArcRatio=function(a){var b=this,c=b.hasType("gauge")?Math.PI:2*Math.PI;return a?(a.endAngle-a.startAngle)/c:null},f.convertToArcData=function(a){return this.addName({id:a.data.id,value:a.value,ratio:this.getArcRatio(a),index:a.index})},f.textForArcLabel=function(a){var b,c,d,e,f,g=this;return g.shouldShowArcLabel()?(b=g.updateAngle(a),c=b?b.value:null,d=g.getArcRatio(b),e=a.data.id,g.hasType("gauge")||g.meetsArcLabelThreshold(d)?(f=g.getArcLabelFormat(),f?f(c,d,e):g.defaultArcValueFormat(c,d)):""):""},f.expandArc=function(b){var c,d=this;return d.transiting?void(c=a.setInterval(function(){d.transiting||(a.clearInterval(c),d.legend.selectAll(".c3-legend-item-focused").size()>0&&d.expandArc(b))},10)):(b=d.mapToTargetIds(b),void d.svg.selectAll(d.selectorTargets(b,"."+i.chartArc)).each(function(a){d.shouldExpand(a.data.id)&&d.d3.select(this).selectAll("path").transition().duration(50).attr("d",d.svgArcExpanded).transition().duration(100).attr("d",d.svgArcExpandedSub).each(function(a){d.isDonutType(a.data)})}))},f.unexpandArc=function(a){var b=this;b.transiting||(a=b.mapToTargetIds(a),b.svg.selectAll(b.selectorTargets(a,"."+i.chartArc)).selectAll("path").transition().duration(50).attr("d",b.svgArc),b.svg.selectAll("."+i.arc).style("opacity",1))},f.shouldExpand=function(a){var b=this,c=b.config;return b.isDonutType(a)&&c.donut_expand||b.isGaugeType(a)&&c.gauge_expand||b.isPieType(a)&&c.pie_expand},f.shouldShowArcLabel=function(){var a=this,b=a.config,c=!0;return a.hasType("donut")?c=b.donut_label_show:a.hasType("pie")&&(c=b.pie_label_show),c},f.meetsArcLabelThreshold=function(a){var b=this,c=b.config,d=b.hasType("donut")?c.donut_label_threshold:c.pie_label_threshold;return a>=d},f.getArcLabelFormat=function(){var a=this,b=a.config,c=b.pie_label_format;return a.hasType("gauge")?c=b.gauge_label_format:a.hasType("donut")&&(c=b.donut_label_format),c},f.getArcTitle=function(){var a=this;return a.hasType("donut")?a.config.donut_title:""},f.updateTargetsForArc=function(a){var b,c,d=this,e=d.main,f=d.classChartArc.bind(d),g=d.classArcs.bind(d),h=d.classFocus.bind(d);b=e.select("."+i.chartArcs).selectAll("."+i.chartArc).data(d.pie(a)).attr("class",function(a){return f(a)+h(a.data)
+}),c=b.enter().append("g").attr("class",f),c.append("g").attr("class",g),c.append("text").attr("dy",d.hasType("gauge")?"-.1em":".35em").style("opacity",0).style("text-anchor","middle").style("pointer-events","none")},f.initArc=function(){var a=this;a.arcs=a.main.select("."+i.chart).append("g").attr("class",i.chartArcs).attr("transform",a.getTranslate("arc")),a.arcs.append("text").attr("class",i.chartArcsTitle).style("text-anchor","middle").text(a.getArcTitle())},f.redrawArc=function(a,b,c){var d,e=this,f=e.d3,g=e.config,h=e.main;d=h.selectAll("."+i.arcs).selectAll("."+i.arc).data(e.arcData.bind(e)),d.enter().append("path").attr("class",e.classArc.bind(e)).style("fill",function(a){return e.color(a.data)}).style("cursor",function(a){return g.data_selection_isselectable(a)?"pointer":null}).style("opacity",0).each(function(a){e.isGaugeType(a.data)&&(a.startAngle=a.endAngle=-1*(Math.PI/2)),this._current=a}).on("mouseover",function(a){var b,c;e.transiting||(b=e.updateAngle(a),c=e.convertToArcData(b),e.expandArc(b.data.id),e.api.focus(b.data.id),e.toggleFocusLegend(b.data.id,!0),e.config.data_onmouseover(c,this))}).on("mousemove",function(a){var b=e.updateAngle(a),c=e.convertToArcData(b),d=[c];e.showTooltip(d,f.mouse(this))}).on("mouseout",function(a){var b,c;e.transiting||(b=e.updateAngle(a),c=e.convertToArcData(b),e.unexpandArc(b.data.id),e.api.revert(),e.revertLegend(),e.hideTooltip(),e.config.data_onmouseout(c,this))}).on("click",function(a,b){var c=e.updateAngle(a),d=e.convertToArcData(c);e.toggleShape&&e.toggleShape(this,d,b),e.config.data_onclick.call(e.api,d,this)}),d.attr("transform",function(a){return!e.isGaugeType(a.data)&&c?"scale(0)":""}).style("opacity",function(a){return a===this._current?0:1}).each(function(){e.transiting=!0}).transition().duration(a).attrTween("d",function(a){var b,c=e.updateAngle(a);return c?(isNaN(this._current.endAngle)&&(this._current.endAngle=this._current.startAngle),b=f.interpolate(this._current,c),this._current=b(0),function(c){var d=b(c);return d.data=a.data,e.getArc(d,!0)}):function(){return"M 0 0"}}).attr("transform",c?"scale(1)":"").style("fill",function(a){return e.levelColor?e.levelColor(a.data.values[0].value):e.color(a.data.id)}).style("opacity",1).call(e.endall,function(){e.transiting=!1}),d.exit().transition().duration(b).style("opacity",0).remove(),h.selectAll("."+i.chartArc).select("text").style("opacity",0).attr("class",function(a){return e.isGaugeType(a.data)?i.gaugeValue:""}).text(e.textForArcLabel.bind(e)).attr("transform",e.transformForArcLabel.bind(e)).style("font-size",function(a){return e.isGaugeType(a.data)?Math.round(e.radius/5)+"px":""}).transition().duration(a).style("opacity",function(a){return e.isTargetToShow(a.data.id)&&e.isArcType(a.data)?1:0}),h.select("."+i.chartArcsTitle).style("opacity",e.hasType("donut")||e.hasType("gauge")?1:0),e.hasType("gauge")&&(e.arcs.select("."+i.chartArcsBackground).attr("d",function(){var a={data:[{value:g.gauge_max}],startAngle:-1*(Math.PI/2),endAngle:Math.PI/2};return e.getArc(a,!0,!0)}),e.arcs.select("."+i.chartArcsGaugeUnit).attr("dy",".75em").text(g.gauge_label_show?g.gauge_units:""),e.arcs.select("."+i.chartArcsGaugeMin).attr("dx",-1*(e.innerRadius+(e.radius-e.innerRadius)/2)+"px").attr("dy","1.2em").text(g.gauge_label_show?g.gauge_min:""),e.arcs.select("."+i.chartArcsGaugeMax).attr("dx",e.innerRadius+(e.radius-e.innerRadius)/2+"px").attr("dy","1.2em").text(g.gauge_label_show?g.gauge_max:""))},f.initGauge=function(){var a=this.arcs;this.hasType("gauge")&&(a.append("path").attr("class",i.chartArcsBackground),a.append("text").attr("class",i.chartArcsGaugeUnit).style("text-anchor","middle").style("pointer-events","none"),a.append("text").attr("class",i.chartArcsGaugeMin).style("text-anchor","middle").style("pointer-events","none"),a.append("text").attr("class",i.chartArcsGaugeMax).style("text-anchor","middle").style("pointer-events","none"))},f.getGaugeLabelHeight=function(){return this.config.gauge_label_show?20:0},f.initRegion=function(){var a=this;a.region=a.main.append("g").attr("clip-path",a.clipPath).attr("class",i.regions)},f.redrawRegion=function(a){var b=this,c=b.config;b.region.style("visibility",b.hasArcType()?"hidden":"visible"),b.mainRegion=b.main.select("."+i.regions).selectAll("."+i.region).data(c.regions),b.mainRegion.enter().append("g").attr("class",b.classRegion.bind(b)).append("rect").style("fill-opacity",0),b.mainRegion.exit().transition().duration(a).style("opacity",0).remove()},f.addTransitionForRegion=function(a){var b=this,c=b.regionX.bind(b),d=b.regionY.bind(b),e=b.regionWidth.bind(b),f=b.regionHeight.bind(b);a.push(b.mainRegion.selectAll("rect").transition().attr("x",c).attr("y",d).attr("width",e).attr("height",f).style("fill-opacity",function(a){return j(a.opacity)?a.opacity:.1}))},f.regionX=function(a){var b,c=this,d=c.config,e="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated&&"start"in a?e(a.start):0:d.axis_rotated?0:"start"in a?c.x(c.isTimeSeries()?c.parseDate(a.start):a.start):0},f.regionY=function(a){var b,c=this,d=c.config,e="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated?0:"end"in a?e(a.end):0:d.axis_rotated&&"start"in a?c.x(c.isTimeSeries()?c.parseDate(a.start):a.start):0},f.regionWidth=function(a){var b,c=this,d=c.config,e=c.regionX(a),f="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated&&"end"in a?f(a.end):c.width:d.axis_rotated?c.width:"end"in a?c.x(c.isTimeSeries()?c.parseDate(a.end):a.end):c.width,e>b?0:b-e},f.regionHeight=function(a){var b,c=this,d=c.config,e=this.regionY(a),f="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated?c.height:"start"in a?f(a.start):c.height:d.axis_rotated&&"end"in a?c.x(c.isTimeSeries()?c.parseDate(a.end):a.end):c.height,e>b?0:b-e},f.isRegionOnX=function(a){return!a.axis||"x"===a.axis},f.drag=function(a){var b,c,d,e,f,g,h,j,k=this,l=k.config,m=k.main,n=k.d3;k.hasArcType()||l.data_selection_enabled&&(!l.zoom_enabled||k.zoom.altDomain)&&l.data_selection_multiple&&(b=k.dragStart[0],c=k.dragStart[1],d=a[0],e=a[1],f=Math.min(b,d),g=Math.max(b,d),h=l.data_selection_grouped?k.margin.top:Math.min(c,e),j=l.data_selection_grouped?k.height:Math.max(c,e),m.select("."+i.dragarea).attr("x",f).attr("y",h).attr("width",g-f).attr("height",j-h),m.selectAll("."+i.shapes).selectAll("."+i.shape).filter(function(a){return l.data_selection_isselectable(a)}).each(function(a,b){var c,d,e,l,m,o,p=n.select(this),q=p.classed(i.SELECTED),r=p.classed(i.INCLUDED),s=!1;if(p.classed(i.circle))c=1*p.attr("cx"),d=1*p.attr("cy"),m=k.togglePoint,s=c>f&&g>c&&d>h&&j>d;else{if(!p.classed(i.bar))return;o=v(this),c=o.x,d=o.y,e=o.width,l=o.height,m=k.togglePath,s=!(c>g||f>c+e||d>j||h>d+l)}s^r&&(p.classed(i.INCLUDED,!r),p.classed(i.SELECTED,!q),m.call(k,!q,p,a,b))}))},f.dragstart=function(a){var b=this,c=b.config;b.hasArcType()||c.data_selection_enabled&&(b.dragStart=a,b.main.select("."+i.chart).append("rect").attr("class",i.dragarea).style("opacity",.1),b.dragging=!0,b.config.data_ondragstart.call(b.api))},f.dragend=function(){var a=this,b=a.config;a.hasArcType()||b.data_selection_enabled&&(a.main.select("."+i.dragarea).transition().duration(100).style("opacity",0).remove(),a.main.selectAll("."+i.shape).classed(i.INCLUDED,!1),a.dragging=!1,a.config.data_ondragend.call(a.api))},f.selectPoint=function(a,b,c){var d=this,e=d.config,f=(e.axis_rotated?d.circleY:d.circleX).bind(d),g=(e.axis_rotated?d.circleX:d.circleY).bind(d),h=d.pointSelectR.bind(d);e.data_onselected.call(d.api,b,a.node()),d.main.select("."+i.selectedCircles+d.getTargetSelectorSuffix(b.id)).selectAll("."+i.selectedCircle+"-"+c).data([b]).enter().append("circle").attr("class",function(){return d.generateClass(i.selectedCircle,c)}).attr("cx",f).attr("cy",g).attr("stroke",function(){return d.color(b)}).attr("r",function(a){return 1.4*d.pointSelectR(a)}).transition().duration(100).attr("r",h)},f.unselectPoint=function(a,b,c){var d=this;d.config.data_onunselected(b,a.node()),d.main.select("."+i.selectedCircles+d.getTargetSelectorSuffix(b.id)).selectAll("."+i.selectedCircle+"-"+c).transition().duration(100).attr("r",0).remove()},f.togglePoint=function(a,b,c,d){a?this.selectPoint(b,c,d):this.unselectPoint(b,c,d)},f.selectPath=function(a,b){var c=this;c.config.data_onselected.call(c,b,a.node()),a.transition().duration(100).style("fill",function(){return c.d3.rgb(c.color(b)).brighter(.75)})},f.unselectPath=function(a,b){var c=this;c.config.data_onunselected.call(c,b,a.node()),a.transition().duration(100).style("fill",function(){return c.color(b)})},f.togglePath=function(a,b,c,d){a?this.selectPath(b,c,d):this.unselectPath(b,c,d)},f.getToggle=function(a,b){var c,d=this;return"circle"===a.nodeName?c=d.isStepType(b)?function(){}:d.togglePoint:"path"===a.nodeName&&(c=d.togglePath),c},f.toggleShape=function(a,b,c){var d=this,e=d.d3,f=d.config,g=e.select(a),h=g.classed(i.SELECTED),j=d.getToggle(a,b).bind(d);f.data_selection_enabled&&f.data_selection_isselectable(b)&&(f.data_selection_multiple||d.main.selectAll("."+i.shapes+(f.data_selection_grouped?d.getTargetSelectorSuffix(b.id):"")).selectAll("."+i.shape).each(function(a,b){var c=e.select(this);c.classed(i.SELECTED)&&j(!1,c.classed(i.SELECTED,!1),a,b)}),g.classed(i.SELECTED,!h),j(!h,g,b,c))},f.initBrush=function(){var a=this,b=a.d3;a.brush=b.svg.brush().on("brush",function(){a.redrawForBrush()}),a.brush.update=function(){return a.context&&a.context.select("."+i.brush).call(this),this},a.brush.scale=function(b){return a.config.axis_rotated?this.y(b):this.x(b)}},f.initSubchart=function(){var a=this,b=a.config,c=a.context=a.svg.append("g").attr("transform",a.getTranslate("context"));b.subchart_show||c.style("visibility","hidden"),c.append("g").attr("clip-path",a.clipPathForSubchart).attr("class",i.chart),c.select("."+i.chart).append("g").attr("class",i.chartBars),c.select("."+i.chart).append("g").attr("class",i.chartLines),c.append("g").attr("clip-path",a.clipPath).attr("class",i.brush).call(a.brush).selectAll("rect").attr(b.axis_rotated?"width":"height",b.axis_rotated?a.width2:a.height2),a.axes.subx=c.append("g").attr("class",i.axisX).attr("transform",a.getTranslate("subx")).attr("clip-path",b.axis_rotated?"":a.clipPathForXAxis)},f.updateTargetsForSubchart=function(a){var b,c,d,e,f=this,g=f.context,h=f.config,j=f.classChartBar.bind(f),k=f.classBars.bind(f),l=f.classChartLine.bind(f),m=f.classLines.bind(f),n=f.classAreas.bind(f);h.subchart_show&&(e=g.select("."+i.chartBars).selectAll("."+i.chartBar).data(a).attr("class",j),d=e.enter().append("g").style("opacity",0).attr("class",j),d.append("g").attr("class",k),c=g.select("."+i.chartLines).selectAll("."+i.chartLine).data(a).attr("class",l),b=c.enter().append("g").style("opacity",0).attr("class",l),b.append("g").attr("class",m),b.append("g").attr("class",n))},f.redrawSubchart=function(a,b,c,d,e,f,g){var h,j,k,l,m,n,o=this,p=o.d3,q=o.context,r=o.config,s=o.barData.bind(o),t=o.lineData.bind(o),u=o.classBar.bind(o),v=o.classLine.bind(o),w=o.classArea.bind(o),x=o.initialOpacity.bind(o);r.subchart_show&&(p.event&&"zoom"===p.event.type&&o.brush.extent(o.x.orgDomain()).update(),a&&(o.brush.empty()||o.brush.extent(o.x.orgDomain()).update(),l=o.generateDrawArea(e,!0),m=o.generateDrawBar(f,!0),n=o.generateDrawLine(g,!0),k=q.selectAll("."+i.bars).selectAll("."+i.bar).data(s),k.enter().append("path").attr("class",u).style("stroke","none").style("fill",o.color),k.style("opacity",x).transition().duration(c).attr("d",m).style("opacity",1),k.exit().transition().duration(c).style("opacity",0).remove(),h=q.selectAll("."+i.lines).selectAll("."+i.line).data(t),h.enter().append("path").attr("class",v).style("stroke",o.color),h.style("opacity",x).transition().duration(c).attr("d",n).style("opacity",1),h.exit().transition().duration(c).style("opacity",0).remove(),j=q.selectAll("."+i.areas).selectAll("."+i.area).data(t),j.enter().append("path").attr("class",w).style("fill",o.color).style("opacity",function(){return o.orgAreaOpacity=+p.select(this).style("opacity"),0}),j.style("opacity",0).transition().duration(c).attr("d",l).style("fill",o.color).style("opacity",o.orgAreaOpacity),j.exit().transition().duration(d).style("opacity",0).remove()))},f.redrawForBrush=function(){var a=this,b=a.x;a.redraw({withTransition:!1,withY:a.config.zoom_rescale,withSubchart:!1,withUpdateXDomain:!0,withDimension:!1}),a.config.subchart_onbrush.call(a.api,b.orgDomain())},f.transformContext=function(a,b){var c,d=this;b&&b.axisSubX?c=b.axisSubX:(c=d.context.select("."+i.axisX),a&&(c=c.transition())),d.context.attr("transform",d.getTranslate("context")),c.attr("transform",d.getTranslate("subx"))},f.getDefaultExtent=function(){var a=this,b=a.config,c=k(b.axis_x_extent)?b.axis_x_extent(a.getXDomain(a.data.targets)):b.axis_x_extent;return a.isTimeSeries()&&(c=[a.parseDate(c[0]),a.parseDate(c[1])]),c},f.initZoom=function(){var a,b=this,c=b.d3,d=b.config;b.zoom=c.behavior.zoom().on("zoomstart",function(){a=c.event.sourceEvent,b.zoom.altDomain=c.event.sourceEvent.altKey?b.x.orgDomain():null,d.zoom_onzoomstart.call(b.api,c.event.sourceEvent)}).on("zoom",function(){b.redrawForZoom.call(b)}).on("zoomend",function(){var e=c.event.sourceEvent;e&&a.clientX===e.clientX&&a.clientY===e.clientY||(b.redrawEventRect(),b.updateZoom(),d.zoom_onzoomend.call(b.api,b.x.orgDomain()))}),b.zoom.scale=function(a){return d.axis_rotated?this.y(a):this.x(a)},b.zoom.orgScaleExtent=function(){var a=d.zoom_extent?d.zoom_extent:[1,10];return[a[0],Math.max(b.getMaxDataCount()/a[1],a[1])]},b.zoom.updateScaleExtent=function(){var a=q(b.x.orgDomain())/q(b.orgXDomain),c=this.orgScaleExtent();return this.scaleExtent([c[0]*a,c[1]*a]),this}},f.updateZoom=function(){var a=this,b=a.config.zoom_enabled?a.zoom:function(){};a.main.select("."+i.zoomRect).call(b).on("dblclick.zoom",null),a.main.selectAll("."+i.eventRect).call(b).on("dblclick.zoom",null)},f.redrawForZoom=function(){var a=this,b=a.d3,c=a.config,d=a.zoom,e=a.x;if(c.zoom_enabled&&0!==a.filterTargetsToShow(a.data.targets).length){if("mousemove"===b.event.sourceEvent.type&&d.altDomain)return e.domain(d.altDomain),void d.scale(e).updateScaleExtent();a.isCategorized()&&e.orgDomain()[0]===a.orgXDomain[0]&&e.domain([a.orgXDomain[0]-1e-10,e.orgDomain()[1]]),a.redraw({withTransition:!1,withY:c.zoom_rescale,withSubchart:!1,withEventRect:!1,withDimension:!1}),"mousemove"===b.event.sourceEvent.type&&(a.cancelClick=!0),c.zoom_onzoom.call(a.api,e.orgDomain())}},f.generateColor=function(){var a=this,b=a.config,c=a.d3,d=b.data_colors,e=s(b.color_pattern)?b.color_pattern:c.scale.category10().range(),f=b.data_color,g=[];return function(a){var b,c=a.id||a;return d[c]instanceof Function?b=d[c](a):d[c]?b=d[c]:(g.indexOf(c)<0&&g.push(c),b=e[g.indexOf(c)%e.length],d[c]=b),f instanceof Function?f(b,a):b}},f.generateLevelColor=function(){var a=this,b=a.config,c=b.color_pattern,d=b.color_threshold,e="value"===d.unit,f=d.values&&d.values.length?d.values:[],g=d.max||100;return s(b.color_threshold)?function(a){var b,d,h=c[c.length-1];for(b=0;b<f.length;b++)if(d=e?a:100*a/g,d<f[b]){h=c[b];break}return h}:null},f.getYFormat=function(a){var b=this,c=a&&!b.hasType("gauge")?b.defaultArcValueFormat:b.yFormat,d=a&&!b.hasType("gauge")?b.defaultArcValueFormat:b.y2Format;return function(a,e,f){var g="y2"===b.getAxisId(f)?d:c;return g.call(b,a,e)}},f.yFormat=function(a){var b=this,c=b.config,d=c.axis_y_tick_format?c.axis_y_tick_format:b.defaultValueFormat;return d(a)},f.y2Format=function(a){var b=this,c=b.config,d=c.axis_y2_tick_format?c.axis_y2_tick_format:b.defaultValueFormat;return d(a)},f.defaultValueFormat=function(a){return j(a)?+a:""},f.defaultArcValueFormat=function(a,b){return(100*b).toFixed(1)+"%"},f.formatByAxisId=function(a){var b=this,c=b.config.data_labels,d=function(a){return j(a)?+a:""};return"function"==typeof c.format?d=c.format:"object"==typeof c.format&&c.format[a]&&(d=c.format[a]),d},f.hasCaches=function(a){for(var b=0;b<a.length;b++)if(!(a[b]in this.cache))return!1;return!0},f.addCache=function(a,b){this.cache[a]=this.cloneTarget(b)},f.getCaches=function(a){var b,c=[];for(b=0;b<a.length;b++)a[b]in this.cache&&c.push(this.cloneTarget(this.cache[a[b]]));return c};var i=f.CLASS={target:"c3-target",chart:"c3-chart",chartLine:"c3-chart-line",chartLines:"c3-chart-lines",chartBar:"c3-chart-bar",chartBars:"c3-chart-bars",chartText:"c3-chart-text",chartTexts:"c3-chart-texts",chartArc:"c3-chart-arc",chartArcs:"c3-chart-arcs",chartArcsTitle:"c3-chart-arcs-title",chartArcsBackground:"c3-chart-arcs-background",chartArcsGaugeUnit:"c3-chart-arcs-gauge-unit",chartArcsGaugeMax:"c3-chart-arcs-gauge-max",chartArcsGaugeMin:"c3-chart-arcs-gauge-min",selectedCircle:"c3-selected-circle",selectedCircles:"c3-selected-circles",eventRect:"c3-event-rect",eventRects:"c3-event-rects",eventRectsSingle:"c3-event-rects-single",eventRectsMultiple:"c3-event-rects-multiple",zoomRect:"c3-zoom-rect",brush:"c3-brush",focused:"c3-focused",defocused:"c3-defocused",region:"c3-region",regions:"c3-regions",tooltipContainer:"c3-tooltip-container",tooltip:"c3-tooltip",tooltipName:"c3-tooltip-name",shape:"c3-shape",shapes:"c3-shapes",line:"c3-line",lines:"c3-lines",bar:"c3-bar",bars:"c3-bars",circle:"c3-circle",circles:"c3-circles",arc:"c3-arc",arcs:"c3-arcs",area:"c3-area",areas:"c3-areas",empty:"c3-empty",text:"c3-text",texts:"c3-texts",gaugeValue:"c3-gauge-value",grid:"c3-grid",gridLines:"c3-grid-lines",xgrid:"c3-xgrid",xgrids:"c3-xgrids",xgridLine:"c3-xgrid-line",xgridLines:"c3-xgrid-lines",xgridFocus:"c3-xgrid-focus",ygrid:"c3-ygrid",ygrids:"c3-ygrids",ygridLine:"c3-ygrid-line",ygridLines:"c3-ygrid-lines",axis:"c3-axis",axisX:"c3-axis-x",axisXLabel:"c3-axis-x-label",axisY:"c3-axis-y",axisYLabel:"c3-axis-y-label",axisY2:"c3-axis-y2",axisY2Label:"c3-axis-y2-label",legendBackground:"c3-legend-background",legendItem:"c3-legend-item",legendItemEvent:"c3-legend-item-event",legendItemTile:"c3-legend-item-tile",legendItemHidden:"c3-legend-item-hidden",legendItemFocused:"c3-legend-item-focused",dragarea:"c3-dragarea",EXPANDED:"_expanded_",SELECTED:"_selected_",INCLUDED:"_included_"};f.generateClass=function(a,b){return" "+a+" "+a+this.getTargetSelectorSuffix(b)},f.classText=function(a){return this.generateClass(i.text,a.index)},f.classTexts=function(a){return this.generateClass(i.texts,a.id)},f.classShape=function(a){return this.generateClass(i.shape,a.index)},f.classShapes=function(a){return this.generateClass(i.shapes,a.id)},f.classLine=function(a){return this.classShape(a)+this.generateClass(i.line,a.id)},f.classLines=function(a){return this.classShapes(a)+this.generateClass(i.lines,a.id)},f.classCircle=function(a){return this.classShape(a)+this.generateClass(i.circle,a.index)},f.classCircles=function(a){return this.classShapes(a)+this.generateClass(i.circles,a.id)},f.classBar=function(a){return this.classShape(a)+this.generateClass(i.bar,a.index)},f.classBars=function(a){return this.classShapes(a)+this.generateClass(i.bars,a.id)},f.classArc=function(a){return this.classShape(a.data)+this.generateClass(i.arc,a.data.id)},f.classArcs=function(a){return this.classShapes(a.data)+this.generateClass(i.arcs,a.data.id)},f.classArea=function(a){return this.classShape(a)+this.generateClass(i.area,a.id)},f.classAreas=function(a){return this.classShapes(a)+this.generateClass(i.areas,a.id)},f.classRegion=function(a,b){return this.generateClass(i.region,b)+" "+("class"in a?a["class"]:"")},f.classEvent=function(a){return this.generateClass(i.eventRect,a.index)},f.classTarget=function(a){var b=this,c=b.config.data_classes[a],d="";return c&&(d=" "+i.target+"-"+c),b.generateClass(i.target,a)+d},f.classFocus=function(a){return this.classFocused(a)+this.classDefocused(a)},f.classFocused=function(a){return" "+(this.focusedTargetIds.indexOf(a.id)>=0?i.focused:"")},f.classDefocused=function(a){return" "+(this.defocusedTargetIds.indexOf(a.id)>=0?i.defocused:"")},f.classChartText=function(a){return i.chartText+this.classTarget(a.id)},f.classChartLine=function(a){return i.chartLine+this.classTarget(a.id)},f.classChartBar=function(a){return i.chartBar+this.classTarget(a.id)},f.classChartArc=function(a){return i.chartArc+this.classTarget(a.data.id)},f.getTargetSelectorSuffix=function(a){return a||0===a?("-"+a).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g,"-"):""},f.selectorTarget=function(a,b){return(b||"")+"."+i.target+this.getTargetSelectorSuffix(a)},f.selectorTargets=function(a,b){var c=this;return a=a||[],a.length?a.map(function(a){return c.selectorTarget(a,b)}):null},f.selectorLegend=function(a){return"."+i.legendItem+this.getTargetSelectorSuffix(a)},f.selectorLegends=function(a){var b=this;return a&&a.length?a.map(function(a){return b.selectorLegend(a)}):null};var j=f.isValue=function(a){return a||0===a},k=f.isFunction=function(a){return"function"==typeof a},l=f.isString=function(a){return"string"==typeof a},m=f.isUndefined=function(a){return"undefined"==typeof a},n=f.isDefined=function(a){return"undefined"!=typeof a},o=f.ceil10=function(a){return 10*Math.ceil(a/10)},p=f.asHalfPixel=function(a){return Math.ceil(a)+.5},q=f.diffDomain=function(a){return a[1]-a[0]},r=f.isEmpty=function(a){return!a||l(a)&&0===a.length||"object"==typeof a&&0===Object.keys(a).length},s=f.notEmpty=function(a){return Object.keys(a).length>0},t=f.getOption=function(a,b,c){return n(a[b])?a[b]:c},u=f.hasValue=function(a,b){var c=!1;return Object.keys(a).forEach(function(d){a[d]===b&&(c=!0)}),c},v=f.getPathBox=function(a){var b=a.getBoundingClientRect(),c=[a.pathSegList.getItem(0),a.pathSegList.getItem(1)],d=c[0].x,e=Math.min(c[0].y,c[1].y);return{x:d,y:e,width:b.width,height:b.height}};e.focus=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a.filter(c.isTargetToShow,c))),this.revert(),this.defocus(),b.classed(i.focused,!0).classed(i.defocused,!1),c.hasArcType()&&c.expandArc(a),c.toggleFocusLegend(a,!0),c.focusedTargetIds=a,c.defocusedTargetIds=c.defocusedTargetIds.filter(function(b){return a.indexOf(b)<0})},e.defocus=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a.filter(c.isTargetToShow,c))),this.revert(),b.classed(i.focused,!1).classed(i.defocused,!0),c.hasArcType()&&c.unexpandArc(a),c.toggleFocusLegend(a,!1),c.focusedTargetIds=c.focusedTargetIds.filter(function(b){return a.indexOf(b)<0}),c.defocusedTargetIds=a},e.revert=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a)),b.classed(i.focused,!1).classed(i.defocused,!1),c.hasArcType()&&c.unexpandArc(a),c.showLegend(a),c.focusedTargetIds=[],c.defocusedTargetIds=[]},e.show=function(a,b){var c,d=this.internal;a=d.mapToTargetIds(a),b=b||{},d.removeHiddenTargetIds(a),c=d.svg.selectAll(d.selectorTargets(a)),c.transition().style("opacity",1,"important").call(d.endall,function(){c.style("opacity",null).style("opacity",1)}),b.withLegend&&d.showLegend(a),d.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},e.hide=function(a,b){var c,d=this.internal;a=d.mapToTargetIds(a),b=b||{},d.addHiddenTargetIds(a),c=d.svg.selectAll(d.selectorTargets(a)),c.transition().style("opacity",0,"important").call(d.endall,function(){c.style("opacity",null).style("opacity",0)}),b.withLegend&&d.hideLegend(a),d.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},e.toggle=function(a){var b=this,c=this.internal;c.mapToTargetIds(a).forEach(function(a){c.isTargetToShow(a)?b.hide(a):b.show(a)})},e.zoom=function(a){var b=this.internal;return a&&(b.isTimeSeries()&&(a=a.map(function(a){return b.parseDate(a)})),b.brush.extent(a),b.redraw({withUpdateXDomain:!0,withY:b.config.zoom_rescale}),b.config.zoom_onzoom.call(this,b.x.orgDomain())),b.brush.extent()},e.zoom.enable=function(a){var b=this.internal;b.config.zoom_enabled=a,b.updateAndRedraw()},e.unzoom=function(){var a=this.internal;a.brush.clear().update(),a.redraw({withUpdateXDomain:!0})},e.load=function(a){var b=this.internal,c=b.config;return a.xs&&b.addXs(a.xs),"classes"in a&&Object.keys(a.classes).forEach(function(b){c.data_classes[b]=a.classes[b]}),"categories"in a&&b.isCategorized()&&(c.axis_x_categories=a.categories),"axes"in a&&Object.keys(a.axes).forEach(function(b){c.data_axes[b]=a.axes[b]}),"cacheIds"in a&&b.hasCaches(a.cacheIds)?void b.load(b.getCaches(a.cacheIds),a.done):void("unload"in a?b.unload(b.mapToTargetIds("boolean"==typeof a.unload&&a.unload?null:a.unload),function(){b.loadFromArgs(a)}):b.loadFromArgs(a))},e.unload=function(a){var b=this.internal;a=a||{},a instanceof Array?a={ids:a}:"string"==typeof a&&(a={ids:[a]}),b.unload(b.mapToTargetIds(a.ids),function(){b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),a.done&&a.done()})},e.flow=function(a){var b,c,d,e,f,g,h,i,k=this.internal,l=[],m=k.getMaxDataCount(),o=0,p=0;if(a.json)c=k.convertJsonToData(a.json,a.keys);else if(a.rows)c=k.convertRowsToData(a.rows);else{if(!a.columns)return;c=k.convertColumnsToData(a.columns)}b=k.convertDataToTargets(c,!0),k.data.targets.forEach(function(a){var c,d,e=!1;for(c=0;c<b.length;c++)if(a.id===b[c].id){for(e=!0,a.values[a.values.length-1]&&(p=a.values[a.values.length-1].index+1),o=b[c].values.length,d=0;o>d;d++)b[c].values[d].index=p+d,k.isTimeSeries()||(b[c].values[d].x=p+d);a.values=a.values.concat(b[c].values),b.splice(c,1);break}e||l.push(a.id)}),k.data.targets.forEach(function(a){var b,c;for(b=0;b<l.length;b++)if(a.id===l[b])for(p=a.values[a.values.length-1].index+1,c=0;o>c;c++)a.values.push({id:a.id,index:p+c,x:k.isTimeSeries()?k.getOtherTargetX(p+c):p+c,value:null})}),k.data.targets.length&&b.forEach(function(a){var b,c=[];for(b=k.data.targets[0].values[0].index;p>b;b++)c.push({id:a.id,index:b,x:k.isTimeSeries()?k.getOtherTargetX(b):b,value:null});a.values.forEach(function(a){a.index+=p,k.isTimeSeries()||(a.x+=p)}),a.values=c.concat(a.values)}),k.data.targets=k.data.targets.concat(b),d=k.getMaxDataCount(),f=k.data.targets[0],g=f.values[0],n(a.to)?(o=0,i=k.isTimeSeries()?k.parseDate(a.to):a.to,f.values.forEach(function(a){a.x<i&&o++})):n(a.length)&&(o=a.length),m?1===m&&k.isTimeSeries()&&(h=(f.values[f.values.length-1].x-g.x)/2,e=[new Date(+g.x-h),new Date(+g.x+h)],k.updateXDomain(null,!0,!0,!1,e)):(h=k.isTimeSeries()?f.values.length>1?f.values[f.values.length-1].x-g.x:g.x-k.getXDomain(k.data.targets)[0]:1,e=[g.x-h,g.x],k.updateXDomain(null,!0,!0,!1,e)),k.updateTargets(k.data.targets),k.redraw({flow:{index:g.index,length:o,duration:j(a.duration)?a.duration:k.config.transition_duration,done:a.done,orgDataCount:m},withLegend:!0,withTransition:m>1,withTrimXDomain:!1,withUpdateXAxis:!0})},f.generateFlow=function(a){var b=this,c=b.config,d=b.d3;return function(){var e,f,g,h=a.targets,j=a.flow,k=a.drawBar,l=a.drawLine,m=a.drawArea,n=a.cx,o=a.cy,p=a.xv,r=a.xForText,s=a.yForText,t=a.duration,u=1,v=j.index,w=j.length,x=b.getValueOnIndex(b.data.targets[0].values,v),y=b.getValueOnIndex(b.data.targets[0].values,v+w),z=b.x.domain(),A=j.duration||t,B=j.done||function(){},C=b.generateWait(),D=b.xgrid||d.selectAll([]),E=b.xgridLines||d.selectAll([]),F=b.mainRegion||d.selectAll([]),G=b.mainText||d.selectAll([]),H=b.mainBar||d.selectAll([]),I=b.mainLine||d.selectAll([]),J=b.mainArea||d.selectAll([]),K=b.mainCircle||d.selectAll([]);b.flowing=!0,b.data.targets.forEach(function(a){a.values.splice(0,w)}),g=b.updateXDomain(h,!0,!0),b.updateXGrid&&b.updateXGrid(!0),j.orgDataCount?e=1===j.orgDataCount||x.x===y.x?b.x(z[0])-b.x(g[0]):b.isTimeSeries()?b.x(z[0])-b.x(g[0]):b.x(x.x)-b.x(y.x):1!==b.data.targets[0].values.length?e=b.x(z[0])-b.x(g[0]):b.isTimeSeries()?(x=b.getValueOnIndex(b.data.targets[0].values,0),y=b.getValueOnIndex(b.data.targets[0].values,b.data.targets[0].values.length-1),e=b.x(x.x)-b.x(y.x)):e=q(g)/2,u=q(z)/q(g),f="translate("+e+",0) scale("+u+",1)",b.hideXGridFocus(),b.hideTooltip(),d.transition().ease("linear").duration(A).each(function(){C.add(b.axes.x.transition().call(b.xAxis)),C.add(H.transition().attr("transform",f)),C.add(I.transition().attr("transform",f)),C.add(J.transition().attr("transform",f)),C.add(K.transition().attr("transform",f)),C.add(G.transition().attr("transform",f)),C.add(F.filter(b.isRegionOnX).transition().attr("transform",f)),C.add(D.transition().attr("transform",f)),C.add(E.transition().attr("transform",f))}).call(C,function(){var a,d=[],e=[],f=[];if(w){for(a=0;w>a;a++)d.push("."+i.shape+"-"+(v+a)),e.push("."+i.text+"-"+(v+a)),f.push("."+i.eventRect+"-"+(v+a));b.svg.selectAll("."+i.shapes).selectAll(d).remove(),b.svg.selectAll("."+i.texts).selectAll(e).remove(),b.svg.selectAll("."+i.eventRects).selectAll(f).remove(),b.svg.select("."+i.xgrid).remove()}D.attr("transform",null).attr(b.xgridAttr),E.attr("transform",null),E.select("line").attr("x1",c.axis_rotated?0:p).attr("x2",c.axis_rotated?b.width:p),E.select("text").attr("x",c.axis_rotated?b.width:0).attr("y",p),H.attr("transform",null).attr("d",k),I.attr("transform",null).attr("d",l),J.attr("transform",null).attr("d",m),K.attr("transform",null).attr("cx",n).attr("cy",o),G.attr("transform",null).attr("x",r).attr("y",s).style("fill-opacity",b.opacityForText.bind(b)),F.attr("transform",null),F.select("rect").filter(b.isRegionOnX).attr("x",b.regionX.bind(b)).attr("width",b.regionWidth.bind(b)),c.interaction_enabled&&b.redrawEventRect(),B(),b.flowing=!1})}},e.selected=function(a){var b=this.internal,c=b.d3;return c.merge(b.main.selectAll("."+i.shapes+b.getTargetSelectorSuffix(a)).selectAll("."+i.shape).filter(function(){return c.select(this).classed(i.SELECTED)}).map(function(a){return a.map(function(a){var b=a.__data__;return b.data?b.data:b})}))},e.select=function(a,b,c){var d=this.internal,e=d.d3,f=d.config;f.data_selection_enabled&&d.main.selectAll("."+i.shapes).selectAll("."+i.shape).each(function(g,h){var j=e.select(this),k=g.data?g.data.id:g.id,l=d.getToggle(this,g).bind(d),m=f.data_selection_grouped||!a||a.indexOf(k)>=0,o=!b||b.indexOf(h)>=0,p=j.classed(i.SELECTED);j.classed(i.line)||j.classed(i.area)||(m&&o?f.data_selection_isselectable(g)&&!p&&l(!0,j.classed(i.SELECTED,!0),g,h):n(c)&&c&&p&&l(!1,j.classed(i.SELECTED,!1),g,h))})},e.unselect=function(a,b){var c=this.internal,d=c.d3,e=c.config;e.data_selection_enabled&&c.main.selectAll("."+i.shapes).selectAll("."+i.shape).each(function(f,g){var h=d.select(this),j=f.data?f.data.id:f.id,k=c.getToggle(this,f).bind(c),l=e.data_selection_grouped||!a||a.indexOf(j)>=0,m=!b||b.indexOf(g)>=0,n=h.classed(i.SELECTED);h.classed(i.line)||h.classed(i.area)||l&&m&&e.data_selection_isselectable(f)&&n&&k(!1,h.classed(i.SELECTED,!1),f,g)})},e.transform=function(a,b){var c=this.internal,d=["pie","donut"].indexOf(a)>=0?{withTransform:!0}:null;c.transformTo(b,a,d)},f.transformTo=function(a,b,c){var d=this,e=!d.hasArcType(),f=c||{withTransitionForAxis:e};f.withTransitionForTransform=!1,d.transiting=!1,d.setTargetType(a,b),d.updateAndRedraw(f)},e.groups=function(a){var b=this.internal,c=b.config;return m(a)?c.data_groups:(c.data_groups=a,b.redraw(),c.data_groups)},e.xgrids=function(a){var b=this.internal,c=b.config;return a?(c.grid_x_lines=a,b.redrawWithoutRescale(),c.grid_x_lines):c.grid_x_lines},e.xgrids.add=function(a){var b=this.internal;return this.xgrids(b.config.grid_x_lines.concat(a?a:[]))},e.xgrids.remove=function(a){var b=this.internal;b.removeGridLines(a,!0)},e.ygrids=function(a){var b=this.internal,c=b.config;return a?(c.grid_y_lines=a,b.redrawWithoutRescale(),c.grid_y_lines):c.grid_y_lines},e.ygrids.add=function(a){var b=this.internal;return this.ygrids(b.config.grid_y_lines.concat(a?a:[]))},e.ygrids.remove=function(a){var b=this.internal;b.removeGridLines(a,!1)},e.regions=function(a){var b=this.internal,c=b.config;return a?(c.regions=a,b.redrawWithoutRescale(),c.regions):c.regions},e.regions.add=function(a){var b=this.internal,c=b.config;return a?(c.regions=c.regions.concat(a),b.redrawWithoutRescale(),c.regions):c.regions},e.regions.remove=function(a){var b,c,d,e=this.internal,f=e.config;return a=a||{},b=e.getOption(a,"duration",f.transition_duration),c=e.getOption(a,"classes",[i.region]),d=e.main.select("."+i.regions).selectAll(c.map(function(a){return"."+a
+})),(b?d.transition().duration(b):d).style("opacity",0).remove(),f.regions=f.regions.filter(function(a){var b=!1;return a["class"]?(a["class"].split(" ").forEach(function(a){c.indexOf(a)>=0&&(b=!0)}),!b):!0}),f.regions},e.data=function(a){var b=this.internal.data.targets;return"undefined"==typeof a?b:b.filter(function(b){return[].concat(a).indexOf(b.id)>=0})},e.data.shown=function(a){return this.internal.filterTargetsToShow(this.data(a))},e.data.values=function(a){var b,c=null;return a&&(b=this.data(a),c=b[0]?b[0].values.map(function(a){return a.value}):null),c},e.data.names=function(a){return this.internal.clearLegendItemTextBoxCache(),this.internal.updateDataAttributes("names",a)},e.data.colors=function(a){return this.internal.updateDataAttributes("colors",a)},e.data.axes=function(a){return this.internal.updateDataAttributes("axes",a)},e.category=function(a,b){var c=this.internal,d=c.config;return arguments.length>1&&(d.axis_x_categories[a]=b,c.redraw()),d.axis_x_categories[a]},e.categories=function(a){var b=this.internal,c=b.config;return arguments.length?(c.axis_x_categories=a,b.redraw(),c.axis_x_categories):c.axis_x_categories},e.color=function(a){var b=this.internal;return b.color(a)},e.x=function(a){var b=this.internal;return arguments.length&&(b.updateTargetX(b.data.targets,a),b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),b.data.xs},e.xs=function(a){var b=this.internal;return arguments.length&&(b.updateTargetXs(b.data.targets,a),b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),b.data.xs},e.axis=function(){},e.axis.labels=function(a){var b=this.internal;arguments.length&&(Object.keys(a).forEach(function(c){b.setAxisLabelText(c,a[c])}),b.updateAxisLabels())},e.axis.max=function(a){var b=this.internal,c=b.config;return arguments.length?("object"==typeof a?(j(a.x)&&(c.axis_x_max=a.x),j(a.y)&&(c.axis_y_max=a.y),j(a.y2)&&(c.axis_y2_max=a.y2)):c.axis_y_max=c.axis_y2_max=a,void b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})):{x:c.axis_x_max,y:c.axis_y_max,y2:c.axis_y2_max}},e.axis.min=function(a){var b=this.internal,c=b.config;return arguments.length?("object"==typeof a?(j(a.x)&&(c.axis_x_min=a.x),j(a.y)&&(c.axis_y_min=a.y),j(a.y2)&&(c.axis_y2_min=a.y2)):c.axis_y_min=c.axis_y2_min=a,void b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})):{x:c.axis_x_min,y:c.axis_y_min,y2:c.axis_y2_min}},e.axis.range=function(a){return arguments.length?(n(a.max)&&this.axis.max(a.max),void(n(a.min)&&this.axis.min(a.min))):{max:this.axis.max(),min:this.axis.min()}},e.legend=function(){},e.legend.show=function(a){var b=this.internal;b.showLegend(b.mapToTargetIds(a)),b.updateAndRedraw({withLegend:!0})},e.legend.hide=function(a){var b=this.internal;b.hideLegend(b.mapToTargetIds(a)),b.updateAndRedraw({withLegend:!0})},e.resize=function(a){var b=this.internal,c=b.config;c.size_width=a?a.width:null,c.size_height=a?a.height:null,this.flush()},e.flush=function(){var a=this.internal;a.updateAndRedraw({withLegend:!0,withTransition:!1,withTransitionForTransform:!1})},e.destroy=function(){var b=this.internal;b.data.targets=void 0,b.data.xs={},b.selectChart.classed("c3",!1).html(""),a.clearInterval(b.intervalForObserveInserted),a.onresize=null},e.tooltip=function(){},e.tooltip.show=function(a){var b,c,d=this.internal;a.mouse&&(c=a.mouse),a.data?d.isMultipleX()?(c=[d.x(a.data.x),d.getYScale(a.data.id)(a.data.value)],b=null):b=j(a.data.index)?a.data.index:d.getIndexByX(a.data.x):"undefined"!=typeof a.x?b=d.getIndexByX(a.x):"undefined"!=typeof a.index&&(b=a.index),d.dispatchEvent("mouseover",b,c),d.dispatchEvent("mousemove",b,c)},e.tooltip.hide=function(){this.internal.dispatchEvent("mouseout",0)};var w;"function"==typeof define&&define.amd?define("c3",["d3"],g):"undefined"!=typeof exports&&"undefined"!=typeof module?module.exports=g:a.c3=g}(window);
\ No newline at end of file
diff --git a/component.json b/component.json
index abf09d2..e74a7ee 100644
--- a/component.json
+++ b/component.json
@@ -2,9 +2,11 @@
   "name": "c3",
   "repo": "masayuki0812/c3",
   "description": "A D3-based reusable chart library",
-  "version": "0.0.1",
+  "version": "0.4.6",
   "keywords": [],
-  "dependencies": {},
+  "dependencies": {
+    "mbostock/d3": "v3.4.4"
+  },
   "development": {},
   "license": "MIT",
   "main": "c3.js",
diff --git a/extensions/exporter/config.json b/extensions/exporter/config.json
new file mode 100644
index 0000000..e3f812a
--- /dev/null
+++ b/extensions/exporter/config.json
@@ -0,0 +1,11 @@
+{
+	"js": [
+		"../../bower_components/d3/d3.min.js",
+		"../../c3.min.js"
+	],
+	"css": [
+		"../../c3.css"
+	],
+
+	"template": "<html><head><meta charset=\"utf-8\"><style>{0}</style></head><body><div id=\"chart\"></div></body></html>"
+}
\ No newline at end of file
diff --git a/extensions/exporter/phantom-exporter.js b/extensions/exporter/phantom-exporter.js
new file mode 100644
index 0000000..92d849d
--- /dev/null
+++ b/extensions/exporter/phantom-exporter.js
@@ -0,0 +1,140 @@
+/**
+*  PNG\JPEG exporter for C3.js, version 0.2
+*  (c) 2014 Yuval Bar-On
+*
+* usage: path/to/phantomjs output options [WxH]
+*
+*/
+
+// useful python-styled string formatting, "hello {0}! Javascript is {1}".format("world", "awesome");
+if (!String.prototype.format) {
+  String.prototype.format = function() {
+    var args = arguments;
+    return this.replace(/{(\d+)}/g, function(match, number) { 
+      return typeof args[number] != 'undefined'
+        ? args[number]
+        : match
+      ;
+    });
+  };
+}
+
+// defaults
+var page   = require('webpage').create(),
+	fs 	   = require('fs'),
+	system = require('system'),
+	config = JSON.parse( fs.read('config.json') ),
+	output,	size;
+
+if (system.args.length < 3 ) {
+    console.log('Usage: phantasm.js filename html [WxH]');
+    phantom.exit(1);
+} else {
+	out  = system.args[1];
+	opts = JSON.parse( system.args[2] );
+
+	if (system.args[3]) {
+		var dimensions = system.args[3].split('x'),
+			width 	   = dimensions[0],
+			height 	   = dimensions[1];
+
+		function checkNum(check) {
+			check = parseInt(check);
+			if (!isNaN(check))
+				return check;
+			return false;
+		}
+
+		width  = checkNum(width);
+		height = checkNum(height);
+
+		if (width && height) {
+			page.viewportSize = {
+				height: height,
+				width: width
+			}
+		}
+
+		// fit chart size to img size, if undefined
+		if (!opts.size) {
+			opts.size = {
+				"height": height,
+				"width": width
+			};
+		}
+	} else {
+		// check if size is defined in chart, 
+		// else apply defaults
+		page.viewportSize = {
+			height: (opts.size && opts.size.height) ? opts.size.height : 320,
+			width:  (opts.size && opts.size.width ) ? opts.size.width  : 710,
+		}
+	}
+}
+
+page.onResourceRequested = function(requestData, request) {
+  console.log('::loading resource ', requestData['url']);
+};	
+
+// helpful debug functions
+page.onConsoleMessage = function(msg){
+    console.log(msg);
+};
+
+page.onError = function(msg, trace) {
+  var msgStack = ['ERROR: ' + msg];
+
+  if (trace && trace.length) {
+    msgStack.push('TRACE:');
+    trace.forEach(function(t) {
+      msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
+    });
+  }
+
+  console.error(msgStack.join('\n'));
+};
+
+// render page
+function injectVerify(script) {
+	var req = page.injectJs(script);
+	if (!req) { 
+		console.log( '\nError!\n' + script + ' not found!\n' );
+		phantom.exit(1); 
+	}
+}
+
+page.onLoadFinished = function() {
+	console.log('::rendering');
+
+	for (var j in config.js) {
+		injectVerify(config.js[j]);
+	}
+
+	page.evaluate(function(chartoptions) {
+		// phantomjs doesn't know how to handle .bind, so we override
+		Function.prototype.bind = Function.prototype.bind || function (thisp) {
+		  var fn = this;
+		  return function () {
+		    return fn.apply(thisp, arguments);
+		  };
+		};
+
+		// generate chart
+		c3.generate(chartoptions);
+
+	}, opts);
+
+// setting transition to 0 has proven not to work thus far, but 300ms isn't much
+// so this is acceptable for now
+	setTimeout(function() {
+		page.render(out);
+		phantom.exit();
+	}, 300);
+}
+
+//  apply css inline because that usually renders better
+var css = '';
+for (var i in config.css) {
+	css += fs.read(config.css[i]);
+}
+page.content = config.template.format(css);
\ No newline at end of file
diff --git a/extensions/exporter/test.png b/extensions/exporter/test.png
new file mode 100644
index 0000000..593b70b
Binary files /dev/null and b/extensions/exporter/test.png differ
diff --git a/extensions/js/c3ext.js b/extensions/js/c3ext.js
new file mode 100644
index 0000000..8ff301f
--- /dev/null
+++ b/extensions/js/c3ext.js
@@ -0,0 +1,380 @@
+var c3ext = {};
+c3ext.generate = function (options) {
+
+    if (options.zoom2 != null) {
+        zoom2_reducers = options.zoom2.reducers || {};
+        zoom2_enabled = options.zoom2.enabled;
+        _zoom2_factor = options.zoom2.factor || 1;
+        _zoom2_maxItems = options.zoom2.maxItems;
+    }
+
+    if (!zoom2_enabled) {
+        return c3.generate(options);
+    }
+
+
+    var originalData = Q.copy(options.data);
+    var zoom2_reducers;
+    var zoom2_enabled;
+    var _zoom2_maxItems;
+
+    if (_zoom2_maxItems == null) {
+        var el = d3.select(options.bindto)[0][0];
+        if (el != null) {
+            var availWidth = el.clientWidth;
+
+            var pointSize = 20;
+            _zoom2_maxItems = Math.ceil(availWidth / pointSize);
+        }
+        if (_zoom2_maxItems == null || _zoom2_maxItems < 10) {
+            _zoom2_maxItems = 10;
+        }
+    }
+
+    function onZoomChanged(e) {
+        refresh();
+    }
+
+    var zoom2 = c3ext.ZoomBehavior({ changed: onZoomChanged, bindto: options.bindto });
+
+    zoom2.enhance = function () {
+        _zoom2_maxItems *= 2;
+        var totalItems = zoom2.getZoom().totalItems;
+        if (_zoom2_maxItems > totalItems)
+            _zoom2_maxItems = totalItems;
+        refresh();
+    }
+    zoom2.dehance = function () {
+        _zoom2_maxItems = Math.ceil(_zoom2_maxItems / 2) + 1;
+        refresh();
+    }
+
+    zoom2.maxItems = function () { return _zoom2_maxItems; };
+    function zoomAndReduceData(list, zoomRange, func, maxItems) {
+        //var maxItems = 10;//Math.ceil(10 * zoomFactor);
+        var list2 = list.slice(zoomRange[0], zoomRange[1]);
+        var chunkSize = 1;
+        var list3 = list2;
+        if (list3.length > maxItems) {
+            var chunkSize = Math.ceil(list2.length / maxItems);
+            list3 = list3.splitIntoChunksOf(chunkSize).map(func);
+        }
+        //console.log("x" + getCurrentZoomLevel() + ", maxItems=" + maxItems + " chunkSize=" + chunkSize + " totalBefore=" + list2.length + ", totalAfter=" + list3.length);
+        return list3;
+    }
+
+    function first(t) { return t[0]; }
+
+    var getDataForZoom = function (data) {
+        if (data.columns == null || data.columns.length == 0)
+            return;
+
+        var zoomInfo = zoom2.getZoom();
+        if (zoomInfo.totalItems != data.columns[0].length - 1) {
+            zoom2.setOptions({ totalItems: data.columns[0].length - 1 });
+            zoomInfo = zoom2.getZoom();
+        }
+        data.columns = originalData.columns.map(function (column) {
+            var name = column[0];
+            var reducer = zoom2_reducers[name] || first; //by default take the first
+
+            var values = column.slice(1);
+            var newValues = zoomAndReduceData(values, zoomInfo.currentZoom, reducer, _zoom2_maxItems);
+            return [name].concat(newValues);
+        });
+        return data;
+    };
+
+    getDataForZoom(options.data);
+    var chart = c3.generate(options);
+    var _chart_load_org = chart.load.bind(chart);
+    chart.zoom2 = zoom2;
+    chart.load = function (data) {
+        if (data.unload) {
+            unload(data.unload);
+            delete data.unload;
+        }
+        Q.copy(data, originalData);
+        refresh();
+    }
+    chart.unload = function (names) {
+        unload(names);
+        refresh();
+    }
+
+    function unload(names) {
+        originalData.columns.removeAll(function (t) { names.contains(t); });
+    }
+
+
+    function refresh() {
+        var data = Q.copy(originalData)
+        getDataForZoom(data);
+        _chart_load_org(data);
+    };
+
+
+    return chart;
+}
+
+c3ext.ZoomBehavior = function (options) {
+    var zoom = { __type: "ZoomBehavior" };
+
+    var _zoom2_factor;
+    var _left;
+    var totalItems;
+    var currentZoom;
+    var bindto = options.bindto;
+    var _zoomChanged = options.changed || function () { };
+    var element;
+    var mousewheelTimer;
+    var deltaY = 0;
+    var leftRatio = 0;
+
+
+    zoom.setOptions = function (options) {
+        if (options == null)
+            options = {};
+        _zoom2_factor = options.factor || 1;
+        _left = 0;
+        totalItems = options.totalItems || 0;
+        currentZoom = [0, totalItems];
+        _zoomChanged = options.changed || _zoomChanged;
+    }
+
+    zoom.setOptions(options);
+
+
+    function verifyZoom(newZoom) {
+        //newZoom.sort();
+        if (newZoom[1] > totalItems) {
+            var diff = newZoom[1] - totalItems;
+            newZoom[0] -= diff;
+            newZoom[1] -= diff;
+        }
+        if (newZoom[0] < 0) {
+            var diff = newZoom[0] * -1;
+            newZoom[0] += diff;
+            newZoom[1] += diff;
+        }
+        if (newZoom[1] > totalItems)
+            newZoom[1] = totalItems;
+        if (newZoom[0] < 0)
+            newZoom[0] = 0;
+    }
+
+    function zoomAndPan(zoomFactor, left) {
+        var itemsToShow = Math.ceil(totalItems / zoomFactor);
+        var newZoom = [left, left + itemsToShow];
+        verifyZoom(newZoom);
+        currentZoom = newZoom;
+        onZoomChanged();
+    }
+
+    function onZoomChanged() {
+        if (_zoomChanged != null)
+            _zoomChanged(zoom.getZoom());
+    }
+    function applyZoomAndPan() {
+        zoomAndPan(_zoom2_factor, _left);
+    }
+    function getItemsToShow() {
+        var itemsToShow = Math.ceil(totalItems / _zoom2_factor);
+        return itemsToShow;
+    }
+
+
+    zoom.getZoom = function () {
+        return { totalItems: totalItems, currentZoom: currentZoom.slice() };
+    }
+
+    zoom.factor = function (factor, skipDraw) {
+        if (arguments.length == 0)
+            return _zoom2_factor;
+        _zoom2_factor = factor;
+        if (_zoom2_factor < 1)
+            _zoom2_factor = 1;
+        if (skipDraw)
+            return;
+        applyZoomAndPan();
+    }
+    zoom.left = function (left, skipDraw) {
+        if (arguments.length == 0)
+            return _left;
+        _left = left;
+        if (_left < 0)
+            _left = 0;
+        var pageSize = getItemsToShow();
+        //_left += pageSize;
+        if (_left + pageSize > totalItems)
+            _left = totalItems - pageSize;
+        console.log({ left: _left, pageSize: pageSize });
+        if (skipDraw)
+            return;
+        applyZoomAndPan();
+    }
+
+    zoom.zoomAndPanByRatio = function (zoomRatio, panRatio) {
+
+        var pageSize = getItemsToShow();
+        var leftOffset = Math.round(pageSize * panRatio);
+        var mouseLeft = _left + leftOffset;
+        zoom.factor(zoom.factor() * zoomRatio, true);
+
+        var finalLeft = mouseLeft;
+        if (zoomRatio != 1) {
+            var pageSize2 = getItemsToShow();
+            var leftOffset2 = Math.round(pageSize2 * panRatio);
+            finalLeft = mouseLeft - leftOffset2;
+        }
+        zoom.left(finalLeft, true);
+        applyZoomAndPan();
+    }
+
+    zoom.zoomIn = function () {
+        zoom.zoomAndPanByRatio(2, 0);
+    }
+
+    zoom.zoomOut = function () {
+        zoom.zoomAndPanByRatio(0.5, 0);
+    }
+
+    zoom.panLeft = function () {
+        zoom.zoomAndPanByRatio(1, -1);
+    }
+    zoom.panRight = function () {
+        zoom.zoomAndPanByRatio(1, 1);
+    }
+
+    zoom.reset = function () {
+        _left = 0;
+        _zoom2_factor = 1;
+        applyZoomAndPan();
+    }
+
+    function doZoom() {
+        if (deltaY != 0) {
+            var maxDelta = 10;
+            var multiply = (maxDelta + deltaY) / maxDelta;
+            //var factor = chart.zoom2.factor()*multiply;
+            //factor= Math.ceil(factor*100) / 100;
+            console.log({ deltaY: deltaY, multiply: multiply });
+            zoom.zoomAndPanByRatio(multiply, leftRatio);//0.5);//leftRatio);
+            deltaY = 0;
+        }
+    }
+
+    function element_mousewheel(e) {
+        deltaY += e.deltaY;
+        leftRatio = (e.offsetX - 70) / (e.currentTarget.offsetWidth - 70);
+        //console.log({ "e.offsetX": e.offsetX, "e.currentTarget.offsetWidth": e.currentTarget.offsetWidth, leftRatio: leftRatio });
+        mousewheelTimer.set(150);
+        e.preventDefault();
+    }
+
+    if (bindto != null) {
+        element = $(options.bindto);
+        if (element.mousewheel) {
+            mousewheelTimer = new Timer(doZoom);
+            element.mousewheel(element_mousewheel);
+        }
+    }
+
+    return zoom;
+
+}
+
+if (typeof (Q) == "undefined") {
+    var Q = function () {
+    };
+
+    Q.copy = function (src, target, options, depth) {
+        ///<summary>Copies an object into a target object, recursively cloning any object or array in the way, overwrite=true will overwrite a primitive field value even if exists</summary>
+        ///<param name="src" />
+        ///<param name="target" />
+        ///<param name="options" type="Object">{ overwrite:false }</param>
+        ///<returns type="Object">The copied object</returns>
+        if (depth == null)
+            depth = 0;
+        if (depth == 100) {
+            console.warn("Q.copy is in depth of 100 - possible circular reference")
+        }
+        options = options || { overwrite: false };
+        if (src == target || src == null)
+            return target;
+        if (typeof (src) != "object") {
+            if (options.overwrite || target == null)
+                return src;
+            return target;
+        }
+        if (typeof (src.clone) == "function") {
+            if (options.overwrite || target == null)
+                return src.clone();
+            return target;
+        }
+        if (target == null) {
+            if (src instanceof Array)
+                target = [];
+            else
+                target = {};
+        }
+
+        if (src instanceof Array) {
+            for (var i = 0; i < src.length; i++) {
+                var item = src[i];
+                var item2 = target[i];
+                item2 = Q.copy(item, item2, options, depth + 1);
+                target[i] = item2;
+            }
+            target.splice(src.length, target.length - src.length);
+            return target;
+        }
+        for (var p in src) {
+            var value = src[p];
+            var value2 = target[p];
+            value2 = Q.copy(value, value2, options, depth + 1);
+            target[p] = value2;
+        }
+        return target;
+    }
+}
+if (typeof (Timer) == "undefined") {
+    var Timer = function (action, ms) {
+        this.action = action;
+        if (ms != null)
+            this.set(ms);
+    }
+
+    Timer.prototype.set = function (ms) {
+        if (ms == null)
+            ms = this._ms;
+        else
+            this._ms = ms;
+        this.clear();
+        if (ms == null)
+            return;
+        this.timeout = window.setTimeout(this.onTick.bind(this), ms);
+    }
+
+    Timer.prototype.onTick = function () {
+        this.clear();
+        this.action();
+    }
+
+    Timer.prototype.clear = function (ms) {
+        if (this.timeout == null)
+            return;
+        window.clearTimeout(this.timeout);
+        this.timeout = null;
+    }
+}
+if (typeof(Array.prototype.splitIntoChunksOf)=="undefined") {
+    Array.prototype.splitIntoChunksOf = function (countInEachChunk) {
+        var chunks = Math.ceil(this.length / countInEachChunk);
+        var list = [];
+        for (var i = 0; i < this.length; i += countInEachChunk) {
+            list.push(this.slice(i, i + countInEachChunk));
+        }
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/htdocs/css/index.css b/htdocs/css/index.css
new file mode 100644
index 0000000..f38c901
--- /dev/null
+++ b/htdocs/css/index.css
@@ -0,0 +1,12 @@
+.row {
+  margin-left: 8px;
+}
+.row a {
+  display: block;
+  text-align: left;
+  font-size: 1.2em;
+  line-height: 1.8;
+}
+.row h3 {
+  color: #777;
+}
\ No newline at end of file
diff --git a/htdocs/data/c3_test.json b/htdocs/data/c3_test.json
new file mode 100644
index 0000000..7486b75
--- /dev/null
+++ b/htdocs/data/c3_test.json
@@ -0,0 +1,5 @@
+{
+  "data1": [120, 140, 170, 150, 180],
+  "data2": [80, 50, 100, 70, 120],
+  "data3": [200, 210, 250, 300, 280]
+}
diff --git a/htdocs/data/c3_test.tsv b/htdocs/data/c3_test.tsv
new file mode 100644
index 0000000..1fcab88
--- /dev/null
+++ b/htdocs/data/c3_test.tsv
@@ -0,0 +1,6 @@
+data1	data2	data3
+520	380	100
+540	350	110
+570	400	150
+550	370	200
+580	420	180
\ No newline at end of file
diff --git a/htdocs/data/c3_test_2.json b/htdocs/data/c3_test_2.json
new file mode 100644
index 0000000..ed18b2f
--- /dev/null
+++ b/htdocs/data/c3_test_2.json
@@ -0,0 +1,5 @@
+{
+  "data1": [20, 40, 70, 50, 80, 30],
+  "data2": [180, 150, 200, 170, 220, 400],
+  "data3": [1200, 1210, 1250, 1300, 1280, 1000]
+}
diff --git a/htdocs/data/c3_test_3.json b/htdocs/data/c3_test_3.json
new file mode 100644
index 0000000..c08c9c7
--- /dev/null
+++ b/htdocs/data/c3_test_3.json
@@ -0,0 +1,6 @@
+[
+  { "id": 1, "name": "abc", "data1": 1200, "data2": 500 },
+  { "id": 2, "name": "efg", "data1": 900,  "data2": 600 },
+  { "id": 3, "name": "pqr", "data1": 1150, "data2": 300 },
+  { "id": 4, "name": "xyz", "data1": 1020, "data2": 900 }
+]
diff --git a/htdocs/index.html b/htdocs/index.html
index 9c9f277..7f2c06a 100644
--- a/htdocs/index.html
+++ b/htdocs/index.html
@@ -1,124 +1,481 @@
 <html>
   <head>
     <link href="./css/bootstrap.min.css" rel="stylesheet">
+    <link href="./css/index.css" rel="stylesheet">
   </head>
   <body>
     <div class="container">
       <div class="section">
-        <a href="#basic" name="basic"><h2># <span>Basic</span></h2></a>
+        <h2># <span>Chart Type</span></h2>
         <div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Simple Line Chart</h3>
-              <p>Simple line chart for getting started.</p>
-              <p><a class="btn btn-default" href="./samples/simple.html" role="button">View details &raquo;</a></p>
+              <h3>Line Chart</h3>
+              <a href="./samples/simple.html">
+                Line chart with ordinary data
+              </a>
+              <a href="./samples/chart_spline.html">
+                Spline chart with ordinary data
+              </a>
+              <a href="./samples/chart_step.html">
+                Step chart with ordinary data
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Multiple Line Chart</h3>
-              <p>Multiple line chart with multiple data.</p>
-              <p><a class="btn btn-default" href="./samples/simple_multiple.html" role="button">View details &raquo;</a></p>
+              <h3>Area Chart</h3>
+              <a href="./samples/chart_area.html">
+                Area chart with ordinary data
+              </a>
+              <a href="./samples/chart_area_spline.html">
+                Area-spline chart with ordinary data
+              </a>
+              <a href="./samples/chart_area_step.html">
+                Area-step chart with ordinary data
+              </a>
+              <a href="./samples/chart_area_stacked.html">
+                Stacked Area chart with ordinary data
+              </a>
+              <a href="./samples/chart_area_spline_stacked.html">
+                Stacked Area-spline chart with ordinary data
+              </a>
+              <a href="./samples/chart_area_step_stacked.html">
+                Stacked Area-step chart with ordinary data
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Bar Chart</h3>
+              <a href="./samples/chart_bar.html">
+                Bar chart with ordinary data
+              </a>
+              <a href="./samples/chart_bar_stacked.html">
+                Stacked Bar chart with ordinary data
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Pie Chart</h3>
+              <a href="./samples/chart_pie.html">
+                Pie chart with ordinary data
+              </a>
+              <a href="./samples/chart_pie_sort.html">
+                Pie chart with/without sort
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Donut Chart</h3>
+              <a href="./samples/chart_donut.html">
+                Donut chart with ordinary data
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Gauge Chart</h3>
+              <a href="./samples/chart_gauge.html">
+                Gauge chart with ordinary data
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Scatter Chart</h3>
+              <a href="./samples/chart_scatter.html">
+                Scatter chart with ordinary data
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Timeseries Chart</h3>
-              <p>Simple line chart with timeseries data.</p>
-              <p><a class="btn btn-default" href="./samples/timeseries.html" role="button">View details &raquo;</a></p>
+              <h3>Combination Chart</h3>
+              <a href="./samples/chart_combination.html">
+                Combination chart with ordinary data
+              </a>
             </div>
           </div>
         </div>
       </div>
+
       <div class="section">
-        <a href="#axes" name="axes"><h2># <span>Axes</span></h2></a>
+        <h2># <span>Axes</span></h2>
         <div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Categorized Axis</h3>
-              <p>Axis with ticks categorizing each data.</p>
-              <p><a class="btn btn-default" href="./samples/categorized.html" role="button">View details &raquo;</a></p>
+              <h3>Timeseries Axis</h3>
+              <a href="./samples/timeseries.html">
+                Line chart with timeseries data
+              </a>
+              <a href="./samples/timeseries_descendent.html">
+                Line chart with descendent timeseries data
+              </a>
+              <a href="./samples/timeseries_raw.html">
+                Line chart with timeseries data as Number
+              </a>
+              <a href="./samples/timeseries_date.html">
+                Line chart with timeseries data as Date object
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Category Axis</h3>
+              <a href="./samples/categorized.html">
+                Chart with category axis
+              </a>
+              <a href="./samples/custom_x_categorized.html">
+                Chart with category data on category axis
+              </a>
             </div>
             <div class="col-md-4">
               <h3>Additional Axis</h3>
-              <p>Additional y axis can be added.</p>
-              <p><a class="btn btn-default" href="./samples/axes_y2.html" role="button">View details &raquo;</a></p>
+              <a href="./samples/axes_y2.html">
+                Add y2 axis
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Axis Range</h3>
+              <a href="./samples/axes_range.html">
+                Set range of axis
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Axis Padding</h3>
+              <a href="./samples/axes_padding.html">
+                Set padding of axis
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>X Axis Tick</h3>
+              <a href="./samples/axes_x_tick_values.html">
+                Set values for x axis
+              </a>
+              <a href="./samples/axes_x_tick_culling.html">
+                Set culling for x axis
+              </a>
+              <a href="./samples/axes_x_tick_fit.html">
+                Set fitting for x axis
+              </a>
+              <a href="./samples/axes_x_tick_rotate.html">
+                Set rotation for x axis
+              </a>
+              <a href="./samples/axes_x_range_timeseries.html">
+                Set range in timeseries for x axis
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Default Y Domain</h3>
+              <a href="./samples/axes_y_default.html">
+                Set default y domain
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Y Domain</h3>
+              <a href="./samples/domain_y.html">
+                Update y domain automatically
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Default X Extent</h3>
+              <a href="./samples/axes_x_extent.html">
+                Set default x extent
+              </a>
             </div>
           </div>
         </div>
       </div>
+
       <div class="section">
-        <a href="#data" name="data"><h2># <span>Data</span></h2></a>
+        <h2># <span>Data</span></h2>
         <div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Column Oriented Data</h3>
-              <p>Column-oriented data can be used as input.</p>
-              <p><a class="btn btn-default" href="./samples/data_columned.html" role="button">View details &raquo;</a></p>
+              <h3>Input Data</h3>
+              <a href="./samples/data_columned.html">
+                Columned data
+              </a>
+              <a href="./samples/data_rowed.html">
+                Rowed data
+              </a>
+              <a href="./samples/data_json.html">
+                JSON data
+              </a>
+              <a href="./samples/data_url.html">
+                Data from URL
+              </a>
+              <a href="./samples/data_hide.html">
+                Hide data when init
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Row Oriented Data</h3>
-              <p>Row-oriented data can be used as input.</p>
-              <p><a class="btn btn-default" href="./samples/data_rowed.html" role="button">View details &raquo;</a></p>
+              <h3>Load Data</h3>
+              <a href="./samples/data_load.html">
+                Load ordinary data
+              </a>
+              <a href="./samples/data_load_timeseries.html">
+                Load timeseries data
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Data from URL</h3>
-              <p>Data from URL can be used as input.</p>
-              <p><a class="btn btn-default" href="./samples/data_url.html" role="button">View details &raquo;</a></p>
+              <h3>Custom X</h3>
+              <a href="./samples/custom_x_scale.html">
+                Custom x for all data
+              </a>
+              <a href="./samples/custom_xs_scale.html">
+                Custom x for each data
+              </a>
             </div>
           </div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Load Data</h3>
-              <p>Load data dynamically.</p>
-              <p><a class="btn btn-default" href="./samples/data_load.html" role="button">View details &raquo;</a></p>
+              <h3>Data Label</h3>
+              <a href="./samples/data_label.html">
+                Show label on data
+              </a>
+              <a href="./samples/data_label_format.html">
+                Show label on data with format
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Data Region</h3>
+              <a href="./samples/data_region.html">
+                Set region of data
+              </a>
+              <a href="./samples/data_region_timeseries.html">
+                Set region of timeseries data
+              </a>
             </div>
           </div>
         </div>
       </div>
+
       <div class="section">
-        <a href="#chart_type" name="chart_type"><h2># <span>Chart Type</span></h2></a>
+        <h2># <span>Components</span></h2>
         <div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Bar Chart</h3>
-              <p>Display as Bar Chart</p>
-              <p><a class="btn btn-default" href="./samples/chart_bar.html" role="button">View details &raquo;</a></p>
+              <h3>Grid</h3>
+              <a href="./samples/grids.html">
+                 Show x/y grids
+              </a>
+              <a href="./samples/grids_timeseries.html">
+                 Show x/y grids with timeseries
+              </a>
+              <a href="./samples/grid_x_lines.html">
+                 Show optional x grids
+              </a>
+              <a href="./samples/grid_x_lines_timeseries.html">
+                 Show optional x grids with timeseries
+              </a>
+              <a href="./samples/grid_focus.html">
+                 Hide focus grid
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Stacked Bar Chart</h3>
-              <p>Display as Stacked Bar Chart</p>
-              <p><a class="btn btn-default" href="./samples/chart_bar_stacked.html" role="button">View details &raquo;</a></p>
+              <h3>Region</h3>
+              <a href="./samples/regions.html">
+                 Show regions
+              </a>
+              <a href="./samples/regions_timeseries.html">
+                 Show regions with timeseries
+              </a>
             </div>
             <div class="col-md-4">
-              <h3>Spline Chart</h3>
-              <p>Display as Spline Chart</p>
-              <p><a class="btn btn-default" href="./samples/chart_spline.html" role="button">View details &raquo;</a></p>
+              <h3>Legend</h3>
+              <a href="./samples/legend.html">
+                 Show legend
+              </a>
             </div>
           </div>
           <div class="row">
             <div class="col-md-4">
-              <h3>Area Chart</h3>
-              <p>Display as Filled Area Chart</p>
-              <p><a class="btn btn-default" href="./samples/chart_area.html" role="button">View details &raquo;</a></p>
+              <h3>Tooltip</h3>
+              <a href="./samples/tooltip_show.html">
+                Show tooltip
+              </a>
+              <a href="./samples/tooltip_grouped.html">
+                Show tooltip as each data
+              </a>
             </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="section">
+        <h2># <span>Chart Option</span></h2>
+        <div>
+          <div class="row">
             <div class="col-md-4">
-              <h3>Combination Chart</h3>
-              <p>Display as Bar Chart</p>
-              <p><a class="btn btn-default" href="./samples/chart_combination.html" role="button">View details &raquo;</a></p>
+              <h3>Bind</h3>
+              <a href="./samples/bindto.html">
+                Specify the element binded
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Padding</h3>
+              <a href="./samples/padding.html">
+                Change padding of chart
+              </a>
+              <a href="./samples/padding_update.html">
+                Auto padding when chart updated
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Empty Data</h3>
+              <a href="./samples/emptydata.html">
+                Show text when empty data
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Point</h3>
+              <a href="./samples/point_r.html">
+                Change radius of data point
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Bar</h3>
+              <a href="./samples/bar_zerobased.html">
+                Disable zero-based y domain
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Area</h3>
+              <a href="./samples/area_zerobased.html">
+                Disable zero-based y domain
+              </a>
             </div>
           </div>
         </div>
       </div>
+
       <div class="section">
-        <a href="#interaction" name="interaction"><h2># <span>Interaction</span></h2></a>
+        <h2># <span>Interaction</span></h2>
         <div>
           <div class="row">
             <div class="col-md-4">
               <h3>Zoom</h3>
-              <p>Zoom by mouse wheel event and slide by drag.</p>
-              <p><a class="btn btn-default" href="./samples/interaction_zoom.html" role="button">View details &raquo;</a></p>
+              <a href="./samples/zoom.html">
+                Enable zoom
+              </a>
+              <a href="./samples/zoom.html">
+                Zoom on category axis
+              </a>
+              <a href="./samples/zoom_reduction.html">
+                Zoom with reduction
+              </a>
+              <a href="./samples/zoom_onzoom.html">
+                Callback on zoom
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Subchart</h3>
+              <a href="./samples/subchart.html">
+                Show subchart
+              </a>
+              <a href="./samples/subchart_onbrush.html">
+                Callback on brush
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Selection</h3>
+              <a href="./samples/selection.html">
+                Select data
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Disable Interaction</h3>
+              <a href="./samples/interaction_enabled.html">
+                Disable interaction
+              </a>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="section">
+        <h2># <span>API</span></h2>
+        <div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Flow</h3>
+              <a href="./samples/api_flow.html">
+                Flow ordinary data
+              </a>
+              <a href="./samples/api_flow_timeseries.html">
+                Flow timeseries data
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Axis</h3>
+              <a href="./samples/api_axis_range.html">
+                Update axis range
+              </a>
+              <a href="./samples/api_axis_label.html">
+                Update axis label
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Grid</h3>
+              <a href="./samples/api_xgrid_lines.html">
+                Update x grid lines
+              </a>
+              <a href="./samples/api_ygrid_lines.html">
+                Update y grid lines
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Legend</h3>
+              <a href="./samples/api_legend.html">
+                Update legend
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Transform</h3>
+              <a href="./samples/api_transform.html">
+                Transform chart
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Element</h3>
+              <a href="./samples/element.html">
+                Access svg element of chart
+              </a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>Data</h3>
+              <a href="./samples/api_data_colors.html">
+                Update data color
+              </a>
+            </div>
+            <div class="col-md-4">
+              <h3>Tooltip</h3>
+              <a href="./samples/api_tooltip_show.html">
+                Show tooltip programmatically
+              </a>
             </div>
           </div>
         </div>
+      </div>
 
+      <div class="section">
+        <h2># <span>Other Library</span></h2>
+        <div>
+          <div class="row">
+            <div class="col-md-4">
+              <h3>RequireJS</h3>
+              <a href="./samples/requirejs.html">
+                Load by RequireJS
+              </a>
+            </div>
+          </div>
+        </div>
       </div>
+
     </div>
   </body>
 </html>
diff --git a/htdocs/js/extensions b/htdocs/js/extensions
new file mode 120000
index 0000000..4761652
--- /dev/null
+++ b/htdocs/js/extensions
@@ -0,0 +1 @@
+../../extensions/js
\ No newline at end of file
diff --git a/htdocs/js/samples/plugin.js b/htdocs/js/samples/plugin.js
new file mode 100644
index 0000000..e5a0718
--- /dev/null
+++ b/htdocs/js/samples/plugin.js
@@ -0,0 +1,13 @@
+c3.chart.internal.fn.isTimeSeries = function () {
+    console.log('custom isTimeSeries');
+    return false;
+};
+c3.chart.internal.fn.additionalConfig.test1 = undefined;
+c3.chart.internal.fn.additionalConfig.test2 = undefined;
+
+c3.chart.fn.hoge = function () {
+    console.log("hoge()", this.internal.isTimeSeries());
+};
+c3.chart.fn.test = function () {
+    console.log('test()', this.internal.config.test1);
+};
diff --git a/htdocs/js/samples/requirejs.js b/htdocs/js/samples/requirejs.js
index eb57fc2..95f5a7d 100644
--- a/htdocs/js/samples/requirejs.js
+++ b/htdocs/js/samples/requirejs.js
@@ -7,7 +7,7 @@ require.config({
 
 require(["d3", "c3"], function(d3, c3) {
 
-    var chart = c3.generate({
+    window.chart = c3.generate({
         data: {
             columns: [
                 ['sample', 30, 200, 100, 400, 150, 250]
@@ -15,4 +15,4 @@ require(["d3", "c3"], function(d3, c3) {
         }
     });
 
-});
\ No newline at end of file
+});
diff --git a/htdocs/js/samples/zoom_reduction.js b/htdocs/js/samples/zoom_reduction.js
new file mode 100644
index 0000000..0c12921
--- /dev/null
+++ b/htdocs/js/samples/zoom_reduction.js
@@ -0,0 +1,81 @@
+var chart;
+function refresh() {
+    if (suspendRefresh)
+        return;
+    chart.load({
+        columns: [
+            ["Value"].concat(zoom(column, currentZoom, "t=>Math.round(t.avg())".toLambda())),
+            ["xColumn"].concat(zoom(xColumn, currentZoom, "t=>t[0]".toLambda())),
+        ]
+    });
+}
+
+function getChart() {
+    return chart;
+}
+function main() {
+    var last = 0;
+    var max = 10000;
+    var column = Array.generate(max, function (i) {
+        return last += Math.randomInt(-10, 10);
+    });
+    var xColumn = Array.generateNumbers(0, max);
+    var options = {
+        bindto: "#divChart",
+        data: {
+            columns: [
+                ["Value"].concat(column),
+                ["x"].concat(xColumn),
+            ],
+            type: "line",
+            x: "x"
+        },
+        zoom2: {
+            enabled: true,
+        }
+    };
+    chart = c3ext.generate(options);
+
+    window.setInterval(refreshStatus, 1000);
+
+    function refreshStatus() {
+        var zoomInfo = chart.zoom2.getZoom();
+        var info = {
+            reduced: chart.zoom2.maxItems(),
+            actual: (zoomInfo.currentZoom[1] - zoomInfo.currentZoom[0]),
+            range: zoomInfo.currentZoom[0] + "-" + zoomInfo.currentZoom[1],
+            total: zoomInfo.totalItems
+        };
+        $("#status").text(JSON.stringify(info, null, " "));
+    }
+
+};
+
+if (typeof (Array.generate) == "undefined") {
+    Array.generate = function (length, generator) {
+        var list = new Array(length);
+        for (var i = 0; i < length; i++) {
+            list[i] = generator(i);
+        }
+        return list;
+    }
+}
+if (typeof (Math.randomInt) == "undefined") {
+    Math.randomInt = function (min, max) {
+        return Math.floor(Math.random() * (max - min + 1)) + min;
+    }
+}
+if (typeof (Array.generateNumbers) == "undefined") {
+    Array.generateNumbers = function (from, until) {
+        if (arguments.length == 1) {
+            until = from;
+            from = 0;
+        }
+        var length = until - from;
+        var list = new Array(length);
+        for (var i = 0; i < length; i++) {
+            list[i] = i + from;
+        }
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/htdocs/samples/api_axis_range.html b/htdocs/samples/api_axis_range.html
new file mode 100644
index 0000000..daa7843
--- /dev/null
+++ b/htdocs/samples/api_axis_range.html
@@ -0,0 +1,81 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          axes: {
+            data1: 'y',
+            data2: 'y2',
+          }
+        },
+        axis: {
+          x: {
+            label: 'X Label'
+          },
+          y: {
+            label: {
+              text: 'Y Axis Label',
+              position: 'outer-middle'
+            }
+          },
+          y2: {
+            show: true,
+            label: {
+              text: 'Y2 Axis Label',
+              position: 'outer-middle'
+            }
+          }
+        },
+        tooltip: {
+//          enabled: false
+        },
+        zoom: {
+//          enabled: true
+        },
+        subchart: {
+//          show: true
+        }
+      });
+
+      setTimeout(function () {
+        chart.axis.max(500);
+      }, 1000);
+
+      setTimeout(function () {
+        chart.axis.min(-500);
+      }, 2000);
+
+      setTimeout(function () {
+        chart.axis.max({y: 600, y2: 100});
+      }, 3000);
+
+      setTimeout(function () {
+        chart.axis.min({y: -600, y2: -100});
+      }, 4000);
+
+      setTimeout(function () {
+        chart.axis.range({max: 1000, min: -1000});
+      }, 5000);
+
+      setTimeout(function () {
+        chart.axis.range({min: {y: 1000}, max: {y: 2000}});
+      }, 6000);
+
+      setTimeout(function () {
+        chart.axis.range({max: {y: 600, y2: 100}, min: {y: -100, y2: 0}});
+      }, 7000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_category.html b/htdocs/samples/api_category.html
new file mode 100644
index 0000000..143c31d
--- /dev/null
+++ b/htdocs/samples/api_category.html
@@ -0,0 +1,48 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+    <div id="message"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart = c3.generate({
+        data: {
+          x: 'x',
+          columns: [
+            ['x', '1e-3', '1e-2', '1'],
+            ['data1', 30, 200, 100, 400, 150, 250, 50, 100, 250]
+          ]
+        },
+        axis: {
+          x: {
+            type: 'categorized'
+          }
+        }
+      });
+
+      setTimeout(function () {
+        d3.select('#message').node().innerHTML = "chart.categories() =>" + chart.categories();
+      }, 1000);
+
+      setTimeout(function () {
+        chart.categories(['updated 1', 'updated 2', 'updated 3', 'updated 4']);
+        d3.select('#message').node().innerHTML = "";
+      }, 2000);
+
+      setTimeout(function () {
+        d3.select('#message').node().innerHTML = "chart.category(1) =>" + chart.category(1);
+      }, 3000);
+
+      setTimeout(function () {
+        chart.category(1, 'UPDATED 1');
+        d3.select('#message').node().innerHTML = "";
+      }, 4000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/selection_line.html b/htdocs/samples/api_data_colors.html
similarity index 57%
rename from htdocs/samples/selection_line.html
rename to htdocs/samples/api_data_colors.html
index fcd36bb..755341a 100644
--- a/htdocs/samples/selection_line.html
+++ b/htdocs/samples/api_data_colors.html
@@ -8,21 +8,26 @@
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
-        bindto: '#chart',
         data: {
           columns: [
-            ['sample1', 30, 200, 100, 400, 150, 250],
-            ['sample2', 130, 300, 200, 500, 250, 350],
-            ['sample3', 230, 400, 300, 600, 350, 450]
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
           ],
-          selection: {
-            enabled: true,
-            grouped: true,
-            multiple: false
+        },
+        axis: {
+          x: {
+            type: 'category'
           }
         }
       });
+
+      setTimeout(function () {
+        chart.data.colors({data1: '#000'});
+      }, 1000);
+
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/api_flow.html b/htdocs/samples/api_flow.html
new file mode 100644
index 0000000..363faf5
--- /dev/null
+++ b/htdocs/samples/api_flow.html
@@ -0,0 +1,223 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+    <style>
+      .c3-region-1 {
+        fill: #dd3333;
+        fill-opacity: 0.8
+      }
+    </style>
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var padding = {}, types = {}, chart, generate = function () { return c3.generate({
+        data: {
+          columns: [
+            ['data1'],
+            ['data2'],
+          ],
+          types: types,
+          labels: true
+        },
+        bar: {
+          width: 10
+        },
+        axis: {
+          x: {
+            padding: padding
+          },
+          y: {
+/*
+            min: -100,
+            max: 1000
+*/
+          }
+        },
+        grid: {
+          x: {
+            show: true,
+            lines: [{value: 3, text:'Label 3'}, {value: 4.5, text: 'Label 4.5'}]
+          },
+          y: {
+            show: true
+          }
+        },
+        regions: [
+          {start:2, end:4, class:'region1'},
+          {start:100, end:200, axis:'y'},
+        ],
+      });
+      };
+
+    function run() {
+
+      chart = generate();
+
+      setTimeout(function () {
+        // Load only one data
+        chart.flow({
+          rows: [
+            ['data1', 'data2', 'data3'],
+            [500, 100, 200],
+            [200, null, null],
+            [100, 50, null] 
+          ],
+          duration: 1500,
+
+          done: function () {
+            // Load 2 data without data2 and remove 1 data
+            chart.flow({
+              columns: [
+                ['data1', 200, 300],
+                ['data3', 100, 100]
+              ],
+              length: 0,
+              duration: 1500,
+
+              done: function () {
+                chart.flow({
+                  columns: [
+                    ['data1', 200, 300],
+                    ['data2', 200, 300],
+                    ['data3', 100, 100]
+                  ],
+                  length: 2,
+                  duration: 1500,
+                  done: function () {
+
+                    chart.flow({
+                      columns: [
+                        ['data1', 500],
+                        ['data2', 100],
+                        ['data3', 200]
+                      ],
+                      length: 1,
+                      duration: 1500,
+                    });
+                  }
+
+                });
+              }// done
+
+            });
+          },
+
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 250],
+            ['data2', 350],
+            ['data3', 150]
+          ],
+          length: 0
+        });
+      }, 9000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 100],
+            ['data2', 50],
+            ['data3', 300]
+          ],
+          length: 2
+        });
+      }, 10000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 600],
+            ['data2', 400],
+            ['data3', 500]
+          ],
+          to: 2,
+        });
+      }, 11000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 100],
+            ['data2', 200],
+            ['data3', 300]
+          ]
+        });
+      }, 12000);
+
+      setTimeout(function () {
+        chart = generate();
+      }, 13000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 500, 100],
+            ['data2', 100, 200],
+            ['data3', 200, 300],
+          ],
+          duration: 1500,
+          done: function () {
+            chart.flow({
+              columns: [
+                ['data1', 200],
+                ['data3', 100]
+              ],
+//              duration: 1000,
+              length: 1
+            });
+          },
+        });
+      }, 14000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 200],
+            ['data2', 300],
+            ['data3', 100]
+          ],
+          to: 1,
+        });
+      }, 18000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['data1', 200],
+            ['data2', 300],
+            ['data3', 400]
+          ]
+        });
+      }, 19000);
+
+    }
+
+    run();
+
+    // Test for no padding
+    setTimeout(function () {
+      padding = {left: 0, right: 0};
+      run();
+    }, 22000);
+
+    // Test for other chart types
+    setTimeout(function () {
+      types = {
+        data2: 'area',
+        data3: 'bar',
+      };
+      run();
+    }, 45000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_flow_timeseries.html b/htdocs/samples/api_flow_timeseries.html
new file mode 100644
index 0000000..216d7e4
--- /dev/null
+++ b/htdocs/samples/api_flow_timeseries.html
@@ -0,0 +1,173 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var padding = {}, types = {};
+
+      var generate = function () { return c3.generate({
+        data: {
+          x: 'x',
+          columns: [
+            ['x', ],
+            ['data1', ],
+            ['data2', ],
+//            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-10', '2013-01-11', '2013-01-12'],
+//            ['data1', 30, 200, 100, 400, 150, 250],
+//            ['data2', 310, 400, 200, 100, 450, 150],
+//            ['data3', 310, 400, 200, 100, null, 150],
+          ],
+          types: types,
+//          labels: true
+        },
+        bar: {
+          width: 10
+        },
+        axis: {
+          x: {
+            type: 'timeseries',
+            tick: {
+              format: '%m/%d',
+            },
+            padding: padding
+          },
+          y: {
+/*
+            min: -100,
+            max: 1000
+*/
+          }
+        },
+/* not supported yet
+        grid: {
+          x: {
+            show: true
+          },
+          y: {
+            show: true
+          }
+        }
+*/
+      }); }, chart;
+
+    function run() {
+
+      chart = generate();
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-01-21'],
+            ['data1', 500],
+            ['data3', 200],
+          ],
+          duration: 1500
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-02-01', '2013-02-08', '2013-02-15'],
+            ['data1', 200, 400, 300],
+            ['data2', 100, 300, 200],
+            ['data3', 100, 200, 50]
+          ],
+          length: 1,
+          duration: 1500
+        });
+      }, 4000);
+
+      setTimeout(function () {
+        console.log("Flow 1");
+        chart.flow({
+          columns: [
+            ['x', '2013-03-01', '2013-03-08'],
+            ['data1', 200, 500],
+            ['data2', 300, 400],
+            ['data3', 400, 200]
+          ],
+          to: '2013-02-08',
+          duration: 1500
+        });
+      }, 7000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-03-15', '2013-05-01'],
+            ['data1', 200, 500],
+            ['data2', 300, 400],
+            ['data3', 400, 200]
+          ],
+          length: 0,
+          duration: 1500
+        });
+      }, 10000);
+
+      setTimeout(function () {
+        chart = generate();
+      }, 14000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-01-21', '2013-01-25', '2013-01-26'],
+            ['data1', 500, 300, 100],
+            ['data3', 200, 150, null],
+          ],
+          duration: 1500
+        });
+      }, 15000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-02-01'],
+            ['data1', 200],
+            ['data2', 100],
+            ['data3', 100]
+          ],
+          length: 0,
+          duration: 1500
+        });
+      }, 18000);
+
+      setTimeout(function () {
+        chart.flow({
+          columns: [
+            ['x', '2013-03-01'],
+            ['data1', 200],
+            ['data2', 300],
+            ['data3', 400]
+          ],
+          to: '2013-02-01',
+          duration: 1500
+        });
+      }, 21000);
+    };
+
+    run();
+
+    setTimeout(function () {
+      padding = {left: 0, right: 0};
+      run();
+    }, 25000);
+
+    setTimeout(function () {
+      types = {
+        data2: 'area',
+        data3: 'bar',
+      }
+      run();
+    }, 50000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_legend.html b/htdocs/samples/api_legend.html
new file mode 100644
index 0000000..dfc6994
--- /dev/null
+++ b/htdocs/samples/api_legend.html
@@ -0,0 +1,136 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var columns = [];
+      for (var i = 0; i < 5; i++ ) {
+        columns[i] = ['datahogehogeohgeohoge' + i, 10 * i, 20 * i, 30 * i];
+      }
+
+      var chart = c3.generate({
+        data: {
+          columns: columns,
+        },
+        axis: {
+          x: {
+            type: 'category'
+          }
+        }
+      });
+
+      setTimeout(function () {
+        chart.legend.hide();
+      }, 1000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          axis: {
+            x: {
+              type: 'category'
+            }
+          },
+          legend: {
+            position: 'right'
+          }
+        });
+      }, 2000);
+
+      setTimeout(function () {
+        chart.legend.hide();
+      }, 3000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          axis: {
+            rotated: true
+          }
+        });
+      }, 4000);
+
+      setTimeout(function () {
+        chart.legend.hide();
+      }, 5000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          legend: {
+            position: 'right'
+          },
+          axis: {
+            rotated: true
+          }
+        });
+      }, 6000);
+
+      setTimeout(function () {
+        chart.legend.hide();
+      }, 7000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          legend: {
+            show: false
+          }
+        });
+      }, 8000);
+
+      setTimeout(function () {
+        chart.legend.show();
+      }, 9000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          legend: {
+            show: false
+          },
+          axis: {
+            rotated: true
+          }
+        });
+      }, 10000);
+
+      setTimeout(function () {
+        chart.legend.show();
+      }, 11000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: columns,
+          },
+          legend: {
+            position: 'right',
+            show: false
+          }
+        });
+      }, 12000);
+
+      setTimeout(function () {
+        chart.legend.show();
+      }, 13000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_tooltip_show.html b/htdocs/samples/api_tooltip_show.html
new file mode 100644
index 0000000..b4a82b5
--- /dev/null
+++ b/htdocs/samples/api_tooltip_show.html
@@ -0,0 +1,38 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+        }
+      });
+
+      setTimeout(function () {
+        chart.tooltip.show({ x: 1 });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.tooltip.show({ index: 3 });
+      }, 2000);
+
+      setTimeout(function () {
+        chart.tooltip.show({ data: {x: 2} });
+      }, 3000);
+
+      setTimeout(function () {
+        chart.tooltip.hide();
+      }, 4000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_transform.html b/htdocs/samples/api_transform.html
new file mode 100644
index 0000000..4a85426
--- /dev/null
+++ b/htdocs/samples/api_transform.html
@@ -0,0 +1,70 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+        },
+      });
+
+      setTimeout(function () {
+        chart.transform('bar');
+      }, 1000);
+
+      setTimeout(function () {
+        chart.transform('pie');
+      }, 2000);
+
+      setTimeout(function () {
+        chart.transform('donut');
+      }, 3000);
+
+      setTimeout(function () {
+        chart.transform('area');
+      }, 4000);
+
+      setTimeout(function () {
+        chart.transform('spline');
+      }, 5000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            columns: [
+              ['data1', 30, 200, 100, 400, 150, 250],
+              ['data2', 50, 20, 10, 40, 15, 25],
+              ['data1_x', 50, 20, 10, 40, 15, 25],
+              ['data2_x', 30, 200, 100, 400, 150, 250],
+            ],
+            xs: {
+              data1: 'data1_x',
+              data2: 'data2_x',
+            },
+            type: 'scatter'
+          },
+        });
+      }, 7000);
+
+      setTimeout(function () {
+        chart.transform('pie');
+      }, 8000);
+
+      setTimeout(function () {
+        chart.transform('scatter');
+      }, 9000);
+
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/api_xgrid_lines.html b/htdocs/samples/api_xgrid_lines.html
new file mode 100644
index 0000000..661d111
--- /dev/null
+++ b/htdocs/samples/api_xgrid_lines.html
@@ -0,0 +1,125 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var axis_rotated = false, axis_x_type = "";
+
+      var generate = function () { return c3.generate({
+        bindto: '#chart',
+        data: {
+          columns: [
+            ['sample', 30, 200, 100, 400, 150, 250]
+          ]
+        },
+        axis: {
+          rotated: axis_rotated,
+          x: {
+            type: axis_x_type
+          }
+        },
+        grid: {
+          x: {
+//            lines: [{value: 3, text:'Label 3'}, {value: 4.5, text: 'Label 4.5'}]
+          }
+        }
+      }); }, chart = generate();
+
+      var queue = [
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids([{value: 2, text:'Label 2'}]);
+      },
+      function () {
+        chart.xgrids.add([{value: 3, text:'Label 3', class:'hoge'}]);
+      },
+      function () {
+        chart.xgrids.remove({value:2});
+      },
+      function () {
+        chart.xgrids.remove({class:'hoge'});
+      },
+      function () {
+        chart.xgrids.remove([{value: 1}, {value: 4}]);
+      },
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids.remove();
+      },
+      function () {
+        axis_rotated = true;
+        chart = generate();
+      },
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids([{value: 2, text:'Label 2'}]);
+      },
+      function () {
+        chart.xgrids.add([{value: 3, text:'Label 3', class:'hoge'}]);
+      },
+      function () {
+        chart.xgrids.remove({value:2});
+      },
+      function () {
+        chart.xgrids.remove({class:'hoge'});
+      },
+      function () {
+        chart.xgrids.remove([{value: 1}, {value: 4}]);
+      },
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids.remove();
+      },
+      function () {
+        axis_rotated = false;
+        axis_x_type = 'category';
+        chart = generate();
+      },
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids([{value: 2, text:'Label 2'}]);
+      },
+      function () {
+        chart.xgrids.add([{value: 3, text:'Label 3', class:'hoge'}]);
+      },
+      function () {
+        chart.xgrids.remove({value:2});
+      },
+      function () {
+        chart.xgrids.remove({class:'hoge'});
+      },
+      function () {
+        chart.xgrids.remove([{value: 1}, {value: 4}]);
+      },
+      function () {
+        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
+      },
+      function () {
+        chart.xgrids.remove();
+      },
+      ];
+
+      var i = 0;
+      queue.forEach(function (f) {
+        setTimeout(f, 1000 * i++);
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/grid_y_lines.html b/htdocs/samples/api_ygrid_lines.html
similarity index 86%
rename from htdocs/samples/grid_y_lines.html
rename to htdocs/samples/api_ygrid_lines.html
index e1e7207..57784ed 100644
--- a/htdocs/samples/grid_y_lines.html
+++ b/htdocs/samples/api_ygrid_lines.html
@@ -20,7 +20,7 @@
         },
         grid: {
           y: {
-            lines: [{value: 30, text:'Label 30'}, {value: 250, text: 'Label 250'}]
+//            lines: [{value: 30, text:'Label 30'}, {value: 250, text: 'Label 250'}]
           }
         }
       });
@@ -34,7 +34,7 @@
       }, 2000);
 
       setTimeout(function () {
-        chart.ygrids.add([{value: 230, text:'Label 230'}]);
+        chart.ygrids.add([{value: 230, text:'Label 230', class: 'hoge'}]);
       }, 3000);
 
       setTimeout(function () {
diff --git a/htdocs/samples/area_zerobased.html b/htdocs/samples/area_zerobased.html
new file mode 100644
index 0000000..f7975c9
--- /dev/null
+++ b/htdocs/samples/area_zerobased.html
@@ -0,0 +1,25 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 1030, 1200, 1100, 1400, 1150, 1250],
+            ['data2', 2130, 2100, 2140, 2200, 2150, 1850]
+          ],
+          type: 'area',
+        },
+        area: {
+          zerobased: false
+        }
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_padding.html b/htdocs/samples/axes_padding.html
new file mode 100644
index 0000000..c562a4a
--- /dev/null
+++ b/htdocs/samples/axes_padding.html
@@ -0,0 +1,62 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 300, 2000, 1000, 4000, 1500, 2500],
+          ],
+          axes: {
+            data2: 'y2'
+          }
+        },
+        axis: {
+          y: {
+            padding: {
+              top: 0.1,
+              bottom: 0.1,
+              unit: 'ratio'
+            }
+          },
+          y2: {
+            show: true,
+            padding: {
+              top: 200,
+              bottom: 200,
+            }
+          }
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', 3000, 20000, 10000, 40000, 15000, 25000],
+          ],
+        },
+        axis: {
+          y: {
+            padding: {
+              top: 0.1,
+              bottom: 0.1,
+              unit: 'ratio'
+            }
+          }
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_range.html b/htdocs/samples/axes_range.html
new file mode 100644
index 0000000..732200a
--- /dev/null
+++ b/htdocs/samples/axes_range.html
@@ -0,0 +1,87 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['sample', 100, 200, 100, 400, 150, 250]
+          ],
+        },
+        axis: {
+          x: {
+              min: -10,
+              max: 10,
+            }
+          },
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          x: 'x',
+          columns: [
+            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
+            ['sample', 100, 200, 100, 400, 150, 250]
+          ],
+        },
+        axis: {
+          x: {
+              type: 'timeseries',
+              min: new Date('2012-12-20'),
+              max: '2013-03-01',
+              tick : {
+                format : "%Y-%m-%d %H:%M:%S" // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+              }
+            }
+          }
+      });
+
+      setTimeout(function () {
+        chart1.axis.max({x: 20});
+      }, 1000);
+
+      setTimeout(function () {
+        chart1.axis.min({x: -5});
+      }, 2000);
+
+      setTimeout(function () {
+        chart1.axis.range({max: {x: 5}, min: {x: 0}});
+      }, 3000);
+
+      setTimeout(function () {
+        chart2.axis.max({x: new Date('2013-02-01')});
+      }, 1000);
+
+      setTimeout(function () {
+        chart2.axis.min({x: new Date('2012-12-01')});
+      }, 2000);
+
+      setTimeout(function () {
+      chart2.axis.range({max: {x: '2013-01-06'}, min: {x: '2013-01-01'}});
+      }, 3000);
+
+      setTimeout(function () {
+        chart2.axis.max({y: 1000});
+      }, 4000);
+
+      setTimeout(function () {
+        chart2.axis.min({y: -1000});
+      }, 5000);
+
+      setTimeout(function () {
+        chart2.axis.range({max: {y: 400}, min: {y: 0}});
+      }, 6000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_x_extent.html b/htdocs/samples/axes_x_extent.html
new file mode 100644
index 0000000..b433824
--- /dev/null
+++ b/htdocs/samples/axes_x_extent.html
@@ -0,0 +1,76 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 100, 200, 50, 300, 400, 290],
+            ['data2', 10, 20, 50, 30, 10, 100],
+          ],
+        },
+        axis: {
+          x: {
+            extent: [2, 4.5]
+          }
+        },
+        subchart: {
+          show: true
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          x: 'x',
+          columns: [
+            ['x', '2014-01-01', '2014-02-01', '2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01'],
+            ['data1', 100, 200, 50, 300, 400, 290],
+            ['data2', 10, 20, 50, 30, 10, 100],
+          ],
+        },
+        axis: {
+          x: {
+            type: 'timeseries',
+            extent: ['2014-03-01', '2014-04-20']
+          }
+        },
+        subchart: {
+          show: true
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', 100, 200, 50, 300, 400, 290],
+            ['data2', 10, 20, 50, 30, 10, 100],
+          ],
+        },
+        axis: {
+          x: {
+            extent: [1, 4.2]
+          }
+        },
+        zoom: {
+          enabled: true
+        },
+        subchart: {
+          show: true
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_x_localtime.html b/htdocs/samples/axes_x_localtime.html
new file mode 100644
index 0000000..3b5813e
--- /dev/null
+++ b/htdocs/samples/axes_x_localtime.html
@@ -0,0 +1,137 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var data, axis_x_localtime;
+
+      var data1 = {
+          x : 'date',
+          columns: [
+            ['date', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05'],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+      };
+
+      var data2 = {
+          x : 'date',
+          columns: [
+            ['date', 1356966000000, 1357052400000, 1357138800000, 1357225200000, 1357311600000],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+      };
+
+      var data3 = {
+          x : 'date',
+          columns: [
+            ['date', new Date(1356966000000), new Date(1357052400000), new Date(1357138800000), new Date(1357225200000), new Date(1357311600000)],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+      };
+
+      var data4 = {
+          x : 'date',
+          x_format : '%Y%m%d',
+          columns: [
+            ['date', '20130101', '20130102', '20130103', '20130104', '20130105'],
+            ['sample', 1030, 1200, 1100, 1400, 1150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+      };
+
+      var data5 = {
+          x : 'date',
+          x_format : '%Y%m%d %H:%M:%S',
+          columns: [
+            ['date', '20130101 00:00:00', '20130102 00:00:00', '20130103 00:00:00', '20130104 00:00:00', '20130105 00:00:00'],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 1130, 1300, 1200, 1450, 1250]
+          ]
+      };
+
+      var generate = function () { return c3.generate({
+        bindto: '#chart',
+        data: data,
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%Y-%m-%d %H:%M:%S" // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+            },
+            localtime: axis_x_localtime
+          }
+        }
+      }); };
+
+      setTimeout(function () {
+        data = data1;
+        axis_x_localtime = true;
+        chart = generate();
+      }, 1000);
+
+      setTimeout(function () {
+        data = data1;
+        axis_x_localtime = false;
+        chart = generate();
+      }, 2000);
+
+      setTimeout(function () {
+        data = data2;
+        axis_x_localtime = true;
+        chart = generate();
+      }, 3000);
+
+      setTimeout(function () {
+        data = data2;
+        axis_x_localtime = false;
+        chart = generate();
+      }, 4000);
+
+      setTimeout(function () {
+        data = data3;
+        axis_x_localtime = true;
+        chart = generate();
+      }, 5000);
+
+      setTimeout(function () {
+        data = data3;
+        axis_x_localtime = false;
+        chart = generate();
+      }, 6000);
+
+      setTimeout(function () {
+        data = data4;
+        axis_x_localtime = true;
+        chart = generate();
+      }, 7000);
+
+      setTimeout(function () {
+        data = data4;
+        axis_x_localtime = false;
+        chart = generate();
+      }, 8000);
+
+      setTimeout(function () {
+        data = data5;
+        axis_x_localtime = true;
+        chart = generate();
+      }, 9000);
+
+      setTimeout(function () {
+        data = data5;
+        axis_x_localtime = false;
+        chart = generate();
+      }, 10000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_x_range_timeseries.html b/htdocs/samples/axes_x_range_timeseries.html
new file mode 100644
index 0000000..4b98bb9
--- /dev/null
+++ b/htdocs/samples/axes_x_range_timeseries.html
@@ -0,0 +1,57 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+    var chart1 = c3.generate({
+      "bindto": "#chart1",
+      "axis": {
+          "x": {
+            "type": "timeseries",
+            "min": 1401879600000,
+            "max": 1401969600000,
+          }
+      },
+      "data": {
+        "type": "line",
+        "columns": [
+            ["epoch", 1401879600000, 1401883200000, 1401886800000],
+            ["y", 1955, 2419, 2262]
+        ],
+        "xs": {
+            "y": "epoch"
+        }
+      }
+    });
+
+    var chart2 = c3.generate({
+      "bindto": "#chart2",
+      "axis": {
+          "x": {
+            "type": "timeseries",
+            "min": new Date(1401879600000),
+            "max": new Date(1401969600000),
+          }
+      },
+      "data": {
+        "type": "line",
+        "columns": [
+            ["epoch", 1401879600000, 1401883200000, 1401886800000],
+            ["y", 1955, 2419, 2262]
+        ],
+        "xs": {
+            "y": "epoch"
+        }
+      }
+    });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/axes_x_tick_values.html b/htdocs/samples/axes_x_tick_values.html
new file mode 100644
index 0000000..c8922e6
--- /dev/null
+++ b/htdocs/samples/axes_x_tick_values.html
@@ -0,0 +1,55 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+        },
+        axis: {
+          x : {
+            tick: {
+              values: [2, 4]
+            }
+          }
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          x : 'date',
+          xFormat : '%Y%m%d',
+          columns: [
+            ['date', '20130101', '20130102', '20130103', '20130104', '20130105', '20130106'],
+            ['sample', 30, 200, 100, 400, 150, 250],
+            ['sample2', 130, 300, 200, 450, 250, 350]
+          ]
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%e %b %y", // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+              values: ['20130103', '20130104']
+            }
+          }
+        }
+      });
+      
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/simple_bar.html b/htdocs/samples/axes_y_default.html
similarity index 60%
rename from htdocs/samples/simple_bar.html
rename to htdocs/samples/axes_y_default.html
index 1496cd2..50119eb 100644
--- a/htdocs/samples/simple_bar.html
+++ b/htdocs/samples/axes_y_default.html
@@ -1,22 +1,23 @@
 <html>
   <head>
-    <link rel="stylesheet" type="text/css" href="/css/style.css">
     <link rel="stylesheet" type="text/css" href="/css/c3.css">
   </head>
   <body>
     <div id="chart"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
       var chart = c3.generate({
-        bindto: '#chart',
         data: {
           columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
+            ['data1'],
+            ['data2'],
           ],
-          types: {
-            'sample': 'bar'
+        },
+        axis: {
+          y: {
+            default: [-100, 100]
           }
         }
       });
diff --git a/htdocs/samples/bar_zerobased.html b/htdocs/samples/bar_zerobased.html
new file mode 100644
index 0000000..55d02a8
--- /dev/null
+++ b/htdocs/samples/bar_zerobased.html
@@ -0,0 +1,25 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 1030, 1200, 1100, 1400, 1150, 1250],
+            ['data2', 2130, 2100, 2140, 2200, 2150, 1850]
+          ],
+          type: 'bar',
+        },
+        bar: {
+          zerobased: false
+        }
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/bindto.html b/htdocs/samples/bindto.html
new file mode 100644
index 0000000..14e813d
--- /dev/null
+++ b/htdocs/samples/bindto.html
@@ -0,0 +1,41 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1" style="height:300px;"></div>
+    <div class="chart2" style="height:150px;"></div>
+    <div class="chart3" style="height:150px;"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 130, 210, 120, 440, 250, 350]
+          ]
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '.chart2',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250]
+          ]
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: document.getElementsByClassName('chart3')[0],
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250]
+          ]
+        }
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/categorized.html b/htdocs/samples/categorized.html
index c041341..0e4a1b5 100644
--- a/htdocs/samples/categorized.html
+++ b/htdocs/samples/categorized.html
@@ -3,14 +3,19 @@
     <link href="/css/c3.css" rel="stylesheet" type="text/css">
   </head>
   <body>
-    <div id="chart"></div>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
         data: {
+          x: 'x',
           columns: [
+            ['x', '1e-3', '1e-2', '1'],
             ['data1', 30, 200, 100, 400, 150, 250, 50, 100, 250]
           ]
         },
@@ -21,9 +26,28 @@
         }
       });
 
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250, 50, 100, 250]
+          ]
+        },
+        axis: {
+          x: {
+            categories: ['1e-3', '1e-2', '1e-1', '0', 'hoge'],
+            type: 'categorized'
+          }
+        }
+      });
+
+      setTimeout(function () {
+        chart1.load({columns:[['data2', 30, 20, 50, 40, 60, 50, 100, 200, 300,100]]});
+      }, 1000);
+
       setTimeout(function () {
-        chart.load({columns:[['data2', 30, 20, 50, 40, 60, 50, 100, 200, 300,100]]});
-      }, 500);
+        chart2.load({columns:[['data2', 30, 20, 50, 40, 60, 50, 100, 200, 300,100]]});
+      }, 2000);
 
     </script>
   </body>
diff --git a/htdocs/samples/chart_area.html b/htdocs/samples/chart_area.html
index caa6d92..04ec6bd 100644
--- a/htdocs/samples/chart_area.html
+++ b/htdocs/samples/chart_area.html
@@ -3,23 +3,86 @@
     <link href="/css/c3.css" rel="stylesheet" type="text/css">
   </head>
   <body>
-    <div id="chart"></div>
+    <h3>Zerobased</h3>
+    <div id="chart1"></div>
+    <h3>Not zerobased because of axis.y.min</h3>
+    <div id="chart2"></div>
+    <h3>Zerobased</h3>
+    <div id="chart3"></div>
+    <h3>Not zerobased because of axis.y.min</h3>
+    <div id="chart4"></div>
+    <h3>+/- vaulues</h3>
+    <div id="chart5"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 0],
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          type: 'area'
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
         data: {
           columns: [
             ['data1', 300, 350, 300, 0, 0, 0],
             ['data2', 130, 100, 140, 200, 150, 50]
           ],
-          types: {
-            data1: 'area',
-            data2: 'area-spline'
+          type: 'area'
+        },
+        axis: {
+          y: {
+            min: 100,
+          }
+        },
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, 0],
+            ['data2', -130, -100, -140, -200, -150, -50]
+          ],
+          type: 'area'
+        }
+      });
+
+      var chart4 = c3.generate({
+        bindto: '#chart4',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, 0],
+            ['data2', -130, -100, -140, -200, -150, -50]
+          ],
+          type: 'area'
+        },
+        axis: {
+          y: {
+            max: -100,
           }
         }
       });
+
+      var chart5 = c3.generate({
+        bindto: '#chart5',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 0],
+            ['data2', -130, -100, 140, -200, 150, -50]
+          ],
+          type: 'area'
+        }
+      });
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/chart_area_spline.html b/htdocs/samples/chart_area_spline.html
new file mode 100644
index 0000000..836474a
--- /dev/null
+++ b/htdocs/samples/chart_area_spline.html
@@ -0,0 +1,49 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 0],
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          type: 'area-spline'
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, 0],
+            ['data2', -130, -100, -140, -200, -150, -50]
+          ],
+          type: 'area-spline'
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 0],
+            ['data2', -130, -100, 140, -200, 150, -50]
+          ],
+          type: 'area-spline'
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_area_spline_stacked.html b/htdocs/samples/chart_area_spline_stacked.html
new file mode 100644
index 0000000..a5448cb
--- /dev/null
+++ b/htdocs/samples/chart_area_spline_stacked.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 100],
+            ['data2', 130, 0, 140, 200, 0, 50],
+          ],
+          type: 'area-spline',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, -100],
+            ['data2', -130, 0, -140, -200, 0, -50]
+          ],
+          type: 'area-spline',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 100],
+            ['data2', -130, 0, 140, -200, 150, -50]
+          ],
+          type: 'area-spline',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_area_stacked.html b/htdocs/samples/chart_area_stacked.html
new file mode 100644
index 0000000..9830d94
--- /dev/null
+++ b/htdocs/samples/chart_area_stacked.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 100],
+            ['data2', 130, 0, 140, 200, 0, 50],
+          ],
+          type: 'area',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, -100],
+            ['data2', -130, 0, -140, -200, 0, -50]
+          ],
+          type: 'area',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 100],
+            ['data2', -130, 0, 140, -200, 150, -50]
+          ],
+          type: 'area',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_area_step.html b/htdocs/samples/chart_area_step.html
new file mode 100644
index 0000000..2ba7a27
--- /dev/null
+++ b/htdocs/samples/chart_area_step.html
@@ -0,0 +1,49 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 0],
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          type: 'area-step'
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, 0],
+            ['data2', -130, -100, -140, -200, -150, -50]
+          ],
+          type: 'area-step'
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 0],
+            ['data2', -130, -100, 140, -200, 150, -50]
+          ],
+          type: 'area-step'
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_area_step_stacked.html b/htdocs/samples/chart_area_step_stacked.html
new file mode 100644
index 0000000..ce470e4
--- /dev/null
+++ b/htdocs/samples/chart_area_step_stacked.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 0],
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          type: 'area-step',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -300, -350, -300, 0, 0, 0],
+            ['data2', -130, -100, -140, -200, -150, -50]
+          ],
+          type: 'area-step',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -300, 350, -300, 0, 0, 0],
+            ['data2', -130, -100, 140, -200, 150, -50]
+          ],
+          type: 'area-step',
+          groups: [['data1', 'data2']],
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_bar.html b/htdocs/samples/chart_bar.html
index 20c3270..1f19af7 100644
--- a/htdocs/samples/chart_bar.html
+++ b/htdocs/samples/chart_bar.html
@@ -11,13 +11,15 @@
       var chart = c3.generate({
         data: {
           columns: [
-            ['data1', 30, 200, 100, 400, 150, 250],
-            ['data2', 130, 100, 140, 200, 150, 50]
+            ['data1', 1030, 1200, 1100, 1400, 1150, 1250],
+            ['data2', 2130, 2100, 2140, 2200, 2150, 1850]
+//           ['data1', 30, 200, 100, 400, 150, 250],
+//           ['data2', 130, 100, 140, 200, 150, 50]
           ],
           type: 'bar',
           onclick: function (d, element) { console.log("onclick", d, element); },
-          onenter: function (d) { console.log("onenter", d); },
-          onleave: function (d) { console.log("onleave", d); }
+          onmouseover: function (d) { console.log("onmouseover", d); },
+          onmouseout: function (d) { console.log("onmouseout", d); }
         },
         axis: {
           x: {
@@ -26,8 +28,9 @@
         },
         bar: {
           width: {
-            ratio: 0.3
-          }
+            ratio: 0.3,
+//            max: 30
+          },
         }
       });
     </script>
diff --git a/htdocs/samples/chart_bar_stacked.html b/htdocs/samples/chart_bar_stacked.html
index affa4fa..d47fdd7 100644
--- a/htdocs/samples/chart_bar_stacked.html
+++ b/htdocs/samples/chart_bar_stacked.html
@@ -8,12 +8,16 @@
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
+
+      var axis_x_type = 'category',
+          axis_rotated = false;
+
+      var generate = function () { return c3.generate({
         data: {
           columns: [
             ['data1', 30, 200, 200, 400, 150, -250],
             ['data2', 130, -100, 100, 200, 150, 50],
-            ['data3', 230, -200, 200, 300, 250, 250]
+            ['data3', 230, -200, 200, 0, 250, 250]
           ],
           type: 'bar',
           groups: [
@@ -22,39 +26,65 @@
         },
         axis: {
           x: {
-            type: 'categorized'
+            type: axis_x_type
           },
-//          rotated: true
+          rotated: axis_rotated
         },
         grid: {
           y: {
             lines: [{value:0}]
           }
         },
-        zoom: {
-//          enabled: true
-        },
-        subchart: {
-//          show: true
-        },
-        tooltip: {
-//          enabled: false
-        }
-      });
+      }); }, chart = generate();
 
-      setTimeout(function () {
+      function update1() {
         chart.groups([['data1', 'data2', 'data3']])
-      }, 500);
+      }
 
-      setTimeout(function () {
+      function update2() {
         chart.load({
           columns: [['data4', 100, 50, 150, -200, 300, -100]]
         });
-      }, 1000);
+      }
 
-      setTimeout(function () {
+      function update3() {
         chart.groups([['data1', 'data2', 'data3', 'data4']])
-      }, 1500);
+      }
+
+
+      setTimeout(update1, 1000);
+      setTimeout(update2, 2000);
+      setTimeout(update3, 3000);
+
+
+      setTimeout(function () {
+        axis_rotated = true;
+        chart = generate();
+      }, 4000);
+      setTimeout(update1, 5000);
+      setTimeout(update2, 6000);
+      setTimeout(update3, 7000);
+
+
+      setTimeout(function () {
+        axis_x_type = '';
+        axis_rotated = false;
+        chart = generate();
+      }, 8000);
+      setTimeout(update1, 9000);
+      setTimeout(update2, 10000);
+      setTimeout(update3, 11000);
+
+
+      setTimeout(function () {
+        axis_x_type = '';
+        axis_rotated = true;
+        chart = generate();
+      }, 12000);
+      setTimeout(update1, 13000);
+      setTimeout(update2, 14000);
+      setTimeout(update3, 15000);
+
 
     </script>
   </body>
diff --git a/htdocs/samples/donut.html b/htdocs/samples/chart_donut.html
similarity index 50%
rename from htdocs/samples/donut.html
rename to htdocs/samples/chart_donut.html
index e986ee5..d8453d3 100644
--- a/htdocs/samples/donut.html
+++ b/htdocs/samples/chart_donut.html
@@ -10,24 +10,19 @@
     <script>
       var chart = c3.generate({
         data: {
-          xs: {
-            setosa: 'setosa_x',
-            versicolor: 'versicolor_x',
-            virginica: 'virginica_x'
-          },
           columns: [
-            ["setosa_x", 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3.0, 3.0, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3.0, 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.6, 3.0, 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3.0, 3.8, 3.2, 3.7, 3.3],
-            ["versicolor_x", 3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2.0, 3.0, 2.2, 2.9, 2.9, 3.1, 3.0, 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3.0, 2.8, 3.0, 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3.0, 3.4, 3.1, 2.3, 3.0, 2.5, 2.6, 3.0, 2.6, 2.3, 2.7, 3.0, 2.9, 2.9, 2.5, 2.8],
-            ["virginica_x", 3.3, 2.7, 3.0, 2.9, 3.0, 3.0, 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3.0, 2.5, 2.8, 3.2, 3.0, 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3.0, 2.8, 3.0, 2.8, 3.8, 2.8, 2.8, 2.6, 3.0, 3.4, 3.1, 3.0, 3.1, 3.1, 3.1, 2.7, 3.2, 3.3, 3.0, 2.5, 3.0, 3.4, 3.0],
-            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
+//            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
             ["versicolor", 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3],
             ["virginica", 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8],
-//            ["setosa", 30],
+            ["setosa", 30],
 //            ["versicolor", 40],
 //            ["virginica", 50],
           ],
           type : 'donut',
-//          type : 'pie',
+          onmouseover: function (d, i) { console.log("onmouseover", d, i, this); },
+          onmouseout: function (d, i) { console.log("onmouseout", d, i, this); },
+          onclick: function (d, i) { console.log("onclick", d, i, this); },
+          order: null // set null to disable sort of data. desc is the default.
         },
         axis: {
           x: {
@@ -42,9 +37,7 @@
 //            format: function (d, ratio) { return ""; }
           },
           title: "Iris Petal Width",
-          onmouseover: function (d, i) { console.log(d, i); },
-          onmouseout: function (d, i) { console.log(d, i); },
-          onclick: function (d, i) { console.log(d, i); },
+          width: 70
         }
       });
 
@@ -57,7 +50,9 @@
       }, 1000);
 
       setTimeout(function () {
-        chart.unload('virginica');
+        chart.unload({
+          ids: 'virginica'
+        });
       }, 2000);
 
     </script>
diff --git a/htdocs/samples/chart_gauge.html b/htdocs/samples/chart_gauge.html
new file mode 100644
index 0000000..a650135
--- /dev/null
+++ b/htdocs/samples/chart_gauge.html
@@ -0,0 +1,181 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            [ 'data', 91.4 ]
+          ],
+          type: 'gauge',
+          onmouseover: function (d, i) { console.log("onmouseover", d, i, this); },
+          onmouseout: function (d, i) { console.log("onmouseout", d, i, this); },
+          onclick: function (d, i) { console.log("onclick", d, i, this); },
+        },
+        gauge: {
+          label: {
+//            format: function(value, ratio) {
+//              return value;
+//            },
+//          show: false // to turn off the min/max labels.
+          },
+//          min: 0, // 0 is default, //can handle negative min e.g. vacuum / voltage / current flow / rate of change
+//          max: 100, // 100 is default
+//          units: ' %',
+//          width: 39 // for adjusting arc thickness
+        },
+        color: {
+          pattern: ['#FF0000', '#F6C600', '#60B044'], // the three color levels for the percentage values.
+          threshold: {
+//            unit: 'value', // percentage is default
+//            max: 200, // 100 is default
+            values: [30, 60, 90] // alternate first value is 'value'
+          }
+        }
+      });
+
+      var chart1 = c3.generate({
+          bindto: '#chart1',
+          data: {
+              columns: [
+                  ['data', 75.0]
+              ],
+              type: 'gauge',
+          },
+          gauge: {
+              min: 50,
+              max: 100
+          }
+      });
+
+      var chart2 = c3.generate({
+          bindto: '#chart2',
+          data: {
+              columns: [
+                  ['data', 0.0]
+              ],
+              type: 'gauge',
+          },
+          gauge: {
+              min: -100,
+              max: 100
+          }
+      });
+
+      var chart3 = c3.generate({
+          bindto: '#chart3',
+          data: {
+              columns: [
+                  ['data', -75.0]
+              ],
+              type: 'gauge',
+          },
+          gauge: {
+              min: -100,
+              max: -50
+          }
+      });
+
+      var cycleDemo = function () {
+
+        setTimeout(function () {
+          d3.select('#chart .c3-chart-arcs-background')
+            .transition()
+            .style('fill', '#333');
+        }, 1000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 10 ]]
+            });
+        }, 2000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 50 ]]
+            });
+        }, 3000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 91.4 ]]
+            });
+        }, 4000);
+
+        setTimeout(function () {
+          d3.select('#chart .c3-chart-arcs-background')
+            .transition()
+            .style('fill', '#e0e0e0');
+        }, 5000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 0 ]]
+            });
+        }, 6000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 50 ]]
+            });
+        }, 7000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 91.4 ]]
+            });
+        }, 8000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 0 ]]
+            });
+        }, 9000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 50 ]]
+            });
+        }, 10000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 91.4 ]]
+            });
+        }, 11000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 0 ]]
+            });
+        }, 12000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 50 ]]
+            });
+        }, 13000);
+
+        setTimeout(function () {
+            chart.load({
+              columns: [[ 'data', 91.4 ]]
+            });
+        }, 14000);
+
+      }
+
+      cycleDemo();
+
+//      setInterval(cycleDemo, 30000);
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_pie.html b/htdocs/samples/chart_pie.html
new file mode 100644
index 0000000..e9b7ccb
--- /dev/null
+++ b/htdocs/samples/chart_pie.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+//            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
+            ["versicolor", 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3],
+            ["virginica", 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8],
+            ["setosa", 30],
+//            ["versicolor", 40],
+//            ["virginica", 50],
+          ],
+          type : 'pie',
+          onmouseover: function (d, i) { console.log("onmouseover", d, i, this); },
+          onmouseout: function (d, i) { console.log("onmouseout", d, i, this); },
+          onclick: function (d, i) { console.log("onclick", d, i, this); },
+        },
+        axis: {
+          x: {
+            label: 'Sepal.Width'
+          },
+          y: {
+            label: 'Petal.Width'
+          }
+        }
+      });
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ["setosa", 130],
+          ]
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.unload({
+          ids: 'virginica'
+        });
+      }, 2000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/pie.html b/htdocs/samples/chart_pie_sort.html
similarity index 51%
rename from htdocs/samples/pie.html
rename to htdocs/samples/chart_pie_sort.html
index e877a66..ca875b8 100644
--- a/htdocs/samples/pie.html
+++ b/htdocs/samples/chart_pie_sort.html
@@ -8,21 +8,16 @@
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
+
+      var sort = true;
+
+      var generate = function () { return c3.generate({
         data: {
-          xs: {
-            setosa: 'setosa_x',
-            versicolor: 'versicolor_x',
-            virginica: 'virginica_x'
-          },
           columns: [
-            ["setosa_x", 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3.0, 3.0, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3.0, 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.6, 3.0, 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3.0, 3.8, 3.2, 3.7, 3.3],
-            ["versicolor_x", 3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2.0, 3.0, 2.2, 2.9, 2.9, 3.1, 3.0, 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3.0, 2.8, 3.0, 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3.0, 3.4, 3.1, 2.3, 3.0, 2.5, 2.6, 3.0, 2.6, 2.3, 2.7, 3.0, 2.9, 2.9, 2.5, 2.8],
-            ["virginica_x", 3.3, 2.7, 3.0, 2.9, 3.0, 3.0, 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3.0, 2.5, 2.8, 3.2, 3.0, 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3.0, 2.8, 3.0, 2.8, 3.8, 2.8, 2.8, 2.6, 3.0, 3.4, 3.1, 3.0, 3.1, 3.1, 3.1, 2.7, 3.2, 3.3, 3.0, 2.5, 3.0, 3.4, 3.0],
-            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
+//            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
             ["versicolor", 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3],
             ["virginica", 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8],
-//            ["setosa", 30],
+            ["setosa", 30],
 //            ["versicolor", 40],
 //            ["virginica", 50],
           ],
@@ -37,26 +32,62 @@
           }
         },
         pie: {
+          sort: sort,
           onmouseover: function (d, i) { console.log(d, i); },
           onmouseout: function (d, i) { console.log(d, i); },
           onclick: function (d, i) { console.log(d, i); },
         }
-      });
+      }); }, chart = generate();
 
       setTimeout(function () {
-      console.log("== LOAD ==");
         chart.load({
           columns: [
-            ["setosa", 30],
+            ["setosa", 130],
           ]
         });
       }, 1000);
 
       setTimeout(function () {
-      console.log("== UNLOAD ==");
-        chart.unload('virginica');
+        chart.unload({
+          ids: 'virginica'
+        });
       }, 2000);
 
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ["new data", 300],
+          ]
+        });
+      }, 3000);
+
+      setTimeout(function () {
+        sort = false;
+        chart = generate();
+      }, 4000);
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ["setosa", 130],
+          ]
+        });
+      }, 5000);
+
+      setTimeout(function () {
+        chart.unload({
+          ids: 'virginica'
+        });
+      }, 6000);
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ["new data", 300],
+          ]
+        });
+      }, 7000);
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/scatter.html b/htdocs/samples/chart_scatter.html
similarity index 100%
rename from htdocs/samples/scatter.html
rename to htdocs/samples/chart_scatter.html
diff --git a/htdocs/samples/chart_step.html b/htdocs/samples/chart_step.html
new file mode 100644
index 0000000..fb32067
--- /dev/null
+++ b/htdocs/samples/chart_step.html
@@ -0,0 +1,38 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 0],
+//            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          types: {
+            data1: 'step',
+            data2: 'area-step'
+          },
+          onclick: function (d) { console.log('clicked', d); }
+        },
+        subchart: {
+          show: true
+        },
+      });
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ]
+        });
+      }, 1000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_step_category.html b/htdocs/samples/chart_step_category.html
new file mode 100644
index 0000000..4be84a8
--- /dev/null
+++ b/htdocs/samples/chart_step_category.html
@@ -0,0 +1,50 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          x: 'x',
+          columns: [
+            ['x', 'hogehoge', 'aaa', 'aaaaaa', 'a', 'b'],
+            ['data1', 300, 350, 300, 0, 0, 0],
+//            ['data2', 130, 100, 140, 200, 150, 50]
+          ],
+          types: {
+            data1: 'step',
+            data2: 'area-step'
+          },
+          empty: {
+            abort: false,
+            label: {
+              text: 'hoge'
+            }
+          }
+        },
+        axis: {
+          x: {
+            type: 'categorized'
+          }
+        },
+        subchart: {
+          show: true
+        },
+      });
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['data2', 130, 100, 140, 200, 150, 50]
+          ]
+        });
+      }, 1000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/chart_xy.html b/htdocs/samples/chart_xy.html
deleted file mode 100644
index 8895167..0000000
--- a/htdocs/samples/chart_xy.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="/css/c3.css">
-  </head>
-  <body>
-    <div id="chart"></div>
-
-    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
-    <script>
-      var chart = c3.generate({
-        bindto: '#chart',
-        data: {
-          x: 'x',
-          columns: [
-            ['x', 30, 40, 100, 200, 250, 350],
-            ['sample', 30, 200, 100, 400, 150, 250]
-          ]
-        }
-      });
-
-      setTimeout(function () {
-        chart.load({
-          columns: [
-            ['sample', 100, 300, 200, 300, 150, 300]
-          ]
-        })
-      }, 1000);
-
-      setTimeout(function () {
-        chart.load({
-          columns: [
-            ['x', 130, 140, 200, 300, 450, 550],
-            ['sample', 200, 350, 100, 200, 50, 100]
-          ]
-        })
-      }, 1500);
-    </script>
-  </body>
-</html>
diff --git a/htdocs/samples/custom_x_scale.html b/htdocs/samples/custom_x_scale.html
index f56569e..7945ee8 100644
--- a/htdocs/samples/custom_x_scale.html
+++ b/htdocs/samples/custom_x_scale.html
@@ -20,8 +20,8 @@
           selection: {
             enabled: true
           },
-          onenter: function (d) { console.log("onenter", d); },
-          onleave: function (d) { console.log("onleave", d); }
+          onmouseover: function (d) { console.log("onmouseover", d); },
+          onmouseout: function (d) { console.log("onmouseout", d); }
         },
       });
 
@@ -45,6 +45,15 @@
         });
       }, 3000);
 
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['x', 130, 140, 200, 300, 450, 550],
+            ['sample', 200, 350, 100, 200, 50, 100]
+          ]
+        })
+      }, 4000);
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/custom_xs_scale.html b/htdocs/samples/custom_xs_scale.html
index 5dd78b8..0364c10 100644
--- a/htdocs/samples/custom_xs_scale.html
+++ b/htdocs/samples/custom_xs_scale.html
@@ -24,8 +24,9 @@
           selection: {
             enabled: true
           },
-          onenter: function (d) { console.log("onenter", d); },
-          onleave: function (d) { console.log("onleave", d); }
+          onclick: function (d) { console.log("onclick", d); },
+          onmouseover: function (d) { console.log("onmouseover", d); },
+          onmouseout: function (d) { console.log("onmouseout", d); }
         }
       });
 
diff --git a/htdocs/samples/data_json.html b/htdocs/samples/data_json.html
new file mode 100644
index 0000000..522fb93
--- /dev/null
+++ b/htdocs/samples/data_json.html
@@ -0,0 +1,90 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart = c3.generate({
+        data: {
+          json: {
+            data1: [30, 20, 50, 40, 60, 50],
+            data2: [200, 130, 90, 240, 130, 220],
+            data3: [300, 200, 160, 400, 250, 250]
+          }
+        }
+      });
+
+    setTimeout(function () {
+      chart = c3.generate({
+        data: {
+          json: [{
+            "date": "2014-06-03",
+             "443": "3000",
+             "995": "500"
+          }, {
+            "date": "2014-06-04",
+             "443": "1000",
+          }, {
+            "date": "2014-06-05",
+             "443": "5000",
+             "995": "1000"
+          }],
+          keys: {
+            x: 'date',
+            value: [ "443", "995" ]
+          }
+        },
+        axis: {
+          x: {
+            type: "category"
+          }
+        }
+      });
+    }, 1000);
+
+    setTimeout(function () {
+      chart = c3.generate({
+        data: {
+//          x: 'name',
+          json: [
+            { id: 1, name: 'abc', visits: 200 },
+            { id: 2, name: 'efg', visits: 400 },
+            { id: 3, name: 'pqr', visits: 150 },
+            { id: 4, name: 'xyz', visits: 420 },
+          ],
+          keys: {
+            x: 'name',
+            value: ['visits'],
+          }
+        },
+        axis: {
+          x: {
+            type: 'categorized'
+          }
+        }
+      });
+    }, 2000);
+
+    setTimeout(function () {
+      chart.load({
+          json: [
+            { id: 1, name: 'abc', visits: 1200 },
+            { id: 2, name: 'efg', visits: 900 },
+            { id: 3, name: 'pqr', visits: 1150 },
+            { id: 4, name: 'xyz', visits: 1020 },
+          ],
+          keys: {
+            x: 'name',
+            value: ['visits'],
+          }
+      });
+    }, 3000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/data_label.html b/htdocs/samples/data_label.html
new file mode 100644
index 0000000..e8cc05c
--- /dev/null
+++ b/htdocs/samples/data_label.html
@@ -0,0 +1,225 @@
+<html>
+  <head>
+    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+    <div id="chart4"></div>
+    <div id="chart5"></div>
+    <div id="chart6"></div>
+    <div id="chart7"></div>
+    <div id="chart8"></div>
+    <div id="chart9" style="width:33%;"></div>
+    <div id="chart10"></div>
+    <div id="chart11"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            ['data1', 190, 200, 190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', -190, -200, -190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', -190, 200, 190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        }
+      });
+
+      var chart4 = c3.generate({
+        bindto: '#chart4',
+        data: {
+          columns: [
+            ['data1', 190, 200, 190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart5 = c3.generate({
+        bindto: '#chart5',
+        data: {
+          columns: [
+            ['data1', -190, -200, -190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart6 = c3.generate({
+        bindto: '#chart6',
+        data: {
+          columns: [
+            ['data1', -190, 200, 190, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart7 = c3.generate({
+        bindto: '#chart7',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 500, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25],
+            ['data3', 250, 220, 210, 240, 215, 225]
+          ],
+          groups: [['data1', 'data2', 'data3']],
+          labels: true,
+          type: 'bar',
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart8 = c3.generate({
+        bindto: '#chart8',
+        data: {
+          columns: [
+            ['data1', -30, -200, -100, -500, -150, -250],
+            ['data2', -50, -20, -10, -40, -15, -25],
+            ['data3', -250, -220, -210, -240, -215, -225]
+          ],
+          groups: [['data1', 'data2', 'data3']],
+          labels: true,
+          type: 'bar',
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart9 = c3.generate({
+        bindto: '#chart9',
+        data: {
+          columns: [
+            ['data1', -19000000000000, 200, 19000000000000, null],
+          ],
+          type: 'bar',
+          labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+          }
+        },
+        axis: {
+          rotated: true
+        }
+      });
+
+      var chart10 = c3.generate({
+        bindto: '#chart10',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 100],
+            ['data2', 130, 0, 140, 200, 0, 50],
+            ['data3', 130, 0, 140, 200, 0, 50],
+            ['data4', 130, 0, 140, 200, 0, 50],
+          ],
+          type: 'area',
+          groups: [['data1', 'data2', 'data3', 'data4']],
+          labels: true
+        }
+      });
+
+      var chart11 = c3.generate({
+        bindto: '#chart11',
+        data: {
+          columns: [
+            ['data1', 300, 350, 300, 0, 0, 100],
+            ['data2', 130, 0, 140, 200, 0, 50],
+            ['data3', 130, 0, 140, 200, 0, 50],
+            ['data4', 130, 0, 140, 200, 0, 50],
+          ],
+          groups: [['data1', 'data2', 'data3', 'data4']],
+          labels: true
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/data_label_format.html b/htdocs/samples/data_label_format.html
index 17fb19d..466a4a0 100644
--- a/htdocs/samples/data_label_format.html
+++ b/htdocs/samples/data_label_format.html
@@ -15,10 +15,10 @@
             ['data2', 50, 20, 10, 40, 15, 25]
           ],
           labels: {
-//            format: function (v) { return "Default Format"; },
+//            format: function (v, id) { return "Default Format on " + id; },
             format: {
-              y: function (v) { return "Y Format"; },
-              y2: function (v) { return "Y2 Format"; }
+              y: function (v, id) { return "Y Format on " + id; },
+              y2: function (v, id) { return "Y2 Format on " + id; }
             }
           },
           axes: {
diff --git a/htdocs/samples/data_load.html b/htdocs/samples/data_load.html
index 11da005..356383d 100644
--- a/htdocs/samples/data_load.html
+++ b/htdocs/samples/data_load.html
@@ -8,10 +8,14 @@
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
         data: {
           url: '/data/c3_test.csv',
-          labels: true
+          labels: true,
+          filter: function (t) {
+            return t.id !== 'data1';
+          }
         },
         subchart: {
           show: true
@@ -20,75 +24,87 @@
           enabled: true
         },
         transition: {
-          duration: 200
+          duration: 500
         }
       });
 
-      setTimeout(function () {
+    var queue = [
+      function () {
         chart.load({
-          url: '/data/c3_test2.csv'
+          url: '/data/c3_test2.csv',
+          filter: function (t) {
+            return t.id !== 'data1';
+          }
         });
-      }, 1000);
-
-      setTimeout(function () {
-//        chart.unload(['data1', 'data2']);
-//        chart.unload('data1');
-        chart.unload('data2');
-      }, 2000);
-
-      setTimeout(function () {
-        chart.load({
-          columns: [
-            ['data1@test', 30, 20, 50, 40, 60, 50],
-          ],
-          unload: true,
-//          unload: ['data2', 'data3'],
-//          unload: ['data2']
-        });
-      }, 3000);
-
-      setTimeout(function () {
+      },
+      function () {
         chart.load({
           rows: [
-            ['data1@test', 'data2', 'data3'],
+            ['data4', 'data5', 'data6'],
             [90, 120, 300],
             [40, 160, 240],
             [50, 200, 290],
             [120, 160, 230],
             [80, 130, 300],
             [90, 220, 320],
+            [1090, 1220, 1320],
           ]
         });
-      }, 4000);
-
-      setTimeout(function () {
+      },
+      function () {
+        chart.unload({
+          ids: ['data4', 'data5']
+        });
+      },
+      function () {
+        chart.unload({
+          ids: 'data6'
+        });
+      },
+      function () {
         chart.load({
           columns:[
-            ['data1', 30, 20, 50, 40, 60, 50,100,200]
+            ['data1', 30, 20, 50, 40, 60, 50, 100, 200],
+            ['data7', 230, 220, 250, 240, 260, 250, 300, 400]
           ]
         });
-      }, 5000);
-
-      setTimeout(function () {
-        chart.unload('data1@test');
-      }, 6000);
-
-      setTimeout(function () {
+      },
+      function () {
         chart.load({
-          columns:[
-            ['data2', null, 30, 20, 50, 40, 60, 50]
-          ]
+          json: {
+            data1: [1030, 1020, 1050, 1040, 1060, 1050, 1100, 1200],
+            data7: [430, 420, 450, 440, 460, 550, 400, 200]
+          }
         });
-      }, 7000);
-
-      setTimeout(function () {
+      },
+      function () {
+        chart.load({
+          columns: [
+            ['data8', 30, 20, 50, 40, 60, 50],
+          ],
+          unload: true,
+        });
+      },
+      function () {
+        chart.load({
+          columns: [
+            ['data9', 130, 120, 150, 140, 160, 150],
+          ],
+          unload: ['data7', 'data8'],
+        });
+      },
+      function () {
+        chart.load({
+          unload: ['data1', 'data2'],
+        });
+      },
+      function () {
         chart.unload();
-      }, 8000);
-
-      setTimeout(function () {
+      },
+      function () {
         chart.load({
           rows: [
-            ['data1@test', 'data2', 'data3'],
+            ['data1', 'data2', 'data3'],
             [90, 120, 300],
             [40, 160, 240],
             [50, 200, 290],
@@ -97,11 +113,18 @@
             [90, 220, 320],
           ]
         });
-      }, 9000);
+      },
+      function () {
+        chart.unload({
+          ids: ['data2', 'data3']
+        });
+      },
+    ];
 
-      setTimeout(function () {
-        chart.unload(['data2', 'data3']);
-      }, 10000);
+    var i = 0;
+    queue.forEach(function (f) {
+      setTimeout(f, 1500 * i++);
+    });
 
     </script>
   </body>
diff --git a/htdocs/samples/data_load_timeseries.html b/htdocs/samples/data_load_timeseries.html
index 46d2fcc..947db37 100644
--- a/htdocs/samples/data_load_timeseries.html
+++ b/htdocs/samples/data_load_timeseries.html
@@ -34,7 +34,9 @@
       }, 1000);
 
       setTimeout(function () {
-        chart.unload('data2');
+        chart.unload({
+          ids: 'data2'
+        });
       }, 2000);
 
       setTimeout(function () {
diff --git a/htdocs/samples/simple_region.html b/htdocs/samples/data_region.html
similarity index 92%
rename from htdocs/samples/simple_region.html
rename to htdocs/samples/data_region.html
index dd5aef9..94789e3 100644
--- a/htdocs/samples/simple_region.html
+++ b/htdocs/samples/data_region.html
@@ -6,7 +6,7 @@
     <div id="chart"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
       var chart = c3.generate({
         bindto: '#chart',
diff --git a/htdocs/samples/timeseries_region.html b/htdocs/samples/data_region_timeseries.html
similarity index 92%
rename from htdocs/samples/timeseries_region.html
rename to htdocs/samples/data_region_timeseries.html
index b604621..8e154b5 100644
--- a/htdocs/samples/timeseries_region.html
+++ b/htdocs/samples/data_region_timeseries.html
@@ -6,13 +6,13 @@
     <div id="chart"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
       var chart = c3.generate({
         bindto: '#chart',
         data: {
           x : 'date',
-          x_format : '%Y%m%d',
+          xFormat : '%Y%m%d',
           columns: [
 //            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
             ['date', '20130101', '20130102', '20130103', '20130104', '20130105', '20130106'],
diff --git a/htdocs/samples/data_url.html b/htdocs/samples/data_url.html
index 17dae3b..95b6eb6 100644
--- a/htdocs/samples/data_url.html
+++ b/htdocs/samples/data_url.html
@@ -6,13 +6,54 @@
     <div id="chart"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
         data: {
           url: '/data/c3_test.csv'
         }
       });
+
+      setTimeout(function () {
+        chart.load({
+          url: '/data/c3_test2.csv',
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.load({
+          url: '/data/c3_test.tsv',
+          mimeType: 'tsv'
+        });
+      }, 2000);
+
+      setTimeout(function () {
+        chart = c3.generate({
+          data: {
+            url: '/data/c3_test.json',
+            mimeType: 'json'
+          }
+        });
+      }, 3000);
+
+      setTimeout(function () {
+        chart.load({
+          url: '/data/c3_test_2.json',
+          mimeType: 'json'
+        });
+      }, 4000);
+
+      setTimeout(function () {
+        chart.load({
+          url: '/data/c3_test_3.json',
+          mimeType: 'json',
+          keys: {
+            value: ['data1', 'data2']
+          }
+        });
+      }, 5000);
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/domain_y.html b/htdocs/samples/domain_y.html
new file mode 100644
index 0000000..95c91ce
--- /dev/null
+++ b/htdocs/samples/domain_y.html
@@ -0,0 +1,71 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <button id="btn1">Bar</button>
+    <button id="btn2">Line</button>
+    <button id="btn3">Area</button>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var normalData = {
+          columns: [
+            ['data1', -1030, -1200, 1000],
+            ['data2', -1150, -220, -1110]
+          ],
+          labels: true,
+      },
+      allPositiveData = {
+          columns: [
+            ['data1', 1030, 1200, 1100],
+            ['data2', 2050, 2020, 2010]
+          ],
+          labels: true,
+      },
+      allNegativeData = {
+          columns: [
+            ['data1', -1030, -2200, -2100],
+            ['data2', -1150, -2010, -1200]
+          ],
+          labels: true,
+      }
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: normalData
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: allPositiveData
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: allNegativeData
+      });
+
+      d3.select('#btn1').on('click', function () {
+        chart1.transform('bar');
+        chart2.transform('bar');
+        chart3.transform('bar');
+      });
+      d3.select('#btn2').on('click', function () {
+        chart1.transform('line');
+        chart2.transform('line');
+        chart3.transform('line');
+      });
+      d3.select('#btn3').on('click', function () {
+        chart1.transform('area');
+        chart2.transform('area');
+        chart3.transform('area');
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/element.html b/htdocs/samples/element.html
new file mode 100644
index 0000000..1c28bd9
--- /dev/null
+++ b/htdocs/samples/element.html
@@ -0,0 +1,37 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        data: {
+          columns: [
+            ['sample', 30, 200, 100, null, 150, 250]
+          ],
+        },
+      });
+
+      var chart2 = c3.generate({
+        data: {
+          columns: [
+            ['sample', 30, 200, 100, null, 150, 250]
+          ],
+          type: 'bar'
+        }
+      });
+
+      document.getElementById('chart1').appendChild(chart1.element);
+
+      $('#chart2').append(chart2.element);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/emptydata.html b/htdocs/samples/emptydata.html
new file mode 100644
index 0000000..10bd55f
--- /dev/null
+++ b/htdocs/samples/emptydata.html
@@ -0,0 +1,37 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart = c3.generate({
+        data: {
+          columns: [
+//            ['data1', 100, 200],
+          ],
+          empty: {
+            label: {
+              text: 'No Data'
+            }
+          }
+        },
+        subchart: {
+          show: true
+        }
+      });
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['data1', 100, 200],
+          ],
+        });
+      }, 1000);
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/simple_grid_x_lines.html b/htdocs/samples/grid_focus.html
similarity index 50%
rename from htdocs/samples/simple_grid_x_lines.html
rename to htdocs/samples/grid_focus.html
index 934d97d..ec6bd97 100644
--- a/htdocs/samples/simple_grid_x_lines.html
+++ b/htdocs/samples/grid_focus.html
@@ -3,28 +3,27 @@
     <link rel="stylesheet" type="text/css" href="/css/c3.css">
   </head>
   <body>
-    <div id="chart"></div>
+    <div id="chart1"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
-        bindto: '#chart',
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
         data: {
           columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 130, 300, 200, 300, 250, 150]
           ]
         },
         grid: {
-          x: {
-            lines: [{
-               value: 3,
-               text: '3',
-               class: 'lineFor3'
-            }]
+          focus: {
+            show: false
           }
         }
       });
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/grid_x_lines.html b/htdocs/samples/grid_x_lines.html
index 6f1e3fe..975a641 100644
--- a/htdocs/samples/grid_x_lines.html
+++ b/htdocs/samples/grid_x_lines.html
@@ -3,47 +3,64 @@
     <link rel="stylesheet" type="text/css" href="/css/c3.css">
   </head>
   <body>
-    <div id="chart"></div>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
-        bindto: '#chart',
+        bindto: '#chart1',
         data: {
           columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
-          ]
-        },
-        axis: {
-//          rotated: true,
+            ['data1', 30, 200, 100, 400, 150, 250]
+          ],
+          type: 'bar'
         },
         grid: {
           x: {
-            lines: [{value: 3, text:'Label 3'}, {value: 4.5, text: 'Label 4.5'}]
+            show: true,
+            lines: [{
+               value: 2,
+               text: 'Label 2',
+               class: 'lineFor2'
+            }]
+          },
+          y: {
+            show: true,
           }
         }
       });
 
-      setTimeout(function () {
-        chart.xgrids([{value: 1, text:'Label 1'}, {value: 4, text: 'Label 4'}]);
-      }, 1000);
-
-      setTimeout(function () {
-        chart.xgrids([{value: 2, text:'Label 2'}]);
-      }, 2000);
-
-      setTimeout(function () {
-        chart.xgrids.add([{value: 3, text:'Label 3', class:'hoge'}]);
-      }, 3000);
-
-      setTimeout(function () {
-        chart.xgrids.remove({value:2});
-      }, 4000);
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          x : 'x',
+          columns: [
+            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05'],
+            ['sample', 30, 200, 100, 400, 150]
+          ],
+        },
+        axis : {
+          x : {
+            type : 'timeseries'
+          }
+        },
+        grid: {
+          x: {
+            lines: [{
+               value: '2013-01-04',
+               text: '2013/01/04',
+               class: 'lineFor20130104'
+            }]
+          },
+          lines: {
+            front: false
+          }
+        }
+      });
 
-      setTimeout(function () {
-        chart.xgrids.remove({class:'hoge'});
-      }, 5000);
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/grid_x_lines_timeseries.html b/htdocs/samples/grid_x_lines_timeseries.html
new file mode 100644
index 0000000..d3517ad
--- /dev/null
+++ b/htdocs/samples/grid_x_lines_timeseries.html
@@ -0,0 +1,73 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+    var chart1 = c3.generate({
+      "bindto": "#chart1",
+      "axis": {
+          "x": {
+            "type": "timeseries",
+            "tick": {
+              format: '%Y-%m-%d %H:%M:%S'
+            }
+          }
+      },
+      "grid": {
+          "x": {
+            "lines": [
+                { "value": 1401883200000, "text": new Date(1401883200000), "color": "#f00" },
+            ]
+          }
+      },
+      "data": {
+        "type": "line",
+        "columns": [
+            ["epoch", 1401879600000, 1401883200000, 1401886800000],
+            ["y", 1955, 2419, 2262]
+        ],
+        "xs": {
+            "y": "epoch"
+        }
+      }
+    });
+
+    var chart2 = c3.generate({
+      "bindto": "#chart2",
+      "axis": {
+          "x": {
+            "type": "timeseries",
+            "tick": {
+              format: '%Y-%m-%d %H:%M:%S'
+            }
+          }
+      },
+      "grid": {
+          "x": {
+            "lines": [
+                { "value": new Date(1401883200000), "text": new Date(1401883200000), "color": "#f00" },
+            ]
+          }
+      },
+      "data": {
+        "type": "line",
+        "columns": [
+            ["epoch", 1401879600000, 1401883200000, 1401886800000],
+            ["y", 1955, 2419, 2262]
+        ],
+        "xs": {
+            "y": "epoch"
+        }
+      }
+    });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/grids.html b/htdocs/samples/grids.html
index 04c06da..e0df334 100644
--- a/htdocs/samples/grids.html
+++ b/htdocs/samples/grids.html
@@ -3,30 +3,109 @@
     <link rel="stylesheet" type="text/css" href="/css/c3.css">
   </head>
   <body>
-    <div id="chart"></div>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+    <div id="chart4"></div>
+    <div id="chart5"></div>
+    <div id="chart6"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
-        bindto: '#chart',
+
+      var smallData = [['sample', 30, 200, 100, 400, 150, 250]],
+          bigData = [['sample', 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250]];
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
         data: {
-          columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
-          ]
+          columns: smallData
+        },
+        grid: {
+          x: {
+            show: true
+          },
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: smallData
+        },
+        grid: {
+          y: {
+            show: true
+          }
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: smallData
         },
         axis: {
-//          rotated: true,
+          rotated: true,
         },
         grid: {
           x: {
             show: true
           },
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart4',
+        data: {
+          columns: smallData
+        },
+        axis: {
+          rotated: true,
+        },
+        grid: {
           y: {
             show: true
           }
         }
       });
+
+      c3.generate({
+        bindto: '#chart5',
+        data: {
+          columns: bigData
+        },
+        grid: {
+          x: {
+            show: true
+          },
+          y: {
+            show: true
+          }
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart6',
+        data: {
+          columns: bigData
+        },
+        axis: {
+          x: {
+            type: 'category'
+          }
+        },
+        grid: {
+          x: {
+            show: true
+          },
+          y: {
+            show: true
+          }
+        }
+      });
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/grids_timeseries.html b/htdocs/samples/grids_timeseries.html
new file mode 100644
index 0000000..53095b0
--- /dev/null
+++ b/htdocs/samples/grids_timeseries.html
@@ -0,0 +1,89 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var smallData = [
+        ['x', '2014-01-01', '2014-02-01', '2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01'],
+        ['sample', 30, 200, 100, 400, 150, 250]
+      ],
+      bigData = [
+        ['x', '2014-01-01', '2014-02-01', '2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01', '2014-07-01', '2014-08-01', '2014-09-01', '2014-10-01', '2014-11-01', '2014-12-01'],
+        ['sample', 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250]
+      ];
+
+      c3.generate({
+        bindto: '#chart1',
+        data: {
+          x: 'x',
+          columns: smallData
+        },
+        axis: {
+          x: {
+            type: 'timeseries',
+            tick: {
+              format: "%Y-%m-%d %H:%M:%S"
+            }
+          }
+        },
+        grid: {
+          x: {
+            show: true,
+          },
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart2',
+        data: {
+          x: 'x',
+          columns: smallData
+        },
+        axis: {
+          rotated: true,
+          x: {
+            type: 'timeseries',
+            tick: {
+              format: "%Y-%m-%d %H:%M:%S"
+            }
+          }
+        },
+        grid: {
+          x: {
+            show: true,
+          },
+        }
+      });
+
+      c3.generate({
+        bindto: '#chart3',
+        data: {
+          x: 'x',
+          columns: bigData
+        },
+        axis: {
+          x: {
+            type: 'timeseries',
+            tick: {
+              format: "%Y-%m-%d %H:%M:%S"
+            }
+          }
+        },
+        grid: {
+          x: {
+            show: true
+          }
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/simple_zoom.html b/htdocs/samples/interaction_enabled.html
similarity index 65%
rename from htdocs/samples/simple_zoom.html
rename to htdocs/samples/interaction_enabled.html
index b7a0f08..9e77fea 100644
--- a/htdocs/samples/simple_zoom.html
+++ b/htdocs/samples/interaction_enabled.html
@@ -6,19 +6,18 @@
     <div id="chart"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
+    <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
-        zoom: {
-          enabled: true
-        },
         data: {
           columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
           ]
         },
-        subchart: {
-          show: true
+        interaction: {
+          enabled: false
         }
       });
     </script>
diff --git a/htdocs/samples/interaction_zoom.html b/htdocs/samples/interaction_zoom.html
deleted file mode 100644
index d26868e..0000000
--- a/htdocs/samples/interaction_zoom.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-  <head>
-    <link href="/css/c3.css" rel="stylesheet" type="text/css">
-  </head>
-  <body>
-    <div id="chart"></div>
-
-    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
-    <script>
-      var chart = c3.generate({
-        data: {
-          columns: [
-            ['sample', 30, 200, 100, 400, 150, 250, 150, 200, 170, 240, 350, 150, 100, 400, 150, 250, 150, 200, 170, 240, 100, 150, 250, 150, 200, 170, 240, 30, 200, 100, 400, 150, 250, 150, 200, 170, 240, 350, 150, 100, 400, 350, 220, 250, 300, 270, 140, 150, 90, 150, 50, 120, 70, 40]
-          ]
-        },
-        zoom: {
-          enabled: true
-        }
-      });
-    </script>
-  </body>
-</html>
diff --git a/htdocs/samples/legend.html b/htdocs/samples/legend.html
new file mode 100644
index 0000000..92c99ae
--- /dev/null
+++ b/htdocs/samples/legend.html
@@ -0,0 +1,87 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+    <div id="chart4"></div>
+    <div id="chart5"></div>
+    <div id="chart6"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var columns = [];
+      for (var i = 0; i < 28; i++ ) {
+        columns[i] = ['datahogehogeohgeohoge' + i, 10 * i, 20 * i];
+      }
+
+      c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: columns,
+        },
+      });
+
+      c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: columns,
+        },
+        legend: {
+          position: 'right'
+        },
+      });
+
+      c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: columns,
+        },
+        legend: {
+          position: 'inset',
+        },
+      });
+
+      c3.generate({
+        bindto: '#chart4',
+        data: {
+          columns: columns,
+        },
+        axis: {
+          rotated: true,
+        },
+      });
+
+      c3.generate({
+        bindto: '#chart5',
+        data: {
+          columns: columns,
+        },
+        legend: {
+          position: 'right'
+        },
+        axis: {
+          rotated: true,
+        },
+      });
+
+      c3.generate({
+        bindto: '#chart6',
+        data: {
+          columns: columns,
+        },
+        legend: {
+          position: 'inset'
+        },
+        axis: {
+          rotated: true,
+        },
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/padding.html b/htdocs/samples/padding.html
new file mode 100644
index 0000000..e9f0026
--- /dev/null
+++ b/htdocs/samples/padding.html
@@ -0,0 +1,138 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+<style type="text/css">
+<!--
+.c3 svg {
+/*    font-size: 13px;*/
+}
+-->
+</style>
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
+    <div id="chart4"></div>
+    <div id="chart5"></div>
+    <div id="chart6"></div>
+    <div id="chart7"></div>
+    <div id="chart8"></div>
+    <div id="chart9"></div>
+    <div id="chart10"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var option = {
+        padding: {
+          top: 50,
+          right: 200,
+          bottom: 50,
+          left: 200,
+        },
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 130, 100, 200, 100, 150, 150]
+          ],
+          axes: {
+            data2: 'y2'
+          },
+        },
+        axis: {
+          rotated: true,
+          y: {
+            label: {
+              text: 'Y Label', 
+              position: 'outer-center'
+            }
+          },
+          y2: {
+            show: true,
+            label: {
+              text: 'Y2 Label',
+              position: 'outer-center'
+            }
+          }
+        },
+        legend: {
+          position: 'bottom'
+        },
+        subchart: {
+          show: false
+        },
+        grid: {
+          x: {
+            show: true,
+          },
+          y: {
+            show: true,
+          }
+        }
+      };
+
+
+      option.bindto = '#chart1';
+      var chart1 = c3.generate(option);
+
+      option.bindto = '#chart2';
+      option.legend.position = 'right'
+      var chart2 = c3.generate(option);
+
+      option.bindto = '#chart3';
+      option.legend.position = 'bottom';
+      option.subchart.show = true;
+      var chart3 = c3.generate(option);
+
+      option.bindto = '#chart4';
+      option.legend.position = 'right';
+      option.subchart.show = true;
+      var chart4 = c3.generate(option);
+
+      option.bindto = '#chart5';
+      option.padding = {
+          top: 0,
+          right: 0,
+          bottom: 0,
+          left: 0,
+      };
+      option.subchart.show = false;
+      option.legend.position = 'bottom';
+      var chart5 = c3.generate(option);
+
+
+      option.axis.rotated = false;
+
+      option.bindto = '#chart6';
+      var chart6 = c3.generate(option);
+
+      option.bindto = '#chart7';
+      option.legend.position = 'right'
+      var chart7 = c3.generate(option);
+
+      option.bindto = '#chart8';
+      option.legend.position = 'bottom';
+      option.subchart.show = true;
+      var chart8 = c3.generate(option);
+
+      option.bindto = '#chart9';
+      option.legend.position = 'right';
+      option.subchart.show = true;
+      var chart9 = c3.generate(option);
+
+      option.bindto = '#chart10';
+      option.padding = {
+          top: 0,
+          right: 0,
+          bottom: 0,
+          left: 0,
+      };
+      option.subchart.show = false;
+      option.legend.position = 'bottom';
+      var chart10 = c3.generate(option);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/padding_update.html b/htdocs/samples/padding_update.html
new file mode 100644
index 0000000..37071d9
--- /dev/null
+++ b/htdocs/samples/padding_update.html
@@ -0,0 +1,88 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+    var axis_rotated = true;
+
+    var generate = function () { return c3.generate({
+      data: {
+        x: 'x',
+        columns: [
+            ['x', '2014-01-01', '2014-02-01', '2014-03-01', '2014-04-01'],
+            ['data1', 190, 200, 190, null],
+        ],
+        type: 'bar',
+        labels: {
+            format: function (v, id) {
+                if (v === null) {
+                    return 'Not Applicable';
+                }
+                return d3.format('$')(v);
+            }
+        }
+      },
+      axis: {
+        x: {
+            type: 'categorized'
+        },
+        rotated: axis_rotated
+      },
+    }); }, chart = generate();
+
+    setTimeout(function () {
+      chart.hide();
+    }, 1000);
+
+    setTimeout(function () {
+      chart.show();
+    }, 2000);
+
+    setTimeout(function () {
+      chart.load({
+        columns: [
+          ['data1', 300, 350, 100]
+        ],
+        categories: ['2014-01-01 10:10:10', '2014-02-01 12:30:00', '2014-03-01 16:30:00']
+      });
+    }, 3000);
+
+    setTimeout(function () {
+      chart.load({
+        columns: [
+          ['data1', 50, 100, 150]
+        ],
+        categories: ['2014', '2015', '2016']
+      });
+    }, 4000);
+
+    setTimeout(function () {
+      axis_rotated = false;
+      chart = generate();
+    }, 5000);
+
+    setTimeout(function () {
+      chart.load({
+        columns: [
+          ['data1', 300, 350, 100000]
+        ],
+      });
+    }, 6000);
+
+    setTimeout(function () {
+      chart.load({
+        columns: [
+          ['data1', 50, 100, 150]
+        ],
+      });
+    }, 7000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/plugin.html b/htdocs/samples/plugin.html
new file mode 100644
index 0000000..cba5227
--- /dev/null
+++ b/htdocs/samples/plugin.html
@@ -0,0 +1,27 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+<!--    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>-->
+    <script src="/js/d3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script src="/js/samples/plugin.js"></script>
+    <script>
+      var chart = c3.generate({
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          onclick: function (d, element) { console.log("onclick", d, element); },
+          onmouseover: function (d) { console.log("onmouseover", d); },
+          onmouseout: function (d) { console.log("onmouseout", d); },
+        },
+        test1: 'TEST1',
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/regions.html b/htdocs/samples/regions.html
index 85c9745..0546383 100644
--- a/htdocs/samples/regions.html
+++ b/htdocs/samples/regions.html
@@ -33,7 +33,6 @@
         }
       });
 
-/*
       setTimeout(function () {
         chart.load({
           columns: [
@@ -41,7 +40,48 @@
           ]
         });
       }, 1000);
-*/
+
+      setTimeout(function () {
+        chart.regions([]);
+      }, 2000);
+
+      setTimeout(function () {
+        chart.regions([{start:0.5,end:2.5}]);
+      }, 3000);
+
+      setTimeout(function () {
+        chart.regions.add([{start:4.5}]);
+      }, 4000);
+
+      setTimeout(function () {
+        chart.regions.add([{start:3,end:3.5,class:"region1"}, {start:4,end:4.5,class:"region2"}]);
+      }, 5000);
+
+      setTimeout(function () {
+        chart.regions.remove({classes:['region1', 'region2'], duration: 0});
+      }, 6000);
+
+      setTimeout(function () {
+        chart.regions.add([
+          {start:3,end:3.5,class:"region3 hoge"},
+          {start:4,end:4.5,class:"region4 hoge"},
+          {start:0,end:0.5,class:"region5 hogehoge"},
+        ]);
+      }, 7000);
+
+      setTimeout(function () {
+        chart.regions.remove({classes:['hoge'], duration: 500});
+      }, 8000);
+
+      setTimeout(function () {
+        chart.regions.remove({classes:['hogehoge']});
+      }, 9000);
+
+      setTimeout(function () {
+        chart.regions.remove({});
+      }, 10000);
+
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/regions_timeseries.html b/htdocs/samples/regions_timeseries.html
new file mode 100644
index 0000000..b3fcd23
--- /dev/null
+++ b/htdocs/samples/regions_timeseries.html
@@ -0,0 +1,49 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+var chart = c3.generate({
+    data: {
+        x: 'date',
+        columns: [
+            ['date', '2014-01-01', '2014-01-10', '2014-01-20', '2014-01-30', '2014-02-01'],
+            ['sample', 30, 200, 100, 400, 150, 250]
+        ]
+    },
+    axis: {
+        x: {
+            type: 'timeseries',
+            tick: {
+                format: '%Y%m%d %H:%M:%S'
+            }
+        },
+    },
+    regions: [
+        {start: '2014-01-05', end: '2014-01-10'},
+//        {start: new Date('2014-01-10'), end: new Date('2014-01-15')},
+        {start: 1390608000000, end: 1391040000000}
+    ]
+});
+
+setTimeout(function () {
+    chart.load({
+        columns: [
+            ['date', +new Date('2014-01-01'), +new Date('2014-01-10'), +new Date('2014-03-01')],
+            ['sample', 100, 200, 300]
+        ]
+    });
+    chart.regions([
+        {start: +new Date('2014-01-10'), end: +new Date('2014-01-15')}
+    ]);
+}, 1000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/selection.html b/htdocs/samples/selection.html
index 994af6c..9fc6811 100644
--- a/htdocs/samples/selection.html
+++ b/htdocs/samples/selection.html
@@ -3,12 +3,36 @@
     <link href="/css/c3.css" rel="stylesheet" type="text/css">
   </head>
   <body>
-    <div id="chart"></div>
+    grouped => true, multiple => true
+    <div id="chart1"></div>
+
+    grouped => true, multiple => true, tooltip.grouped = false
+    <div id="chart1-1"></div>
+
+    grouped => true, multiple => false
+    <div id="chart2"></div>
+
+    grouped => true, multiple => false, tooltip.grouped = false
+    <div id="chart2-1"></div>
+
+    grouped => false, multiple => true
+    <div id="chart3"></div>
+
+    grouped => false, multiple => true, tooltip.grouped = false
+    <div id="chart3-1"></div>
+
+    grouped => false, multiple => false
+    <div id="chart4"></div>
+
+    grouped => false, multiple => false, tooltip.grouped = false
+    <div id="chart4-1"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
-      var chart = c3.generate({
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
         data: {
           columns: [
             ['data1', 30, 200, 100, 400, 150, 250],
@@ -17,7 +41,7 @@
           selection: {
             enabled: true,
             grouped: true,
-            multiple: false,
+            multiple: true,
           },
           onclick: function (d, element) { console.log("onclick", d, element); },
           onselected: function (d, element) { console.log("onselected", d, element); },
@@ -26,6 +50,124 @@
           ondragend: function () { console.log("ondragend"); },
         },
       });
+
+      var chart11 = c3.generate({
+        bindto: '#chart1-1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: true,
+            multiple: true,
+          },
+        },
+        tooltip: {
+          grouped: false
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: true,
+            multiple: false,
+          }
+        }
+      });
+
+      var chart21 = c3.generate({
+        bindto: '#chart2-1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: true,
+            multiple: false,
+          }
+        },
+        tooltip: {
+          grouped: false
+        }
+      });
+
+      var chart3 = c3.generate({
+        bindto: '#chart3',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: false,
+            multiple: true,
+          }
+        }
+      });
+
+      var chart31 = c3.generate({
+        bindto: '#chart3-1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: false,
+            multiple: true,
+          }
+        },
+        tooltip: {
+          grouped: false
+        }
+      });
+
+      var chart4 = c3.generate({
+        bindto: '#chart4',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: false,
+            multiple: false,
+          }
+        }
+      });
+
+      var chart41 = c3.generate({
+        bindto: '#chart4-1',
+        data: {
+          columns: [
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
+          ],
+          selection: {
+            enabled: true,
+            grouped: false,
+            multiple: false,
+          }
+        },
+        tooltip: {
+          grouped: false
+        }
+      });
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/simple.html b/htdocs/samples/simple.html
index dc83518..0aeb681 100644
--- a/htdocs/samples/simple.html
+++ b/htdocs/samples/simple.html
@@ -9,14 +9,14 @@
     <script src="/js/c3.js"></script>
     <script>
       var chart = c3.generate({
-        bindto: '#chart',
         data: {
           columns: [
-            ['sample', 30, 200, 100, 400, 150, 250]
+            ['data1', 30, 200, 100, 400, 150, 250],
+            ['data2', 50, 20, 10, 40, 15, 25]
           ],
           onclick: function (d, element) { console.log("onclick", d, element); },
-          onenter: function (d) { console.log("onenter", d); },
-          onleave: function (d) { console.log("onleave", d); },
+          onmouseover: function (d) { console.log("onmouseover", d); },
+          onmouseout: function (d) { console.log("onmouseout", d); },
         }
       });
     </script>
diff --git a/htdocs/samples/multiple_charts.html b/htdocs/samples/subchart.html
similarity index 52%
rename from htdocs/samples/multiple_charts.html
rename to htdocs/samples/subchart.html
index fab25fe..e068043 100644
--- a/htdocs/samples/multiple_charts.html
+++ b/htdocs/samples/subchart.html
@@ -1,60 +1,67 @@
 <html>
   <head>
-    <link href="/css/c3.css" rel="stylesheet" type="text/css">
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
   </head>
   <body>
-    <div id="chart1" style="height:300px;"></div>
-    <div id="chart2" style="height:150px;"></div>
-    <div id="chart3" style="height:150px;"></div>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+    <div id="chart3"></div>
 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
+
       var chart1 = c3.generate({
         bindto: '#chart1',
         data: {
-//          xs: {
-//            'data2': 'data1',
-//          },
           columns: [
-            ['data1', 130, 210, 120, 440, 250, 350],
+            ['data1', 30, 200, 100, 400, 150, 250],
             ['data2', 50, 20, 10, 40, 15, 25]
           ],
-//          type: 'scatter'
-//          type: 'pie'
-          selection: {
-            enabled: true
-          }
+          labels: true
         },
-        zoom: {
-          enabled: true
-        },
-        subchart : {
+        subchart: {
           show: true
-        }
+        },
       });
+
       var chart2 = c3.generate({
         bindto: '#chart2',
         data: {
           columns: [
             ['data1', 30, 200, 100, 400, 150, 250],
-            ['data2', 150, 120, 210, 240, 215, 125]
+            ['data2', 50, 20, 10, 40, 15, 25]
           ],
-//          type: 'scatter'
-//          type: 'pie'
+          labels: true
+        },
+        subchart: {
+          show: true
         },
+        axis: {
+          rotated: true
+        }
       });
+
       var chart3 = c3.generate({
         bindto: '#chart3',
         data: {
           columns: [
             ['data1', 30, 200, 100, 400, 150, 250],
-            ['data2', 550, 520, 510, 540, 515, 525]
+            ['data2', 50, 20, 10, 40, 15, 25]
           ],
-//          type: 'scatter'
-//          type: 'pie'
+          labels: true
+        },
+        axis: {
+          x: {
+            default: [3, 5]
+          }
+        },
+        subchart: {
+          show: true
         },
       });
+
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/subchart_onbrush.html b/htdocs/samples/subchart_onbrush.html
new file mode 100644
index 0000000..2cd2158
--- /dev/null
+++ b/htdocs/samples/subchart_onbrush.html
@@ -0,0 +1,57 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          x : 'x',
+          columns: [
+            ['x', '2013-01-01', '2013-02-01', '2013-03-01', '2013-04-01', '2013-05-01'],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%Y-%m-%d"
+            }
+          }
+        },
+        subchart: {
+          show: true,
+          onbrush: function (domain) {
+            console.log(this, domain);
+          }
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+        },
+        subchart: {
+          show: true,
+          onbrush: function (domain) {
+            console.log(this, domain);
+          }
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/timeseries.html b/htdocs/samples/timeseries.html
index d7c6a16..af1265c 100644
--- a/htdocs/samples/timeseries.html
+++ b/htdocs/samples/timeseries.html
@@ -12,7 +12,7 @@
         bindto: '#chart',
         data: {
           x : 'date',
-          x_format : '%Y%m%d',
+          xFormat : '%Y%m%d',
           columns: [
 //            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
             ['date', '20130101', '20130102', '20130103', '20130104', '20130105', '20130106'],
diff --git a/htdocs/samples/timeseries_date.html b/htdocs/samples/timeseries_date.html
new file mode 100644
index 0000000..475d10c
--- /dev/null
+++ b/htdocs/samples/timeseries_date.html
@@ -0,0 +1,64 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+      var chart = c3.generate({
+        bindto: '#chart',
+        data: {
+          x : 'x',
+          xFormat : '%Y%m%d',
+          columns: [
+            ['x', new Date('2013-01-01 00:00:00'), new Date('2013-01-02 00:00:00'), new Date('2013-01-03 00:00:00'), new Date('2013-01-04 00:00:00'), new Date('2013-01-05 00:00:00'), new Date('2013-01-06 00:00:00')],
+            ['sample', 30, 200, 100, 400, 150, 250],
+            ['sample2', 130, 300, 200, 450, 250, 350]
+          ]
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+//              format : "%m/%d" // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+              format : "%e %b %y" // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+            }
+          }
+        }
+      });
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['sample', 200, 130, 90, 240, 130, 100],
+            ['sample2', 300, 200, 160, 400, 250, 250]
+          ]
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['x', '20140101', '20140201', '20140301', '20140401', '20140501', '20140601'],
+            ['sample', 500, 630, 690, 440, 630, 900],
+            ['sample2', 400, 600, 460, 200, 350, 450]
+          ]
+        });
+      }, 2000);
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['x', new Date('2014-01-02 00:00:00'), new Date('2014-02-02 00:00:00'), new Date('2014-03-02 00:00:00'), new Date('2014-04-02 00:00:00'), new Date('2014-05-02 00:00:00'), new Date('2014-06-02 00:00:00')],
+            ['sample', 500, 630, 690, 440, 630, 900],
+            ['sample2', 400, 600, 460, 200, 350, 450]
+          ]
+        });
+      }, 3000);
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/timeseries_descendent.html b/htdocs/samples/timeseries_descendent.html
new file mode 100644
index 0000000..58246f6
--- /dev/null
+++ b/htdocs/samples/timeseries_descendent.html
@@ -0,0 +1,72 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+<!--    <script src="/js/c3.min.0.1.35.js"></script>-->
+    <script>
+
+      var dates = ['date',
+        1401908040000,
+        1401907980000,
+        1401907920000,
+        1401907860000,
+        1401907800000,
+        1401907740000,
+        1401907680000,
+        1401907620000,
+        1401907560000,
+        1401907500000
+      ];
+
+      var chart = c3.generate({
+        bindto: '#chart',
+        data: {
+          x : 'date',
+          columns: [
+            dates,
+            ['data1', 30, 200, 100, 400, 150, 250, 30, 200, 100, 400],
+            ['data2', 130, 300, 200, 450, 250, 350, 130, 300, 200, 450]
+          ],
+          types: {
+            data1: 'bar',
+          }
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%Y-%m-%d %H:%M:%S"
+            }
+          }
+        }
+      });
+
+/*
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['sample', 200, 130, 90, 240, 130, 100],
+            ['sample2', 300, 200, 160, 400, 250, 250]
+          ]
+        });
+      }, 1000);
+
+      setTimeout(function () {
+        chart.load({
+          columns: [
+            ['date', '20140101', '20140201', '20140301', '20140401', '20140501', '20140601'],
+            ['sample', 500, 630, 690, 440, 630, 900],
+            ['sample2', 400, 600, 460, 200, 350, 450]
+          ]
+        });
+      }, 2000);
+
+*/
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/timeseries_grid_x_lines.html b/htdocs/samples/timeseries_grid_x_lines.html
deleted file mode 100644
index 9abdb91..0000000
--- a/htdocs/samples/timeseries_grid_x_lines.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="/css/c3.css">
-  </head>
-  <body>
-    <div id="chart"></div>
-
-    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
-    <script src="/js/c3.min.js"></script>
-    <script>
-      var chart = c3.generate({
-        bindto: '#chart',
-        data: {
-          x : 'date',
-          x_format : '%Y%m%d',
-          columns: [
-//            ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
-            ['date', '20130101', '20130102', '20130103', '20130104', '20130105', '20130106'],
-            ['sample', 30, 200, 100, 400, 150, 250]
-          ]
-        },
-        axis : {
-          x : {
-            type : 'timeseries'
-          }
-        },
-        grid: {
-          x: {
-            lines: [{
-               value: '20130104',
-               text: '2013/01/04',
-               class: 'lineFor20130104'
-            }]
-          }
-        }
-      });
-    </script>
-  </body>
-</html>
diff --git a/htdocs/samples/timeseries_raw.html b/htdocs/samples/timeseries_raw.html
new file mode 100644
index 0000000..06d61f3
--- /dev/null
+++ b/htdocs/samples/timeseries_raw.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var rows = [["x","Views","GMV"]];
+      rows = rows.concat([[1398709800000,780,136],
+              [1398450600000,812,134],
+              [1399401000000,784,154],
+              [1399228200000,786,135],
+              [1399573800000,802,131],
+              [1399487400000,773,166],
+              [1399314600000,787,146],
+              [1399919400000,1496,309],
+              [1399833000000,767,138],
+              [1399746600000,797,141],
+              [1399660200000,796,146],
+              [1398623400000,779,143],
+              [1399055400000,794,140],
+              [1398969000000,791,140],
+              [1398882600000,825,107],
+              [1399141800000,786,136],
+              [1398537000000,773,143],
+              [1398796200000,783,154],
+              [1400005800000,1754,284]].sort(function (a, b) {
+        return a[0] - b[0];
+      }));
+
+      var chart = c3.generate({
+        bindto: '#chart',
+        data: {
+          x : 'x',
+          rows: rows
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%Y-%m-%d" // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
+            }
+          }
+        }
+      });
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/simple_multiple.html b/htdocs/samples/tooltip_grouped.html
similarity index 79%
rename from htdocs/samples/simple_multiple.html
rename to htdocs/samples/tooltip_grouped.html
index 0b34ac1..6f77562 100644
--- a/htdocs/samples/simple_multiple.html
+++ b/htdocs/samples/tooltip_grouped.html
@@ -8,6 +8,7 @@
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
     <script src="/js/c3.js"></script>
     <script>
+
       var chart = c3.generate({
         data: {
           columns: [
@@ -16,15 +17,10 @@
           ]
         },
         tooltip: {
-//          enabled: false
-        },
-        zoom: {
-//          enabled: true
-        },
-        subchart: {
-//          show: true
+          grouped: false
         }
       });
+
     </script>
   </body>
 </html>
diff --git a/htdocs/samples/simple_tooltip_show.html b/htdocs/samples/tooltip_show.html
similarity index 100%
rename from htdocs/samples/simple_tooltip_show.html
rename to htdocs/samples/tooltip_show.html
diff --git a/htdocs/samples/zoom.html b/htdocs/samples/zoom.html
new file mode 100644
index 0000000..73af5ab
--- /dev/null
+++ b/htdocs/samples/zoom.html
@@ -0,0 +1,71 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <button onclick="load()">Load</button>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          columns: [
+            generateData(100)
+          ],
+        },
+        axis: {
+          x: {
+            default: [30, 60]
+          }
+        },
+        zoom: {
+          enabled: true,
+          onzoomstart: function (event) {
+            console.log("onzoomstart", event);
+          },
+          onzoomend: function (domain) {
+            console.log("onzoomend", domain);
+          },
+        },
+        subchart: { show: true }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            generateData(100)
+          ],
+        },
+        axis: {
+          x: {
+            default: [30, 60]
+          }
+        },
+        zoom: { enabled: true },
+      });
+
+      function load() {
+        chart1.load({
+          columns: [
+            generateData(Math.random() * 1000)
+          ],
+        });
+      }
+
+      function generateData(n) {
+        var column = ['sample'];
+        for (var i = 0; i < n; i++) {
+          column.push(Math.random() * 500);
+        }
+        return column;
+      }
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/zoom_category.html b/htdocs/samples/zoom_category.html
new file mode 100644
index 0000000..e8e7e24
--- /dev/null
+++ b/htdocs/samples/zoom_category.html
@@ -0,0 +1,47 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart"></div>
+    <button onclick="load()">Load</button>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart = c3.generate({
+        bindto: '#chart',
+        data: {
+          columns: [
+            generateData(100)
+          ],
+        },
+        axis: {
+          x: {
+            type: 'category'
+          }
+        },
+        zoom: { enabled: true },
+        subchart: { show: true }
+      });
+
+      function load() {
+        chart.load({
+          columns: [
+            generateData(Math.random() * 1000)
+          ],
+        });
+      }
+
+      function generateData(n) {
+        var column = ['sample'];
+        for (var i = 0; i < n; i++) {
+          column.push(Math.random() * 500);
+        }
+        return column;
+      }
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/zoom_onzoom.html b/htdocs/samples/zoom_onzoom.html
new file mode 100644
index 0000000..f79e5ba
--- /dev/null
+++ b/htdocs/samples/zoom_onzoom.html
@@ -0,0 +1,57 @@
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="/css/c3.css">
+  </head>
+  <body>
+    <div id="chart1"></div>
+    <div id="chart2"></div>
+
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script>
+
+      var chart1 = c3.generate({
+        bindto: '#chart1',
+        data: {
+          x : 'x',
+          columns: [
+            ['x', '2013-01-01', '2013-02-01', '2013-03-01', '2013-04-01', '2013-05-01'],
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+        },
+        axis : {
+          x : {
+            type : 'timeseries',
+            tick : {
+              format : "%Y-%m-%d"
+            }
+          }
+        },
+        zoom: {
+          enabled: true,
+          onzoom: function (domain) {
+            console.log(this, domain);
+          }
+        }
+      });
+
+      var chart2 = c3.generate({
+        bindto: '#chart2',
+        data: {
+          columns: [
+            ['sample', 30, 200, 100, 400, 150],
+            ['sample2', 130, 300, 200, 450, 250]
+          ]
+        },
+        zoom: {
+          enabled: true,
+          onzoom: function (domain) {
+            console.log(this, domain);
+          }
+        }
+      });
+
+    </script>
+  </body>
+</html>
diff --git a/htdocs/samples/zoom_reduction.html b/htdocs/samples/zoom_reduction.html
new file mode 100644
index 0000000..4a9873a
--- /dev/null
+++ b/htdocs/samples/zoom_reduction.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>c3ext</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="shortcut icon" href="/images/logo_128.ico" />
+    <link href="/css/c3.css" rel="stylesheet" />
+    <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
+    <script src="https://rawgithub.com/brandonaaron/jquery-mousewheel/master/jquery.mousewheel.min.js"></script>
+    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+    <script src="/js/c3.js"></script>
+    <script src="/js/extensions/c3ext.js"></script>
+    <script src="/js/samples/zoom_reduction.js"></script>
+</head>
+<body onload="main()">
+    <div class="container-fluid">
+        <h1>C3 DataSet Reduction by Zoom Level</h1>
+        <h2>Hackathon May 2014</h2>
+        <h4>By Dan-el Khen</h4>
+        <p>Rendering graphs in the browser has many advantages, the downside is that takes a long time to render when having large datasets. </p>
+        <p>This feature allows you reduces the dataset according to your current zoom level. 
+        It allows the developer to implement the reduction algorithm in a simple function that accepts an array of values, and returns a reduced single value.
+        The default reducer will take the first item, but avg/sum/first/last or any other algorithm is simple to implement.
+        </p>
+        <h3>Example</h3>
+        <p>
+            In the following example, we'll render 10K data points, each time we'll reduce those to about 100 items (depending on available size on your screen),
+            when zooming in, the resolution of the data will be better and more accurate. This would help in showing the big picture, even when the amount of data is bigger than the numbers of pixels on the screen.
+        </p>
+        <p>Click on the buttons or scroll with your mouse wheel inside the graph to zoom and/or pan.</p>
+        <pre id="status"></pre>
+        <div>
+            <button onclick="chart.zoom2.zoomIn()">zoomIn</button>
+            <button onclick="chart.zoom2.zoomOut()">zoomOut</button>
+            <button onclick="chart.zoom2.panLeft()">panLeft</button>
+            <button onclick="chart.zoom2.panRight()">panRight</button>
+            <button onclick="chart.zoom2.enhance()">enhance</button>
+            <button onclick="chart.zoom2.dehance()">dehance</button>
+            <button onclick="chart.zoom2.reset()">reset</button>
+        </div>
+        <div id="divChart" style="height:300px"></div>
+        <h3>Notes</h3>
+        <p>Only 'columns' data format is supported for now.</p>
+    </div>
+</body>
+</html>
diff --git a/package.json b/package.json
index f43f502..a05749f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "c3",
-  "version": "0.1.34",
+  "version": "0.4.6",
   "description": "D3-based reusable chart library",
   "main": "c3.js",
   "scripts": {
@@ -19,11 +19,17 @@
   "license": "MIT",
   "gitHead": "84e03109d9a590f9c8ef687c03d751f666080c6f",
   "readmeFilename": "README.md",
+  "dependencies": {
+    "d3": "~3.4.4"
+  },
   "devDependencies": {
     "grunt": "~0.4.1",
+    "grunt-contrib-concat": "~0.5.0",
+    "grunt-contrib-cssmin": "^0.10.0",
+    "grunt-contrib-jasmine": "~0.8.0",
     "grunt-contrib-jshint": "~0.7.1",
-    "grunt-contrib-jasmine": "~0.5.2",
-    "load-grunt-tasks": "~0.2.0",
-    "grunt-contrib-uglify": "~0.4.0"
+    "grunt-contrib-uglify": "~0.4.0",
+    "grunt-contrib-watch": "^0.6.1",
+    "load-grunt-tasks": "~0.2.0"
   }
 }
diff --git a/spec/api.data-spec.js b/spec/api.data-spec.js
new file mode 100644
index 0000000..2e7bd25
--- /dev/null
+++ b/spec/api.data-spec.js
@@ -0,0 +1,170 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 api data', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 5000, 2000, 1000, 4000, 1500, 2500]
+            ],
+            names: {
+                data1: 'Data Name 1',
+                data2: 'Data Name 2'
+            },
+            colors: {
+                data1: '#FF0000',
+                data2: '#00FF00'
+            },
+            axes: {
+                data1: 'y',
+                data2: 'y2'
+            }
+        },
+        axis: {
+            y2: {
+                show: true
+            }
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('data()', function () {
+
+        it('should return all of data if no argument given', function () {
+            var results = chart.data(),
+                expected = ['data1', 'data2'];
+            results.forEach(function (result, i) {
+                expect(result.id).toBe(expected[i]);
+            });
+        });
+
+        it('should return specifid data if string argument given', function () {
+            var results = chart.data('data1');
+            expect(results.length).toBe(1);
+            expect(results[0].id).toBe('data1');
+        });
+
+        it('should return specifid data if array argument given', function () {
+            var results = chart.data(['data1', 'data2']);
+            expect(results.length).toBe(2);
+            expect(results[0].id).toBe('data1');
+            expect(results[1].id).toBe('data2');
+        });
+
+    });
+
+    describe('data.shown()', function () {
+
+        it('should return only shown targets', function () {
+            var results;
+            chart.hide('data1');
+            results = chart.data.shown();
+            expect(results.length).toBe(1);
+            expect(results[0].id).toBe('data2');
+        });
+
+    });
+
+    describe('data.values()', function () {
+
+        it('should return values for specified target', function () {
+            var values = chart.data.values('data1'),
+                expectedValues = [30, 200, 100, 400, 150, 250];
+            expect(values.length).toBe(6);
+            values.forEach(function (v, i) {
+                expect(v).toBe(expectedValues[i]);
+            });
+        });
+
+        it('should return null when no args', function () {
+            var values = chart.data.values();
+            expect(values).toBeNull();
+        });
+
+    });
+
+    describe('data.names()', function () {
+
+        it('should return data.names specified as argument', function () {
+            var results = chart.data.names();
+            expect(results.data1).toBe('Data Name 1');
+            expect(results.data2).toBe('Data Name 2');
+        });
+
+        it('should return data.names specified as api', function () {
+            var results = chart.data.names({
+                data1: 'New Data Name 1',
+                data2: 'New Data Name 2'
+            });
+            expect(results.data1).toBe('New Data Name 1');
+            expect(results.data2).toBe('New Data Name 2');
+        });
+
+        it('should set data.names specified as api', function () {
+            expect(d3.select('.c3-legend-item-data1 text').text()).toBe("New Data Name 1");
+            expect(d3.select('.c3-legend-item-data2 text').text()).toBe("New Data Name 2");
+        });
+
+    });
+
+    describe('data.colors()', function () {
+
+        it('should return data.colors specified as argument', function () {
+            var results = chart.data.colors();
+            expect(results.data1).toBe('#FF0000');
+            expect(results.data2).toBe('#00FF00');
+        });
+
+        it('should return data.colors specified as api', function () {
+            var results = chart.data.colors({
+                data1: '#00FF00',
+                data2: '#FF0000'
+            });
+            expect(results.data1).toBe('#00FF00');
+            expect(results.data2).toBe('#FF0000');
+        });
+
+        it('should set data.colors specified as api', function () {
+            expect(d3.select('.c3-line-data1').style('stroke')).toBe("#00ff00");
+            expect(d3.select('.c3-line-data2').style('stroke')).toBe("#ff0000");
+            expect(d3.select('.c3-legend-item-data1 .c3-legend-item-tile').style('fill')).toBe("#00ff00");
+            expect(d3.select('.c3-legend-item-data2 .c3-legend-item-tile').style('fill')).toBe("#ff0000");
+        });
+
+    });
+
+    describe('data.axes()', function () {
+
+        it('should return data.axes specified as argument', function () {
+            var results = chart.data.axes();
+            expect(results.data1).toBe('y');
+            expect(results.data2).toBe('y2');
+            expect(d3.select('.c3-axis-y g.tick text').text()).toBe('0');
+            expect(d3.select('.c3-axis-y2 g.tick text').text()).toBe('1000');
+        });
+
+        it('should return data.axes specified as api', function () {
+            var results = chart.data.axes({
+                data1: 'y2',
+                data2: 'y'
+            });
+            expect(results.data1).toBe('y2');
+            expect(results.data2).toBe('y');
+            expect(d3.select('.c3-axis-y g.tick text').text()).toBe('1000');
+            expect(d3.select('.c3-axis-y2 g.tick text').text()).toBe('0');
+        });
+
+    });
+
+});
diff --git a/spec/api.focus-spec.js b/spec/api.focus-spec.js
new file mode 100644
index 0000000..bc41a33
--- /dev/null
+++ b/spec/api.focus-spec.js
@@ -0,0 +1,371 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 api load', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400],
+                ['data2', 1000, 800, 500, 2000],
+                ['data3', 5000, 2000, 1000, 4000]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('focus', function () {
+
+        it('should focus all targets', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus();
+            setTimeout(function () {
+                var targets = main.select('.c3-chart-line.c3-target'),
+                    legendItems = legend.select('.c3-legend-item');
+                targets.each(function () {
+                    var line = d3.select(this);
+                    expect(line.classed('c3-focused')).toBeTruthy();
+                });
+                legendItems.each(function () {
+                    var item = d3.select(this);
+                    expect(item.classed('c3-legend-item-focused')).toBeTruthy();
+                });
+                done();
+            }, 500);
+        });
+
+        it('should focus one target', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus('data2');
+            setTimeout(function () {
+                var targets = {
+                    data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                    data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                    data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                },
+                legendItems = {
+                    data1: legend.select('.c3-legend-item-data1'),
+                    data2: legend.select('.c3-legend-item-data2'),
+                    data3: legend.select('.c3-legend-item-data3')
+                };
+                expect(targets.data1.classed('c3-focused')).toBeFalsy();
+                expect(targets.data2.classed('c3-focused')).toBeTruthy();
+                expect(targets.data3.classed('c3-focused')).toBeFalsy();
+                expect(legendItems.data1.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(legendItems.data2.classed('c3-legend-item-focused')).toBeTruthy();
+                expect(legendItems.data3.classed('c3-legend-item-focused')).toBeFalsy();
+                done();
+            }, 500);
+        });
+
+        it('should focus multiple targets', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus(['data1', 'data2']);
+            setTimeout(function () {
+                var targets = {
+                    data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                    data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                    data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                },
+                legendItems = {
+                    data1: legend.select('.c3-legend-item-data1'),
+                    data2: legend.select('.c3-legend-item-data2'),
+                    data3: legend.select('.c3-legend-item-data3')
+                };
+                expect(targets.data1.classed('c3-focused')).toBeTruthy();
+                expect(targets.data2.classed('c3-focused')).toBeTruthy();
+                expect(targets.data3.classed('c3-focused')).toBeFalsy();
+                expect(legendItems.data1.classed('c3-legend-item-focused')).toBeTruthy();
+                expect(legendItems.data2.classed('c3-legend-item-focused')).toBeTruthy();
+                expect(legendItems.data3.classed('c3-legend-item-focused')).toBeFalsy();
+                done();
+            }, 500);
+        });
+
+    });
+
+    describe('defocus', function () {
+
+        it('should defocus all targets', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus();
+            setTimeout(function () {
+                var targets = main.select('.c3-chart-line.c3-target'),
+                    legendItems = legend.select('.c3-legend-item');
+                targets.each(function () {
+                    var line = d3.select(this);
+                    expect(line.classed('c3-focused')).toBeFalsy();
+                    expect(line.classed('c3-defocused')).toBeTruthy();
+                });
+                legendItems.each(function () {
+                    var item = d3.select(this);
+                    expect(item.classed('c3-legend-item-focused')).toBeFalsy();
+                    expect(+item.style('opacity')).toBeCloseTo(0.3);
+                });
+                done();
+            }, 500);
+        });
+
+        it('should defocus one target', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus('data2');
+            setTimeout(function () {
+                var targets = {
+                    data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                    data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                    data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                },
+                legendItems = {
+                    data1: legend.select('.c3-legend-item-data1'),
+                    data2: legend.select('.c3-legend-item-data2'),
+                    data3: legend.select('.c3-legend-item-data3')
+                };
+                expect(targets.data1.classed('c3-defocused')).toBeFalsy();
+                expect(targets.data2.classed('c3-defocused')).toBeTruthy();
+                expect(targets.data3.classed('c3-defocused')).toBeFalsy();
+                expect(legendItems.data1.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(legendItems.data2.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(legendItems.data3.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(+legendItems.data1.style('opacity')).toBeCloseTo(1);
+                expect(+legendItems.data2.style('opacity')).toBeCloseTo(0.3);
+                expect(+legendItems.data3.style('opacity')).toBeCloseTo(1);
+                done();
+            }, 500);
+        });
+
+        it('should defocus multiple targets', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus(['data1', 'data2']);
+            setTimeout(function () {
+                var targets = {
+                    data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                    data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                    data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                },
+                legendItems = {
+                    data1: legend.select('.c3-legend-item-data1'),
+                    data2: legend.select('.c3-legend-item-data2'),
+                    data3: legend.select('.c3-legend-item-data3')
+                };
+                expect(targets.data1.classed('c3-defocused')).toBeTruthy();
+                expect(targets.data2.classed('c3-defocused')).toBeTruthy();
+                expect(targets.data3.classed('c3-defocused')).toBeFalsy();
+                expect(legendItems.data1.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(legendItems.data2.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(legendItems.data3.classed('c3-legend-item-focused')).toBeFalsy();
+                expect(+legendItems.data1.style('opacity')).toBeCloseTo(0.3);
+                expect(+legendItems.data2.style('opacity')).toBeCloseTo(0.3);
+                expect(+legendItems.data3.style('opacity')).toBeCloseTo(1);
+                done();
+            }, 500);
+        });
+
+        it('should defocus multiple targets after focused', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus();
+            setTimeout(function () {
+                chart.defocus(['data1', 'data2']);
+                setTimeout(function () {
+                    var targets = {
+                        data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                        data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                        data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                    },
+                    legendItems = {
+                        data1: legend.select('.c3-legend-item-data1'),
+                        data2: legend.select('.c3-legend-item-data2'),
+                        data3: legend.select('.c3-legend-item-data3')
+                    };
+                    expect(targets.data1.classed('c3-defocused')).toBeTruthy();
+                    expect(targets.data2.classed('c3-defocused')).toBeTruthy();
+                    expect(targets.data3.classed('c3-defocused')).toBeFalsy();
+                    expect(legendItems.data1.classed('c3-legend-item-focused')).toBeFalsy();
+                    expect(legendItems.data2.classed('c3-legend-item-focused')).toBeFalsy();
+                    expect(legendItems.data3.classed('c3-legend-item-focused')).toBeTruthy();
+                    expect(+legendItems.data1.style('opacity')).toBeCloseTo(0.3);
+                    expect(+legendItems.data2.style('opacity')).toBeCloseTo(0.3);
+                    expect(+legendItems.data3.style('opacity')).toBeCloseTo(1);
+                    done();
+                }, 500);
+            });
+        }, 500);
+
+    });
+
+    describe('revert', function () {
+
+        it('should revert all targets after focus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus();
+            setTimeout(function () {
+                chart.revert();
+                setTimeout(function () {
+                    var targets = main.select('.c3-chart-line.c3-target'),
+                        legendItems = legend.select('.c3-legend-item');
+                    targets.each(function () {
+                        var line = d3.select(this);
+                        expect(line.classed('c3-focused')).toBeFalsy();
+                    });
+                    legendItems.each(function () {
+                        var item = d3.select(this);
+                        expect(+item.style('opacity')).toBeCloseTo(1);
+                    });
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+        it('should revert all targets after defocus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus();
+            setTimeout(function () {
+                chart.revert();
+                setTimeout(function () {
+                    var targets = main.select('.c3-chart-line.c3-target'),
+                        legendItems = legend.select('.c3-legend-item');
+                    targets.each(function () {
+                        var line = d3.select(this);
+                        expect(line.classed('c3-defocused')).toBeFalsy();
+                    });
+                    legendItems.each(function () {
+                        var item = d3.select(this);
+                        expect(+item.style('opacity')).toBeCloseTo(1);
+                    });
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+        it('should revert one target after focus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus();
+            setTimeout(function () {
+                chart.revert('data2');
+                setTimeout(function () {
+                    var targets = {
+                        data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                        data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                        data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                    },
+                    legendItems = {
+                        data1: legend.select('.c3-legend-item-data1'),
+                        data2: legend.select('.c3-legend-item-data2'),
+                        data3: legend.select('.c3-legend-item-data3')
+                    };
+                    expect(targets.data1.classed('c3-focused')).toBeTruthy();
+                    expect(targets.data2.classed('c3-focused')).toBeFalsy();
+                    expect(targets.data3.classed('c3-focused')).toBeTruthy();
+                    expect(+legendItems.data1.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data2.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data3.style('opacity')).toBeCloseTo(1);
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+        it('should revert one target after defocus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus();
+            setTimeout(function () {
+                chart.revert('data2');
+                setTimeout(function () {
+                    var targets = {
+                        data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                        data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                        data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                    },
+                    legendItems = {
+                        data1: legend.select('.c3-legend-item-data1'),
+                        data2: legend.select('.c3-legend-item-data2'),
+                        data3: legend.select('.c3-legend-item-data3')
+                    };
+                    expect(targets.data1.classed('c3-defocused')).toBeTruthy();
+                    expect(targets.data2.classed('c3-defocused')).toBeFalsy();
+                    expect(targets.data3.classed('c3-defocused')).toBeTruthy();
+                    expect(+legendItems.data1.style('opacity')).toBeCloseTo(0.3);
+                    expect(+legendItems.data2.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data3.style('opacity')).toBeCloseTo(0.3);
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+        it('should focus multiple targets after focus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.focus();
+            setTimeout(function () {
+                chart.revert(['data1', 'data2']);
+                setTimeout(function () {
+                    var targets = {
+                        data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                        data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                        data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                    },
+                    legendItems = {
+                        data1: legend.select('.c3-legend-item-data1'),
+                        data2: legend.select('.c3-legend-item-data2'),
+                        data3: legend.select('.c3-legend-item-data3')
+                    };
+                    expect(targets.data1.classed('c3-focused')).toBeFalsy();
+                    expect(targets.data2.classed('c3-focused')).toBeFalsy();
+                    expect(targets.data3.classed('c3-focused')).toBeTruthy();
+                    expect(+legendItems.data1.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data2.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data3.style('opacity')).toBeCloseTo(1);
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+        it('should focus multiple targets after defocus', function (done) {
+            var main = chart.internal.main,
+                legend = chart.internal.legend;
+            chart.defocus();
+            setTimeout(function () {
+                chart.revert(['data1', 'data2']);
+                setTimeout(function () {
+                    var targets = {
+                        data1: main.select('.c3-chart-line.c3-target.c3-target-data1'),
+                        data2: main.select('.c3-chart-line.c3-target.c3-target-data2'),
+                        data3: main.select('.c3-chart-line.c3-target.c3-target-data3')
+                    },
+                    legendItems = {
+                        data1: legend.select('.c3-legend-item-data1'),
+                        data2: legend.select('.c3-legend-item-data2'),
+                        data3: legend.select('.c3-legend-item-data3')
+                    };
+                    expect(targets.data1.classed('c3-defocused')).toBeFalsy();
+                    expect(targets.data2.classed('c3-defocused')).toBeFalsy();
+                    expect(targets.data3.classed('c3-defocused')).toBeTruthy();
+                    expect(+legendItems.data1.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data2.style('opacity')).toBeCloseTo(1);
+                    expect(+legendItems.data3.style('opacity')).toBeCloseTo(0.3);
+                    done();
+                }, 500);
+            }, 500);
+        });
+
+    });
+
+});
diff --git a/spec/api.grid-spec.js b/spec/api.grid-spec.js
new file mode 100644
index 0000000..605cf4d
--- /dev/null
+++ b/spec/api.grid-spec.js
@@ -0,0 +1,122 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 api grid', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('ygrid.add and ygrid.remove', function () {
+
+        it('should update y grids', function (done) {
+            var main = chart.internal.main,
+                expectedGrids = [
+                    {
+                        value: 100,
+                        text: 'Pressure Low'
+                    },
+                    {
+                        value: 200,
+                        text: 'Pressure High'
+                    }
+                ],
+                grids;
+
+            // Call ygrids.add
+            chart.ygrids.add(expectedGrids);
+            setTimeout(function () {
+                grids = main.selectAll('.c3-ygrid-line');
+                expect(grids.size()).toBe(expectedGrids.length);
+                grids.each(function (d, i) {
+                    var y = +d3.select(this).select('line').attr('y1'),
+                        text = d3.select(this).select('text').text(),
+                        expectedY = Math.round(chart.internal.y(expectedGrids[i].value)),
+                        expectedText = expectedGrids[i].text;
+                    expect(y).toBe(expectedY);
+                    expect(text).toBe(expectedText);
+                });
+
+                // Call ygrids.remove
+                chart.ygrids.remove(expectedGrids);
+                setTimeout(function () {
+                    grids = main.selectAll('.c3-ygrid-line');
+                    expect(grids.size()).toBe(0);
+                }, 500);
+
+            }, 500);
+
+            setTimeout(function () {
+                done();
+            }, 1200);
+        });
+
+        it("should update x ygrids even if it's zoomed", function (done) {
+            var main = chart.internal.main,
+                expectedGrids = [
+                    {
+                        value: 0,
+                        text: 'Pressure Low'
+                    },
+                    {
+                        value: 1,
+                        text: 'Pressure High'
+                    }
+                ],
+                grids, domain;
+
+            chart.zoom([0, 2]);
+            setTimeout(function () {
+
+                // Call xgrids
+                chart.xgrids(expectedGrids);
+                setTimeout(function () {
+                    grids = main.selectAll('.c3-xgrid-line');
+                    expect(grids.size()).toBe(expectedGrids.length);
+                    grids.each(function (d, i) {
+                        var x = +d3.select(this).select('line').attr('x1'),
+                            text = d3.select(this).select('text').text(),
+                            expectedX = Math.round(chart.internal.x(expectedGrids[i].value)),
+                            expectedText = expectedGrids[i].text;
+                        expect(x).toBe(expectedX);
+                        expect(text).toBe(expectedText);
+                    });
+
+                    // check if it was not rescaled
+                    domain = chart.internal.y.domain();
+                    expect(domain[0]).toBeLessThan(0);
+                    expect(domain[1]).toBeGreaterThan(400);
+
+                    // Call xgrids.remove
+                    chart.xgrids.remove(expectedGrids);
+                    setTimeout(function () {
+                        grids = main.selectAll('.c3-xgrid-line');
+                        expect(grids.size()).toBe(0);
+                    }, 500); // for xgrids.remove()
+
+                }, 500); // for xgrids()
+
+            }, 500); // for zoom
+
+            setTimeout(function () {
+                done();
+            }, 1700);
+        });
+
+    });
+
+});
diff --git a/spec/api.load-spec.js b/spec/api.load-spec.js
new file mode 100644
index 0000000..20193b7
--- /dev/null
+++ b/spec/api.load-spec.js
@@ -0,0 +1,124 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 api load', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 5000, 2000, 1000, 4000, 1500, 2500]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('indexed data', function () {
+
+        describe('as column', function () {
+
+            it('should load additional data', function (done) {
+                var main = chart.internal.main,
+                    legend = chart.internal.legend;
+                chart.load({
+                    columns: [
+                        ['data3', 800, 500, 900, 500, 1000, 700]
+                    ]
+                });
+                setTimeout(function () {
+                    var target = main.select('.c3-chart-line.c3-target.c3-target-data3'),
+                        legendItem = legend.select('.c3-legend-item.c3-legend-item-data3');
+                    expect(target.size()).toBe(1);
+                    expect(legendItem.size()).toBe(1);
+                    done();
+                }, 500);
+            });
+
+        });
+
+    });
+
+    describe('category data', function () {
+
+        it('should update arg to category data', function () {
+            args = {
+                data: {
+                    x: 'x',
+                    columns: [
+                        ['x', 'cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6'],
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 5000, 2000, 1000, 4000, 1500, 2500]
+                    ]
+                },
+                axis: {
+                    x: {
+                        type: 'category'
+                    }
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        describe('as column', function () {
+
+            it('should load additional data', function (done) {
+                var main = chart.internal.main,
+                    legend = chart.internal.legend;
+                chart.load({
+                    columns: [
+                        ['data3', 800, 500, 900, 500, 1000, 700]
+                    ]
+                });
+                setTimeout(function () {
+                    var target = main.select('.c3-chart-line.c3-target.c3-target-data3'),
+                        legendItem = legend.select('.c3-legend-item.c3-legend-item-data3'),
+                        tickTexts = main.selectAll('.c3-axis-x g.tick text'),
+                        expected = ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6'];
+                    expect(target.size()).toBe(1);
+                    expect(legendItem.size()).toBe(1);
+                    tickTexts.each(function (d, i) {
+                        var text = d3.select(this).select('tspan').text();
+                        expect(text).toBe(expected[i]);
+                    });
+                    done();
+                }, 500);
+            });
+
+            it('should load additional data', function (done) {
+                var main = chart.internal.main,
+                    legend = chart.internal.legend;
+                chart.load({
+                    columns: [
+                        ['x', 'new1', 'new2', 'new3', 'new4', 'new5', 'new6'],
+                        ['data3', 800, 500, 900, 500, 1000, 700]
+                    ]
+                });
+                setTimeout(function () {
+                    var target = main.select('.c3-chart-line.c3-target.c3-target-data3'),
+                        legendItem = legend.select('.c3-legend-item.c3-legend-item-data3'),
+                        tickTexts = main.selectAll('.c3-axis-x g.tick text'),
+                        expected = ['new1', 'new2', 'new3', 'new4', 'new5', 'new6'];
+                    expect(target.size()).toBe(1);
+                    expect(legendItem.size()).toBe(1);
+                    tickTexts.each(function (d, i) {
+                        var text = d3.select(this).select('tspan').text();
+                        expect(text).toBe(expected[i]);
+                    });
+                    done();
+                }, 500);
+            });
+
+        });
+
+    });
+
+});
diff --git a/spec/api.zoom-spec.js b/spec/api.zoom-spec.js
new file mode 100644
index 0000000..bab4814
--- /dev/null
+++ b/spec/api.zoom-spec.js
@@ -0,0 +1,126 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 api zoom', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ]
+        },
+        zoom: {
+            enabled: true
+        }
+    };
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            window.initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+//        chart.internal.d3.select('.jasmine_html-reporter').style('display', 'none');
+
+        window.setTimeout(function () {
+            done();
+        }, 10);
+    });
+
+    describe('zoom', function () {
+
+        it('should be zoomed properly', function () {
+            var target = [3, 5], domain;
+            chart.zoom(target);
+            domain = chart.internal.x.domain();
+            expect(domain[0]).toBe(target[0]);
+            expect(domain[1]).toBe(target[1]);
+        });
+
+        it('should be zoomed properly again', function () {
+            var target = [1, 4], domain;
+            chart.zoom(target);
+            domain = chart.internal.x.domain();
+            expect(domain[0]).toBe(target[0]);
+            expect(domain[1]).toBe(target[1]);
+        });
+
+        it('should load timeseries data', function () {
+            args = {
+                data: {
+                    x: 'date',
+                    columns: [
+                        ['date', '2014-01-01', '2014-01-02', '2014-08-01', '2014-10-19'],
+                        ['data1', 30, 200, 100, 400]
+                    ]
+                },
+                axis: {
+                    x: {
+                        type: 'timeseries'
+                    }
+                },
+                zoom: {
+                    enabled: true
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should be zoomed properly', function () {
+            var target = [new Date(2014, 7, 1), new Date(2014, 8, 1)], domain;
+            chart.zoom(target);
+            domain = chart.internal.x.domain();
+            expect(+domain[0]).toBe(+target[0]);
+            expect(+domain[1]).toBe(+target[1]);
+        });
+
+        it('should be zoomed properly', function () {
+            var target = ['2014-08-01', '2014-09-01'], domain;
+            chart.zoom(target);
+            domain = chart.internal.x.domain();
+            expect(+domain[0]).toBe(+chart.internal.parseDate(target[0]));
+            expect(+domain[1]).toBe(+chart.internal.parseDate(target[1]));
+        });
+
+    });
+
+    describe('unzoom', function () {
+
+        it('should load indexed data', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250]
+                    ]
+                },
+                zoom: {
+                    enabled: true
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should be unzoomed properly', function () {
+            var target = [1, 4], orginal = chart.internal.x.domain(), domain;
+
+            chart.zoom(target);
+            domain = chart.internal.x.domain();
+            expect(domain[0]).toBe(target[0]);
+            expect(domain[1]).toBe(target[1]);
+
+            chart.unzoom();
+            domain = chart.internal.x.domain();
+            expect(domain[0]).toBe(orginal[0]);
+            expect(domain[1]).toBe(orginal[1]);
+        });
+
+    });
+
+});
diff --git a/spec/arc-spec.js b/spec/arc-spec.js
new file mode 100644
index 0000000..3a74ee9
--- /dev/null
+++ b/spec/arc-spec.js
@@ -0,0 +1,78 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart axis', function () {
+    'use strict';
+
+    var chart, d3, args;
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            window.initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+        chart.internal.d3.select('.jasmine_html-reporter')
+            .style('position', 'absolute')
+            .style('right', 0);
+
+        window.setTimeout(function () {
+            done();
+        }, 50);
+    });
+
+    describe('show pie chart', function () {
+
+        args = {
+            data: {
+                columns: [
+                    ['data1', 30],
+                    ['data2', 150],
+                    ['data3', 120]
+                ],
+                type: 'pie'
+            }
+        };
+
+        it('should have correct classes', function () {
+            var chartArc = d3.select('.c3-chart-arcs'),
+            arcs = {
+                data1: chartArc.select('.c3-chart-arc.c3-target.c3-target-data1')
+                    .select('g.c3-shapes.c3-shapes-data1.c3-arcs.c3-arcs-data1')
+                    .select('path.c3-shape.c3-shape.c3-arc.c3-arc-data1'),
+                data2: chartArc.select('.c3-chart-arc.c3-target.c3-target-data2')
+                    .select('g.c3-shapes.c3-shapes-data2.c3-arcs.c3-arcs-data2')
+                    .select('path.c3-shape.c3-shape.c3-arc.c3-arc-data2'),
+                data3: chartArc.select('.c3-chart-arc.c3-target.c3-target-data3')
+                    .select('g.c3-shapes.c3-shapes-data3.c3-arcs.c3-arcs-data3')
+                    .select('path.c3-shape.c3-shape.c3-arc.c3-arc-data3')
+            };
+            expect(arcs.data1.size()).toBe(1);
+            expect(arcs.data2.size()).toBe(1);
+            expect(arcs.data3.size()).toBe(1);
+        });
+
+        it('should have correct d', function () {
+            expect(d3.select('.c3-arc-data1').attr('d')).toMatch(/M-124\..+,-171\..+A211\..+,211\..+ 0 0,1 -3\..+,-211\..+L0,0Z/);
+            expect(d3.select('.c3-arc-data2').attr('d')).toMatch(/M1\..+,-211\..+A211\..+,211\..+ 0 0,1 1\..+,211\..+L0,0Z/);
+            expect(d3.select('.c3-arc-data3').attr('d')).toMatch(/M1\..+,211\..+A211\..+,211\..+ 0 0,1 -124\..+,-171\..+L0,0Z/);
+        });
+
+        it('should set args with data id that can be converted to a color', function () {
+            args.data.columns = [
+                ['black', 30],
+                ['data2', 150],
+                ['data3', 120]
+            ];
+            expect(true).toBeTruthy();
+        });
+
+        it('should have correct d even if data id can be converted to a color', function () {
+            expect(d3.select('.c3-arc-black').attr('d')).toMatch(/M-124\..+,-171\..+A211\..+,211\..+ 0 0,1 -3\..+,-211\..+L0,0Z/);
+        });
+
+    });
+
+});
diff --git a/spec/axis-spec.js b/spec/axis-spec.js
new file mode 100644
index 0000000..01a48b8
--- /dev/null
+++ b/spec/axis-spec.js
@@ -0,0 +1,677 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart axis', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ]
+        },
+        axis: {
+            y: {
+                tick: {
+                    values: null,
+                    count: undefined
+                }
+            },
+            y2: {
+                tick: {
+                    values: null,
+                    count: undefined
+                }
+            }
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('axis.y.tick.count', function () {
+
+        var i = 1;
+
+        beforeEach(function () {
+            args.axis.y.tick.count = i++;
+            chart = window.c3.generate(args);
+        });
+
+        it('should have only 1 tick on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(1);
+        });
+
+        it('should have 2 ticks on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(2);
+        });
+
+        it('should have 3 ticks on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(3);
+        });
+
+    });
+
+    describe('axis.y.tick.values', function () {
+
+        var values = [100, 500];
+
+        beforeEach(function () {
+            args.axis.y.tick.values = values;
+            chart = window.c3.generate(args);
+        });
+
+        it('should have only 2 tick on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(2);
+        });
+
+        it('should have specified tick texts', function () {
+            d3.select('.c3-axis-y').selectAll('g.tick').each(function (d, i) {
+                var text = d3.select(this).select('text').text();
+                expect(+text).toBe(values[i]);
+            });
+        });
+
+    });
+
+    describe('axis y timeseries', function () {
+
+        var args = {
+            data: {
+                columns: [
+                    ["times", 60000, 120000, 180000, 240000]
+                ]
+            },
+            axis: {
+                y: {
+                    type : 'timeseries',
+                    tick: {
+                        time: {
+                        }
+                    }
+                }
+            }
+        };
+
+        beforeEach(function () {
+            chart = window.c3.generate(args);
+        });
+
+        it('should have 7 ticks on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(7); // the count starts at initial value and increments by the set interval
+        });
+
+        it('should have specified 30 second intervals', function () {
+            var prevValue;
+            d3.select('.c3-axis-y').selectAll('g.tick').each(function (d, i) {
+                if (i !== 0) {
+                    var result = d - prevValue;
+                    expect(result).toEqual(30000); // expressed in milliseconds
+                }
+                prevValue = d;
+            });
+        });
+
+        it('should update args to set axis.y.time', function () {
+            args.axis.y.tick.time = {
+                value : 'seconds',
+                interval : 60
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should have 4 ticks on y axis', function () {
+            var ticksSize = d3.select('.c3-axis-y').selectAll('g.tick').size();
+            expect(ticksSize).toBe(4); // the count starts at initial value and increments by the set interval
+        });
+
+        it('should have specified 60 second intervals', function () {
+            var prevValue;
+            d3.select('.c3-axis-y').selectAll('g.tick').each(function (d, i) {
+                if (i !== 0) {
+                    var result = d - prevValue;
+                    expect(result).toEqual(60000); // expressed in milliseconds
+                }
+                prevValue = d;
+            });
+        });
+    });
+
+    describe('axis.x.tick.width', function () {
+
+        describe('indexed x axis and y/y2 axis', function () {
+
+            describe('not rotated', function () {
+
+                it('should update args successfully', function () {
+                    args = {
+                        data: {
+                            columns: [
+                                ['data1', 30, 200, 100, 400, 150, 250],
+                                ['data2', 50, 20, 10, 40, 15, 25]
+                            ],
+                            axes: {
+                                data2: 'y2'
+                            }
+                        },
+                        axis: {
+                            y2: {
+                                show: true
+                            }
+                        }
+                    };
+                    expect(true).toBeTruthy();
+                });
+
+                it('should construct indexed x axis properly', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick'),
+                        expectedX = '0',
+                        expectedDy = '.71em';
+                    expect(ticks.size()).toBe(6);
+                    ticks.each(function (d, i) {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                        tspans.each(function () {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(i + '');
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            expect(tspan.attr('dy')).toBe(expectedDy);
+                        });
+                    });
+                });
+
+                it('should set axis.x.tick.format', function () {
+                    args.axis.x = {
+                        tick: {
+                            format: function () {
+                                return 'very long tick text on x axis';
+                            }
+                        }
+                    };
+                    expect(true).toBeTruthy();
+                });
+
+                it('should split x axis tick text to multiple lines', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick'),
+                        expectedTexts = ['very long tick text', 'on x axis'],
+                        expectedX = '0';
+                    expect(ticks.size()).toBe(6);
+                    ticks.each(function () {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(2);
+                        tspans.each(function (d, i) {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(expectedTexts[i]);
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            if (i === 0) {
+                                expect(tspan.attr('dy')).toBe('.71em');
+                            } else {
+                                expect(tspan.attr('dy')).toBeGreaterThan(8);
+                            }
+                        });
+                    });
+                });
+
+                it('should construct y axis properly', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-y').selectAll('g.tick'),
+                        expectedX = '-9',
+                        expectedDy = '3';
+                    expect(ticks.size()).toBe(9);
+                    ticks.each(function (d) {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                        tspans.each(function () {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(d + '');
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            expect(tspan.attr('dy')).toBe(expectedDy);
+                        });
+                    });
+                });
+
+                it('should construct y2 axis properly', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-y2').selectAll('g.tick'),
+                        expectedX = '9',
+                        expectedDy = '3';
+                    expect(ticks.size()).toBe(9);
+                    ticks.each(function (d) {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                        tspans.each(function () {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(d + '');
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            expect(tspan.attr('dy')).toBe(expectedDy);
+                        });
+                    });
+                });
+
+                it('should set big values in y', function () {
+                    args.data.columns = [
+                        ['data1', 3000000000000000, 200, 100, 400, 150, 250],
+                        ['data2', 50, 20, 10, 40, 15, 25]
+                    ];
+                    expect(true).toBeTruthy();
+                });
+
+                it('should not split y axis tick text to multiple lines', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-y2').selectAll('g.tick');
+                    ticks.each(function () {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                    });
+                });
+
+            });
+
+            describe('rotated', function () {
+
+                it('should update args to rotate axis', function () {
+                    args.axis.rotated = true;
+                    expect(true).toBeTruthy();
+                });
+
+                it('should split x axis tick text to multiple lines', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick'),
+                        expectedTexts = ['very long tick', 'text on x axis'],
+                        expectedX = '-9';
+                    expect(ticks.size()).toBe(6);
+                    ticks.each(function () {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(2);
+                        tspans.each(function (d, i) {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(expectedTexts[i]);
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            if (i === 0) {
+                                expect(tspan.attr('dy')).toBeLessThan(0);
+                            } else {
+                                expect(tspan.attr('dy')).toBeGreaterThan(9);
+                            }
+                        });
+                    });
+                });
+
+                it('should not split y axis tick text to multiple lines', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-y').selectAll('g.tick'),
+                        expectedTexts = [
+                            '0',
+                            '500000000000000',
+                            '1000000000000000',
+                            '1500000000000000',
+                            '2000000000000000',
+                            '2500000000000000',
+                            '3000000000000000'
+                        ],
+                        expectedX = '0',
+                        expectedDy = '.71em';
+                    expect(ticks.size()).toBe(7);
+                    ticks.each(function (d, i) {
+                        var tspans = d3.select(this).selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                        tspans.each(function () {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(expectedTexts[i]);
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            expect(tspan.attr('dy')).toBe(expectedDy);
+                        });
+                    });
+                });
+
+            });
+        });
+
+        describe('category axis', function () {
+
+            describe('not rotated', function () {
+
+                it('should update args successfully', function () {
+                    args = {
+                        data: {
+                            x: 'x',
+                            columns: [
+                                ['x', 'this is a very long tick text on category axis', 'cat1', 'cat2', 'cat3', 'cat4', 'cat5'],
+                                ['data1', 30, 200, 100, 400, 150, 250],
+                                ['data2', 50, 20, 10, 40, 15, 25]
+                            ]
+                        },
+                        axis: {
+                            x: {
+                                type: 'category'
+                            }
+                        }
+                    };
+                    expect(true).toBeTruthy();
+                });
+
+                it('should locate ticks properly', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick');
+                    ticks.each(function (d, i) {
+                        var tspans = d3.select(this).selectAll('tspan'),
+                            expectedX = '0',
+                            expectedDy = '.71em';
+                        if (i > 0) { // i === 0 should be checked in next test
+                            expect(tspans.size()).toBe(1);
+                            tspans.each(function () {
+                                var tspan = d3.select(this);
+                                expect(tspan.attr('x')).toBe(expectedX);
+                                expect(tspan.attr('dy')).toBe(expectedDy);
+                            });
+                        }
+                    });
+                });
+
+                it('should split tick text properly', function () {
+                    var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
+                        tspans = tick.selectAll('tspan'),
+                        expectedTickTexts = [
+                            'this is a very',
+                            'long tick text',
+                            'on category',
+                            'axis',
+                        ],
+                        expectedX = '0';
+                    expect(tspans.size()).toBe(4);
+                    tspans.each(function (d, i) {
+                        var tspan = d3.select(this);
+                        expect(tspan.text()).toBe(expectedTickTexts[i]);
+                        expect(tspan.attr('x')).toBe(expectedX);
+                        // unable to define pricise number because it differs depends on environment..
+                        if (i === 0) {
+                            expect(tspan.attr('dy')).toBe('.71em');
+                        } else {
+                            expect(tspan.attr('dy')).toBeGreaterThan(8);
+                        }
+                    });
+                });
+            });
+
+            describe('rotated', function () {
+
+                it('should update args to rotate axis', function () {
+                    args.axis.rotated = true;
+                    expect(true).toBeTruthy();
+                });
+
+                it('should locate ticks on rotated axis properly', function () {
+                    var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick');
+                    ticks.each(function (d, i) {
+                        var tspans = d3.select(this).selectAll('tspan'),
+                            expectedX = '-9',
+                            expectedDy = '2';
+                        if (i > 0) { // i === 0 should be checked in next test
+                            expect(tspans.size()).toBe(1);
+                            tspans.each(function () {
+                                var tspan = d3.select(this);
+                                expect(tspan.attr('x')).toBe(expectedX);
+                                expect(tspan.attr('dy')).toBe(expectedDy);
+                            });
+                        }
+                    });
+                });
+
+                it('should split tick text on rotated axis properly', function () {
+                    var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
+                        tspans = tick.selectAll('tspan'),
+                        expectedTickTexts = [
+                            'this is a very',
+                            'long tick text on',
+                            'category axis'
+                        ],
+                        expectedX = '-9';
+                    expect(tspans.size()).toBe(3);
+                    tspans.each(function (d, i) {
+                        var tspan = d3.select(this);
+                        expect(tspan.text()).toBe(expectedTickTexts[i]);
+                        expect(tspan.attr('x')).toBe(expectedX);
+                        // unable to define pricise number because it differs depends on environment..
+                        if (i === 0) {
+                            expect(tspan.attr('dy')).toBeLessThan(0);
+                        } else {
+                            expect(tspan.attr('dy')).toBeGreaterThan(8);
+                        }
+                    });
+                });
+
+            });
+
+            describe('option used', function () {
+
+                describe('as null', function () {
+
+                    it('should update args not to split ticks', function () {
+                        args.axis.x.tick = {
+                            multiline: false
+                        };
+                        expect(true).toBeTruthy();
+                    });
+
+                    it('should split x tick', function () {
+                        var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
+                            tspans = tick.selectAll('tspan');
+                        expect(tspans.size()).toBe(1);
+                    });
+
+                });
+
+                describe('as value', function () {
+
+                    it('should update args not to split ticks', function () {
+                        args.axis.x.tick = {
+                            width: 150
+                        };
+                        expect(true).toBeTruthy();
+                    });
+
+                    it('should split x tick to 2 lines properly', function () {
+                        var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
+                            tspans = tick.selectAll('tspan'),
+                            expectedTickTexts = [
+                                'this is a very long tick',
+                                'text on category axis'
+                            ],
+                            expectedX = '-9';
+                        expect(tspans.size()).toBe(2);
+                        tspans.each(function (d, i) {
+                            var tspan = d3.select(this);
+                            expect(tspan.text()).toBe(expectedTickTexts[i]);
+                            expect(tspan.attr('x')).toBe(expectedX);
+                            // unable to define pricise number because it differs depends on environment..
+                            if (i === 0) {
+                                expect(tspan.attr('dy')).toBeLessThan(0);
+                            } else {
+                                expect(tspan.attr('dy')).toBeGreaterThan(8);
+                            }
+                        });
+                    });
+                });
+            });
+        });
+
+        describe('with axis.x.tick.format', function () {
+
+            it('should update args to use axis.x.tick.format', function () {
+                args.axis.x.tick.format = function () {
+                    return ['this is a very long tick text', 'on category axis'];
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have multiline tick text', function () {
+                var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
+                    tspans = tick.selectAll('tspan'),
+                    expectedTickTexts = ['this is a very long tick text', 'on category axis'];
+                expect(tspans.size()).toBe(2);
+                tspans.each(function (d, i) {
+                    var tspan = d3.select(this);
+                    expect(tspan.text()).toBe(expectedTickTexts[i]);
+                });
+            });
+
+        });
+    });
+
+    describe('axis.x.tick.rotate', function () {
+
+        describe('not rotated', function () {
+
+            it('should update args successfully', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', 'category 1', 'category 2', 'category 3', 'category 4', 'category 5', 'category 6'],
+                            ['data1', 30, 200, 100, 400, 150, 250],
+                            ['data2', 50, 20, 10, 40, 15, 25]
+                        ]
+                    },
+                    axis: {
+                        x: {
+                            type: 'category',
+                            tick: {
+                                rotate: 60
+                            }
+                        }
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should rotate tick texts', function () {
+                chart.internal.main.selectAll('.c3-axis-x g.tick').each(function () {
+                    var tick = d3.select(this),
+                        text = tick.select('text'),
+                        tspan = text.select('tspan');
+                    expect(text.attr('transform')).toBe('rotate(60)');
+                    expect(text.attr('y')).toBe('1.5');
+                    expect(tspan.attr('dx')).toBe('6.928203230275509');
+                });
+            });
+
+            it('should have automatically calculated x axis height', function () {
+                var box = chart.internal.main.select('.c3-axis-x').node().getBoundingClientRect();
+                expect(box.height).toBeGreaterThan(50);
+            });
+
+        });
+    });
+
+    describe('axis.x.tick.fit', function () {
+
+        describe('axis.x.tick.fit = true', function () {
+
+            it('should set args for indexed data', function () {
+                args = {
+                    data: {
+                        columns: [
+                            ['data1', 30, 200, 100, 400, 150, 250],
+                            ['data2', 50, 20, 10, 40, 15, 25],
+                            ['data3', 150, 120, 110, 140, 115, 125]
+                        ]
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should show fitted ticks on indexed data', function () {
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(6);
+            });
+
+            it('should set args for x-based data', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', 10, 20, 100, 110, 200, 1000],
+                            ['data1', 30, 200, 100, 400, 150, 250],
+                            ['data2', 50, 20, 10, 40, 15, 25],
+                            ['data3', 150, 120, 110, 140, 115, 125]
+                        ]
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should show fitted ticks on indexed data', function () {
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(6);
+            });
+
+            it('should show fitted ticks after hide and show', function () {
+                chart.hide();
+                chart.show();
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(6);
+            });
+
+        });
+
+        describe('axis.x.tick.fit = false', function () {
+
+            it('should set args for indexed data', function () {
+                args = {
+                    data: {
+                        columns: [
+                            ['data1', 30, 200, 100, 400, 150, 250],
+                            ['data2', 50, 20, 10, 40, 15, 25],
+                            ['data3', 150, 120, 110, 140, 115, 125]
+                        ]
+                    },
+                    axis: {
+                        x: {
+                            tick: {
+                                fit: false
+                            }
+                        }
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should show fitted ticks on indexed data', function () {
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(11);
+            });
+
+            it('should set args for x-based data', function () {
+                args.data = {
+                    x: 'x',
+                    columns: [
+                        ['x', 10, 20, 100, 110, 200, 1000],
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 50, 20, 10, 40, 15, 25],
+                        ['data3', 150, 120, 110, 140, 115, 125]
+                    ]
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should show fitted ticks on indexed data', function () {
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(10);
+            });
+
+            it('should show fitted ticks after hide and show', function () {
+                chart.hide();
+                chart.show();
+                var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick');
+                expect(ticks.size()).toBe(10);
+            });
+
+        });
+    });
+});
diff --git a/spec/c3-helper.js b/spec/c3-helper.js
new file mode 100644
index 0000000..39f6104
--- /dev/null
+++ b/spec/c3-helper.js
@@ -0,0 +1,43 @@
+function initDom() {
+    'use strict';
+
+    var div = document.createElement('div');
+    div.id = 'chart';
+    div.style.width = '640px';
+    div.style.height = '480px';
+    document.body.appendChild(div);
+    document.body.style.margin = '0px';
+}
+typeof initDom !== 'undefined';
+
+function setMouseEvent(chart, name, x, y, element) {
+    'use strict';
+
+    var paddingLeft = chart.internal.main.node().transform.baseVal.getItem(0).matrix.e,
+        event = document.createEvent("MouseEvents");
+    event.initMouseEvent(name, true, true, window,
+                       0, 0, 0, x + paddingLeft, y + 5,
+                       false, false, false, false, 0, null);
+    chart.internal.d3.event = event;
+    if (element) { element.dispatchEvent(event); }
+}
+typeof setMouseEvent !== 'undefined';
+
+function initChart(chart, args, done) {
+    'use strict';
+
+    if (typeof chart === 'undefined') {
+        window.initDom();
+    }
+    chart = window.c3.generate(args);
+    chart.internal.d3.select('.jasmine_html-reporter')
+        .style('position', 'absolute')
+        .style('right', 0);
+
+    window.setTimeout(function () {
+        done();
+    }, 10);
+
+    return chart;
+}
+typeof initChart !== 'undefined';
diff --git a/spec/c3-spec.js b/spec/c3-spec.js
index 49735c2..c2455b0 100644
--- a/spec/c3-spec.js
+++ b/spec/c3-spec.js
@@ -1,20 +1,15 @@
-
-var describe = window.describe;
-var expect = window.expect;
-var it = window.it;
-
-var c3 = window.c3;
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it;
 
 describe('c3', function () {
     'use strict';
 
-    it('exists', function () {
+    var c3 = window.c3;
 
-        expect(c3).not.toBe(null);
+    it('exists', function () {
+        expect(c3).not.toBeNull();
         expect(typeof c3).toBe('object');
-
     });
-
-    // ...write other tests here
-
 });
+
diff --git a/spec/class-spec.js b/spec/class-spec.js
new file mode 100644
index 0000000..86b54e1
--- /dev/null
+++ b/spec/class-spec.js
@@ -0,0 +1,67 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart class', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2 prefix', 50, 20, 10, 40, 15, 25],
+                ['data3 мужчины', 150, 120, 110, 140, 115, 125]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('internal.getTargetSelectorSuffix', function () {
+
+        it('should not replace any characters', function () {
+            var input = 'data1',
+                expected = '-' + input,
+                suffix = chart.internal.getTargetSelectorSuffix(input);
+            expect(suffix).toBe(expected);
+        });
+
+        it('should replace space to "-"', function () {
+            var input = 'data1 suffix',
+                expected = '-data1-suffix',
+                suffix = chart.internal.getTargetSelectorSuffix(input);
+            expect(suffix).toBe(expected);
+        });
+
+        it('should replace space to "-" with multibyte characters', function () {
+            var input = 'data1 suffix 日本語',
+                expected = '-data1-suffix-日本語',
+                suffix = chart.internal.getTargetSelectorSuffix(input);
+            expect(suffix).toBe(expected);
+        });
+
+        it('should replace special charactors to "-"', function () {
+            var input = 'data1 !@#$%^&*()_=+,.<>"\':;[]/|?~`{}\\',
+                expected = '-data1--------------------------------',
+                suffix = chart.internal.getTargetSelectorSuffix(input);
+            expect(suffix).toBe(expected);
+        });
+
+    });
+
+    describe('multibyte characters on chart', function () {
+
+        it('should replace space to "-" with multibyte characters', function () {
+            var selector = '.c3-target-data3-мужчины';
+            expect(chart.internal.main.select(selector).size()).toBe(1);
+        });
+
+    });
+
+});
diff --git a/spec/core-spec.js b/spec/core-spec.js
new file mode 100644
index 0000000..662a1a7
--- /dev/null
+++ b/spec/core-spec.js
@@ -0,0 +1,118 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('init', function () {
+
+        it('should be created', function () {
+            var svg = d3.select('#chart svg');
+            expect(svg).not.toBeNull();
+        });
+
+        it('should set 3rd party property to Function', function () {
+            Function.prototype.$extIsFunction = true;
+            expect(true).toBeTruthy();
+        });
+
+        it('should be created even if 3rd party property has been set', function () {
+            var svg = d3.select('#chart svg');
+            expect(svg).not.toBeNull();
+        });
+
+    });
+
+    describe('size', function () {
+
+        it('should have same width', function () {
+            var svg = d3.select('#chart svg');
+            expect(+svg.attr('width')).toBe(640);
+        });
+
+        it('should have same height', function () {
+            var svg = d3.select('#chart svg');
+            expect(+svg.attr('height')).toBe(480);
+        });
+
+    });
+
+    describe('bindto', function () {
+
+        it('should accept d3.selection object', function () {
+            args.bindto = d3.select('#chart');
+            expect(true).toBeTruthy();
+        });
+
+        it('should be created', function () {
+            var svg = d3.select('#chart svg');
+            expect(svg).not.toBeNull();
+        });
+
+    });
+
+    describe('empty data', function () {
+
+        it('should upaate args for empty data', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1'],
+                        ['data2']
+                    ]
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should generate a chart', function () {
+            var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick');
+            expect(ticks.size()).toBe(0);
+        });
+
+        it('should upaate args for empty data', function () {
+            args = {
+                data: {
+                    x: 'x',
+                    columns: [
+                        ['x'],
+                        ['data1'],
+                        ['data2']
+                    ]
+                },
+                axis: {
+                    x: {
+                        type: 'timeseries'
+                    }
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should generate a chart', function () {
+            var ticks = chart.internal.main.select('.c3-axis-x').selectAll('g.tick');
+            expect(ticks.size()).toBe(0);
+        });
+
+    });
+
+});
diff --git a/spec/data-spec.js b/spec/data-spec.js
new file mode 100644
index 0000000..2a21d40
--- /dev/null
+++ b/spec/data-spec.js
@@ -0,0 +1,150 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart data', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ],
+            order: function () {
+                return 0;
+            }
+        }
+    };
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            window.initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+        chart.internal.d3.select('.jasmine_html-reporter').style('display', 'none');
+
+        window.setTimeout(function () {
+            done();
+        }, 10);
+    });
+
+    describe('function in data.order', function () {
+        it('should return false in isOrderAsc and isOrderDesc functions', function () {
+            expect(chart.internal.isOrderAsc() || chart.internal.isOrderDesc()).toBe(false);
+        });
+    });
+
+    describe('data.xs', function () {
+
+        describe('normal x', function () {
+ 
+            it('should have correct number of xs for each', function () {
+                expect(Object.keys(chart.internal.data.xs).length).toBe(3);
+                expect(chart.internal.data.xs.data1.length).toBe(6);
+                expect(chart.internal.data.xs.data2.length).toBe(6);
+                expect(chart.internal.data.xs.data3.length).toBe(6);
+            });
+
+            it('should have integer index as x', function () {
+                for (var i = 0; i < chart.internal.data.xs.data3.length; i++) {
+                    expect(chart.internal.data.xs.data1[i]).toBe(i);
+                    expect(chart.internal.data.xs.data2[i]).toBe(i);
+                    expect(chart.internal.data.xs.data3[i]).toBe(i);
+                }
+            });
+
+        });
+
+        describe('timeseries x', function () {
+            it('should load timeseries data successfully', function () {
+                args = {
+                    data: {
+                        x : 'date',
+                        columns: [
+                            ['date', '2013-01-01', '2013-01-02', '2013-01-03'],
+                            ['data1', 30, 200, 100],
+                            ['data2', 130, 300, 200]
+                        ]
+                    },
+                    axis : {
+                        x : {
+                            type : 'timeseries'
+                        }
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have correct number of xs', function () {
+                expect(Object.keys(chart.internal.data.xs).length).toBe(2);
+                expect(chart.internal.data.xs.data1.length).toBe(3);
+                expect(chart.internal.data.xs.data2.length).toBe(3);
+            });
+
+            it('should have Date object as x', function () {
+                var xs = chart.internal.data.xs;
+                expect(+xs.data1[0]).toBe(+new Date(2013, 0, 1, 0, 0, 0));
+                expect(+xs.data1[1]).toBe(+new Date(2013, 0, 2, 0, 0, 0));
+                expect(+xs.data1[2]).toBe(+new Date(2013, 0, 3, 0, 0, 0));
+                expect(+xs.data2[0]).toBe(+new Date(2013, 0, 1, 0, 0, 0));
+                expect(+xs.data2[1]).toBe(+new Date(2013, 0, 2, 0, 0, 0));
+                expect(+xs.data2[2]).toBe(+new Date(2013, 0, 3, 0, 0, 0));
+            });
+        });
+
+        describe('milliseconds timeseries x', function () {
+            it('should load timeseries data successfully', function () {
+                args = {
+                    data: {
+                        x : 'date',
+                        xFormat: '%Y-%m-%d %H:%M:%S.%L',
+                        columns: [
+                            ['date', "2014-05-20 17:25:00.123", "2014-05-20 17:30:00.345"],
+                            ['data1', 30, 200],
+                            ['data2', 130, 300]
+                        ]
+                    },
+                    axis: {
+                        x: {
+                            type: 'timeseries',
+                            tick: {
+                                format: '%Y-%m-%d %H:%M:%S.%L',
+                                multiline: false
+                            }
+                        }
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have correct number of xs', function () {
+                expect(Object.keys(chart.internal.data.xs).length).toBe(2);
+                expect(chart.internal.data.xs.data1.length).toBe(2);
+                expect(chart.internal.data.xs.data2.length).toBe(2);
+            });
+
+            it('should have Date object as x', function () {
+                var xs = chart.internal.data.xs;
+                expect(+xs.data1[0]).toBe(+new Date(2014, 4, 20, 17, 25, 0, 123));
+                expect(+xs.data1[1]).toBe(+new Date(2014, 4, 20, 17, 30, 0, 345));
+                expect(+xs.data2[0]).toBe(+new Date(2014, 4, 20, 17, 25, 0, 123));
+                expect(+xs.data2[1]).toBe(+new Date(2014, 4, 20, 17, 30, 0, 345));
+            });
+
+            it('should have milliseconds tick format', function () {
+                var expected = ["2014-05-20 17:25:00.123", "2014-05-20 17:30:00.345"];
+                chart.internal.main.selectAll('.c3-axis-x g.tick text').each(function (d, i) {
+                    expect(d3.select(this).text()).toBe(expected[i]);
+                });
+            });
+
+        });
+
+    });
+});
diff --git a/spec/domain-spec.js b/spec/domain-spec.js
new file mode 100644
index 0000000..c4b353e
--- /dev/null
+++ b/spec/domain-spec.js
@@ -0,0 +1,96 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+var initDom = window.initDom;
+
+describe('c3 chart axis', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25]
+            ]
+        },
+        axis: {
+            y: {},
+            y2: {}
+        }
+    };
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+        chart.internal.d3.select('.jasmine_html-reporter').style('display', 'none');
+
+        window.setTimeout(function () {
+            done();
+        }, 10);
+    });
+
+    describe('axis.y.min', function () {
+
+        it('should change axis.y.min to -100', function () {
+            args.axis.y.min = -100;
+            expect(true).toBeTruthy();
+        });
+
+        it('should be set properly when smaller than max of data', function () {
+            var domain = chart.internal.y.domain();
+            expect(domain[0]).toBe(-150);
+            expect(domain[1]).toBe(450);
+        });
+
+        it('should change axis.y.min to 500', function () {
+            args.axis.y.min = 500;
+            expect(true).toBeTruthy();
+        });
+
+        it('should be set properly when bigger than max of data', function () {
+            var domain = chart.internal.y.domain();
+            expect(domain[0]).toBe(499);
+            expect(domain[1]).toBe(511);
+        });
+
+        it('should change axis.y.min to undefined', function () {
+            args.axis.y.min = undefined;
+            expect(true).toBeTruthy();
+        });
+
+    });
+
+    describe('axis.y.max', function () {
+
+        it('should change axis.y.max to 1000', function () {
+            args.axis.y.max = 1000;
+            expect(true).toBeTruthy();
+        });
+
+        it('should be set properly when bigger than min of data', function () {
+            var domain = chart.internal.y.domain();
+            expect(domain[0]).toBe(-89);
+            expect(domain[1]).toBe(1099);
+        });
+
+        it('should change axis.y.max to 0', function () {
+            args.axis.y.max = 0;
+            expect(true).toBeTruthy();
+        });
+
+        it('should be set properly when smaller than min of data', function () {
+            var domain = chart.internal.y.domain();
+            expect(domain[0]).toBe(-11);
+            expect(domain[1]).toBe(1);
+        });
+
+    });
+
+});
diff --git a/spec/grid-spec.js b/spec/grid-spec.js
new file mode 100644
index 0000000..9939be8
--- /dev/null
+++ b/spec/grid-spec.js
@@ -0,0 +1,83 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart grid', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250]
+            ]
+        },
+        axis: {
+            y: {
+                tick: {
+                }
+            }
+        },
+        grid: {
+            y: {
+                show: false
+            }
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('y grid', function () {
+
+        it('should not show y grids', function () {
+            expect(chart.internal.main.select('.c3-ygrids').size()).toBe(0);
+        });
+
+        it('should update args to show y grids', function () {
+            args.grid.y.show = true;
+            expect(true).toBeTruthy();
+        });
+
+        it('should show y grids', function () {
+            var ygrids = chart.internal.main.select('.c3-ygrids');
+            expect(ygrids.size()).toBe(1);
+            expect(ygrids.selectAll('.c3-ygrid').size()).toBe(9);
+        });
+
+        it('should update args to show only 3 y grids', function () {
+            args.grid.y.ticks = 3;
+            expect(true).toBeTruthy();
+        });
+
+        it('should show only 3 y grids', function () {
+            var ygrids = chart.internal.main.select('.c3-ygrids');
+            expect(ygrids.size()).toBe(1);
+            expect(ygrids.selectAll('.c3-ygrid').size()).toBe(3);
+        });
+
+        it('should update args to show y grids depending on y axis ticks', function () {
+            args.axis.y.tick.count = 5;
+            expect(true).toBeTruthy();
+        });
+
+        it('should show grids depending on y axis ticks', function () {
+            var ygrids = chart.internal.main.select('.c3-ygrids'),
+                expectedYs = [];
+            ygrids.selectAll('.c3-ygrid').each(function (d, i) {
+                expectedYs[i] = +d3.select(this).attr('y1');
+            });
+            expect(ygrids.size()).toBe(1);
+            expect(ygrids.selectAll('.c3-ygrid').size()).toBe(5);
+            chart.internal.main.select('.c3-axis-y').selectAll('.tick').each(function (d, i) {
+                var t = d3.transform(d3.select(this).attr('transform'));
+                expect(t.translate[1]).toBe(expectedYs[i]);
+            });
+        });
+
+    });
+});
diff --git a/spec/interaction-spec.js b/spec/interaction-spec.js
new file mode 100644
index 0000000..a96f0ba
--- /dev/null
+++ b/spec/interaction-spec.js
@@ -0,0 +1,140 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart interaction', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            window.initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+        chart.internal.d3.select('.jasmine_html-reporter').style('display', 'none');
+
+        window.setTimeout(function () {
+            done();
+        }, 10);
+    });
+
+    describe('generate event rects', function () {
+
+        describe('custom x', function () {
+
+            it('should generate bar chart', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', 0, 1000, 3000, 10000],
+                            ['data', 10, 10, 10, 10]
+                        ],
+                        type: 'bar'
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have 4 event rects properly', function () {
+                var lefts = [77.5, 137, 203.5, 402.5],
+                    widths = [59.5, 66.5, 199, 191.5];
+                d3.selectAll('.c3-event-rect').each(function (d, i) {
+                    var box = d3.select(this).node().getBoundingClientRect();
+                    expect(box.left).toBe(lefts[i]);
+                    expect(box.width).toBe(widths[i]);
+                });
+            });
+
+            it('should generate bar chart with only one data', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', 0],
+                            ['data', 10]
+                        ],
+                        type: 'bar'
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have 1 event rects properly', function () {
+                var eventRects = d3.selectAll('.c3-event-rect');
+                expect(eventRects.size()).toBe(1);
+                eventRects.each(function () {
+                    var box = d3.select(this).node().getBoundingClientRect();
+                    expect(box.left).toBe(40.5);
+                    expect(box.width).toBe(590);
+                });
+            });
+        });
+
+        describe('timeseries', function () {
+
+            it('should generate line chart with timeseries', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', '20140101', '20140201', '20140210',  '20140301'],
+                            ['data', 10, 10, 10, 10]
+                        ]
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have 4 event rects properly', function () {
+                var lefts = [43.5, 191, 349, 494],
+                    widths = [147.5, 158, 145, 134];
+                d3.selectAll('.c3-event-rect').each(function (d, i) {
+                    var box = d3.select(this).node().getBoundingClientRect();
+                    expect(box.left).toBe(lefts[i]);
+                    expect(box.width).toBe(widths[i]);
+                });
+
+            });
+
+            it('should generate line chart with only 1 data timeseries', function () {
+                args = {
+                    data: {
+                        x: 'x',
+                        columns: [
+                            ['x', '20140101'],
+                            ['data', 10]
+                        ]
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should have 1 event rects properly', function () {
+                var eventRects = d3.selectAll('.c3-event-rect');
+                expect(eventRects.size()).toBe(1);
+                eventRects.each(function () {
+                    var box = d3.select(this).node().getBoundingClientRect();
+                    expect(box.left).toBe(40.5);
+                    expect(box.width).toBe(590);
+                });
+            });
+
+        });
+
+    });
+
+});
diff --git a/spec/legend-spec.js b/spec/legend-spec.js
new file mode 100644
index 0000000..a70f494
--- /dev/null
+++ b/spec/legend-spec.js
@@ -0,0 +1,186 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart legend', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        if (typeof chart === 'undefined') {
+            window.initDom();
+        }
+        chart = window.c3.generate(args);
+        d3 = chart.internal.d3;
+        chart.internal.d3.select('.jasmine_html-reporter')
+            .style('position', 'absolute')
+            .style('right', 0);
+
+        window.setTimeout(function () {
+            done();
+        }, 10);
+    });
+
+    describe('legend position', function () {
+
+        it('should be located on the center of chart', function () {
+            var box = chart.internal.legend.node().getBoundingClientRect();
+            expect(box.left + box.right).toBe(640);
+        });
+
+    });
+
+    describe('legend as inset', function () {
+
+        it('should change the legend to "inset" successfully', function () {
+            args.legend = {
+                position: 'inset',
+                inset: {
+                    step: null
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should be positioned properly', function () {
+            var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
+            expect(box.top).toBe(5.5);
+            expect(box.left).toBe(60.5);
+        });
+
+        it('should have automatically calculated height', function () {
+            var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
+            expect(box.height).toBe(48);
+        });
+
+        it('should change the legend step to 1 successfully', function () {
+            args.legend.inset.step = 1;
+            expect(true).toBeTruthy();
+        });
+
+        it('should have automatically calculated height', function () {
+            var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
+            expect(box.height).toBe(28);
+        });
+
+        it('should change the legend step to 2 successfully', function () {
+            args.legend.inset.step = 2;
+            expect(true).toBeTruthy();
+        });
+
+        it('should have automatically calculated height', function () {
+            var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
+            expect(box.height).toBe(48);
+        });
+
+        it('should update args to have only one series', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                    ]
+                },
+                legend: {
+                    position: 'inset'
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should locate legend properly', function () {
+            var box = d3.select('.c3-legend-background').node().getBoundingClientRect();
+            expect(box.height).toBe(28);
+            expect(box.width).toBeGreaterThan(64);
+        });
+
+    });
+
+    describe('legend.hide', function () {
+
+        it('should update args', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 130, 100, 200, 100, 250, 150]
+                    ]
+                },
+                legend: {
+                    hide: true
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should not show legends', function () {
+            d3.selectAll('.c3-legend-item').each(function () {
+                expect(d3.select(this).style('visibility')).toBe('hidden');
+            });
+        });
+
+        it('should update args', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 130, 100, 200, 100, 250, 150]
+                    ]
+                },
+                legend: {
+                    hide: 'data2'
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should not show legends', function () {
+            expect(d3.select('.c3-legend-item-data1').style('visibility')).toBe('visible');
+            expect(d3.select('.c3-legend-item-data2').style('visibility')).toBe('hidden');
+        });
+
+    });
+
+    describe('legend.show', function () {
+
+        it('should update args', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 130, 100, 200, 100, 250, 150]
+                    ]
+                },
+                legend: {
+                    show: false
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should not initially have rendered any legend items', function () {
+            expect(d3.selectAll('.c3-legend-item').empty()).toBe(true);
+        });
+
+        it('allows us to show the legend on showLegend call', function () {
+            chart.legend.show();
+            d3.selectAll('.c3-legend-item').each(function () {
+                expect(d3.select(this).style('visibility')).toBe('visible');
+                // This selects all the children, but we expect it to be empty
+                expect(d3.select(this).selectAll("*").length).not.toEqual(0);
+            });
+        });
+
+    });
+
+});
diff --git a/spec/shape.bar-spec.js b/spec/shape.bar-spec.js
new file mode 100644
index 0000000..7babc1e
--- /dev/null
+++ b/spec/shape.bar-spec.js
@@ -0,0 +1,91 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+var setMouseEvent = window.setMouseEvent;
+
+describe('c3 chart shape bar', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, -150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', -150, 120, 110, 140, 115, 125]
+            ],
+            type: 'bar'
+        },
+        axis: {
+            rotated: false
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('internal.isWithinBar', function () {
+
+        describe('with normal axis', function () {
+
+            it('should not be within bar', function () {
+                var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 0, 0);
+                expect(chart.internal.isWithinBar(bar)).toBeFalsy();
+            });
+
+            it('should be within bar', function () {
+                var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 31, 280);
+                expect(chart.internal.isWithinBar(bar)).toBeTruthy();
+            });
+
+            it('should not be within bar of negative value', function () {
+                var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 68, 280);
+                expect(chart.internal.isWithinBar(bar)).toBeFalsy();
+            });
+
+            it('should be within bar of negative value', function () {
+                var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 68, 350);
+                expect(chart.internal.isWithinBar(bar)).toBeTruthy();
+            });
+
+        });
+
+        describe('with rotated axis', function () {
+
+            it('should change the chart as axis rotated', function () {
+                args.axis.rotated = true;
+                expect(true).toBeTruthy();
+            });
+
+            it('should not be within bar', function () {
+                var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 0, 0);
+                expect(chart.internal.isWithinBar(bar)).toBeFalsy();
+            });
+
+            it('should be within bar', function () {
+                var bar = d3.select('.c3-target-data1 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 190, 20);
+                expect(chart.internal.isWithinBar(bar)).toBeTruthy();
+            });
+
+            it('should be within bar of negative value', function () {
+                var bar = d3.select('.c3-target-data3 .c3-bar-0').node();
+                setMouseEvent(chart, 'click', 68, 50);
+                expect(chart.internal.isWithinBar(bar)).toBeTruthy();
+            });
+
+        });
+
+    });
+
+});
diff --git a/spec/shape.line-spec.js b/spec/shape.line-spec.js
new file mode 100644
index 0000000..40c1fa7
--- /dev/null
+++ b/spec/shape.line-spec.js
@@ -0,0 +1,102 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart shape line', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, -150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', -150, 120, 110, 140, 115, 125]
+            ],
+            type: 'line'
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('shape-rendering for line chart', function () {
+
+        it("should not have shape-rendering when it's line chart", function () {
+            d3.selectAll('.c3-line').each(function () {
+                var style = d3.select(this).style('shape-rendering');
+                expect(style).toBe('auto');
+            });
+        });
+
+        it('should chnage to step chart', function () {
+            args.data.type = 'step';
+            expect(true).toBeTruthy();
+        });
+
+        it("should have shape-rendering = crispedges when it's step chart", function () {
+            d3.selectAll('.c3-line').each(function () {
+                var style = d3.select(this).style('shape-rendering');
+                expect(style).toBe('crispedges');
+            });
+        });
+
+    });
+
+    describe('point.show option', function () {
+
+        it('should change args to include null data', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, null, 100, 400, -150, 250],
+                        ['data2', 50, 20, 10, 40, 15, 25],
+                        ['data3', -150, 120, 110, 140, 115, 125]
+                    ],
+                    type: 'line'
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should not show the circle for null', function (done) {
+            setTimeout(function () {
+                var target = chart.internal.main.select('.c3-chart-line.c3-target-data1');
+                expect(+target.select('.c3-circle-0').style('opacity')).toBe(1);
+                expect(+target.select('.c3-circle-1').style('opacity')).toBe(0);
+                expect(+target.select('.c3-circle-2').style('opacity')).toBe(1);
+                done();
+            }, 500);
+        });
+
+        it('should change args to include null data on scatter plot', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, null, 100, 400, -150, 250],
+                        ['data2', 50, 20, 10, 40, 15, 25],
+                        ['data3', -150, 120, 110, 140, 115, 125]
+                    ],
+                    type: 'scatter'
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should not show the circle for null', function (done) {
+            setTimeout(function () {
+                var target = chart.internal.main.select('.c3-chart-line.c3-target-data1');
+                expect(+target.select('.c3-circle-0').style('opacity')).toBe(0.5);
+                expect(+target.select('.c3-circle-1').style('opacity')).toBe(0);
+                expect(+target.select('.c3-circle-2').style('opacity')).toBe(0.5);
+                done();
+            }, 500);
+        });
+
+    });
+
+});
diff --git a/spec/tooltip-spec.js b/spec/tooltip-spec.js
new file mode 100644
index 0000000..72dec4d
--- /dev/null
+++ b/spec/tooltip-spec.js
@@ -0,0 +1,69 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart tooltip', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ]
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('tooltip position', function () {
+
+        describe('without left margin', function () {
+
+            it('should show tooltip on proper position', function () {
+                var eventRect = d3.select('.c3-event-rect-2').node();
+                window.setMouseEvent(chart, 'mousemove', 100, 100, eventRect);
+
+                var tooltipContainer = d3.select('.c3-tooltip-container'),
+                    top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
+                    left = Math.floor(+tooltipContainer.style('left').replace(/px/, '')),
+                    topExpected = 115,
+                    leftExpected = 304;
+                expect(top).toBe(topExpected);
+                expect(left).toBe(leftExpected);
+            });
+
+        });
+
+        describe('with left margin', function () {
+
+            it('should set left margin', function () {
+                d3.select('#chart').style('margin-left', '300px');
+                expect(true).toBeTruthy();
+            });
+
+            it('should show tooltip on proper position', function () {
+                var eventRect = d3.select('.c3-event-rect-2').node();
+                window.setMouseEvent(chart, 'mousemove', 100, 100, eventRect);
+
+                var tooltipContainer = d3.select('.c3-tooltip-container'),
+                    top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
+                    left = Math.floor(+tooltipContainer.style('left').replace(/px/, '')),
+                    topExpected = 115,
+                    leftExpected = 304;
+                expect(top).toBe(topExpected);
+                expect(left).toBe(leftExpected);
+            });
+
+        });
+
+    });
+
+});
diff --git a/spec/type-spec.js b/spec/type-spec.js
new file mode 100644
index 0000000..2661b17
--- /dev/null
+++ b/spec/type-spec.js
@@ -0,0 +1,140 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart types', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 150, 250],
+                ['data2', 50, 20, 10, 40, 15, 25],
+                ['data3', 150, 120, 110, 140, 115, 125]
+            ],
+            type: 'pie'
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('internal.hasArcType', function () {
+
+        describe('with data', function () {
+
+            it('should return true', function () {
+                expect(chart.internal.hasArcType()).toBeTruthy();
+            });
+
+            it('should change chart type to "bar"', function () {
+                args.data.type = 'bar';
+                expect(true).toBeTruthy();
+            });
+
+            it('should return false', function () {
+                expect(chart.internal.hasArcType()).toBeFalsy();
+            });
+
+        });
+
+        describe('with empty data', function () {
+
+            it('should update args to have empty data', function () {
+                args = {
+                    data: {
+                        columns: [],
+                        type: 'pie'
+                    }
+                };
+                expect(true).toBeTruthy();
+            });
+
+            it('should return true', function () {
+                expect(chart.internal.hasArcType()).toBeTruthy();
+            });
+
+            it('should change chart type to "bar"', function () {
+                args.data.type = 'bar';
+                expect(true).toBeTruthy();
+            });
+
+            it('should return false', function () {
+                expect(chart.internal.hasArcType()).toBeFalsy();
+            });
+
+        });
+
+    });
+
+    describe('internal.hasType', function () {
+
+        it('should update args', function () {
+            args = {
+                data: {
+                    columns: [
+                        ['data1', 30, 200, 100, 400, 150, 250],
+                        ['data2', 50, 20, 10, 40, 15, 25],
+                        ['data3', 150, 120, 110, 140, 115, 125]
+                    ],
+                    type: 'pie'
+                }
+            };
+            expect(true).toBeTruthy();
+        });
+
+        it('should return true for "pie" type', function () {
+            expect(chart.internal.hasType('pie')).toBeTruthy();
+        });
+
+        it('should return false for "line" type', function () {
+            expect(chart.internal.hasType('line')).toBeFalsy();
+        });
+
+        it('should return false for "bar" type', function () {
+            expect(chart.internal.hasType('bar')).toBeFalsy();
+        });
+
+        it('should unload successfully', function () {
+            chart.unload([]);
+            expect(true).toBeTruthy();
+        });
+
+        it('should return true for "pie" type even if no data', function () {
+            expect(chart.internal.hasType('pie')).toBeTruthy();
+        });
+
+        it('should return false for "line" type even if no data', function () {
+            expect(chart.internal.hasType('line')).toBeFalsy();
+        });
+
+        it('should return false for "bar" type even if no data', function () {
+            expect(chart.internal.hasType('bar')).toBeFalsy();
+        });
+
+        it('should change chart type to "bar" successfully', function () {
+            args.data.type = 'bar';
+            expect(true).toBeTruthy();
+        });
+
+        it('should return false for "pie" type even if no data', function () {
+            expect(chart.internal.hasType('pie')).toBeFalsy();
+        });
+
+        it('should return false for "line" type even if no data', function () {
+            expect(chart.internal.hasType('line')).toBeFalsy();
+        });
+
+        it('should return true for "bar" type even if no data', function () {
+            expect(chart.internal.hasType('bar')).toBeTruthy();
+        });
+
+
+    });
+
+});
diff --git a/spec/zoom-spec.js b/spec/zoom-spec.js
new file mode 100644
index 0000000..060769c
--- /dev/null
+++ b/spec/zoom-spec.js
@@ -0,0 +1,73 @@
+var describe = window.describe,
+    expect = window.expect,
+    it = window.it,
+    beforeEach = window.beforeEach;
+
+describe('c3 chart zoom', function () {
+    'use strict';
+
+    var chart, d3;
+
+    var args = {
+        data: {
+            columns: [
+                ['data1', 30, 200, 100, 400, 3150, 250],
+                ['data2', 50, 20, 10, 40, 15, 6025]
+            ]
+        },
+        axis: {
+            x: {
+                extent: [1, 2]
+            }
+        },
+        zoom: {
+            enable: true
+        },
+        subchart: {
+            show: true
+        }
+    };
+
+    beforeEach(function (done) {
+        chart = window.initChart(chart, args, done);
+        d3 = chart.internal.d3;
+    });
+
+    describe('default extent', function () {
+
+        describe('main chart domain', function () {
+
+            it('should have original y domain', function () {
+                var yDomain = chart.internal.y.domain(),
+                    expectedYDomain = [-591.5, 6626.5];
+                expect(yDomain[0]).toBe(expectedYDomain[0]);
+                expect(yDomain[1]).toBe(expectedYDomain[1]);
+            });
+
+        });
+
+        describe('main chart domain', function () {
+
+            it('should have original y domain in subchart', function () {
+                var yDomain = chart.internal.y.domain(),
+                    subYDomain = chart.internal.subY.domain();
+                expect(subYDomain[0]).toBe(yDomain[0]);
+                expect(subYDomain[1]).toBe(yDomain[1]);
+            });
+
+        });
+
+        describe('main chart domain', function () {
+
+            it('should have specified brush extent', function () {
+                var brushExtent = chart.internal.brush.extent(),
+                    expectedBrushExtent = [1, 2];
+                expect(brushExtent[0]).toBe(expectedBrushExtent[0]);
+                expect(brushExtent[1]).toBe(expectedBrushExtent[1]);
+            });
+
+        });
+
+    });
+
+});
diff --git a/src/api.axis.js b/src/api.axis.js
new file mode 100644
index 0000000..c1e4846
--- /dev/null
+++ b/src/api.axis.js
@@ -0,0 +1,60 @@
+c3_chart_fn.axis = function () {};
+c3_chart_fn.axis.labels = function (labels) {
+    var $$ = this.internal;
+    if (arguments.length) {
+        Object.keys(labels).forEach(function (axisId) {
+            $$.setAxisLabelText(axisId, labels[axisId]);
+        });
+        $$.updateAxisLabels();
+    }
+    // TODO: return some values?
+};
+c3_chart_fn.axis.max = function (max) {
+    var $$ = this.internal, config = $$.config;
+    if (arguments.length) {
+        if (typeof max === 'object') {
+            if (isValue(max.x)) { config.axis_x_max = max.x; }
+            if (isValue(max.y)) { config.axis_y_max = max.y; }
+            if (isValue(max.y2)) { config.axis_y2_max = max.y2; }
+        } else {
+            config.axis_y_max = config.axis_y2_max = max;
+        }
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+    } else {
+        return {
+            x: config.axis_x_max,
+            y: config.axis_y_max,
+            y2: config.axis_y2_max
+        };
+    }
+};
+c3_chart_fn.axis.min = function (min) {
+    var $$ = this.internal, config = $$.config;
+    if (arguments.length) {
+        if (typeof min === 'object') {
+            if (isValue(min.x)) { config.axis_x_min = min.x; }
+            if (isValue(min.y)) { config.axis_y_min = min.y; }
+            if (isValue(min.y2)) { config.axis_y2_min = min.y2; }
+        } else {
+            config.axis_y_min = config.axis_y2_min = min;
+        }
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+    } else {
+        return {
+            x: config.axis_x_min,
+            y: config.axis_y_min,
+            y2: config.axis_y2_min
+        };
+    }
+};
+c3_chart_fn.axis.range = function (range) {
+    if (arguments.length) {
+        if (isDefined(range.max)) { this.axis.max(range.max); }
+        if (isDefined(range.min)) { this.axis.min(range.min); }
+    } else {
+        return {
+            max: this.axis.max(),
+            min: this.axis.min()
+        };
+    }
+};
diff --git a/src/api.category.js b/src/api.category.js
new file mode 100644
index 0000000..1616c4a
--- /dev/null
+++ b/src/api.category.js
@@ -0,0 +1,15 @@
+c3_chart_fn.category = function (i, category) {
+    var $$ = this.internal, config = $$.config;
+    if (arguments.length > 1) {
+        config.axis_x_categories[i] = category;
+        $$.redraw();
+    }
+    return config.axis_x_categories[i];
+};
+c3_chart_fn.categories = function (categories) {
+    var $$ = this.internal, config = $$.config;
+    if (!arguments.length) { return config.axis_x_categories; }
+    config.axis_x_categories = categories;
+    $$.redraw();
+    return config.axis_x_categories;
+};
diff --git a/src/api.chart.js b/src/api.chart.js
new file mode 100644
index 0000000..1e11181
--- /dev/null
+++ b/src/api.chart.js
@@ -0,0 +1,20 @@
+c3_chart_fn.resize = function (size) {
+    var $$ = this.internal, config = $$.config;
+    config.size_width = size ? size.width : null;
+    config.size_height = size ? size.height : null;
+    this.flush();
+};
+
+c3_chart_fn.flush = function () {
+    var $$ = this.internal;
+    $$.updateAndRedraw({withLegend: true, withTransition: false, withTransitionForTransform: false});
+};
+
+c3_chart_fn.destroy = function () {
+    var $$ = this.internal;
+    $$.data.targets = undefined;
+    $$.data.xs = {};
+    $$.selectChart.classed('c3', false).html("");
+    window.clearInterval($$.intervalForObserveInserted);
+    window.onresize = null;
+};
diff --git a/src/api.color.js b/src/api.color.js
new file mode 100644
index 0000000..15aaa3e
--- /dev/null
+++ b/src/api.color.js
@@ -0,0 +1,5 @@
+// TODO: fix
+c3_chart_fn.color = function (id) {
+    var $$ = this.internal;
+    return $$.color(id); // more patterns
+};
diff --git a/src/api.data.js b/src/api.data.js
new file mode 100644
index 0000000..be5b8f7
--- /dev/null
+++ b/src/api.data.js
@@ -0,0 +1,27 @@
+c3_chart_fn.data = function (targetIds) {
+    var targets = this.internal.data.targets;
+    return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
+        return [].concat(targetIds).indexOf(t.id) >= 0;
+    });
+};
+c3_chart_fn.data.shown = function (targetIds) {
+    return this.internal.filterTargetsToShow(this.data(targetIds));
+};
+c3_chart_fn.data.values = function (targetId) {
+    var targets, values = null;
+    if (targetId) {
+        targets = this.data(targetId);
+        values = targets[0] ? targets[0].values.map(function (d) { return d.value; }) : null;
+    }
+    return values;
+};
+c3_chart_fn.data.names = function (names) {
+    this.internal.clearLegendItemTextBoxCache();
+    return this.internal.updateDataAttributes('names', names);
+};
+c3_chart_fn.data.colors = function (colors) {
+    return this.internal.updateDataAttributes('colors', colors);
+};
+c3_chart_fn.data.axes = function (axes) {
+    return this.internal.updateDataAttributes('axes', axes);
+};
diff --git a/src/api.flow.js b/src/api.flow.js
new file mode 100644
index 0000000..d8afc19
--- /dev/null
+++ b/src/api.flow.js
@@ -0,0 +1,294 @@
+c3_chart_fn.flow = function (args) {
+    var $$ = this.internal,
+        targets, data, notfoundIds = [], orgDataCount = $$.getMaxDataCount(),
+        dataCount, domain, baseTarget, baseValue, length = 0, tail = 0, diff, to;
+
+    if (args.json) {
+        data = $$.convertJsonToData(args.json, args.keys);
+    }
+    else if (args.rows) {
+        data = $$.convertRowsToData(args.rows);
+    }
+    else if (args.columns) {
+        data = $$.convertColumnsToData(args.columns);
+    }
+    else {
+        return;
+    }
+    targets = $$.convertDataToTargets(data, true);
+
+    // Update/Add data
+    $$.data.targets.forEach(function (t) {
+        var found = false, i, j;
+        for (i = 0; i < targets.length; i++) {
+            if (t.id === targets[i].id) {
+                found = true;
+
+                if (t.values[t.values.length - 1]) {
+                    tail = t.values[t.values.length - 1].index + 1;
+                }
+                length = targets[i].values.length;
+
+                for (j = 0; j < length; j++) {
+                    targets[i].values[j].index = tail + j;
+                    if (!$$.isTimeSeries()) {
+                        targets[i].values[j].x = tail + j;
+                    }
+                }
+                t.values = t.values.concat(targets[i].values);
+
+                targets.splice(i, 1);
+                break;
+            }
+        }
+        if (!found) { notfoundIds.push(t.id); }
+    });
+
+    // Append null for not found targets
+    $$.data.targets.forEach(function (t) {
+        var i, j;
+        for (i = 0; i < notfoundIds.length; i++) {
+            if (t.id === notfoundIds[i]) {
+                tail = t.values[t.values.length - 1].index + 1;
+                for (j = 0; j < length; j++) {
+                    t.values.push({
+                        id: t.id,
+                        index: tail + j,
+                        x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
+                        value: null
+                    });
+                }
+            }
+        }
+    });
+
+    // Generate null values for new target
+    if ($$.data.targets.length) {
+        targets.forEach(function (t) {
+            var i, missing = [];
+            for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
+                missing.push({
+                    id: t.id,
+                    index: i,
+                    x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
+                    value: null
+                });
+            }
+            t.values.forEach(function (v) {
+                v.index += tail;
+                if (!$$.isTimeSeries()) {
+                    v.x += tail;
+                }
+            });
+            t.values = missing.concat(t.values);
+        });
+    }
+    $$.data.targets = $$.data.targets.concat(targets); // add remained
+
+    // check data count because behavior needs to change when it's only one
+    dataCount = $$.getMaxDataCount();
+    baseTarget = $$.data.targets[0];
+    baseValue = baseTarget.values[0];
+
+    // Update length to flow if needed
+    if (isDefined(args.to)) {
+        length = 0;
+        to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
+        baseTarget.values.forEach(function (v) {
+            if (v.x < to) { length++; }
+        });
+    } else if (isDefined(args.length)) {
+        length = args.length;
+    }
+
+    // If only one data, update the domain to flow from left edge of the chart
+    if (!orgDataCount) {
+        if ($$.isTimeSeries()) {
+            if (baseTarget.values.length > 1) {
+                diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
+            } else {
+                diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
+            }
+        } else {
+            diff = 1;
+        }
+        domain = [baseValue.x - diff, baseValue.x];
+        $$.updateXDomain(null, true, true, false, domain);
+    } else if (orgDataCount === 1) {
+        if ($$.isTimeSeries()) {
+            diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
+            domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
+            $$.updateXDomain(null, true, true, false, domain);
+        }
+    }
+
+    // Set targets
+    $$.updateTargets($$.data.targets);
+
+    // Redraw with new targets
+    $$.redraw({
+        flow: {
+            index: baseValue.index,
+            length: length,
+            duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
+            done: args.done,
+            orgDataCount: orgDataCount,
+        },
+        withLegend: true,
+        withTransition: orgDataCount > 1,
+        withTrimXDomain: false,
+        withUpdateXAxis: true,
+    });
+};
+
+c3_chart_internal_fn.generateFlow = function (args) {
+    var $$ = this, config = $$.config, d3 = $$.d3;
+
+    return function () {
+        var targets = args.targets,
+            flow = args.flow,
+            drawBar = args.drawBar,
+            drawLine = args.drawLine,
+            drawArea = args.drawArea,
+            cx = args.cx,
+            cy = args.cy,
+            xv = args.xv,
+            xForText = args.xForText,
+            yForText = args.yForText,
+            duration = args.duration;
+
+        var translateX, scaleX = 1, transform,
+            flowIndex = flow.index,
+            flowLength = flow.length,
+            flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
+            flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
+            orgDomain = $$.x.domain(), domain,
+            durationForFlow = flow.duration || duration,
+            done = flow.done || function () {},
+            wait = $$.generateWait();
+
+        var xgrid = $$.xgrid || d3.selectAll([]),
+            xgridLines = $$.xgridLines || d3.selectAll([]),
+            mainRegion = $$.mainRegion || d3.selectAll([]),
+            mainText = $$.mainText || d3.selectAll([]),
+            mainBar = $$.mainBar || d3.selectAll([]),
+            mainLine = $$.mainLine || d3.selectAll([]),
+            mainArea = $$.mainArea || d3.selectAll([]),
+            mainCircle = $$.mainCircle || d3.selectAll([]);
+
+        // set flag
+        $$.flowing = true;
+
+        // remove head data after rendered
+        $$.data.targets.forEach(function (d) {
+            d.values.splice(0, flowLength);
+        });
+
+        // update x domain to generate axis elements for flow
+        domain = $$.updateXDomain(targets, true, true);
+        // update elements related to x scale
+        if ($$.updateXGrid) { $$.updateXGrid(true); }
+
+        // generate transform to flow
+        if (!flow.orgDataCount) { // if empty
+            if ($$.data.targets[0].values.length !== 1) {
+                translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+            } else {
+                if ($$.isTimeSeries()) {
+                    flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
+                    flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
+                    translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
+                } else {
+                    translateX = diffDomain(domain) / 2;
+                }
+            }
+        } else if (flow.orgDataCount === 1 || flowStart.x === flowEnd.x) {
+            translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
+        } else {
+            if ($$.isTimeSeries()) {
+                translateX = ($$.x(orgDomain[0]) - $$.x(domain[0]));
+            } else {
+                translateX = ($$.x(flowStart.x) - $$.x(flowEnd.x));
+            }
+        }
+        scaleX = (diffDomain(orgDomain) / diffDomain(domain));
+        transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
+
+        // hide tooltip
+        $$.hideXGridFocus();
+        $$.hideTooltip();
+
+        d3.transition().ease('linear').duration(durationForFlow).each(function () {
+            wait.add($$.axes.x.transition().call($$.xAxis));
+            wait.add(mainBar.transition().attr('transform', transform));
+            wait.add(mainLine.transition().attr('transform', transform));
+            wait.add(mainArea.transition().attr('transform', transform));
+            wait.add(mainCircle.transition().attr('transform', transform));
+            wait.add(mainText.transition().attr('transform', transform));
+            wait.add(mainRegion.filter($$.isRegionOnX).transition().attr('transform', transform));
+            wait.add(xgrid.transition().attr('transform', transform));
+            wait.add(xgridLines.transition().attr('transform', transform));
+        })
+        .call(wait, function () {
+            var i, shapes = [], texts = [], eventRects = [];
+
+            // remove flowed elements
+            if (flowLength) {
+                for (i = 0; i < flowLength; i++) {
+                    shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
+                    texts.push('.' + CLASS.text + '-' + (flowIndex + i));
+                    eventRects.push('.' + CLASS.eventRect + '-' + (flowIndex + i));
+                }
+                $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
+                $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
+                $$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove();
+                $$.svg.select('.' + CLASS.xgrid).remove();
+            }
+
+            // draw again for removing flowed elements and reverting attr
+            xgrid
+                .attr('transform', null)
+                .attr($$.xgridAttr);
+            xgridLines
+                .attr('transform', null);
+            xgridLines.select('line')
+                .attr("x1", config.axis_rotated ? 0 : xv)
+                .attr("x2", config.axis_rotated ? $$.width : xv);
+            xgridLines.select('text')
+                .attr("x", config.axis_rotated ? $$.width : 0)
+                .attr("y", xv);
+            mainBar
+                .attr('transform', null)
+                .attr("d", drawBar);
+            mainLine
+                .attr('transform', null)
+                .attr("d", drawLine);
+            mainArea
+                .attr('transform', null)
+                .attr("d", drawArea);
+            mainCircle
+                .attr('transform', null)
+                .attr("cx", cx)
+                .attr("cy", cy);
+            mainText
+                .attr('transform', null)
+                .attr('x', xForText)
+                .attr('y', yForText)
+                .style('fill-opacity', $$.opacityForText.bind($$));
+            mainRegion
+                .attr('transform', null);
+            mainRegion.select('rect').filter($$.isRegionOnX)
+                .attr("x", $$.regionX.bind($$))
+                .attr("width", $$.regionWidth.bind($$));
+
+            if (config.interaction_enabled) {
+                $$.redrawEventRect();
+            }
+
+            // callback for end of flow
+            done();
+
+            $$.flowing = false;
+        });
+    };
+};
diff --git a/src/api.focus.js b/src/api.focus.js
new file mode 100644
index 0000000..97ec8a5
--- /dev/null
+++ b/src/api.focus.js
@@ -0,0 +1,54 @@
+c3_chart_fn.focus = function (targetIds) {
+    var $$ = this.internal, candidates;
+
+    targetIds = $$.mapToTargetIds(targetIds);
+    candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
+
+    this.revert();
+    this.defocus();
+    candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
+    if ($$.hasArcType()) {
+        $$.expandArc(targetIds);
+    }
+    $$.toggleFocusLegend(targetIds, true);
+
+    $$.focusedTargetIds = targetIds;
+    $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
+        return targetIds.indexOf(id) < 0;
+    });
+};
+
+c3_chart_fn.defocus = function (targetIds) {
+    var $$ = this.internal, candidates;
+
+    targetIds = $$.mapToTargetIds(targetIds);
+    candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
+
+    this.revert();
+    candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
+    if ($$.hasArcType()) {
+        $$.unexpandArc(targetIds);
+    }
+    $$.toggleFocusLegend(targetIds, false);
+
+    $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
+        return targetIds.indexOf(id) < 0;
+    });
+    $$.defocusedTargetIds = targetIds;
+};
+
+c3_chart_fn.revert = function (targetIds) {
+    var $$ = this.internal, candidates;
+
+    targetIds = $$.mapToTargetIds(targetIds);
+    candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
+
+    candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
+    if ($$.hasArcType()) {
+        $$.unexpandArc(targetIds);
+    }
+    $$.showLegend(targetIds);
+
+    $$.focusedTargetIds = [];
+    $$.defocusedTargetIds = [];
+};
diff --git a/src/api.grid.js b/src/api.grid.js
new file mode 100644
index 0000000..038aa6b
--- /dev/null
+++ b/src/api.grid.js
@@ -0,0 +1,31 @@
+c3_chart_fn.xgrids = function (grids) {
+    var $$ = this.internal, config = $$.config;
+    if (! grids) { return config.grid_x_lines; }
+    config.grid_x_lines = grids;
+    $$.redrawWithoutRescale();
+    return config.grid_x_lines;
+};
+c3_chart_fn.xgrids.add = function (grids) {
+    var $$ = this.internal;
+    return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
+};
+c3_chart_fn.xgrids.remove = function (params) { // TODO: multiple
+    var $$ = this.internal;
+    $$.removeGridLines(params, true);
+};
+
+c3_chart_fn.ygrids = function (grids) {
+    var $$ = this.internal, config = $$.config;
+    if (! grids) { return config.grid_y_lines; }
+    config.grid_y_lines = grids;
+    $$.redrawWithoutRescale();
+    return config.grid_y_lines;
+};
+c3_chart_fn.ygrids.add = function (grids) {
+    var $$ = this.internal;
+    return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
+};
+c3_chart_fn.ygrids.remove = function (params) { // TODO: multiple
+    var $$ = this.internal;
+    $$.removeGridLines(params, false);
+};
diff --git a/src/api.group.js b/src/api.group.js
new file mode 100644
index 0000000..47fedb4
--- /dev/null
+++ b/src/api.group.js
@@ -0,0 +1,7 @@
+c3_chart_fn.groups = function (groups) {
+    var $$ = this.internal, config = $$.config;
+    if (isUndefined(groups)) { return config.data_groups; }
+    config.data_groups = groups;
+    $$.redraw();
+    return config.data_groups;
+};
diff --git a/src/api.legend.js b/src/api.legend.js
new file mode 100644
index 0000000..182caa1
--- /dev/null
+++ b/src/api.legend.js
@@ -0,0 +1,11 @@
+c3_chart_fn.legend = function () {};
+c3_chart_fn.legend.show = function (targetIds) {
+    var $$ = this.internal;
+    $$.showLegend($$.mapToTargetIds(targetIds));
+    $$.updateAndRedraw({withLegend: true});
+};
+c3_chart_fn.legend.hide = function (targetIds) {
+    var $$ = this.internal;
+    $$.hideLegend($$.mapToTargetIds(targetIds));
+    $$.updateAndRedraw({withLegend: true});
+};
diff --git a/src/api.load.js b/src/api.load.js
new file mode 100644
index 0000000..e186f89
--- /dev/null
+++ b/src/api.load.js
@@ -0,0 +1,51 @@
+c3_chart_fn.load = function (args) {
+    var $$ = this.internal, config = $$.config;
+    // update xs if specified
+    if (args.xs) {
+        $$.addXs(args.xs);
+    }
+    // update classes if exists
+    if ('classes' in args) {
+        Object.keys(args.classes).forEach(function (id) {
+            config.data_classes[id] = args.classes[id];
+        });
+    }
+    // update categories if exists
+    if ('categories' in args && $$.isCategorized()) {
+        config.axis_x_categories = args.categories;
+    }
+    // update axes if exists
+    if ('axes' in args) {
+        Object.keys(args.axes).forEach(function (id) {
+            config.data_axes[id] = args.axes[id];
+        });
+    }
+    // use cache if exists
+    if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
+        $$.load($$.getCaches(args.cacheIds), args.done);
+        return;
+    }
+    // unload if needed
+    if ('unload' in args) {
+        // TODO: do not unload if target will load (included in url/rows/columns)
+        $$.unload($$.mapToTargetIds((typeof args.unload === 'boolean' && args.unload) ? null : args.unload), function () {
+            $$.loadFromArgs(args);
+        });
+    } else {
+        $$.loadFromArgs(args);
+    }
+};
+
+c3_chart_fn.unload = function (args) {
+    var $$ = this.internal;
+    args = args || {};
+    if (args instanceof Array) {
+        args = {ids: args};
+    } else if (typeof args === 'string') {
+        args = {ids: [args]};
+    }
+    $$.unload($$.mapToTargetIds(args.ids), function () {
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+        if (args.done) { args.done(); }
+    });
+};
diff --git a/src/api.region.js b/src/api.region.js
new file mode 100644
index 0000000..b587b4f
--- /dev/null
+++ b/src/api.region.js
@@ -0,0 +1,40 @@
+c3_chart_fn.regions = function (regions) {
+    var $$ = this.internal, config = $$.config;
+    if (!regions) { return config.regions; }
+    config.regions = regions;
+    $$.redrawWithoutRescale();
+    return config.regions;
+};
+c3_chart_fn.regions.add = function (regions) {
+    var $$ = this.internal, config = $$.config;
+    if (!regions) { return config.regions; }
+    config.regions = config.regions.concat(regions);
+    $$.redrawWithoutRescale();
+    return config.regions;
+};
+c3_chart_fn.regions.remove = function (options) {
+    var $$ = this.internal, config = $$.config,
+        duration, classes, regions;
+
+    options = options || {};
+    duration = $$.getOption(options, "duration", config.transition_duration);
+    classes = $$.getOption(options, "classes", [CLASS.region]);
+
+    regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) { return '.' + c; }));
+    (duration ? regions.transition().duration(duration) : regions)
+        .style('opacity', 0)
+        .remove();
+
+    config.regions = config.regions.filter(function (region) {
+        var found = false;
+        if (!region['class']) {
+            return true;
+        }
+        region['class'].split(' ').forEach(function (c) {
+            if (classes.indexOf(c) >= 0) { found = true; }
+        });
+        return !found;
+    });
+
+    return config.regions;
+};
diff --git a/src/api.selection.js b/src/api.selection.js
new file mode 100644
index 0000000..02ad601
--- /dev/null
+++ b/src/api.selection.js
@@ -0,0 +1,54 @@
+c3_chart_fn.selected = function (targetId) {
+    var $$ = this.internal, d3 = $$.d3;
+    return d3.merge(
+        $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
+            .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
+            .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
+    );
+};
+c3_chart_fn.select = function (ids, indices, resetOther) {
+    var $$ = this.internal, d3 = $$.d3, config = $$.config;
+    if (! config.data_selection_enabled) { return; }
+    $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+        var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+            toggle = $$.getToggle(this, d).bind($$),
+            isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+            isTargetIndex = !indices || indices.indexOf(i) >= 0,
+            isSelected = shape.classed(CLASS.SELECTED);
+        // line/area selection not supported yet
+        if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+            return;
+        }
+        if (isTargetId && isTargetIndex) {
+            if (config.data_selection_isselectable(d) && !isSelected) {
+                toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
+            }
+        } else if (isDefined(resetOther) && resetOther) {
+            if (isSelected) {
+                toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+            }
+        }
+    });
+};
+c3_chart_fn.unselect = function (ids, indices) {
+    var $$ = this.internal, d3 = $$.d3, config = $$.config;
+    if (! config.data_selection_enabled) { return; }
+    $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
+        var shape = d3.select(this), id = d.data ? d.data.id : d.id,
+            toggle = $$.getToggle(this, d).bind($$),
+            isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
+            isTargetIndex = !indices || indices.indexOf(i) >= 0,
+            isSelected = shape.classed(CLASS.SELECTED);
+        // line/area selection not supported yet
+        if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
+            return;
+        }
+        if (isTargetId && isTargetIndex) {
+            if (config.data_selection_isselectable(d)) {
+                if (isSelected) {
+                    toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
+                }
+            }
+        }
+    });
+};
diff --git a/src/api.show.js b/src/api.show.js
new file mode 100644
index 0000000..541ec96
--- /dev/null
+++ b/src/api.show.js
@@ -0,0 +1,50 @@
+c3_chart_fn.show = function (targetIds, options) {
+    var $$ = this.internal, targets;
+
+    targetIds = $$.mapToTargetIds(targetIds);
+    options = options || {};
+
+    $$.removeHiddenTargetIds(targetIds);
+    targets = $$.svg.selectAll($$.selectorTargets(targetIds));
+
+    targets.transition()
+        .style('opacity', 1, 'important')
+        .call($$.endall, function () {
+            targets.style('opacity', null).style('opacity', 1);
+        });
+
+    if (options.withLegend) {
+        $$.showLegend(targetIds);
+    }
+
+    $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+};
+
+c3_chart_fn.hide = function (targetIds, options) {
+    var $$ = this.internal, targets;
+
+    targetIds = $$.mapToTargetIds(targetIds);
+    options = options || {};
+
+    $$.addHiddenTargetIds(targetIds);
+    targets = $$.svg.selectAll($$.selectorTargets(targetIds));
+
+    targets.transition()
+        .style('opacity', 0, 'important')
+        .call($$.endall, function () {
+            targets.style('opacity', null).style('opacity', 0);
+        });
+
+    if (options.withLegend) {
+        $$.hideLegend(targetIds);
+    }
+
+    $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+};
+
+c3_chart_fn.toggle = function (targetIds) {
+    var that = this, $$ = this.internal;
+    $$.mapToTargetIds(targetIds).forEach(function (targetId) {
+        $$.isTargetToShow(targetId) ? that.hide(targetId) : that.show(targetId);
+    });
+};
diff --git a/src/api.tooltip.js b/src/api.tooltip.js
new file mode 100644
index 0000000..045a52e
--- /dev/null
+++ b/src/api.tooltip.js
@@ -0,0 +1,35 @@
+c3_chart_fn.tooltip = function () {};
+c3_chart_fn.tooltip.show = function (args) {
+    var $$ = this.internal, index, mouse;
+
+    // determine mouse position on the chart
+    if (args.mouse) {
+        mouse = args.mouse;
+    }
+
+    // determine focus data
+    if (args.data) {
+        if ($$.isMultipleX()) {
+            // if multiple xs, target point will be determined by mouse
+            mouse = [$$.x(args.data.x), $$.getYScale(args.data.id)(args.data.value)];
+            index = null;
+        } else {
+            // TODO: when tooltip_grouped = false
+            index = isValue(args.data.index) ? args.data.index : $$.getIndexByX(args.data.x);
+        }
+    }
+    else if (typeof args.x !== 'undefined') {
+        index = $$.getIndexByX(args.x);
+    }
+    else if (typeof args.index !== 'undefined') {
+        index = args.index;
+    }
+
+    // emulate mouse events to show
+    $$.dispatchEvent('mouseover', index, mouse);
+    $$.dispatchEvent('mousemove', index, mouse);
+};
+c3_chart_fn.tooltip.hide = function () {
+    // TODO: get target data by checking the state of focus
+    this.internal.dispatchEvent('mouseout', 0);
+};
diff --git a/src/api.transform.js b/src/api.transform.js
new file mode 100644
index 0000000..62cbe80
--- /dev/null
+++ b/src/api.transform.js
@@ -0,0 +1,15 @@
+c3_chart_fn.transform = function (type, targetIds) {
+    var $$ = this.internal,
+        options = ['pie', 'donut'].indexOf(type) >= 0 ? {withTransform: true} : null;
+    $$.transformTo(targetIds, type, options);
+};
+
+c3_chart_internal_fn.transformTo = function (targetIds, type, optionsForRedraw) {
+    var $$ = this,
+        withTransitionForAxis = !$$.hasArcType(),
+        options = optionsForRedraw || {withTransitionForAxis: withTransitionForAxis};
+    options.withTransitionForTransform = false;
+    $$.transiting = false;
+    $$.setTargetType(targetIds, type);
+    $$.updateAndRedraw(options);
+};
diff --git a/src/api.x.js b/src/api.x.js
new file mode 100644
index 0000000..93d25d4
--- /dev/null
+++ b/src/api.x.js
@@ -0,0 +1,16 @@
+c3_chart_fn.x = function (x) {
+    var $$ = this.internal;
+    if (arguments.length) {
+        $$.updateTargetX($$.data.targets, x);
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+    }
+    return $$.data.xs;
+};
+c3_chart_fn.xs = function (xs) {
+    var $$ = this.internal;
+    if (arguments.length) {
+        $$.updateTargetXs($$.data.targets, xs);
+        $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
+    }
+    return $$.data.xs;
+};
diff --git a/src/api.zoom.js b/src/api.zoom.js
new file mode 100644
index 0000000..07e7a58
--- /dev/null
+++ b/src/api.zoom.js
@@ -0,0 +1,22 @@
+c3_chart_fn.zoom = function (domain) {
+    var $$ = this.internal;
+    if (domain) {
+        if ($$.isTimeSeries()) {
+            domain = domain.map(function (x) { return $$.parseDate(x); });
+        }
+        $$.brush.extent(domain);
+        $$.redraw({withUpdateXDomain: true, withY: $$.config.zoom_rescale});
+        $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
+    }
+    return $$.brush.extent();
+};
+c3_chart_fn.zoom.enable = function (enabled) {
+    var $$ = this.internal;
+    $$.config.zoom_enabled = enabled;
+    $$.updateAndRedraw();
+};
+c3_chart_fn.unzoom = function () {
+    var $$ = this.internal;
+    $$.brush.clear().update();
+    $$.redraw({withUpdateXDomain: true});
+};
diff --git a/src/arc.js b/src/arc.js
new file mode 100644
index 0000000..c70077f
--- /dev/null
+++ b/src/arc.js
@@ -0,0 +1,388 @@
+c3_chart_internal_fn.initPie = function () {
+    var $$ = this, d3 = $$.d3, config = $$.config;
+    $$.pie = d3.layout.pie().value(function (d) {
+        return d.values.reduce(function (a, b) { return a + b.value; }, 0);
+    });
+    if (!config.data_order) {
+        $$.pie.sort(null);
+    }
+};
+
+c3_chart_internal_fn.updateRadius = function () {
+    var $$ = this, config = $$.config,
+        w = config.gauge_width || config.donut_width;
+    $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2;
+    $$.radius = $$.radiusExpanded * 0.95;
+    $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
+    $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
+};
+
+c3_chart_internal_fn.updateArc = function () {
+    var $$ = this;
+    $$.svgArc = $$.getSvgArc();
+    $$.svgArcExpanded = $$.getSvgArcExpanded();
+    $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
+};
+
+c3_chart_internal_fn.updateAngle = function (d) {
+    var $$ = this, config = $$.config,
+        found = false, index = 0,
+        gMin = config.gauge_min, gMax = config.gauge_max, gTic, gValue;
+    $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
+        if (! found && t.data.id === d.data.id) {
+            found = true;
+            d = t;
+            d.index = index;
+        }
+        index++;
+    });
+    if (isNaN(d.endAngle)) {
+        d.endAngle = d.startAngle;
+    }
+    if ($$.isGaugeType(d.data)) {
+        gTic = (Math.PI) / (gMax - gMin);
+        gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
+        d.startAngle = -1 * (Math.PI / 2);
+        d.endAngle = d.startAngle + gTic * gValue;
+    }
+    return found ? d : null;
+};
+
+c3_chart_internal_fn.getSvgArc = function () {
+    var $$ = this,
+        arc = $$.d3.svg.arc().outerRadius($$.radius).innerRadius($$.innerRadius),
+        newArc = function (d, withoutUpdate) {
+            var updated;
+            if (withoutUpdate) { return arc(d); } // for interpolate
+            updated = $$.updateAngle(d);
+            return updated ? arc(updated) : "M 0 0";
+        };
+    // TODO: extends all function
+    newArc.centroid = arc.centroid;
+    return newArc;
+};
+
+c3_chart_internal_fn.getSvgArcExpanded = function (rate) {
+    var $$ = this,
+        arc = $$.d3.svg.arc().outerRadius($$.radiusExpanded * (rate ? rate : 1)).innerRadius($$.innerRadius);
+    return function (d) {
+        var updated = $$.updateAngle(d);
+        return updated ? arc(updated) : "M 0 0";
+    };
+};
+
+c3_chart_internal_fn.getArc = function (d, withoutUpdate, force) {
+    return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
+};
+
+
+c3_chart_internal_fn.transformForArcLabel = function (d) {
+    var $$ = this,
+        updated = $$.updateAngle(d), c, x, y, h, ratio, translate = "";
+    if (updated && !$$.hasType('gauge')) {
+        c = this.svgArc.centroid(updated);
+        x = isNaN(c[0]) ? 0 : c[0];
+        y = isNaN(c[1]) ? 0 : c[1];
+        h = Math.sqrt(x * x + y * y);
+        // TODO: ratio should be an option?
+        ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
+        translate = "translate(" + (x * ratio) +  ',' + (y * ratio) +  ")";
+    }
+    return translate;
+};
+
+c3_chart_internal_fn.getArcRatio = function (d) {
+    var $$ = this,
+        whole = $$.hasType('gauge') ? Math.PI : (Math.PI * 2);
+    return d ? (d.endAngle - d.startAngle) / whole : null;
+};
+
+c3_chart_internal_fn.convertToArcData = function (d) {
+    return this.addName({
+        id: d.data.id,
+        value: d.value,
+        ratio: this.getArcRatio(d),
+        index: d.index
+    });
+};
+
+c3_chart_internal_fn.textForArcLabel = function (d) {
+    var $$ = this,
+        updated, value, ratio, id, format;
+    if (! $$.shouldShowArcLabel()) { return ""; }
+    updated = $$.updateAngle(d);
+    value = updated ? updated.value : null;
+    ratio = $$.getArcRatio(updated);
+    id = d.data.id;
+    if (! $$.hasType('gauge') && ! $$.meetsArcLabelThreshold(ratio)) { return ""; }
+    format = $$.getArcLabelFormat();
+    return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
+};
+
+c3_chart_internal_fn.expandArc = function (targetIds) {
+    var $$ = this, interval;
+
+    // MEMO: avoid to cancel transition
+    if ($$.transiting) {
+        interval = window.setInterval(function () {
+            if (!$$.transiting) {
+                window.clearInterval(interval);
+                if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
+                    $$.expandArc(targetIds);
+                }
+            }
+        }, 10);
+        return;
+    }
+
+    targetIds = $$.mapToTargetIds(targetIds);
+
+    $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
+        if (! $$.shouldExpand(d.data.id)) { return; }
+        $$.d3.select(this).selectAll('path')
+            .transition().duration(50)
+            .attr("d", $$.svgArcExpanded)
+            .transition().duration(100)
+            .attr("d", $$.svgArcExpandedSub)
+            .each(function (d) {
+                if ($$.isDonutType(d.data)) {
+                    // callback here
+                }
+            });
+    });
+};
+
+c3_chart_internal_fn.unexpandArc = function (targetIds) {
+    var $$ = this;
+
+    if ($$.transiting) { return; }
+
+    targetIds = $$.mapToTargetIds(targetIds);
+
+    $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
+        .transition().duration(50)
+        .attr("d", $$.svgArc);
+    $$.svg.selectAll('.' + CLASS.arc)
+        .style("opacity", 1);
+};
+
+c3_chart_internal_fn.shouldExpand = function (id) {
+    var $$ = this, config = $$.config;
+    return ($$.isDonutType(id) && config.donut_expand) || ($$.isGaugeType(id) && config.gauge_expand) || ($$.isPieType(id) && config.pie_expand);
+};
+
+c3_chart_internal_fn.shouldShowArcLabel = function () {
+    var $$ = this, config = $$.config, shouldShow = true;
+    if ($$.hasType('donut')) {
+        shouldShow = config.donut_label_show;
+    } else if ($$.hasType('pie')) {
+        shouldShow = config.pie_label_show;
+    }
+    // when gauge, always true
+    return shouldShow;
+};
+
+c3_chart_internal_fn.meetsArcLabelThreshold = function (ratio) {
+    var $$ = this, config = $$.config,
+        threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
+    return ratio >= threshold;
+};
+
+c3_chart_internal_fn.getArcLabelFormat = function () {
+    var $$ = this, config = $$.config,
+        format = config.pie_label_format;
+    if ($$.hasType('gauge')) {
+        format = config.gauge_label_format;
+    } else if ($$.hasType('donut')) {
+        format = config.donut_label_format;
+    }
+    return format;
+};
+
+c3_chart_internal_fn.getArcTitle = function () {
+    var $$ = this;
+    return $$.hasType('donut') ? $$.config.donut_title : "";
+};
+
+c3_chart_internal_fn.updateTargetsForArc = function (targets) {
+    var $$ = this, main = $$.main,
+        mainPieUpdate, mainPieEnter,
+        classChartArc = $$.classChartArc.bind($$),
+        classArcs = $$.classArcs.bind($$),
+        classFocus = $$.classFocus.bind($$);
+    mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
+        .data($$.pie(targets))
+        .attr("class", function (d) { return classChartArc(d) + classFocus(d.data); });
+    mainPieEnter = mainPieUpdate.enter().append("g")
+        .attr("class", classChartArc);
+    mainPieEnter.append('g')
+        .attr('class', classArcs);
+    mainPieEnter.append("text")
+        .attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
+        .style("opacity", 0)
+        .style("text-anchor", "middle")
+        .style("pointer-events", "none");
+    // MEMO: can not keep same color..., but not bad to update color in redraw
+    //mainPieUpdate.exit().remove();
+};
+
+c3_chart_internal_fn.initArc = function () {
+    var $$ = this;
+    $$.arcs = $$.main.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartArcs)
+        .attr("transform", $$.getTranslate('arc'));
+    $$.arcs.append('text')
+        .attr('class', CLASS.chartArcsTitle)
+        .style("text-anchor", "middle")
+        .text($$.getArcTitle());
+};
+
+c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransform) {
+    var $$ = this, d3 = $$.d3, config = $$.config, main = $$.main,
+        mainArc;
+    mainArc = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc)
+        .data($$.arcData.bind($$));
+    mainArc.enter().append('path')
+        .attr("class", $$.classArc.bind($$))
+        .style("fill", function (d) { return $$.color(d.data); })
+        .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; })
+        .style("opacity", 0)
+        .each(function (d) {
+            if ($$.isGaugeType(d.data)) {
+                d.startAngle = d.endAngle = -1 * (Math.PI / 2);
+            }
+            this._current = d;
+        })
+        .on('mouseover', function (d) {
+            var updated, arcData;
+            if ($$.transiting) { // skip while transiting
+                return;
+            }
+            updated = $$.updateAngle(d);
+            arcData = $$.convertToArcData(updated);
+            // transitions
+            $$.expandArc(updated.data.id);
+            $$.api.focus(updated.data.id);
+            $$.toggleFocusLegend(updated.data.id, true);
+            $$.config.data_onmouseover(arcData, this);
+        })
+        .on('mousemove', function (d) {
+            var updated = $$.updateAngle(d),
+                arcData = $$.convertToArcData(updated),
+                selectedData = [arcData];
+            $$.showTooltip(selectedData, d3.mouse(this));
+        })
+        .on('mouseout', function (d) {
+            var updated, arcData;
+            if ($$.transiting) { // skip while transiting
+                return;
+            }
+            updated = $$.updateAngle(d);
+            arcData = $$.convertToArcData(updated);
+            // transitions
+            $$.unexpandArc(updated.data.id);
+            $$.api.revert();
+            $$.revertLegend();
+            $$.hideTooltip();
+            $$.config.data_onmouseout(arcData, this);
+        })
+        .on('click', function (d, i) {
+            var updated = $$.updateAngle(d),
+                arcData = $$.convertToArcData(updated);
+            if ($$.toggleShape) { $$.toggleShape(this, arcData, i); }
+            $$.config.data_onclick.call($$.api, arcData, this);
+        });
+    mainArc
+        .attr("transform", function (d) { return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : ""; })
+        .style("opacity", function (d) { return d === this._current ? 0 : 1; })
+        .each(function () { $$.transiting = true; })
+        .transition().duration(duration)
+        .attrTween("d", function (d) {
+            var updated = $$.updateAngle(d), interpolate;
+            if (! updated) {
+                return function () { return "M 0 0"; };
+            }
+            //                if (this._current === d) {
+            //                    this._current = {
+            //                        startAngle: Math.PI*2,
+            //                        endAngle: Math.PI*2,
+            //                    };
+            //                }
+            if (isNaN(this._current.endAngle)) {
+                this._current.endAngle = this._current.startAngle;
+            }
+            interpolate = d3.interpolate(this._current, updated);
+            this._current = interpolate(0);
+            return function (t) {
+                var interpolated = interpolate(t);
+                interpolated.data = d.data; // data.id will be updated by interporator
+                return $$.getArc(interpolated, true);
+            };
+        })
+        .attr("transform", withTransform ? "scale(1)" : "")
+        .style("fill", function (d) {
+            return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
+        }) // Where gauge reading color would receive customization.
+        .style("opacity", 1)
+        .call($$.endall, function () {
+            $$.transiting = false;
+        });
+    mainArc.exit().transition().duration(durationForExit)
+        .style('opacity', 0)
+        .remove();
+    main.selectAll('.' + CLASS.chartArc).select('text')
+        .style("opacity", 0)
+        .attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
+        .text($$.textForArcLabel.bind($$))
+        .attr("transform", $$.transformForArcLabel.bind($$))
+        .style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
+      .transition().duration(duration)
+        .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
+    main.select('.' + CLASS.chartArcsTitle)
+        .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
+
+    if ($$.hasType('gauge')) {
+        $$.arcs.select('.' + CLASS.chartArcsBackground)
+            .attr("d", function () {
+                var d = {
+                    data: [{value: config.gauge_max}],
+                    startAngle: -1 * (Math.PI / 2),
+                    endAngle: Math.PI / 2
+                };
+                return $$.getArc(d, true, true);
+            });
+        $$.arcs.select('.' + CLASS.chartArcsGaugeUnit)
+            .attr("dy", ".75em")
+            .text(config.gauge_label_show ? config.gauge_units : '');
+        $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
+            .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
+            .attr("dy", "1.2em")
+            .text(config.gauge_label_show ? config.gauge_min : '');
+        $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
+            .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
+            .attr("dy", "1.2em")
+            .text(config.gauge_label_show ? config.gauge_max : '');
+    }
+};
+c3_chart_internal_fn.initGauge = function () {
+    var arcs = this.arcs;
+    if (this.hasType('gauge')) {
+        arcs.append('path')
+            .attr("class", CLASS.chartArcsBackground);
+        arcs.append("text")
+            .attr("class", CLASS.chartArcsGaugeUnit)
+            .style("text-anchor", "middle")
+            .style("pointer-events", "none");
+        arcs.append("text")
+            .attr("class", CLASS.chartArcsGaugeMin)
+            .style("text-anchor", "middle")
+            .style("pointer-events", "none");
+        arcs.append("text")
+            .attr("class", CLASS.chartArcsGaugeMax)
+            .style("text-anchor", "middle")
+            .style("pointer-events", "none");
+    }
+};
+c3_chart_internal_fn.getGaugeLabelHeight = function () {
+    return this.config.gauge_label_show ? 20 : 0;
+};
diff --git a/src/axis.js b/src/axis.js
new file mode 100644
index 0000000..c3c9d91
--- /dev/null
+++ b/src/axis.js
@@ -0,0 +1,373 @@
+c3_chart_internal_fn.initAxis = function () {
+    var $$ = this, config = $$.config, main = $$.main;
+    $$.axes.x = main.append("g")
+        .attr("class", CLASS.axis + ' ' + CLASS.axisX)
+        .attr("clip-path", $$.clipPathForXAxis)
+        .attr("transform", $$.getTranslate('x'))
+        .style("visibility", config.axis_x_show ? 'visible' : 'hidden');
+    $$.axes.x.append("text")
+        .attr("class", CLASS.axisXLabel)
+        .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+        .style("text-anchor", $$.textAnchorForXAxisLabel.bind($$));
+
+    $$.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');
+    $$.axes.y.append("text")
+        .attr("class", CLASS.axisYLabel)
+        .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+        .style("text-anchor", $$.textAnchorForYAxisLabel.bind($$));
+
+    $$.axes.y2 = main.append("g")
+        .attr("class", CLASS.axis + ' ' + CLASS.axisY2)
+        // clip-path?
+        .attr("transform", $$.getTranslate('y2'))
+        .style("visibility", config.axis_y2_show ? 'visible' : 'hidden');
+    $$.axes.y2.append("text")
+        .attr("class", CLASS.axisY2Label)
+        .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+        .style("text-anchor", $$.textAnchorForY2AxisLabel.bind($$));
+};
+c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+    var $$ = this, config = $$.config,
+        axisParams = {
+            isCategory: $$.isCategorized(),
+            withOuterTick: withOuterTick,
+            tickMultiline: config.axis_x_tick_multiline,
+            tickWidth: config.axis_x_tick_width
+        },
+        axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
+
+    if ($$.isTimeSeries() && tickValues) {
+        tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
+    }
+
+    // Set tick
+    axis.tickFormat(tickFormat).tickValues(tickValues);
+    if ($$.isCategorized()) {
+        axis.tickCentered(config.axis_x_tick_centered);
+        if (isEmpty(config.axis_x_tick_culling)) {
+            config.axis_x_tick_culling = false;
+        }
+    } else {
+        // TODO: move this to c3_axis
+        axis.tickOffset = function () {
+            var scale = this.scale(),
+                edgeX = $$.getEdgeX($$.data.targets), diff = scale(edgeX[1]) - scale(edgeX[0]),
+                base = diff ? diff : (config.axis_rotated ? $$.height : $$.width);
+            return (base / $$.getMaxDataCount()) / 2;
+        };
+    }
+
+    return axis;
+};
+c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
+    var axisParams = {withOuterTick: withOuterTick},
+        axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
+    if (this.isTimeSeriesY()) {
+        axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
+    } else {
+        axis.tickValues(tickValues);
+    }
+    return axis;
+};
+c3_chart_internal_fn.getAxisId = function (id) {
+    var config = this.config;
+    return id in config.data_axes ? config.data_axes[id] : 'y';
+};
+c3_chart_internal_fn.getXAxisTickFormat = function () {
+    var $$ = this, config = $$.config,
+        format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
+    if (config.axis_x_tick_format) {
+        if (isFunction(config.axis_x_tick_format)) {
+            format = config.axis_x_tick_format;
+        } else if ($$.isTimeSeries()) {
+            format = function (date) {
+                return date ? $$.axisTimeFormat(config.axis_x_tick_format)(date) : "";
+            };
+        }
+    }
+    return isFunction(format) ? function (v) { return format.call($$, v); } : format;
+};
+c3_chart_internal_fn.getAxisTickValues = function (tickValues, axis) {
+    return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
+};
+c3_chart_internal_fn.getXAxisTickValues = function () {
+    return this.getAxisTickValues(this.config.axis_x_tick_values, this.xAxis);
+};
+c3_chart_internal_fn.getYAxisTickValues = function () {
+    return this.getAxisTickValues(this.config.axis_y_tick_values, this.yAxis);
+};
+c3_chart_internal_fn.getY2AxisTickValues = function () {
+    return this.getAxisTickValues(this.config.axis_y2_tick_values, this.y2Axis);
+};
+c3_chart_internal_fn.getAxisLabelOptionByAxisId = function (axisId) {
+    var $$ = this, config = $$.config, option;
+    if (axisId === 'y') {
+        option = config.axis_y_label;
+    } else if (axisId === 'y2') {
+        option = config.axis_y2_label;
+    } else if (axisId === 'x') {
+        option = config.axis_x_label;
+    }
+    return option;
+};
+c3_chart_internal_fn.getAxisLabelText = function (axisId) {
+    var option = this.getAxisLabelOptionByAxisId(axisId);
+    return isString(option) ? option : option ? option.text : null;
+};
+c3_chart_internal_fn.setAxisLabelText = function (axisId, text) {
+    var $$ = this, config = $$.config,
+        option = $$.getAxisLabelOptionByAxisId(axisId);
+    if (isString(option)) {
+        if (axisId === 'y') {
+            config.axis_y_label = text;
+        } else if (axisId === 'y2') {
+            config.axis_y2_label = text;
+        } else if (axisId === 'x') {
+            config.axis_x_label = text;
+        }
+    } else if (option) {
+        option.text = text;
+    }
+};
+c3_chart_internal_fn.getAxisLabelPosition = function (axisId, defaultPosition) {
+    var option = this.getAxisLabelOptionByAxisId(axisId),
+        position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
+    return {
+        isInner: position.indexOf('inner') >= 0,
+        isOuter: position.indexOf('outer') >= 0,
+        isLeft: position.indexOf('left') >= 0,
+        isCenter: position.indexOf('center') >= 0,
+        isRight: position.indexOf('right') >= 0,
+        isTop: position.indexOf('top') >= 0,
+        isMiddle: position.indexOf('middle') >= 0,
+        isBottom: position.indexOf('bottom') >= 0
+    };
+};
+c3_chart_internal_fn.getXAxisLabelPosition = function () {
+    return this.getAxisLabelPosition('x', this.config.axis_rotated ? 'inner-top' : 'inner-right');
+};
+c3_chart_internal_fn.getYAxisLabelPosition = function () {
+    return this.getAxisLabelPosition('y', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+};
+c3_chart_internal_fn.getY2AxisLabelPosition = function () {
+    return this.getAxisLabelPosition('y2', this.config.axis_rotated ? 'inner-right' : 'inner-top');
+};
+c3_chart_internal_fn.getAxisLabelPositionById = function (id) {
+    return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
+};
+c3_chart_internal_fn.textForXAxisLabel = function () {
+    return this.getAxisLabelText('x');
+};
+c3_chart_internal_fn.textForYAxisLabel = function () {
+    return this.getAxisLabelText('y');
+};
+c3_chart_internal_fn.textForY2AxisLabel = function () {
+    return this.getAxisLabelText('y2');
+};
+c3_chart_internal_fn.xForAxisLabel = function (forHorizontal, position) {
+    var $$ = this;
+    if (forHorizontal) {
+        return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
+    } else {
+        return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
+    }
+};
+c3_chart_internal_fn.dxForAxisLabel = function (forHorizontal, position) {
+    if (forHorizontal) {
+        return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
+    } else {
+        return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
+    }
+};
+c3_chart_internal_fn.textAnchorForAxisLabel = function (forHorizontal, position) {
+    if (forHorizontal) {
+        return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
+    } else {
+        return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
+    }
+};
+c3_chart_internal_fn.xForXAxisLabel = function () {
+    return this.xForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+};
+c3_chart_internal_fn.xForYAxisLabel = function () {
+    return this.xForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+};
+c3_chart_internal_fn.xForY2AxisLabel = function () {
+    return this.xForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+};
+c3_chart_internal_fn.dxForXAxisLabel = function () {
+    return this.dxForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
+};
+c3_chart_internal_fn.dxForYAxisLabel = function () {
+    return this.dxForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
+};
+c3_chart_internal_fn.dxForY2AxisLabel = function () {
+    return this.dxForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
+};
+c3_chart_internal_fn.dyForXAxisLabel = function () {
+    var $$ = this, config = $$.config,
+        position = $$.getXAxisLabelPosition();
+    if (config.axis_rotated) {
+        return position.isInner ? "1.2em" : -25 - $$.getMaxTickWidth('x');
+    } else {
+        return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
+    }
+};
+c3_chart_internal_fn.dyForYAxisLabel = function () {
+    var $$ = this,
+        position = $$.getYAxisLabelPosition();
+    if ($$.config.axis_rotated) {
+        return position.isInner ? "-0.5em" : "3em";
+    } else {
+        return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : ($$.getMaxTickWidth('y') + 10));
+    }
+};
+c3_chart_internal_fn.dyForY2AxisLabel = function () {
+    var $$ = this,
+        position = $$.getY2AxisLabelPosition();
+    if ($$.config.axis_rotated) {
+        return position.isInner ? "1.2em" : "-2.2em";
+    } else {
+        return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth('y2') + 15));
+    }
+};
+c3_chart_internal_fn.textAnchorForXAxisLabel = function () {
+    var $$ = this;
+    return $$.textAnchorForAxisLabel(!$$.config.axis_rotated, $$.getXAxisLabelPosition());
+};
+c3_chart_internal_fn.textAnchorForYAxisLabel = function () {
+    var $$ = this;
+    return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getYAxisLabelPosition());
+};
+c3_chart_internal_fn.textAnchorForY2AxisLabel = function () {
+    var $$ = this;
+    return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getY2AxisLabelPosition());
+};
+
+c3_chart_internal_fn.xForRotatedTickText = function (r) {
+    return 8 * Math.sin(Math.PI * (r / 180));
+};
+c3_chart_internal_fn.yForRotatedTickText = function (r) {
+    return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
+};
+c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
+    axis.selectAll('.tick text')
+        .style("text-anchor", rotate > 0 ? "start" : "end");
+    transition.selectAll('.tick text')
+        .attr("y", this.yForRotatedTickText(rotate))
+        .attr("transform", "rotate(" + rotate + ")")
+      .selectAll('tspan')
+        .attr('dx', this.xForRotatedTickText(rotate));
+};
+
+c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
+    var $$ = this, config = $$.config,
+        maxWidth = 0, targetsToShow, scale, axis;
+    if (withoutRecompute && $$.currentMaxTickWidths[id]) {
+        return $$.currentMaxTickWidths[id];
+    }
+    if ($$.svg) {
+        targetsToShow = $$.filterTargetsToShow($$.data.targets);
+        if (id === 'y') {
+            scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
+            axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
+        } else if (id === 'y2') {
+            scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
+            axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
+        } else {
+            scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
+            axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
+        }
+        $$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
+            $$.d3.select(this).selectAll('text tspan').each(function () {
+                var box = this.getBoundingClientRect();
+                if (box.left > 0 && maxWidth < box.width) { maxWidth = box.width; }
+            });
+        }).remove();
+    }
+    $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
+    return $$.currentMaxTickWidths[id];
+};
+
+c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
+    var $$ = this;
+    var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
+        axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
+        axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
+    (withTransition ? axisXLabel.transition() : axisXLabel)
+        .attr("x", $$.xForXAxisLabel.bind($$))
+        .attr("dx", $$.dxForXAxisLabel.bind($$))
+        .attr("dy", $$.dyForXAxisLabel.bind($$))
+        .text($$.textForXAxisLabel.bind($$));
+    (withTransition ? axisYLabel.transition() : axisYLabel)
+        .attr("x", $$.xForYAxisLabel.bind($$))
+        .attr("dx", $$.dxForYAxisLabel.bind($$))
+        .attr("dy", $$.dyForYAxisLabel.bind($$))
+        .text($$.textForYAxisLabel.bind($$));
+    (withTransition ? axisY2Label.transition() : axisY2Label)
+        .attr("x", $$.xForY2AxisLabel.bind($$))
+        .attr("dx", $$.dxForY2AxisLabel.bind($$))
+        .attr("dy", $$.dyForY2AxisLabel.bind($$))
+        .text($$.textForY2AxisLabel.bind($$));
+};
+
+c3_chart_internal_fn.getAxisPadding = function (padding, key, defaultValue, all) {
+    var ratio = padding.unit === 'ratio' ? all : 1;
+    return isValue(padding[key]) ? padding[key] * ratio : defaultValue;
+};
+
+c3_chart_internal_fn.generateTickValues = function (values, tickCount, forTimeSeries) {
+    var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
+    if (tickCount) {
+        targetCount = isFunction(tickCount) ? tickCount() : tickCount;
+        // compute ticks according to tickCount
+        if (targetCount === 1) {
+            tickValues = [values[0]];
+        } else if (targetCount === 2) {
+            tickValues = [values[0], values[values.length - 1]];
+        } else if (targetCount > 2) {
+            count = targetCount - 2;
+            start = values[0];
+            end = values[values.length - 1];
+            interval = (end - start) / (count + 1);
+            // re-construct unique values
+            tickValues = [start];
+            for (i = 0; i < count; i++) {
+                tickValue = +start + interval * (i + 1);
+                tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
+            }
+            tickValues.push(end);
+        }
+    }
+    if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
+    return tickValues;
+};
+c3_chart_internal_fn.generateAxisTransitions = function (duration) {
+    var $$ = this, axes = $$.axes;
+    return {
+        axisX: duration ? axes.x.transition().duration(duration) : axes.x,
+        axisY: duration ? axes.y.transition().duration(duration) : axes.y,
+        axisY2: duration ? axes.y2.transition().duration(duration) : axes.y2,
+        axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
+    };
+};
+c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
+    var $$ = this, config = $$.config;
+    $$.axes.x.style("opacity", isHidden ? 0 : 1);
+    $$.axes.y.style("opacity", isHidden ? 0 : 1);
+    $$.axes.y2.style("opacity", isHidden ? 0 : 1);
+    $$.axes.subx.style("opacity", isHidden ? 0 : 1);
+    transitions.axisX.call($$.xAxis);
+    transitions.axisY.call($$.yAxis);
+    transitions.axisY2.call($$.y2Axis);
+    transitions.axisSubX.call($$.subXAxis);
+    // rotate tick text if needed
+    if (!config.axis_rotated && config.axis_x_tick_rotate) {
+        $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
+        $$.rotateTickText($$.axes.subx, transitions.axisSubX, config.axis_x_tick_rotate);
+    }
+};
diff --git a/src/c3.axis.js b/src/c3.axis.js
new file mode 100644
index 0000000..caa00ff
--- /dev/null
+++ b/src/c3.axis.js
@@ -0,0 +1,285 @@
+// Features:
+// 1. category axis
+// 2. ceil values of translate/x/y to int for half pixel antialiasing
+// 3. multiline tick text
+var tickTextCharSize;
+function c3_axis(d3, params) {
+    var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
+
+    var tickOffset = 0, tickCulling = true, tickCentered;
+
+    params = params || {};
+    outerTickSize = params.withOuterTick ? 6 : 0;
+
+    function axisX(selection, x) {
+        selection.attr("transform", function (d) {
+            return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
+        });
+    }
+    function axisY(selection, y) {
+        selection.attr("transform", function (d) {
+            return "translate(0," + Math.ceil(y(d)) + ")";
+        });
+    }
+    function scaleExtent(domain) {
+        var start = domain[0], stop = domain[domain.length - 1];
+        return start < stop ? [ start, stop ] : [ stop, start ];
+    }
+    function generateTicks(scale) {
+        var i, domain, ticks = [];
+        if (scale.ticks) {
+            return scale.ticks.apply(scale, tickArguments);
+        }
+        domain = scale.domain();
+        for (i = Math.ceil(domain[0]); i < domain[1]; i++) {
+            ticks.push(i);
+        }
+        if (ticks.length > 0 && ticks[0] > 0) {
+            ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
+        }
+        return ticks;
+    }
+    function copyScale() {
+        var newScale = scale.copy(), domain;
+        if (params.isCategory) {
+            domain = scale.domain();
+            newScale.domain([domain[0], domain[1] - 1]);
+        }
+        return newScale;
+    }
+    function textFormatted(v) {
+        return tickFormat ? tickFormat(v) : v;
+    }
+    function getSizeFor1Char(tick) {
+        if (tickTextCharSize) {
+            return tickTextCharSize;
+        }
+        var size = {
+            h: 11.5,
+            w: 5.5
+        };
+        tick.select('text').text(textFormatted).each(function (d) {
+            var box = this.getBoundingClientRect(),
+                text = textFormatted(d),
+                h = box.height,
+                w = text ? (box.width / text.length) : undefined;
+            if (h && w) {
+                size.h = h;
+                size.w = w;
+            }
+        }).text('');
+        tickTextCharSize = size;
+        return size;
+    }
+    function axis(g) {
+        g.each(function () {
+            var g = d3.select(this);
+            var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale();
+
+            var ticks = tickValues ? tickValues : generateTicks(scale1),
+                tick = g.selectAll(".tick").data(ticks, scale1),
+                tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
+                // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
+                tickExit = tick.exit().remove(),
+                tickUpdate = d3.transition(tick).style("opacity", 1),
+                tickTransform, tickX, tickY;
+
+            var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
+                path = g.selectAll(".domain").data([ 0 ]),
+                pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path));
+            tickEnter.append("line");
+            tickEnter.append("text");
+
+            var lineEnter = tickEnter.select("line"),
+                lineUpdate = tickUpdate.select("line"),
+                textEnter = tickEnter.select("text"),
+                textUpdate = tickUpdate.select("text");
+
+            if (params.isCategory) {
+                tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
+                tickX = tickCentered ? 0 : tickOffset;
+                tickY = tickCentered ? tickOffset : 0;
+            } else {
+                tickOffset = tickX = 0;
+            }
+
+            var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = [];
+            var tickLength = Math.max(innerTickSize, 0) + tickPadding,
+                isVertical = orient === 'left' || orient === 'right';
+
+            // this should be called only when category axis
+            function splitTickText(d, maxWidth) {
+                var tickText = textFormatted(d),
+                    subtext, spaceIndex, textWidth, splitted = [];
+
+                if (Object.prototype.toString.call(tickText) === "[object Array]") {
+                    return tickText;
+                }
+
+                if (!maxWidth || maxWidth <= 0) {
+                    maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110;
+                }
+
+                function split(splitted, text) {
+                    spaceIndex = undefined;
+                    for (var i = 1; i < text.length; i++) {
+                        if (text.charAt(i) === ' ') {
+                            spaceIndex = i;
+                        }
+                        subtext = text.substr(0, i + 1);
+                        textWidth = sizeFor1Char.w * subtext.length;
+                        // if text width gets over tick width, split by space index or crrent index
+                        if (maxWidth < textWidth) {
+                            return split(
+                                splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)),
+                                text.slice(spaceIndex ? spaceIndex + 1 : i)
+                            );
+                        }
+                    }
+                    return splitted.concat(text);
+                }
+
+                return split(splitted, tickText + "");
+            }
+
+            function tspanDy(d, i) {
+                var dy = sizeFor1Char.h;
+                if (i === 0) {
+                    if (orient === 'left' || orient === 'right') {
+                        dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - (params.isCategory ? 2 : 3));
+                    } else {
+                        dy = ".71em";
+                    }
+                }
+                return dy;
+            }
+
+            function tickSize(d) {
+                var tickPosition = scale(d) + tickOffset;
+                return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0;
+            }
+
+            text = tick.select("text");
+            tspan = text.selectAll('tspan')
+                .data(function (d, i) {
+                    var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
+                    counts[i] = splitted.length;
+                    return splitted.map(function (s) {
+                        return { index: i, splitted: s };
+                    });
+                });
+            tspan.enter().append('tspan');
+            tspan.exit().remove();
+            tspan.text(function (d) { return d.splitted; });
+
+            switch (orient) {
+            case "bottom":
+                {
+                    tickTransform = axisX;
+                    lineEnter.attr("y2", innerTickSize);
+                    textEnter.attr("y", tickLength);
+                    lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
+                    textUpdate.attr("x", 0).attr("y", tickLength);
+                    text.style("text-anchor", "middle");
+                    tspan.attr('x', 0).attr("dy", tspanDy);
+                    pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+                    break;
+                }
+            case "top":
+                {
+                    tickTransform = axisX;
+                    lineEnter.attr("y2", -innerTickSize);
+                    textEnter.attr("y", -tickLength);
+                    lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+                    textUpdate.attr("x", 0).attr("y", -tickLength);
+                    text.style("text-anchor", "middle");
+                    tspan.attr('x', 0).attr("dy", "0em");
+                    pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+                    break;
+                }
+            case "left":
+                {
+                    tickTransform = axisY;
+                    lineEnter.attr("x2", -innerTickSize);
+                    textEnter.attr("x", -tickLength);
+                    lineUpdate.attr("x2", -innerTickSize).attr("y1", tickY).attr("y2", tickY);
+                    textUpdate.attr("x", -tickLength).attr("y", tickOffset);
+                    text.style("text-anchor", "end");
+                    tspan.attr('x', -tickLength).attr("dy", tspanDy);
+                    pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+                    break;
+                }
+            case "right":
+                {
+                    tickTransform = axisY;
+                    lineEnter.attr("x2", innerTickSize);
+                    textEnter.attr("x", tickLength);
+                    lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+                    textUpdate.attr("x", tickLength).attr("y", 0);
+                    text.style("text-anchor", "start");
+                    tspan.attr('x', tickLength).attr("dy", tspanDy);
+                    pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
+                    break;
+                }
+            }
+            if (scale1.rangeBand) {
+                var x = scale1, dx = x.rangeBand() / 2;
+                scale0 = scale1 = function (d) {
+                    return x(d) + dx;
+                };
+            } else if (scale0.rangeBand) {
+                scale0 = scale1;
+            } else {
+                tickExit.call(tickTransform, scale1);
+            }
+            tickEnter.call(tickTransform, scale0);
+            tickUpdate.call(tickTransform, scale1);
+        });
+    }
+    axis.scale = function (x) {
+        if (!arguments.length) { return scale; }
+        scale = x;
+        return axis;
+    };
+    axis.orient = function (x) {
+        if (!arguments.length) { return orient; }
+        orient = x in {top: 1, right: 1, bottom: 1, left: 1} ? x + "" : "bottom";
+        return axis;
+    };
+    axis.tickFormat = function (format) {
+        if (!arguments.length) { return tickFormat; }
+        tickFormat = format;
+        return axis;
+    };
+    axis.tickCentered = function (isCentered) {
+        if (!arguments.length) { return tickCentered; }
+        tickCentered = isCentered;
+        return axis;
+    };
+    axis.tickOffset = function () { // This will be overwritten when normal x axis
+        return tickOffset;
+    };
+    axis.ticks = function () {
+        if (!arguments.length) { return tickArguments; }
+        tickArguments = arguments;
+        return axis;
+    };
+    axis.tickCulling = function (culling) {
+        if (!arguments.length) { return tickCulling; }
+        tickCulling = culling;
+        return axis;
+    };
+    axis.tickValues = function (x) {
+        if (typeof x === 'function') {
+            tickValues = function () {
+                return x(scale.domain());
+            };
+        }
+        else {
+            if (!arguments.length) { return tickValues; }
+            tickValues = x;
+        }
+        return axis;
+    };
+    return axis;
+}
diff --git a/src/cache.js b/src/cache.js
new file mode 100644
index 0000000..6566616
--- /dev/null
+++ b/src/cache.js
@@ -0,0 +1,16 @@
+c3_chart_internal_fn.hasCaches = function (ids) {
+    for (var i = 0; i < ids.length; i++) {
+        if (! (ids[i] in this.cache)) { return false; }
+    }
+    return true;
+};
+c3_chart_internal_fn.addCache = function (id, target) {
+    this.cache[id] = this.cloneTarget(target);
+};
+c3_chart_internal_fn.getCaches = function (ids) {
+    var targets = [], i;
+    for (i = 0; i < ids.length; i++) {
+        if (ids[i] in this.cache) { targets.push(this.cloneTarget(this.cache[ids[i]])); }
+    }
+    return targets;
+};
diff --git a/src/category.js b/src/category.js
new file mode 100644
index 0000000..5143c6c
--- /dev/null
+++ b/src/category.js
@@ -0,0 +1,4 @@
+c3_chart_internal_fn.categoryName = function (i) {
+    var config = this.config;
+    return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
+};
diff --git a/src/class.js b/src/class.js
new file mode 100644
index 0000000..335f17c
--- /dev/null
+++ b/src/class.js
@@ -0,0 +1,174 @@
+var CLASS = c3_chart_internal_fn.CLASS = {
+    target: 'c3-target',
+    chart: 'c3-chart',
+    chartLine: 'c3-chart-line',
+    chartLines: 'c3-chart-lines',
+    chartBar: 'c3-chart-bar',
+    chartBars: 'c3-chart-bars',
+    chartText: 'c3-chart-text',
+    chartTexts: 'c3-chart-texts',
+    chartArc: 'c3-chart-arc',
+    chartArcs: 'c3-chart-arcs',
+    chartArcsTitle: 'c3-chart-arcs-title',
+    chartArcsBackground: 'c3-chart-arcs-background',
+    chartArcsGaugeUnit: 'c3-chart-arcs-gauge-unit',
+    chartArcsGaugeMax: 'c3-chart-arcs-gauge-max',
+    chartArcsGaugeMin: 'c3-chart-arcs-gauge-min',
+    selectedCircle: 'c3-selected-circle',
+    selectedCircles: 'c3-selected-circles',
+    eventRect: 'c3-event-rect',
+    eventRects: 'c3-event-rects',
+    eventRectsSingle: 'c3-event-rects-single',
+    eventRectsMultiple: 'c3-event-rects-multiple',
+    zoomRect: 'c3-zoom-rect',
+    brush: 'c3-brush',
+    focused: 'c3-focused',
+    defocused: 'c3-defocused',
+    region: 'c3-region',
+    regions: 'c3-regions',
+    tooltipContainer: 'c3-tooltip-container',
+    tooltip: 'c3-tooltip',
+    tooltipName: 'c3-tooltip-name',
+    shape: 'c3-shape',
+    shapes: 'c3-shapes',
+    line: 'c3-line',
+    lines: 'c3-lines',
+    bar: 'c3-bar',
+    bars: 'c3-bars',
+    circle: 'c3-circle',
+    circles: 'c3-circles',
+    arc: 'c3-arc',
+    arcs: 'c3-arcs',
+    area: 'c3-area',
+    areas: 'c3-areas',
+    empty: 'c3-empty',
+    text: 'c3-text',
+    texts: 'c3-texts',
+    gaugeValue: 'c3-gauge-value',
+    grid: 'c3-grid',
+    gridLines: 'c3-grid-lines',
+    xgrid: 'c3-xgrid',
+    xgrids: 'c3-xgrids',
+    xgridLine: 'c3-xgrid-line',
+    xgridLines: 'c3-xgrid-lines',
+    xgridFocus: 'c3-xgrid-focus',
+    ygrid: 'c3-ygrid',
+    ygrids: 'c3-ygrids',
+    ygridLine: 'c3-ygrid-line',
+    ygridLines: 'c3-ygrid-lines',
+    axis: 'c3-axis',
+    axisX: 'c3-axis-x',
+    axisXLabel: 'c3-axis-x-label',
+    axisY: 'c3-axis-y',
+    axisYLabel: 'c3-axis-y-label',
+    axisY2: 'c3-axis-y2',
+    axisY2Label: 'c3-axis-y2-label',
+    legendBackground: 'c3-legend-background',
+    legendItem: 'c3-legend-item',
+    legendItemEvent: 'c3-legend-item-event',
+    legendItemTile: 'c3-legend-item-tile',
+    legendItemHidden: 'c3-legend-item-hidden',
+    legendItemFocused: 'c3-legend-item-focused',
+    dragarea: 'c3-dragarea',
+    EXPANDED: '_expanded_',
+    SELECTED: '_selected_',
+    INCLUDED: '_included_'
+};
+c3_chart_internal_fn.generateClass = function (prefix, targetId) {
+    return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId);
+};
+c3_chart_internal_fn.classText = function (d) {
+    return this.generateClass(CLASS.text, d.index);
+};
+c3_chart_internal_fn.classTexts = function (d) {
+    return this.generateClass(CLASS.texts, d.id);
+};
+c3_chart_internal_fn.classShape = function (d) {
+    return this.generateClass(CLASS.shape, d.index);
+};
+c3_chart_internal_fn.classShapes = function (d) {
+    return this.generateClass(CLASS.shapes, d.id);
+};
+c3_chart_internal_fn.classLine = function (d) {
+    return this.classShape(d) + this.generateClass(CLASS.line, d.id);
+};
+c3_chart_internal_fn.classLines = function (d) {
+    return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
+};
+c3_chart_internal_fn.classCircle = function (d) {
+    return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
+};
+c3_chart_internal_fn.classCircles = function (d) {
+    return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
+};
+c3_chart_internal_fn.classBar = function (d) {
+    return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
+};
+c3_chart_internal_fn.classBars = function (d) {
+    return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
+};
+c3_chart_internal_fn.classArc = function (d) {
+    return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
+};
+c3_chart_internal_fn.classArcs = function (d) {
+    return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
+};
+c3_chart_internal_fn.classArea = function (d) {
+    return this.classShape(d) + this.generateClass(CLASS.area, d.id);
+};
+c3_chart_internal_fn.classAreas = function (d) {
+    return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
+};
+c3_chart_internal_fn.classRegion = function (d, i) {
+    return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
+};
+c3_chart_internal_fn.classEvent = function (d) {
+    return this.generateClass(CLASS.eventRect, d.index);
+};
+c3_chart_internal_fn.classTarget = function (id) {
+    var $$ = this;
+    var additionalClassSuffix = $$.config.data_classes[id], additionalClass = '';
+    if (additionalClassSuffix) {
+        additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
+    }
+    return $$.generateClass(CLASS.target, id) + additionalClass;
+};
+c3_chart_internal_fn.classFocus = function (d) {
+    return this.classFocused(d) + this.classDefocused(d);
+};
+c3_chart_internal_fn.classFocused = function (d) {
+    return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
+};
+c3_chart_internal_fn.classDefocused = function (d) {
+    return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
+};
+c3_chart_internal_fn.classChartText = function (d) {
+    return CLASS.chartText + this.classTarget(d.id);
+};
+c3_chart_internal_fn.classChartLine = function (d) {
+    return CLASS.chartLine + this.classTarget(d.id);
+};
+c3_chart_internal_fn.classChartBar = function (d) {
+    return CLASS.chartBar + this.classTarget(d.id);
+};
+c3_chart_internal_fn.classChartArc = function (d) {
+    return CLASS.chartArc + this.classTarget(d.data.id);
+};
+c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
+    return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g, '-') : '';
+};
+c3_chart_internal_fn.selectorTarget = function (id, prefix) {
+    return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
+};
+c3_chart_internal_fn.selectorTargets = function (ids, prefix) {
+    var $$ = this;
+    ids = ids || [];
+    return ids.length ? ids.map(function (id) { return $$.selectorTarget(id, prefix); }) : null;
+};
+c3_chart_internal_fn.selectorLegend = function (id) {
+    return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
+};
+c3_chart_internal_fn.selectorLegends = function (ids) {
+    var $$ = this;
+    return ids && ids.length ? ids.map(function (id) { return $$.selectorLegend(id); }) : null;
+};
diff --git a/src/clip.js b/src/clip.js
new file mode 100644
index 0000000..63ffa60
--- /dev/null
+++ b/src/clip.js
@@ -0,0 +1,57 @@
+c3_chart_internal_fn.getClipPath = function (id) {
+    var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
+    return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
+};
+c3_chart_internal_fn.appendClip = function (parent, id) {
+    return parent.append("clipPath").attr("id", id).append("rect");
+};
+c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
+    // axis line width + padding for left
+    var left = Math.max(30, this.margin.left);
+    return forHorizontal ? -(1 + left) : -(left - 1);
+};
+c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
+    return forHorizontal ? -20 : -this.margin.top;
+};
+c3_chart_internal_fn.getXAxisClipX = function () {
+    var $$ = this;
+    return $$.getAxisClipX(!$$.config.axis_rotated);
+};
+c3_chart_internal_fn.getXAxisClipY = function () {
+    var $$ = this;
+    return $$.getAxisClipY(!$$.config.axis_rotated);
+};
+c3_chart_internal_fn.getYAxisClipX = function () {
+    var $$ = this;
+    return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
+};
+c3_chart_internal_fn.getYAxisClipY = function () {
+    var $$ = this;
+    return $$.getAxisClipY($$.config.axis_rotated);
+};
+c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
+    var $$ = this,
+        left = Math.max(30, $$.margin.left),
+        right = Math.max(30, $$.margin.right);
+    // width + axis line width + padding for left/right
+    return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
+};
+c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
+    return (forHorizontal ? this.margin.bottom : (this.margin.top + this.height)) + 8;
+};
+c3_chart_internal_fn.getXAxisClipWidth = function () {
+    var $$ = this;
+    return $$.getAxisClipWidth(!$$.config.axis_rotated);
+};
+c3_chart_internal_fn.getXAxisClipHeight = function () {
+    var $$ = this;
+    return $$.getAxisClipHeight(!$$.config.axis_rotated);
+};
+c3_chart_internal_fn.getYAxisClipWidth = function () {
+    var $$ = this;
+    return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
+};
+c3_chart_internal_fn.getYAxisClipHeight = function () {
+    var $$ = this;
+    return $$.getAxisClipHeight($$.config.axis_rotated);
+};
diff --git a/src/color.js b/src/color.js
new file mode 100644
index 0000000..4243f65
--- /dev/null
+++ b/src/color.js
@@ -0,0 +1,46 @@
+c3_chart_internal_fn.generateColor = function () {
+    var $$ = this, config = $$.config, d3 = $$.d3,
+        colors = config.data_colors,
+        pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.scale.category10().range(),
+        callback = config.data_color,
+        ids = [];
+
+    return function (d) {
+        var id = d.id || d, color;
+
+        // if callback function is provided
+        if (colors[id] instanceof Function) {
+            color = colors[id](d);
+        }
+        // if specified, choose that color
+        else if (colors[id]) {
+            color = colors[id];
+        }
+        // if not specified, choose from pattern
+        else {
+            if (ids.indexOf(id) < 0) { ids.push(id); }
+            color = pattern[ids.indexOf(id) % pattern.length];
+            colors[id] = color;
+        }
+        return callback instanceof Function ? callback(color, d) : color;
+    };
+};
+c3_chart_internal_fn.generateLevelColor = function () {
+    var $$ = this, config = $$.config,
+        colors = config.color_pattern,
+        threshold = config.color_threshold,
+        asValue = threshold.unit === 'value',
+        values = threshold.values && threshold.values.length ? threshold.values : [],
+        max = threshold.max || 100;
+    return notEmpty(config.color_threshold) ? function (value) {
+        var i, v, color = colors[colors.length - 1];
+        for (i = 0; i < values.length; i++) {
+            v = asValue ? value : (value * 100 / max);
+            if (v < values[i]) {
+                color = colors[i];
+                break;
+            }
+        }
+        return color;
+    } : null;
+};
diff --git a/src/config.js b/src/config.js
new file mode 100644
index 0000000..d64a783
--- /dev/null
+++ b/src/config.js
@@ -0,0 +1,227 @@
+c3_chart_internal_fn.getDefaultConfig = function () {
+    var config = {
+        bindto: '#chart',
+        size_width: undefined,
+        size_height: undefined,
+        padding_left: undefined,
+        padding_right: undefined,
+        padding_top: undefined,
+        padding_bottom: undefined,
+        zoom_enabled: false,
+        zoom_extent: undefined,
+        zoom_privileged: false,
+        zoom_rescale: false,
+        zoom_onzoom: function () {},
+        zoom_onzoomstart: function () {},
+        zoom_onzoomend: function () {},
+        interaction_enabled: true,
+        onmouseover: function () {},
+        onmouseout: function () {},
+        onresize: function () {},
+        onresized: function () {},
+        oninit: function () {},
+        transition_duration: 350,
+        data_x: undefined,
+        data_xs: {},
+        data_xFormat: '%Y-%m-%d',
+        data_xLocaltime: true,
+        data_xSort: true,
+        data_idConverter: function (id) { return id; },
+        data_names: {},
+        data_classes: {},
+        data_groups: [],
+        data_axes: {},
+        data_type: undefined,
+        data_types: {},
+        data_labels: {},
+        data_order: 'desc',
+        data_regions: {},
+        data_color: undefined,
+        data_colors: {},
+        data_hide: false,
+        data_filter: undefined,
+        data_selection_enabled: false,
+        data_selection_grouped: false,
+        data_selection_isselectable: function () { return true; },
+        data_selection_multiple: true,
+        data_onclick: function () {},
+        data_onmouseover: function () {},
+        data_onmouseout: function () {},
+        data_onselected: function () {},
+        data_onunselected: function () {},
+        data_ondragstart: function () {},
+        data_ondragend: function () {},
+        data_url: undefined,
+        data_json: undefined,
+        data_rows: undefined,
+        data_columns: undefined,
+        data_mimeType: undefined,
+        data_keys: undefined,
+        // configuration for no plot-able data supplied.
+        data_empty_label_text: "",
+        // subchart
+        subchart_show: false,
+        subchart_size_height: 60,
+        subchart_onbrush: function () {},
+        // color
+        color_pattern: [],
+        color_threshold: {},
+        // legend
+        legend_show: true,
+        legend_hide: false,
+        legend_position: 'bottom',
+        legend_inset_anchor: 'top-left',
+        legend_inset_x: 10,
+        legend_inset_y: 0,
+        legend_inset_step: undefined,
+        legend_item_onclick: undefined,
+        legend_item_onmouseover: undefined,
+        legend_item_onmouseout: undefined,
+        legend_equally: false,
+        // axis
+        axis_rotated: false,
+        axis_x_show: true,
+        axis_x_type: 'indexed',
+        axis_x_localtime: true,
+        axis_x_categories: [],
+        axis_x_tick_centered: false,
+        axis_x_tick_format: undefined,
+        axis_x_tick_culling: {},
+        axis_x_tick_culling_max: 10,
+        axis_x_tick_count: undefined,
+        axis_x_tick_fit: true,
+        axis_x_tick_values: null,
+        axis_x_tick_rotate: 0,
+        axis_x_tick_outer: true,
+        axis_x_tick_multiline: true,
+        axis_x_tick_width: null,
+        axis_x_max: undefined,
+        axis_x_min: undefined,
+        axis_x_padding: {},
+        axis_x_height: undefined,
+        axis_x_extent: undefined,
+        axis_x_label: {},
+        axis_y_show: true,
+        axis_y_type: undefined,
+        axis_y_max: undefined,
+        axis_y_min: undefined,
+        axis_y_center: undefined,
+        axis_y_inner: undefined,
+        axis_y_label: {},
+        axis_y_tick_format: undefined,
+        axis_y_tick_outer: true,
+        axis_y_tick_values: null,
+        axis_y_tick_count: undefined,
+        axis_y_tick_time_value: undefined,
+        axis_y_tick_time_interval: undefined,
+        axis_y_padding: {},
+        axis_y_default: undefined,
+        axis_y2_show: false,
+        axis_y2_max: undefined,
+        axis_y2_min: undefined,
+        axis_y2_center: undefined,
+        axis_y2_inner: undefined,
+        axis_y2_label: {},
+        axis_y2_tick_format: undefined,
+        axis_y2_tick_outer: true,
+        axis_y2_tick_values: null,
+        axis_y2_tick_count: undefined,
+        axis_y2_padding: {},
+        axis_y2_default: undefined,
+        // grid
+        grid_x_show: false,
+        grid_x_type: 'tick',
+        grid_x_lines: [],
+        grid_y_show: false,
+        // not used
+        // grid_y_type: 'tick',
+        grid_y_lines: [],
+        grid_y_ticks: 10,
+        grid_focus_show: true,
+        grid_lines_front: true,
+        // point - point of each data
+        point_show: true,
+        point_r: 2.5,
+        point_focus_expand_enabled: true,
+        point_focus_expand_r: undefined,
+        point_select_r: undefined,
+        // line
+        line_connectNull: false,
+        line_step_type: 'step',
+        // bar
+        bar_width: undefined,
+        bar_width_ratio: 0.6,
+        bar_width_max: undefined,
+        bar_zerobased: true,
+        // area
+        area_zerobased: true,
+        // pie
+        pie_label_show: true,
+        pie_label_format: undefined,
+        pie_label_threshold: 0.05,
+        pie_expand: true,
+        // gauge
+        gauge_label_show: true,
+        gauge_label_format: undefined,
+        gauge_expand: true,
+        gauge_min: 0,
+        gauge_max: 100,
+        gauge_units: undefined,
+        gauge_width: undefined,
+        // donut
+        donut_label_show: true,
+        donut_label_format: undefined,
+        donut_label_threshold: 0.05,
+        donut_width: undefined,
+        donut_expand: true,
+        donut_title: "",
+        // region - region to change style
+        regions: [],
+        // tooltip - show when mouseover on each data
+        tooltip_show: true,
+        tooltip_grouped: true,
+        tooltip_format_title: undefined,
+        tooltip_format_name: undefined,
+        tooltip_format_value: undefined,
+        tooltip_contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
+            return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
+        },
+        tooltip_init_show: false,
+        tooltip_init_x: 0,
+        tooltip_init_position: {top: '0px', left: '50px'}
+    };
+
+    Object.keys(this.additionalConfig).forEach(function (key) {
+        config[key] = this.additionalConfig[key];
+    }, this);
+
+    return config;
+};
+c3_chart_internal_fn.additionalConfig = {};
+
+c3_chart_internal_fn.loadConfig = function (config) {
+    var this_config = this.config, target, keys, read;
+    function find() {
+        var key = keys.shift();
+//        console.log("key =>", key, ", target =>", target);
+        if (key && target && typeof target === 'object' && key in target) {
+            target = target[key];
+            return find();
+        }
+        else if (!key) {
+            return target;
+        }
+        else {
+            return undefined;
+        }
+    }
+    Object.keys(this_config).forEach(function (key) {
+        target = config;
+        keys = key.split('_');
+        read = find();
+//        console.log("CONFIG : ", key, read);
+        if (isDefined(read)) {
+            this_config[key] = read;
+        }
+    });
+};
diff --git a/src/core.js b/src/core.js
new file mode 100644
index 0000000..c6159f3
--- /dev/null
+++ b/src/core.js
@@ -0,0 +1,919 @@
+var c3 = { version: "0.4.6" };
+
+var c3_chart_fn, c3_chart_internal_fn;
+
+function Chart(config) {
+    var $$ = this.internal = new ChartInternal(this);
+    $$.loadConfig(config);
+    $$.init();
+
+    // bind "this" to nested API
+    (function bindThis(fn, target, argThis) {
+        Object.keys(fn).forEach(function (key) {
+            target[key] = fn[key].bind(argThis);
+            if (Object.keys(fn[key]).length > 0) {
+                bindThis(fn[key], target[key], argThis);
+            }
+        });
+    })(c3_chart_fn, this, this);
+}
+
+function ChartInternal(api) {
+    var $$ = this;
+    $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
+    $$.api = api;
+    $$.config = $$.getDefaultConfig();
+    $$.data = {};
+    $$.cache = {};
+    $$.axes = {};
+}
+
+c3.generate = function (config) {
+    return new Chart(config);
+};
+
+c3.chart = {
+    fn: Chart.prototype,
+    internal: {
+        fn: ChartInternal.prototype
+    }
+};
+c3_chart_fn = c3.chart.fn;
+c3_chart_internal_fn = c3.chart.internal.fn;
+
+
+c3_chart_internal_fn.init = function () {
+    var $$ = this, config = $$.config;
+
+    $$.initParams();
+
+    if (config.data_url) {
+        $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_keys, $$.initWithData);
+    }
+    else if (config.data_json) {
+        $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
+    }
+    else if (config.data_rows) {
+        $$.initWithData($$.convertRowsToData(config.data_rows));
+    }
+    else if (config.data_columns) {
+        $$.initWithData($$.convertColumnsToData(config.data_columns));
+    }
+    else {
+        throw Error('url or json or rows or columns is required.');
+    }
+};
+
+c3_chart_internal_fn.initParams = function () {
+    var $$ = this, d3 = $$.d3, config = $$.config;
+
+    // MEMO: clipId needs to be unique because it conflicts when multiple charts exist
+    $$.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);
+    $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid),
+    $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart),
+
+    $$.dragStart = null;
+    $$.dragging = false;
+    $$.flowing = false;
+    $$.cancelClick = false;
+    $$.mouseover = false;
+    $$.transiting = false;
+
+    $$.color = $$.generateColor();
+    $$.levelColor = $$.generateLevelColor();
+
+    $$.dataTimeFormat = config.data_xLocaltime ? d3.time.format : d3.time.format.utc;
+    $$.axisTimeFormat = config.axis_x_localtime ? d3.time.format : d3.time.format.utc;
+    $$.defaultAxisTimeFormat = $$.axisTimeFormat.multi([
+        [".%L", function (d) { return d.getMilliseconds(); }],
+        [":%S", function (d) { return d.getSeconds(); }],
+        ["%I:%M", function (d) { return d.getMinutes(); }],
+        ["%I %p", function (d) { return d.getHours(); }],
+        ["%-m/%-d", function (d) { return d.getDay() && d.getDate() !== 1; }],
+        ["%-m/%-d", function (d) { return d.getDate() !== 1; }],
+        ["%-m/%-d", function (d) { return d.getMonth(); }],
+        ["%Y/%-m/%-d", function () { return true; }]
+    ]);
+
+    $$.hiddenTargetIds = [];
+    $$.hiddenLegendIds = [];
+    $$.focusedTargetIds = [];
+    $$.defocusedTargetIds = [];
+
+    $$.xOrient = config.axis_rotated ? "left" : "bottom";
+    $$.yOrient = config.axis_rotated ? (config.axis_y_inner ? "top" : "bottom") : (config.axis_y_inner ? "right" : "left");
+    $$.y2Orient = config.axis_rotated ? (config.axis_y_inner ? "bottom" : "top") : (config.axis_y_inner ? "left" : "right");
+    $$.subXOrient = config.axis_rotated ? "left" : "bottom";
+
+    $$.isLegendRight = config.legend_position === 'right';
+    $$.isLegendInset = config.legend_position === 'inset';
+    $$.isLegendTop = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'top-right';
+    $$.isLegendLeft = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'bottom-left';
+    $$.legendStep = 0;
+    $$.legendItemWidth = 0;
+    $$.legendItemHeight = 0;
+
+    $$.currentMaxTickWidths = {
+        x: 0,
+        y: 0,
+        y2: 0
+    };
+
+    $$.rotated_padding_left = 30;
+    $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
+    $$.rotated_padding_top = 5;
+
+    $$.withoutFadeIn = {};
+
+    $$.intervalForObserveInserted = undefined;
+
+    $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
+};
+
+c3_chart_internal_fn.initChartElements = function () {
+    if (this.initBar) { this.initBar(); }
+    if (this.initLine) { this.initLine(); }
+    if (this.initArc) { this.initArc(); }
+    if (this.initGauge) { this.initGauge(); }
+    if (this.initText) { this.initText(); }
+};
+
+c3_chart_internal_fn.initWithData = function (data) {
+    var $$ = this, d3 = $$.d3, config = $$.config;
+    var defs, main, binding = true;
+
+    if ($$.initPie) { $$.initPie(); }
+    if ($$.initBrush) { $$.initBrush(); }
+    if ($$.initZoom) { $$.initZoom(); }
+
+    $$.selectChart = typeof config.bindto.node === 'function' ? config.bindto : d3.select(config.bindto);
+    if ($$.selectChart.empty()) {
+        $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
+        $$.observeInserted($$.selectChart);
+        binding = false;
+    }
+    $$.selectChart.html("").classed("c3", true);
+
+    // Init data as targets
+    $$.data.xs = {};
+    $$.data.targets = $$.convertDataToTargets(data);
+
+    if (config.data_filter) {
+        $$.data.targets = $$.data.targets.filter(config.data_filter);
+    }
+
+    // Set targets to hide if needed
+    if (config.data_hide) {
+        $$.addHiddenTargetIds(config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide);
+    }
+    if (config.legend_hide) {
+        $$.addHiddenLegendIds(config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide);
+    }
+
+    // when gauge, hide legend // TODO: fix
+    if ($$.hasType('gauge')) {
+        config.legend_show = false;
+    }
+
+    // Init sizes and scales
+    $$.updateSizes();
+    $$.updateScales();
+
+    // Set domains for each scale
+    $$.x.domain(d3.extent($$.getXDomain($$.data.targets)));
+    $$.y.domain($$.getYDomain($$.data.targets, 'y'));
+    $$.y2.domain($$.getYDomain($$.data.targets, 'y2'));
+    $$.subX.domain($$.x.domain());
+    $$.subY.domain($$.y.domain());
+    $$.subY2.domain($$.y2.domain());
+
+    // Save original x domain for zoom update
+    $$.orgXDomain = $$.x.domain();
+
+    // Set initialized scales to brush and zoom
+    if ($$.brush) { $$.brush.scale($$.subX); }
+    if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+
+    /*-- Basic Elements --*/
+
+    // Define svgs
+    $$.svg = $$.selectChart.append("svg")
+        .style("overflow", "hidden")
+        .on('mouseenter', function () { return config.onmouseover.call($$); })
+        .on('mouseleave', function () { return config.onmouseout.call($$); });
+
+    // Define defs
+    defs = $$.svg.append("defs");
+    $$.clipChart = $$.appendClip(defs, $$.clipId);
+    $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
+    $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
+    $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
+    $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
+    $$.updateSvgSize();
+
+    // Define regions
+    main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main'));
+
+    if ($$.initSubchart) { $$.initSubchart(); }
+    if ($$.initTooltip) { $$.initTooltip(); }
+    if ($$.initLegend) { $$.initLegend(); }
+
+    /*-- Main Region --*/
+
+    // text when empty
+    main.append("text")
+        .attr("class", CLASS.text + ' ' + CLASS.empty)
+        .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
+        .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
+
+    // Regions
+    $$.initRegion();
+
+    // Grids
+    $$.initGrid();
+
+    // Define g for chart area
+    main.append('g')
+        .attr("clip-path", $$.clipPath)
+        .attr('class', CLASS.chart);
+
+    // Grid lines
+    if (config.grid_lines_front) { $$.initGridLines(); }
+
+    // Cover whole with rects for events
+    $$.initEventRect();
+
+    // Define g for chart
+    $$.initChartElements();
+
+    // if zoom privileged, insert rect to forefront
+    // TODO: is this needed?
+    main.insert('rect', config.zoom_privileged ? null : 'g.' + CLASS.regions)
+        .attr('class', CLASS.zoomRect)
+        .attr('width', $$.width)
+        .attr('height', $$.height)
+        .style('opacity', 0)
+        .on("dblclick.zoom", null);
+
+    // Set default extent if defined
+    if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
+
+    // Add Axis
+    $$.initAxis();
+
+    // Set targets
+    $$.updateTargets($$.data.targets);
+
+    // Draw with targets
+    if (binding) {
+        $$.updateDimension();
+        $$.config.oninit.call($$);
+        $$.redraw({
+            withTransform: true,
+            withUpdateXDomain: true,
+            withUpdateOrgXDomain: true,
+            withTransitionForAxis: false
+        });
+    }
+
+    // Bind resize event
+    if (window.onresize == null) {
+        window.onresize = $$.generateResize();
+    }
+    if (window.onresize.add) {
+        window.onresize.add(function () {
+            config.onresize.call($$);
+        });
+        window.onresize.add(function () {
+            $$.api.flush();
+        });
+        window.onresize.add(function () {
+            config.onresized.call($$);
+        });
+    }
+
+    // export element of the chart
+    $$.api.element = $$.selectChart.node();
+};
+
+c3_chart_internal_fn.smoothLines = function (el, type) {
+    var $$ = this;
+    if (type === 'grid') {
+        el.each(function () {
+            var g = $$.d3.select(this),
+                x1 = g.attr('x1'),
+                x2 = g.attr('x2'),
+                y1 = g.attr('y1'),
+                y2 = g.attr('y2');
+            g.attr({
+                'x1': Math.ceil(x1),
+                'x2': Math.ceil(x2),
+                'y1': Math.ceil(y1),
+                'y2': Math.ceil(y2)
+            });
+        });
+    }
+};
+
+
+c3_chart_internal_fn.updateSizes = function () {
+    var $$ = this, config = $$.config;
+    var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
+        legendWidth = $$.legend ? $$.getLegendWidth() : 0,
+        legendHeightForBottom = $$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
+        hasArc = $$.hasArcType(),
+        xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
+        subchartHeight = config.subchart_show && !hasArc ? (config.subchart_size_height + xAxisHeight) : 0;
+
+    $$.currentWidth = $$.getCurrentWidth();
+    $$.currentHeight = $$.getCurrentHeight();
+
+    // for main
+    $$.margin = config.axis_rotated ? {
+        top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
+        right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+        bottom: $$.getHorizontalAxisHeight('y') + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+        left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
+    } : {
+        top: 4 + $$.getCurrentPaddingTop(), // for top tick text
+        right: hasArc ? 0 : $$.getCurrentPaddingRight(),
+        bottom: xAxisHeight + subchartHeight + legendHeightForBottom + $$.getCurrentPaddingBottom(),
+        left: hasArc ? 0 : $$.getCurrentPaddingLeft()
+    };
+
+    // for subchart
+    $$.margin2 = config.axis_rotated ? {
+        top: $$.margin.top,
+        right: NaN,
+        bottom: 20 + legendHeightForBottom,
+        left: $$.rotated_padding_left
+    } : {
+        top: $$.currentHeight - subchartHeight - legendHeightForBottom,
+        right: NaN,
+        bottom: xAxisHeight + legendHeightForBottom,
+        left: $$.margin.left
+    };
+
+    // for legend
+    $$.margin3 = {
+        top: 0,
+        right: NaN,
+        bottom: 0,
+        left: 0
+    };
+    if ($$.updateSizeForLegend) { $$.updateSizeForLegend(legendHeight, legendWidth); }
+
+    $$.width = $$.currentWidth - $$.margin.left - $$.margin.right;
+    $$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom;
+    if ($$.width < 0) { $$.width = 0; }
+    if ($$.height < 0) { $$.height = 0; }
+
+    $$.width2 = config.axis_rotated ? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right : $$.width;
+    $$.height2 = config.axis_rotated ? $$.height : $$.currentHeight - $$.margin2.top - $$.margin2.bottom;
+    if ($$.width2 < 0) { $$.width2 = 0; }
+    if ($$.height2 < 0) { $$.height2 = 0; }
+
+    // for arc
+    $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
+    $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
+    if ($$.hasType('gauge')) {
+        $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
+    }
+    if ($$.updateRadius) { $$.updateRadius(); }
+
+    if ($$.isLegendRight && hasArc) {
+        $$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1;
+    }
+};
+
+c3_chart_internal_fn.updateTargets = function (targets) {
+    var $$ = this, config = $$.config;
+
+    /*-- Main --*/
+
+    //-- Text --//
+    $$.updateTargetsForText(targets);
+
+    //-- Bar --//
+    $$.updateTargetsForBar(targets);
+
+    //-- Line --//
+    $$.updateTargetsForLine(targets);
+
+    //-- Arc --//
+    if ($$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
+    if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
+
+    /*-- Show --*/
+
+    // Fade-in each chart
+    $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); })
+      .transition().duration(config.transition_duration)
+        .style("opacity", 1);
+};
+
+c3_chart_internal_fn.redraw = function (options, transitions) {
+    var $$ = this, main = $$.main, d3 = $$.d3, config = $$.config;
+    var areaIndices = $$.getShapeIndices($$.isAreaType), barIndices = $$.getShapeIndices($$.isBarType), lineIndices = $$.getShapeIndices($$.isLineType);
+    var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis,
+        withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend,
+        withEventRect, withDimension, withUpdateXAxis;
+    var hideAxis = $$.hasArcType();
+    var drawArea, drawBar, drawLine, xForText, yForText;
+    var duration, durationForExit, durationForAxis;
+    var waitForDraw, flow;
+    var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling, xDomainForZoom;
+    var xv = $$.xv.bind($$), cx, cy;
+
+    options = options || {};
+    withY = getOption(options, "withY", true);
+    withSubchart = getOption(options, "withSubchart", true);
+    withTransition = getOption(options, "withTransition", true);
+    withTransform = getOption(options, "withTransform", false);
+    withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
+    withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
+    withTrimXDomain = getOption(options, "withTrimXDomain", true);
+    withUpdateXAxis = getOption(options, "withUpdateXAxis", withUpdateXDomain);
+    withLegend = getOption(options, "withLegend", false);
+    withEventRect = getOption(options, "withEventRect", true);
+    withDimension = getOption(options, "withDimension", true);
+    withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
+    withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
+
+    duration = withTransition ? config.transition_duration : 0;
+    durationForExit = withTransitionForExit ? duration : 0;
+    durationForAxis = withTransitionForAxis ? duration : 0;
+
+    transitions = transitions || $$.generateAxisTransitions(durationForAxis);
+
+    // update legend and transform each g
+    if (withLegend && config.legend_show) {
+        $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
+    } else if (withDimension) {
+        // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
+        // no need to update axis in it because they will be updated in redraw()
+        $$.updateDimension(true);
+    }
+
+    // MEMO: needed for grids calculation
+    if ($$.isCategorized() && targetsToShow.length === 0) {
+        $$.x.domain([0, $$.axes.x.selectAll('.tick').size()]);
+    }
+
+    if (targetsToShow.length) {
+        $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
+        if (!config.axis_x_tick_values) {
+            if (config.axis_x_tick_fit || config.axis_x_tick_count) {
+                tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count, $$.isTimeSeries());
+            } else {
+                tickValues = undefined;
+            }
+            $$.xAxis.tickValues(tickValues);
+            $$.subXAxis.tickValues(tickValues);
+        }
+    } else {
+        $$.xAxis.tickValues([]);
+        $$.subXAxis.tickValues([]);
+    }
+
+    if (config.zoom_rescale && !options.flow) {
+        xDomainForZoom = $$.x.orgDomain();
+    }
+
+    $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
+    $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
+
+    if (!config.axis_y_tick_values && config.axis_y_tick_count) {
+        $$.yAxis.tickValues($$.generateTickValues($$.y.domain(), config.axis_y_tick_count));
+    }
+    if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
+        $$.y2Axis.tickValues($$.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
+    }
+
+    // axes
+    $$.redrawAxis(transitions, hideAxis);
+
+    // Update axis label
+    $$.updateAxisLabels(withTransition);
+
+    // show/hide if manual culling needed
+    if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
+        if (config.axis_x_tick_culling && tickValues) {
+            for (i = 1; i < tickValues.length; i++) {
+                if (tickValues.length / i < config.axis_x_tick_culling_max) {
+                    intervalForCulling = i;
+                    break;
+                }
+            }
+            $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
+                var index = tickValues.indexOf(e);
+                if (index >= 0) {
+                    d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
+                }
+            });
+        } else {
+            $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
+        }
+    }
+
+    // setup drawer - MEMO: these must be called after axis updated
+    drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
+    drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
+    drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
+    xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
+    yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false);
+
+    // Update sub domain
+    if (withY) {
+        $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
+        $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
+    }
+
+    // tooltip
+    $$.tooltip.style("display", "none");
+
+    // xgrid focus
+    $$.updateXgridFocus();
+
+    // Data empty label positioning and text.
+    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);
+
+    // grid
+    $$.redrawGrid(duration);
+
+    // rect for regions
+    $$.redrawRegion(duration);
+
+    // bars
+    $$.redrawBar(durationForExit);
+
+    // lines, areas and cricles
+    $$.redrawLine(durationForExit);
+    $$.redrawArea(durationForExit);
+    $$.redrawCircle();
+
+    // text
+    if ($$.hasDataLabel()) {
+        $$.redrawText(durationForExit);
+    }
+
+    // arc
+    if ($$.redrawArc) { $$.redrawArc(duration, durationForExit, withTransform); }
+
+    // subchart
+    if ($$.redrawSubchart) {
+        $$.redrawSubchart(withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices);
+    }
+
+    // circles for select
+    main.selectAll('.' + CLASS.selectedCircles)
+        .filter($$.isBarType.bind($$))
+        .selectAll('circle')
+        .remove();
+
+    // event rects will redrawn when flow called
+    if (config.interaction_enabled && !options.flow && withEventRect) {
+        $$.redrawEventRect();
+        if ($$.updateZoom) { $$.updateZoom(); }
+    }
+
+    // update circleY based on updated parameters
+    $$.updateCircleY();
+
+    // generate circle x/y functions depending on updated params
+    cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
+    cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
+
+    // transition should be derived from one transition
+    d3.transition().duration(duration).each(function () {
+        var transitions = [];
+
+        $$.addTransitionForBar(transitions, drawBar);
+        $$.addTransitionForLine(transitions, drawLine);
+        $$.addTransitionForArea(transitions, drawArea);
+        $$.addTransitionForCircle(transitions, cx, cy);
+        $$.addTransitionForText(transitions, xForText, yForText, options.flow);
+        $$.addTransitionForRegion(transitions);
+        $$.addTransitionForGrid(transitions);
+
+        // Wait for end of transitions if called from flow API
+        if (options.flow) {
+            waitForDraw = $$.generateWait();
+            transitions.forEach(function (t) {
+                waitForDraw.add(t);
+            });
+            flow = $$.generateFlow({
+                targets: targetsToShow,
+                flow: options.flow,
+                duration: duration,
+                drawBar: drawBar,
+                drawLine: drawLine,
+                drawArea: drawArea,
+                cx: cx,
+                cy: cy,
+                xv: xv,
+                xForText: xForText,
+                yForText: yForText
+            });
+        }
+    })
+    .call(waitForDraw || function () {}, flow || function () {});
+
+    // update fadein condition
+    $$.mapToIds($$.data.targets).forEach(function (id) {
+        $$.withoutFadeIn[id] = true;
+    });
+};
+
+c3_chart_internal_fn.updateAndRedraw = function (options) {
+    var $$ = this, config = $$.config, transitions;
+    options = options || {};
+    // same with redraw
+    options.withTransition = getOption(options, "withTransition", true);
+    options.withTransform = getOption(options, "withTransform", false);
+    options.withLegend = getOption(options, "withLegend", false);
+    // NOT same with redraw
+    options.withUpdateXDomain = true;
+    options.withUpdateOrgXDomain = true;
+    options.withTransitionForExit = false;
+    options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
+    // MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
+    $$.updateSizes();
+    // MEMO: called in updateLegend in redraw if withLegend
+    if (!(options.withLegend && config.legend_show)) {
+        transitions = $$.generateAxisTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
+        // Update scales
+        $$.updateScales();
+        $$.updateSvgSize();
+        // Update g positions
+        $$.transformAll(options.withTransitionForTransform, transitions);
+    }
+    // Draw with new sizes & scales
+    $$.redraw(options, transitions);
+};
+c3_chart_internal_fn.redrawWithoutRescale = function () {
+    this.redraw({
+        withY: false,
+        withSubchart: false,
+        withEventRect: false,
+        withTransitionForAxis: false
+    });
+};
+
+c3_chart_internal_fn.isTimeSeries = function () {
+    return this.config.axis_x_type === 'timeseries';
+};
+c3_chart_internal_fn.isCategorized = function () {
+    return this.config.axis_x_type.indexOf('categor') >= 0;
+};
+c3_chart_internal_fn.isCustomX = function () {
+    var $$ = this, config = $$.config;
+    return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
+};
+
+c3_chart_internal_fn.isTimeSeriesY = function () {
+    return this.config.axis_y_type === 'timeseries';
+};
+
+c3_chart_internal_fn.getTranslate = function (target) {
+    var $$ = this, config = $$.config, x, y;
+    if (target === 'main') {
+        x = asHalfPixel($$.margin.left);
+        y = asHalfPixel($$.margin.top);
+    } else if (target === 'context') {
+        x = asHalfPixel($$.margin2.left);
+        y = asHalfPixel($$.margin2.top);
+    } else if (target === 'legend') {
+        x = $$.margin3.left;
+        y = $$.margin3.top;
+    } else if (target === 'x') {
+        x = 0;
+        y = config.axis_rotated ? 0 : $$.height;
+    } else if (target === 'y') {
+        x = 0;
+        y = config.axis_rotated ? $$.height : 0;
+    } else if (target === 'y2') {
+        x = config.axis_rotated ? 0 : $$.width;
+        y = config.axis_rotated ? 1 : 0;
+    } else if (target === 'subx') {
+        x = 0;
+        y = config.axis_rotated ? 0 : $$.height2;
+    } else if (target === 'arc') {
+        x = $$.arcWidth / 2;
+        y = $$.arcHeight / 2;
+    }
+    return "translate(" + x + "," + y + ")";
+};
+c3_chart_internal_fn.initialOpacity = function (d) {
+    return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
+};
+c3_chart_internal_fn.initialOpacityForCircle = function (d) {
+    return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
+};
+c3_chart_internal_fn.opacityForCircle = function (d) {
+    var opacity = this.config.point_show ? 1 : 0;
+    return isValue(d.value) ? (this.isScatterType(d) ? 0.5 : opacity) : 0;
+};
+c3_chart_internal_fn.opacityForText = function () {
+    return this.hasDataLabel() ? 1 : 0;
+};
+c3_chart_internal_fn.xx = function (d) {
+    return d ? this.x(d.x) : null;
+};
+c3_chart_internal_fn.xv = function (d) {
+    var $$ = this;
+    return Math.ceil($$.x($$.isTimeSeries() ? $$.parseDate(d.value) : d.value));
+};
+c3_chart_internal_fn.yv = function (d) {
+    var $$ = this,
+        yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y;
+    return Math.ceil(yScale(d.value));
+};
+c3_chart_internal_fn.subxx = function (d) {
+    return d ? this.subX(d.x) : null;
+};
+
+c3_chart_internal_fn.transformMain = function (withTransition, transitions) {
+    var $$ = this,
+        xAxis, yAxis, y2Axis;
+    if (transitions && transitions.axisX) {
+        xAxis = transitions.axisX;
+    } else {
+        xAxis  = $$.main.select('.' + CLASS.axisX);
+        if (withTransition) { xAxis = xAxis.transition(); }
+    }
+    if (transitions && transitions.axisY) {
+        yAxis = transitions.axisY;
+    } else {
+        yAxis = $$.main.select('.' + CLASS.axisY);
+        if (withTransition) { yAxis = yAxis.transition(); }
+    }
+    if (transitions && transitions.axisY2) {
+        y2Axis = transitions.axisY2;
+    } else {
+        y2Axis = $$.main.select('.' + CLASS.axisY2);
+        if (withTransition) { y2Axis = y2Axis.transition(); }
+    }
+    (withTransition ? $$.main.transition() : $$.main).attr("transform", $$.getTranslate('main'));
+    xAxis.attr("transform", $$.getTranslate('x'));
+    yAxis.attr("transform", $$.getTranslate('y'));
+    y2Axis.attr("transform", $$.getTranslate('y2'));
+    $$.main.select('.' + CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
+};
+c3_chart_internal_fn.transformAll = function (withTransition, transitions) {
+    var $$ = this;
+    $$.transformMain(withTransition, transitions);
+    if ($$.config.subchart_show) { $$.transformContext(withTransition, transitions); }
+    if ($$.legend) { $$.transformLegend(withTransition); }
+};
+
+c3_chart_internal_fn.updateSvgSize = function () {
+    var $$ = this,
+        brush = $$.svg.select(".c3-brush .background");
+    $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
+    $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect')
+        .attr('width', $$.width)
+        .attr('height', $$.height);
+    $$.svg.select('#' + $$.clipIdForXAxis).select('rect')
+        .attr('x', $$.getXAxisClipX.bind($$))
+        .attr('y', $$.getXAxisClipY.bind($$))
+        .attr('width', $$.getXAxisClipWidth.bind($$))
+        .attr('height', $$.getXAxisClipHeight.bind($$));
+    $$.svg.select('#' + $$.clipIdForYAxis).select('rect')
+        .attr('x', $$.getYAxisClipX.bind($$))
+        .attr('y', $$.getYAxisClipY.bind($$))
+        .attr('width', $$.getYAxisClipWidth.bind($$))
+        .attr('height', $$.getYAxisClipHeight.bind($$));
+    $$.svg.select('#' + $$.clipIdForSubchart).select('rect')
+        .attr('width', $$.width)
+        .attr('height', brush.size() ? brush.attr('height') : 0);
+    $$.svg.select('.' + CLASS.zoomRect)
+        .attr('width', $$.width)
+        .attr('height', $$.height);
+    // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
+    $$.selectChart.style('max-height', $$.currentHeight + "px");
+};
+
+
+c3_chart_internal_fn.updateDimension = function (withoutAxis) {
+    var $$ = this;
+    if (!withoutAxis) {
+        if ($$.config.axis_rotated) {
+            $$.axes.x.call($$.xAxis);
+            $$.axes.subx.call($$.subXAxis);
+        } else {
+            $$.axes.y.call($$.yAxis);
+            $$.axes.y2.call($$.y2Axis);
+        }
+    }
+    $$.updateSizes();
+    $$.updateScales();
+    $$.updateSvgSize();
+    $$.transformAll(false);
+};
+
+c3_chart_internal_fn.observeInserted = function (selection) {
+    var $$ = this, observer = new MutationObserver(function (mutations) {
+        mutations.forEach(function (mutation) {
+            if (mutation.type === 'childList' && mutation.previousSibling) {
+                observer.disconnect();
+                // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
+                $$.intervalForObserveInserted = window.setInterval(function () {
+                    // parentNode will NOT be null when completed
+                    if (selection.node().parentNode) {
+                        window.clearInterval($$.intervalForObserveInserted);
+                        $$.updateDimension();
+                        $$.config.oninit.call($$);
+                        $$.redraw({
+                            withTransform: true,
+                            withUpdateXDomain: true,
+                            withUpdateOrgXDomain: true,
+                            withTransition: false,
+                            withTransitionForTransform: false,
+                            withLegend: true
+                        });
+                        selection.transition().style('opacity', 1);
+                    }
+                }, 10);
+            }
+        });
+    });
+    observer.observe(selection.node(), {attributes: true, childList: true, characterData: true});
+};
+
+
+c3_chart_internal_fn.generateResize = function () {
+    var resizeFunctions = [];
+    function callResizeFunctions() {
+        resizeFunctions.forEach(function (f) {
+            f();
+        });
+    }
+    callResizeFunctions.add = function (f) {
+        resizeFunctions.push(f);
+    };
+    return callResizeFunctions;
+};
+
+c3_chart_internal_fn.endall = function (transition, callback) {
+    var n = 0;
+    transition
+        .each(function () { ++n; })
+        .each("end", function () {
+            if (!--n) { callback.apply(this, arguments); }
+        });
+};
+c3_chart_internal_fn.generateWait = function () {
+    var transitionsToWait = [],
+        f = function (transition, callback) {
+            var timer = setInterval(function () {
+                var done = 0;
+                transitionsToWait.forEach(function (t) {
+                    if (t.empty()) {
+                        done += 1;
+                        return;
+                    }
+                    try {
+                        t.transition();
+                    } catch (e) {
+                        done += 1;
+                    }
+                });
+                if (done === transitionsToWait.length) {
+                    clearInterval(timer);
+                    if (callback) { callback(); }
+                }
+            }, 10);
+        };
+    f.add = function (transition) {
+        transitionsToWait.push(transition);
+    };
+    return f;
+};
+
+c3_chart_internal_fn.parseDate = function (date) {
+    var $$ = this, parsedDate;
+    if (date instanceof Date) {
+        parsedDate = date;
+    } else if (typeof date === 'number') {
+        parsedDate = new Date(date);
+    } else {
+        parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
+    }
+    if (!parsedDate || isNaN(+parsedDate)) {
+        window.console.error("Failed to parse x '" + date + "' to Date object");
+    }
+    return parsedDate;
+};
diff --git a/src/data.convert.js b/src/data.convert.js
new file mode 100644
index 0000000..c274ef5
--- /dev/null
+++ b/src/data.convert.js
@@ -0,0 +1,187 @@
+c3_chart_internal_fn.convertUrlToData = function (url, mimeType, keys, done) {
+    var $$ = this, type = mimeType ? mimeType : 'csv';
+    $$.d3.xhr(url, function (error, data) {
+        var d;
+        if (type === 'json') {
+            d = $$.convertJsonToData(JSON.parse(data.response), keys);
+        } else if (type === 'tsv') {
+            d = $$.convertTsvToData(data.response);
+        } else {
+            d = $$.convertCsvToData(data.response);
+        }
+        done.call($$, d);
+    });
+};
+c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
+    var rows = parser.parseRows(xsv), d;
+    if (rows.length === 1) {
+        d = [{}];
+        rows[0].forEach(function (id) {
+            d[0][id] = null;
+        });
+    } else {
+        d = parser.parse(xsv);
+    }
+    return d;
+};
+c3_chart_internal_fn.convertCsvToData = function (csv) {
+    return this.convertXsvToData(csv, this.d3.csv);
+};
+c3_chart_internal_fn.convertTsvToData = function (tsv) {
+    return this.convertXsvToData(tsv, this.d3.tsv);
+};
+c3_chart_internal_fn.convertJsonToData = function (json, keys) {
+    var $$ = this,
+        new_rows = [], targetKeys, data;
+    if (keys) { // when keys specified, json would be an array that includes objects
+        targetKeys = keys.value;
+        if (keys.x) {
+            targetKeys.push(keys.x);
+            $$.config.data_x = keys.x;
+        }
+        new_rows.push(targetKeys);
+        json.forEach(function (o) {
+            var new_row = [];
+            targetKeys.forEach(function (key) {
+                // convert undefined to null because undefined data will be removed in convertDataToTargets()
+                var v = isUndefined(o[key]) ? null : o[key];
+                new_row.push(v);
+            });
+            new_rows.push(new_row);
+        });
+        data = $$.convertRowsToData(new_rows);
+    } else {
+        Object.keys(json).forEach(function (key) {
+            new_rows.push([key].concat(json[key]));
+        });
+        data = $$.convertColumnsToData(new_rows);
+    }
+    return data;
+};
+c3_chart_internal_fn.convertRowsToData = function (rows) {
+    var keys = rows[0], new_row = {}, new_rows = [], i, j;
+    for (i = 1; i < rows.length; i++) {
+        new_row = {};
+        for (j = 0; j < rows[i].length; j++) {
+            if (isUndefined(rows[i][j])) {
+                throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
+            }
+            new_row[keys[j]] = rows[i][j];
+        }
+        new_rows.push(new_row);
+    }
+    return new_rows;
+};
+c3_chart_internal_fn.convertColumnsToData = function (columns) {
+    var new_rows = [], i, j, key;
+    for (i = 0; i < columns.length; i++) {
+        key = columns[i][0];
+        for (j = 1; j < columns[i].length; j++) {
+            if (isUndefined(new_rows[j - 1])) {
+                new_rows[j - 1] = {};
+            }
+            if (isUndefined(columns[i][j])) {
+                throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
+            }
+            new_rows[j - 1][key] = columns[i][j];
+        }
+    }
+    return new_rows;
+};
+c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
+    var $$ = this, config = $$.config,
+        ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
+        xs = $$.d3.keys(data[0]).filter($$.isX, $$),
+        targets;
+
+    // save x for update data by load when custom x and c3.x API
+    ids.forEach(function (id) {
+        var xKey = $$.getXKey(id);
+
+        if ($$.isCustomX() || $$.isTimeSeries()) {
+            // if included in input data
+            if (xs.indexOf(xKey) >= 0) {
+                $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
+                    data.map(function (d) { return d[xKey]; })
+                        .filter(isValue)
+                        .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
+                );
+            }
+            // if not included in input data, find from preloaded data of other id's x
+            else if (config.data_x) {
+                $$.data.xs[id] = $$.getOtherTargetXs();
+            }
+            // if not included in input data, find from preloaded data
+            else if (notEmpty(config.data_xs)) {
+                $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
+            }
+            // MEMO: if no x included, use same x of current will be used
+        } else {
+            $$.data.xs[id] = data.map(function (d, i) { return i; });
+        }
+    });
+
+
+    // check x is defined
+    ids.forEach(function (id) {
+        if (!$$.data.xs[id]) {
+            throw new Error('x is not defined for id = "' + id + '".');
+        }
+    });
+
+    // convert to target
+    targets = ids.map(function (id, index) {
+        var convertedId = config.data_idConverter(id);
+        return {
+            id: convertedId,
+            id_org: id,
+            values: data.map(function (d, i) {
+                var xKey = $$.getXKey(id), rawX = d[xKey], x = $$.generateTargetX(rawX, id, i);
+                // use x as categories if custom x and categorized
+                if ($$.isCustomX() && $$.isCategorized() && index === 0 && rawX) {
+                    if (i === 0) { config.axis_x_categories = []; }
+                    config.axis_x_categories.push(rawX);
+                }
+                // mark as x = undefined if value is undefined and filter to remove after mapped
+                if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
+                    x = undefined;
+                }
+                return {x: x, value: d[id] !== null && !isNaN(d[id]) ? +d[id] : null, id: convertedId};
+            }).filter(function (v) { return isDefined(v.x); })
+        };
+    });
+
+    // finish targets
+    targets.forEach(function (t) {
+        var i;
+        // sort values by its x
+        if (config.data_xSort) {
+            t.values = t.values.sort(function (v1, v2) {
+                var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
+                    x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
+                return x1 - x2;
+            });
+        }
+        // indexing each value
+        i = 0;
+        t.values.forEach(function (v) {
+            v.index = i++;
+        });
+        // this needs to be sorted because its index and value.index is identical
+        $$.data.xs[t.id].sort(function (v1, v2) {
+            return v1 - v2;
+        });
+    });
+
+    // set target types
+    if (config.data_type) {
+        $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
+    }
+
+    // cache as original id keyed
+    targets.forEach(function (d) {
+        $$.addCache(d.id_org, d);
+    });
+
+    return targets;
+};
diff --git a/src/data.js b/src/data.js
new file mode 100644
index 0000000..abe8bb2
--- /dev/null
+++ b/src/data.js
@@ -0,0 +1,369 @@
+c3_chart_internal_fn.isX = function (key) {
+    var $$ = this, config = $$.config;
+    return (config.data_x && key === config.data_x) || (notEmpty(config.data_xs) && hasValue(config.data_xs, key));
+};
+c3_chart_internal_fn.isNotX = function (key) {
+    return !this.isX(key);
+};
+c3_chart_internal_fn.getXKey = function (id) {
+    var $$ = this, config = $$.config;
+    return config.data_x ? config.data_x : notEmpty(config.data_xs) ? config.data_xs[id] : null;
+};
+c3_chart_internal_fn.getXValuesOfXKey = function (key, targets) {
+    var $$ = this,
+        xValues, ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : [];
+    ids.forEach(function (id) {
+        if ($$.getXKey(id) === key) {
+            xValues = $$.data.xs[id];
+        }
+    });
+    return xValues;
+};
+c3_chart_internal_fn.getIndexByX = function (x) {
+    var $$ = this,
+        data = $$.filterByX($$.data.targets, x);
+    return data.length ? data[0].index : null;
+};
+c3_chart_internal_fn.getXValue = function (id, i) {
+    var $$ = this;
+    return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
+};
+c3_chart_internal_fn.getOtherTargetXs = function () {
+    var $$ = this,
+        idsForX = Object.keys($$.data.xs);
+    return idsForX.length ? $$.data.xs[idsForX[0]] : null;
+};
+c3_chart_internal_fn.getOtherTargetX = function (index) {
+    var xs = this.getOtherTargetXs();
+    return xs && index < xs.length ? xs[index] : null;
+};
+c3_chart_internal_fn.addXs = function (xs) {
+    var $$ = this;
+    Object.keys(xs).forEach(function (id) {
+        $$.config.data_xs[id] = xs[id];
+    });
+};
+c3_chart_internal_fn.hasMultipleX = function (xs) {
+    return this.d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() > 1;
+};
+c3_chart_internal_fn.isMultipleX = function () {
+    return notEmpty(this.config.data_xs) || !this.config.data_xSort || this.hasType('scatter');
+};
+c3_chart_internal_fn.addName = function (data) {
+    var $$ = this, name;
+    if (data) {
+        name = $$.config.data_names[data.id];
+        data.name = name ? name : data.id;
+    }
+    return data;
+};
+c3_chart_internal_fn.getValueOnIndex = function (values, index) {
+    var valueOnIndex = values.filter(function (v) { return v.index === index; });
+    return valueOnIndex.length ? valueOnIndex[0] : null;
+};
+c3_chart_internal_fn.updateTargetX = function (targets, x) {
+    var $$ = this;
+    targets.forEach(function (t) {
+        t.values.forEach(function (v, i) {
+            v.x = $$.generateTargetX(x[i], t.id, i);
+        });
+        $$.data.xs[t.id] = x;
+    });
+};
+c3_chart_internal_fn.updateTargetXs = function (targets, xs) {
+    var $$ = this;
+    targets.forEach(function (t) {
+        if (xs[t.id]) {
+            $$.updateTargetX([t], xs[t.id]);
+        }
+    });
+};
+c3_chart_internal_fn.generateTargetX = function (rawX, id, index) {
+    var $$ = this, x;
+    if ($$.isTimeSeries()) {
+        x = rawX ? $$.parseDate(rawX) : $$.parseDate($$.getXValue(id, index));
+    }
+    else if ($$.isCustomX() && !$$.isCategorized()) {
+        x = isValue(rawX) ? +rawX : $$.getXValue(id, index);
+    }
+    else {
+        x = index;
+    }
+    return x;
+};
+c3_chart_internal_fn.cloneTarget = function (target) {
+    return {
+        id : target.id,
+        id_org : target.id_org,
+        values : target.values.map(function (d) {
+            return {x: d.x, value: d.value, id: d.id};
+        })
+    };
+};
+c3_chart_internal_fn.updateXs = function () {
+    var $$ = this;
+    if ($$.data.targets.length) {
+        $$.xs = [];
+        $$.data.targets[0].values.forEach(function (v) {
+            $$.xs[v.index] = v.x;
+        });
+    }
+};
+c3_chart_internal_fn.getPrevX = function (i) {
+    var x = this.xs[i - 1];
+    return typeof x !== 'undefined' ? x : null;
+};
+c3_chart_internal_fn.getNextX = function (i) {
+    var x = this.xs[i + 1];
+    return typeof x !== 'undefined' ? x : null;
+};
+c3_chart_internal_fn.getMaxDataCount = function () {
+    var $$ = this;
+    return $$.d3.max($$.data.targets, function (t) { return t.values.length; });
+};
+c3_chart_internal_fn.getMaxDataCountTarget = function (targets) {
+    var length = targets.length, max = 0, maxTarget;
+    if (length > 1) {
+        targets.forEach(function (t) {
+            if (t.values.length > max) {
+                maxTarget = t;
+                max = t.values.length;
+            }
+        });
+    } else {
+        maxTarget = length ? targets[0] : null;
+    }
+    return maxTarget;
+};
+c3_chart_internal_fn.getEdgeX = function (targets) {
+    var $$ = this;
+    return !targets.length ? [0, 0] : [
+        $$.d3.min(targets, function (t) { return t.values[0].x; }),
+        $$.d3.max(targets, function (t) { return t.values[t.values.length - 1].x; })
+    ];
+};
+c3_chart_internal_fn.mapToIds = function (targets) {
+    return targets.map(function (d) { return d.id; });
+};
+c3_chart_internal_fn.mapToTargetIds = function (ids) {
+    var $$ = this;
+    return ids ? (isString(ids) ? [ids] : ids) : $$.mapToIds($$.data.targets);
+};
+c3_chart_internal_fn.hasTarget = function (targets, id) {
+    var ids = this.mapToIds(targets), i;
+    for (i = 0; i < ids.length; i++) {
+        if (ids[i] === id) {
+            return true;
+        }
+    }
+    return false;
+};
+c3_chart_internal_fn.isTargetToShow = function (targetId) {
+    return this.hiddenTargetIds.indexOf(targetId) < 0;
+};
+c3_chart_internal_fn.isLegendToShow = function (targetId) {
+    return this.hiddenLegendIds.indexOf(targetId) < 0;
+};
+c3_chart_internal_fn.filterTargetsToShow = function (targets) {
+    var $$ = this;
+    return targets.filter(function (t) { return $$.isTargetToShow(t.id); });
+};
+c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
+    var $$ = this;
+    var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
+    return $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
+};
+c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
+    this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
+};
+c3_chart_internal_fn.removeHiddenTargetIds = function (targetIds) {
+    this.hiddenTargetIds = this.hiddenTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+};
+c3_chart_internal_fn.addHiddenLegendIds = function (targetIds) {
+    this.hiddenLegendIds = this.hiddenLegendIds.concat(targetIds);
+};
+c3_chart_internal_fn.removeHiddenLegendIds = function (targetIds) {
+    this.hiddenLegendIds = this.hiddenLegendIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
+};
+c3_chart_internal_fn.getValuesAsIdKeyed = function (targets) {
+    var ys = {};
+    targets.forEach(function (t) {
+        ys[t.id] = [];
+        t.values.forEach(function (v) {
+            ys[t.id].push(v.value);
+        });
+    });
+    return ys;
+};
+c3_chart_internal_fn.checkValueInTargets = function (targets, checker) {
+    var ids = Object.keys(targets), i, j, values;
+    for (i = 0; i < ids.length; i++) {
+        values = targets[ids[i]].values;
+        for (j = 0; j < values.length; j++) {
+            if (checker(values[j].value)) {
+                return true;
+            }
+        }
+    }
+    return false;
+};
+c3_chart_internal_fn.hasNegativeValueInTargets = function (targets) {
+    return this.checkValueInTargets(targets, function (v) { return v < 0; });
+};
+c3_chart_internal_fn.hasPositiveValueInTargets = function (targets) {
+    return this.checkValueInTargets(targets, function (v) { return v > 0; });
+};
+c3_chart_internal_fn.isOrderDesc = function () {
+    var config = this.config;
+    return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'desc';
+};
+c3_chart_internal_fn.isOrderAsc = function () {
+    var config = this.config;
+    return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'asc';
+};
+c3_chart_internal_fn.orderTargets = function (targets) {
+    var $$ = this, config = $$.config, orderAsc = $$.isOrderAsc(), orderDesc = $$.isOrderDesc();
+    if (orderAsc || orderDesc) {
+        targets.sort(function (t1, t2) {
+            var reducer = function (p, c) { return p + Math.abs(c.value); };
+            var t1Sum = t1.values.reduce(reducer, 0),
+                t2Sum = t2.values.reduce(reducer, 0);
+            return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
+        });
+    } else if (isFunction(config.data_order)) {
+        targets.sort(config.data_order);
+    } // TODO: accept name array for order
+    return targets;
+};
+c3_chart_internal_fn.filterByX = function (targets, x) {
+    return this.d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
+};
+c3_chart_internal_fn.filterRemoveNull = function (data) {
+    return data.filter(function (d) { return isValue(d.value); });
+};
+c3_chart_internal_fn.filterByXDomain = function (targets, xDomain) {
+    return targets.map(function (t) {
+        return {
+            id: t.id,
+            id_org: t.id_org,
+            values: t.values.filter(function (v) {
+                return xDomain[0] <= v.x && v.x <= xDomain[1];
+            })
+        };
+    });
+};
+c3_chart_internal_fn.hasDataLabel = function () {
+    var config = this.config;
+    if (typeof config.data_labels === 'boolean' && config.data_labels) {
+        return true;
+    } else if (typeof config.data_labels === 'object' && notEmpty(config.data_labels)) {
+        return true;
+    }
+    return false;
+};
+c3_chart_internal_fn.getDataLabelLength = function (min, max, axisId, key) {
+    var $$ = this,
+        lengths = [0, 0], paddingCoef = 1.3;
+    $$.selectChart.select('svg').selectAll('.dummy')
+        .data([min, max])
+        .enter().append('text')
+        .text(function (d) { return $$.formatByAxisId(axisId)(d); })
+        .each(function (d, i) {
+            lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
+        })
+        .remove();
+    return lengths;
+};
+c3_chart_internal_fn.isNoneArc = function (d) {
+    return this.hasTarget(this.data.targets, d.id);
+},
+c3_chart_internal_fn.isArc = function (d) {
+    return 'data' in d && this.hasTarget(this.data.targets, d.data.id);
+};
+c3_chart_internal_fn.findSameXOfValues = function (values, index) {
+    var i, targetX = values[index].x, sames = [];
+    for (i = index - 1; i >= 0; i--) {
+        if (targetX !== values[i].x) { break; }
+        sames.push(values[i]);
+    }
+    for (i = index; i < values.length; i++) {
+        if (targetX !== values[i].x) { break; }
+        sames.push(values[i]);
+    }
+    return sames;
+};
+
+c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
+    var $$ = this, candidates;
+
+    // map to array of closest points of each target
+    candidates = targets.map(function (target) {
+        return $$.findClosest(target.values, pos);
+    });
+
+    // decide closest point and return
+    return $$.findClosest(candidates, pos);
+};
+c3_chart_internal_fn.findClosest = function (values, pos) {
+    var $$ = this, minDist = 100, closest;
+
+    // find mouseovering bar
+    values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
+        var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
+        if (!closest && $$.isWithinBar(shape)) {
+            closest = v;
+        }
+    });
+
+    // find closest point from non-bar
+    values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
+        var d = $$.dist(v, pos);
+        if (d < minDist) {
+            minDist = d;
+            closest = v;
+        }
+    });
+
+    return closest;
+};
+c3_chart_internal_fn.dist = function (data, pos) {
+    var $$ = this, config = $$.config,
+        xIndex = config.axis_rotated ? 1 : 0,
+        yIndex = config.axis_rotated ? 0 : 1,
+        y = $$.circleY(data, data.index),
+        x = $$.x(data.x);
+    return Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2);
+};
+c3_chart_internal_fn.convertValuesToStep = function (values) {
+    var converted = [].concat(values), i;
+
+    if (!this.isCategorized()) {
+        return values;
+    }
+
+    for (i = values.length + 1; 0 < i; i--) {
+        converted[i] = converted[i - 1];
+    }
+
+    converted[0] = {
+        x: converted[0].x - 1,
+        value: converted[0].value,
+        id: converted[0].id
+    };
+    converted[values.length + 1] = {
+        x: converted[values.length].x + 1,
+        value: converted[values.length].value,
+        id: converted[values.length].id
+    };
+
+    return converted;
+};
+c3_chart_internal_fn.updateDataAttributes = function (name, attrs) {
+    var $$ = this, config = $$.config, current = config['data_' + name];
+    if (typeof attrs === 'undefined') { return current; }
+    Object.keys(attrs).forEach(function (id) {
+        current[id] = attrs[id];
+    });
+    $$.redraw({withLegend: true});
+    return current;
+};
diff --git a/src/data.load.js b/src/data.load.js
new file mode 100644
index 0000000..242bcdd
--- /dev/null
+++ b/src/data.load.js
@@ -0,0 +1,87 @@
+c3_chart_internal_fn.load = function (targets, args) {
+    var $$ = this;
+    if (targets) {
+        // filter loading targets if needed
+        if (args.filter) {
+            targets = targets.filter(args.filter);
+        }
+        // set type if args.types || args.type specified
+        if (args.type || args.types) {
+            targets.forEach(function (t) {
+                $$.setTargetType(t.id, args.types ? args.types[t.id] : args.type);
+            });
+        }
+        // Update/Add data
+        $$.data.targets.forEach(function (d) {
+            for (var i = 0; i < targets.length; i++) {
+                if (d.id === targets[i].id) {
+                    d.values = targets[i].values;
+                    targets.splice(i, 1);
+                    break;
+                }
+            }
+        });
+        $$.data.targets = $$.data.targets.concat(targets); // add remained
+    }
+
+    // Set targets
+    $$.updateTargets($$.data.targets);
+
+    // Redraw with new targets
+    $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
+
+    if (args.done) { args.done(); }
+};
+c3_chart_internal_fn.loadFromArgs = function (args) {
+    var $$ = this;
+    if (args.data) {
+        $$.load($$.convertDataToTargets(args.data), args);
+    }
+    else if (args.url) {
+        $$.convertUrlToData(args.url, args.mimeType, args.keys, function (data) {
+            $$.load($$.convertDataToTargets(data), args);
+        });
+    }
+    else if (args.json) {
+        $$.load($$.convertDataToTargets($$.convertJsonToData(args.json, args.keys)), args);
+    }
+    else if (args.rows) {
+        $$.load($$.convertDataToTargets($$.convertRowsToData(args.rows)), args);
+    }
+    else if (args.columns) {
+        $$.load($$.convertDataToTargets($$.convertColumnsToData(args.columns)), args);
+    }
+    else {
+        $$.load(null, args);
+    }
+};
+c3_chart_internal_fn.unload = function (targetIds, done) {
+    var $$ = this;
+    if (!done) {
+        done = function () {};
+    }
+    // filter existing target
+    targetIds = targetIds.filter(function (id) { return $$.hasTarget($$.data.targets, id); });
+    // If no target, call done and return
+    if (!targetIds || targetIds.length === 0) {
+        done();
+        return;
+    }
+    $$.svg.selectAll(targetIds.map(function (id) { return $$.selectorTarget(id); }))
+        .transition()
+        .style('opacity', 0)
+        .remove()
+        .call($$.endall, done);
+    targetIds.forEach(function (id) {
+        // Reset fadein for future load
+        $$.withoutFadeIn[id] = false;
+        // Remove target's elements
+        if ($$.legend) {
+            $$.legend.selectAll('.' + CLASS.legendItem + $$.getTargetSelectorSuffix(id)).remove();
+        }
+        // Remove target
+        $$.data.targets = $$.data.targets.filter(function (t) {
+            return t.id !== id;
+        });
+    });
+};
diff --git a/src/domain.js b/src/domain.js
new file mode 100644
index 0000000..9e81929
--- /dev/null
+++ b/src/domain.js
@@ -0,0 +1,236 @@
+c3_chart_internal_fn.getYDomainMin = function (targets) {
+    var $$ = this, config = $$.config,
+        ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+        j, k, baseId, idsInGroup, id, hasNegativeValue;
+    if (config.data_groups.length > 0) {
+        hasNegativeValue = $$.hasNegativeValueInTargets(targets);
+        for (j = 0; j < config.data_groups.length; j++) {
+            // Determine baseId
+            idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+            if (idsInGroup.length === 0) { continue; }
+            baseId = idsInGroup[0];
+            // Consider negative values
+            if (hasNegativeValue && ys[baseId]) {
+                ys[baseId].forEach(function (v, i) {
+                    ys[baseId][i] = v < 0 ? v : 0;
+                });
+            }
+            // Compute min
+            for (k = 1; k < idsInGroup.length; k++) {
+                id = idsInGroup[k];
+                if (! ys[id]) { continue; }
+                ys[id].forEach(function (v, i) {
+                    if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
+                        ys[baseId][i] += +v;
+                    }
+                });
+            }
+        }
+    }
+    return $$.d3.min(Object.keys(ys).map(function (key) { return $$.d3.min(ys[key]); }));
+};
+c3_chart_internal_fn.getYDomainMax = function (targets) {
+    var $$ = this, config = $$.config,
+        ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
+        j, k, baseId, idsInGroup, id, hasPositiveValue;
+    if (config.data_groups.length > 0) {
+        hasPositiveValue = $$.hasPositiveValueInTargets(targets);
+        for (j = 0; j < config.data_groups.length; j++) {
+            // Determine baseId
+            idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
+            if (idsInGroup.length === 0) { continue; }
+            baseId = idsInGroup[0];
+            // Consider positive values
+            if (hasPositiveValue && ys[baseId]) {
+                ys[baseId].forEach(function (v, i) {
+                    ys[baseId][i] = v > 0 ? v : 0;
+                });
+            }
+            // Compute max
+            for (k = 1; k < idsInGroup.length; k++) {
+                id = idsInGroup[k];
+                if (! ys[id]) { continue; }
+                ys[id].forEach(function (v, i) {
+                    if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
+                        ys[baseId][i] += +v;
+                    }
+                });
+            }
+        }
+    }
+    return $$.d3.max(Object.keys(ys).map(function (key) { return $$.d3.max(ys[key]); }));
+};
+c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
+    var $$ = this, config = $$.config,
+        targetsByAxisId = targets.filter(function (t) { return $$.getAxisId(t.id) === axisId; }),
+        yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
+        yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
+        yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
+        yDomainMin = isValue(yMin) ? yMin : $$.getYDomainMin(yTargets),
+        yDomainMax = isValue(yMax) ? yMax : $$.getYDomainMax(yTargets),
+        domainLength, padding, padding_top, padding_bottom,
+        center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
+        yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative,
+        isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
+        showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
+        showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
+
+    if (yDomainMax < yDomainMin) {
+        if (isValue(yMin)) {
+            yDomainMax = yDomainMin + 10; // TODO: introduce axis.y.maxMin
+        } else {
+            yDomainMin = yDomainMax - 10; // TODO: introduce axis.y.minMax
+        }
+    }
+
+    if (yTargets.length === 0) { // use current domain if target of axisId is none
+        return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
+    }
+    if (isNaN(yDomainMin)) { // set minimum to zero when not number
+        yDomainMin = 0;
+    }
+    if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin
+        yDomainMax = yDomainMin;
+    }
+    if (yDomainMin === yDomainMax) {
+        yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
+    }
+    isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
+    isAllNegative = yDomainMin <= 0 && yDomainMax <= 0;
+
+    // Cancel zerobased if axis_*_min / axis_*_max specified
+    if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) {
+        isZeroBased = false;
+    }
+
+    // Bar/Area chart should be 0-based if all positive|negative
+    if (isZeroBased) {
+        if (isAllPositive) { yDomainMin = 0; }
+        if (isAllNegative) { yDomainMax = 0; }
+    }
+
+    domainLength = Math.abs(yDomainMax - yDomainMin);
+    padding = padding_top = padding_bottom = domainLength * 0.1;
+
+    if (center) {
+        yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
+        yDomainMax = yDomainAbs - center;
+        yDomainMin = center - yDomainAbs;
+    }
+    // add padding for data label
+    if (showHorizontalDataLabel) {
+        lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'width');
+        diff = diffDomain($$.y.range());
+        ratio = [lengths[0] / diff, lengths[1] / diff];
+        padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
+        padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
+    } else if (showVerticalDataLabel) {
+        lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'height');
+        padding_top += lengths[1];
+        padding_bottom += lengths[0];
+    }
+    if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
+        padding_top = $$.getAxisPadding(config.axis_y_padding, 'top', padding, domainLength);
+        padding_bottom = $$.getAxisPadding(config.axis_y_padding, 'bottom', padding, domainLength);
+    }
+    if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
+        padding_top = $$.getAxisPadding(config.axis_y2_padding, 'top', padding, domainLength);
+        padding_bottom = $$.getAxisPadding(config.axis_y2_padding, 'bottom', padding, domainLength);
+    }
+    // Bar/Area chart should be 0-based if all positive|negative
+    if (isZeroBased) {
+        if (isAllPositive) { padding_bottom = yDomainMin; }
+        if (isAllNegative) { padding_top = -yDomainMax; }
+    }
+    return [yDomainMin - padding_bottom, yDomainMax + padding_top];
+};
+c3_chart_internal_fn.getXDomainMin = function (targets) {
+    var $$ = this, config = $$.config;
+    return isDefined(config.axis_x_min) ?
+        ($$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min) :
+    $$.d3.min(targets, function (t) { return $$.d3.min(t.values, function (v) { return v.x; }); });
+};
+c3_chart_internal_fn.getXDomainMax = function (targets) {
+    var $$ = this, config = $$.config;
+    return isDefined(config.axis_x_max) ?
+        ($$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max) :
+    $$.d3.max(targets, function (t) { return $$.d3.max(t.values, function (v) { return v.x; }); });
+};
+c3_chart_internal_fn.getXDomainPadding = function (domain) {
+    var $$ = this, config = $$.config,
+        diff = domain[1] - domain[0],
+        maxDataCount, padding, paddingLeft, paddingRight;
+    if ($$.isCategorized()) {
+        padding = 0;
+    } else if ($$.hasType('bar')) {
+        maxDataCount = $$.getMaxDataCount();
+        padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
+    } else {
+        padding = diff * 0.01;
+    }
+    if (typeof config.axis_x_padding === 'object' && notEmpty(config.axis_x_padding)) {
+        paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding;
+        paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding;
+    } else if (typeof config.axis_x_padding === 'number') {
+        paddingLeft = paddingRight = config.axis_x_padding;
+    } else {
+        paddingLeft = paddingRight = padding;
+    }
+    return {left: paddingLeft, right: paddingRight};
+};
+c3_chart_internal_fn.getXDomain = function (targets) {
+    var $$ = this,
+        xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
+        firstX = xDomain[0], lastX = xDomain[1],
+        padding = $$.getXDomainPadding(xDomain),
+        min = 0, max = 0;
+    // show center of x domain if min and max are the same
+    if ((firstX - lastX) === 0 && !$$.isCategorized()) {
+        if ($$.isTimeSeries()) {
+            firstX = new Date(firstX.getTime() * 0.5);
+            lastX = new Date(lastX.getTime() * 1.5);
+        } else {
+            firstX = firstX === 0 ? 1 : (firstX * 0.5);
+            lastX = lastX === 0 ? -1 : (lastX * 1.5);
+        }
+    }
+    if (firstX || firstX === 0) {
+        min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
+    }
+    if (lastX || lastX === 0) {
+        max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
+    }
+    return [min, max];
+};
+c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
+    var $$ = this, config = $$.config;
+
+    if (withUpdateOrgXDomain) {
+        $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
+        $$.orgXDomain = $$.x.domain();
+        if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
+        $$.subX.domain($$.x.domain());
+        if ($$.brush) { $$.brush.scale($$.subX); }
+    }
+    if (withUpdateXDomain) {
+        $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent());
+        if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
+    }
+
+    // Trim domain when too big by zoom mousemove event
+    if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); }
+
+    return $$.x.domain();
+};
+c3_chart_internal_fn.trimXDomain = function (domain) {
+    var $$ = this;
+    if (domain[0] <= $$.orgXDomain[0]) {
+        domain[1] = +domain[1] + ($$.orgXDomain[0] - domain[0]);
+        domain[0] = $$.orgXDomain[0];
+    }
+    if ($$.orgXDomain[1] <= domain[1]) {
+        domain[0] = +domain[0] - (domain[1] - $$.orgXDomain[1]);
+        domain[1] = $$.orgXDomain[1];
+    }
+    return domain;
+};
diff --git a/src/drag.js b/src/drag.js
new file mode 100644
index 0000000..6d0a877
--- /dev/null
+++ b/src/drag.js
@@ -0,0 +1,84 @@
+c3_chart_internal_fn.drag = function (mouse) {
+    var $$ = this, config = $$.config, main = $$.main, d3 = $$.d3;
+    var sx, sy, mx, my, minX, maxX, minY, maxY;
+
+    if ($$.hasArcType()) { return; }
+    if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+    if (config.zoom_enabled && ! $$.zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior
+    if (!config.data_selection_multiple) { return; } // skip when single selection because drag is used for multiple selection
+
+    sx = $$.dragStart[0];
+    sy = $$.dragStart[1];
+    mx = mouse[0];
+    my = mouse[1];
+    minX = Math.min(sx, mx);
+    maxX = Math.max(sx, mx);
+    minY = (config.data_selection_grouped) ? $$.margin.top : Math.min(sy, my);
+    maxY = (config.data_selection_grouped) ? $$.height : Math.max(sy, my);
+
+    main.select('.' + CLASS.dragarea)
+        .attr('x', minX)
+        .attr('y', minY)
+        .attr('width', maxX - minX)
+        .attr('height', maxY - minY);
+    // TODO: binary search when multiple xs
+    main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape)
+        .filter(function (d) { return config.data_selection_isselectable(d); })
+        .each(function (d, i) {
+            var shape = d3.select(this),
+                isSelected = shape.classed(CLASS.SELECTED),
+                isIncluded = shape.classed(CLASS.INCLUDED),
+                _x, _y, _w, _h, toggle, isWithin = false, box;
+            if (shape.classed(CLASS.circle)) {
+                _x = shape.attr("cx") * 1;
+                _y = shape.attr("cy") * 1;
+                toggle = $$.togglePoint;
+                isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
+            }
+            else if (shape.classed(CLASS.bar)) {
+                box = getPathBox(this);
+                _x = box.x;
+                _y = box.y;
+                _w = box.width;
+                _h = box.height;
+                toggle = $$.togglePath;
+                isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
+            } else {
+                // line/area selection not supported yet
+                return;
+            }
+            if (isWithin ^ isIncluded) {
+                shape.classed(CLASS.INCLUDED, !isIncluded);
+                // TODO: included/unincluded callback here
+                shape.classed(CLASS.SELECTED, !isSelected);
+                toggle.call($$, !isSelected, shape, d, i);
+            }
+        });
+};
+
+c3_chart_internal_fn.dragstart = function (mouse) {
+    var $$ = this, config = $$.config;
+    if ($$.hasArcType()) { return; }
+    if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+    $$.dragStart = mouse;
+    $$.main.select('.' + CLASS.chart).append('rect')
+        .attr('class', CLASS.dragarea)
+        .style('opacity', 0.1);
+    $$.dragging = true;
+    $$.config.data_ondragstart.call($$.api);
+};
+
+c3_chart_internal_fn.dragend = function () {
+    var $$ = this, config = $$.config;
+    if ($$.hasArcType()) { return; }
+    if (! config.data_selection_enabled) { return; } // do nothing if not selectable
+    $$.main.select('.' + CLASS.dragarea)
+        .transition().duration(100)
+        .style('opacity', 0)
+        .remove();
+    $$.main.selectAll('.' + CLASS.shape)
+        .classed(CLASS.INCLUDED, false);
+    $$.dragging = false;
+    $$.config.data_ondragend.call($$.api);
+};
+
diff --git a/src/format.js b/src/format.js
new file mode 100644
index 0000000..3cb8530
--- /dev/null
+++ b/src/format.js
@@ -0,0 +1,38 @@
+c3_chart_internal_fn.getYFormat = function (forArc) {
+    var $$ = this,
+        formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
+        formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
+    return function (v, ratio, id) {
+        var format = $$.getAxisId(id) === 'y2' ? formatForY2 : formatForY;
+        return format.call($$, v, ratio);
+    };
+};
+c3_chart_internal_fn.yFormat = function (v) {
+    var $$ = this, config = $$.config,
+        format = config.axis_y_tick_format ? config.axis_y_tick_format : $$.defaultValueFormat;
+    return format(v);
+};
+c3_chart_internal_fn.y2Format = function (v) {
+    var $$ = this, config = $$.config,
+        format = config.axis_y2_tick_format ? config.axis_y2_tick_format : $$.defaultValueFormat;
+    return format(v);
+};
+c3_chart_internal_fn.defaultValueFormat = function (v) {
+    return isValue(v) ? +v : "";
+};
+c3_chart_internal_fn.defaultArcValueFormat = function (v, ratio) {
+    return (ratio * 100).toFixed(1) + '%';
+};
+c3_chart_internal_fn.formatByAxisId = function (axisId) {
+    var $$ = this, data_labels = $$.config.data_labels,
+        format = function (v) { return isValue(v) ? +v : ""; };
+    // find format according to axis id
+    if (typeof data_labels.format === 'function') {
+        format = data_labels.format;
+    } else if (typeof data_labels.format === 'object') {
+        if (data_labels.format[axisId]) {
+            format = data_labels.format[axisId];
+        }
+    }
+    return format;
+};
diff --git a/src/grid.js b/src/grid.js
new file mode 100644
index 0000000..0465c04
--- /dev/null
+++ b/src/grid.js
@@ -0,0 +1,225 @@
+c3_chart_internal_fn.initGrid = function () {
+    var $$ = this, config = $$.config, d3 = $$.d3;
+    $$.grid = $$.main.append('g')
+        .attr("clip-path", $$.clipPathForGrid)
+        .attr('class', CLASS.grid);
+    if (config.grid_x_show) {
+        $$.grid.append("g").attr("class", CLASS.xgrids);
+    }
+    if (config.grid_y_show) {
+        $$.grid.append('g').attr('class', CLASS.ygrids);
+    }
+    if (config.grid_focus_show) {
+        $$.grid.append('g')
+            .attr("class", CLASS.xgridFocus)
+            .append('line')
+            .attr('class', CLASS.xgridFocus);
+    }
+    $$.xgrid = d3.selectAll([]);
+    if (!config.grid_lines_front) { $$.initGridLines(); }
+};
+c3_chart_internal_fn.initGridLines = function () {
+    var $$ = this, d3 = $$.d3;
+    $$.gridLines = $$.main.append('g')
+        .attr("clip-path", $$.clipPathForGrid)
+        .attr('class', CLASS.grid + ' ' + CLASS.gridLines);
+    $$.gridLines.append('g').attr("class", CLASS.xgridLines);
+    $$.gridLines.append('g').attr('class', CLASS.ygridLines);
+    $$.xgridLines = d3.selectAll([]);
+};
+c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
+    var $$ = this, config = $$.config, d3 = $$.d3,
+        xgridData = $$.generateGridData(config.grid_x_type, $$.x),
+        tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0;
+
+    $$.xgridAttr = config.axis_rotated ? {
+        'x1': 0,
+        'x2': $$.width,
+        'y1': function (d) { return $$.x(d) - tickOffset; },
+        'y2': function (d) { return $$.x(d) - tickOffset; }
+    } : {
+        'x1': function (d) { return $$.x(d) + tickOffset; },
+        'x2': function (d) { return $$.x(d) + tickOffset; },
+        'y1': 0,
+        'y2': $$.height
+    };
+
+    $$.xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid)
+        .data(xgridData);
+    $$.xgrid.enter().append('line').attr("class", CLASS.xgrid);
+    if (!withoutUpdate) {
+        $$.xgrid.attr($$.xgridAttr)
+            .style("opacity", function () { return +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1') === (config.axis_rotated ? $$.height : 0) ? 0 : 1; });
+    }
+    $$.xgrid.exit().remove();
+};
+
+c3_chart_internal_fn.updateYGrid = function () {
+    var $$ = this, config = $$.config,
+        gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
+    $$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
+        .data(gridValues);
+    $$.ygrid.enter().append('line')
+        .attr('class', CLASS.ygrid);
+    $$.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);
+    $$.ygrid.exit().remove();
+    $$.smoothLines($$.ygrid, 'grid');
+};
+
+
+c3_chart_internal_fn.redrawGrid = function (duration) {
+    var $$ = this, main = $$.main, config = $$.config,
+        xgridLine, ygridLine, yv;
+
+    // hide if arc type
+    $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+    main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+    if (config.grid_x_show) {
+        $$.updateXGrid();
+    }
+    $$.xgridLines = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine)
+        .data(config.grid_x_lines);
+    // enter
+    xgridLine = $$.xgridLines.enter().append('g')
+        .attr("class", function (d) { return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : ''); });
+    xgridLine.append('line')
+        .style("opacity", 0);
+    xgridLine.append('text')
+        .attr("text-anchor", "end")
+        .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
+        .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+        .attr('dy', -5)
+        .style("opacity", 0);
+    // udpate
+    // done in d3.transition() of the end of this function
+    // exit
+    $$.xgridLines.exit().transition().duration(duration)
+        .style("opacity", 0)
+        .remove();
+
+    // Y-Grid
+    if (config.grid_y_show) {
+        $$.updateYGrid();
+    }
+    $$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
+        .data(config.grid_y_lines);
+    // enter
+    ygridLine = $$.ygridLines.enter().append('g')
+        .attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
+    ygridLine.append('line')
+        .style("opacity", 0);
+    ygridLine.append('text')
+        .attr("text-anchor", "end")
+        .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
+        .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
+        .attr('dy', -5)
+        .style("opacity", 0);
+    // update
+    yv = $$.yv.bind($$);
+    $$.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);
+    $$.ygridLines.select('text')
+      .transition().duration(duration)
+        .attr("x", config.axis_rotated ? 0 : $$.width)
+        .attr("y", yv)
+        .text(function (d) { return d.text; })
+        .style("opacity", 1);
+    // exit
+    $$.ygridLines.exit().transition().duration(duration)
+        .style("opacity", 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForGrid = function (transitions) {
+    var $$ = this, config = $$.config, xv = $$.xv.bind($$);
+    transitions.push($$.xgridLines.select('line').transition()
+                     .attr("x1", config.axis_rotated ? 0 : xv)
+                     .attr("x2", config.axis_rotated ? $$.width : xv)
+                     .attr("y1", config.axis_rotated ? xv : $$.margin.top)
+                     .attr("y2", config.axis_rotated ? xv : $$.height)
+                     .style("opacity", 1));
+    transitions.push($$.xgridLines.select('text').transition()
+                     .attr("x", config.axis_rotated ? $$.width : 0)
+                     .attr("y", xv)
+                     .text(function (d) { return d.text; })
+                     .style("opacity", 1));
+};
+c3_chart_internal_fn.showXGridFocus = function (selectedData) {
+    var $$ = this, config = $$.config,
+        dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
+        focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
+        xx = $$.xx.bind($$);
+    if (! config.tooltip_show) { return; }
+    // Hide when scatter plot exists
+    if ($$.hasType('scatter') || $$.hasArcType()) { return; }
+    focusEl
+        .style("visibility", "visible")
+        .data([dataToShow[0]])
+        .attr(config.axis_rotated ? 'y1' : 'x1', xx)
+        .attr(config.axis_rotated ? 'y2' : 'x2', xx);
+    $$.smoothLines(focusEl, 'grid');
+};
+c3_chart_internal_fn.hideXGridFocus = function () {
+    this.main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
+};
+c3_chart_internal_fn.updateXgridFocus = function () {
+    var $$ = this, config = $$.config;
+    $$.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);
+};
+c3_chart_internal_fn.generateGridData = function (type, scale) {
+    var $$ = this,
+        gridData = [], xDomain, firstYear, lastYear, i,
+        tickNum = $$.main.select("." + CLASS.axisX).selectAll('.tick').size();
+    if (type === 'year') {
+        xDomain = $$.getXDomain();
+        firstYear = xDomain[0].getFullYear();
+        lastYear = xDomain[1].getFullYear();
+        for (i = firstYear; i <= lastYear; i++) {
+            gridData.push(new Date(i + '-01-01 00:00:00'));
+        }
+    } else {
+        gridData = scale.ticks(10);
+        if (gridData.length > tickNum) { // use only int
+            gridData = gridData.filter(function (d) { return ("" + d).indexOf('.') < 0; });
+        }
+    }
+    return gridData;
+};
+c3_chart_internal_fn.getGridFilterToRemove = function (params) {
+    return params ? function (line) {
+        var found = false;
+        [].concat(params).forEach(function (param) {
+            if ((('value' in param && line.value === param.value) || ('class' in param && line['class'] === param['class']))) {
+                found = true;
+            }
+        });
+        return found;
+    } : function () { return true; };
+};
+c3_chart_internal_fn.removeGridLines = function (params, forX) {
+    var $$ = this, config = $$.config,
+        toRemove = $$.getGridFilterToRemove(params),
+        toShow = function (line) { return !toRemove(line); },
+        classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
+        classLine = forX ? CLASS.xgridLine : CLASS.ygridLine;
+    $$.main.select('.' + classLines).selectAll('.' + classLine).filter(toRemove)
+        .transition().duration(config.transition_duration)
+        .style('opacity', 0).remove();
+    if (forX) {
+        config.grid_x_lines = config.grid_x_lines.filter(toShow);
+    } else {
+        config.grid_y_lines = config.grid_y_lines.filter(toShow);
+    }
+};
diff --git a/src/head.js b/src/head.js
new file mode 100644
index 0000000..d77cbd0
--- /dev/null
+++ b/src/head.js
@@ -0,0 +1,4 @@
+(function (window) {
+    'use strict';
+
+    /*global define, module, exports, require */
diff --git a/src/interaction.js b/src/interaction.js
new file mode 100644
index 0000000..0b9039c
--- /dev/null
+++ b/src/interaction.js
@@ -0,0 +1,352 @@
+c3_chart_internal_fn.initEventRect = function () {
+    var $$ = this;
+    $$.main.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.eventRects)
+        .style('fill-opacity', 0);
+};
+c3_chart_internal_fn.redrawEventRect = function () {
+    var $$ = this, config = $$.config,
+        eventRectUpdate, maxDataCountTarget,
+        isMultipleX = $$.isMultipleX();
+
+    // rects for mouseover
+    var eventRects = $$.main.select('.' + CLASS.eventRects)
+            .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null)
+            .classed(CLASS.eventRectsMultiple, isMultipleX)
+            .classed(CLASS.eventRectsSingle, !isMultipleX);
+
+    // clear old rects
+    eventRects.selectAll('.' + CLASS.eventRect).remove();
+
+    // open as public variable
+    $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+
+    if (isMultipleX) {
+        eventRectUpdate = $$.eventRect.data([0]);
+        // enter : only one rect will be added
+        $$.generateEventRectsForMultipleXs(eventRectUpdate.enter());
+        // update
+        $$.updateEventRect(eventRectUpdate);
+        // exit : not needed because always only one rect exists
+    }
+    else {
+        // Set data and update $$.eventRect
+        maxDataCountTarget = $$.getMaxDataCountTarget($$.data.targets);
+        eventRects.datum(maxDataCountTarget ? maxDataCountTarget.values : []);
+        $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
+        eventRectUpdate = $$.eventRect.data(function (d) { return d; });
+        // enter
+        $$.generateEventRectsForSingleX(eventRectUpdate.enter());
+        // update
+        $$.updateEventRect(eventRectUpdate);
+        // exit
+        eventRectUpdate.exit().remove();
+    }
+};
+c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
+    var $$ = this, config = $$.config,
+        x, y, w, h, rectW, rectX;
+
+    // set update selection if null
+    eventRectUpdate = eventRectUpdate || $$.eventRect.data(function (d) { return d; });
+
+    if ($$.isMultipleX()) {
+        // TODO: rotated not supported yet
+        x = 0;
+        y = 0;
+        w = $$.width;
+        h = $$.height;
+    }
+    else {
+        if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
+
+            // update index for x that is used by prevX and nextX
+            $$.updateXs();
+
+            rectW = function (d) {
+                var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
+
+                // if there this is a single data point make the eventRect full width (or height)
+                if (prevX === null && nextX === null) {
+                    return config.axis_rotated ? $$.height : $$.width;
+                }
+
+                if (prevX === null) { prevX = $$.x.domain()[0]; }
+                if (nextX === null) { nextX = $$.x.domain()[1]; }
+
+                return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
+            };
+            rectX = function (d) {
+                var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
+                    thisX = $$.data.xs[d.id][d.index];
+
+                // if there this is a single data point position the eventRect at 0
+                if (prevX === null && nextX === null) {
+                    return 0;
+                }
+
+                if (prevX === null) { prevX = $$.x.domain()[0]; }
+
+                return ($$.x(thisX) + $$.x(prevX)) / 2;
+            };
+        } else {
+            rectW = $$.getEventRectWidth();
+            rectX = function (d) {
+                return $$.x(d.x) - (rectW / 2);
+            };
+        }
+        x = config.axis_rotated ? 0 : rectX;
+        y = config.axis_rotated ? rectX : 0;
+        w = config.axis_rotated ? $$.width : rectW;
+        h = config.axis_rotated ? rectW : $$.height;
+    }
+
+    eventRectUpdate
+        .attr('class', $$.classEvent.bind($$))
+        .attr("x", x)
+        .attr("y", y)
+        .attr("width", w)
+        .attr("height", h);
+};
+c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) {
+    var $$ = this, d3 = $$.d3, config = $$.config;
+    eventRectEnter.append("rect")
+        .attr("class", $$.classEvent.bind($$))
+        .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
+        .on('mouseover', function (d) {
+            var index = d.index, selectedData, newData;
+
+            if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+            if ($$.hasArcType()) { return; }
+
+            selectedData = $$.data.targets.map(function (t) {
+                return $$.addName($$.getValueOnIndex(t.values, index));
+            });
+
+            // Sort selectedData as names order
+            newData = [];
+            Object.keys(config.data_names).forEach(function (id) {
+                for (var j = 0; j < selectedData.length; j++) {
+                    if (selectedData[j] && selectedData[j].id === id) {
+                        newData.push(selectedData[j]);
+                        selectedData.shift(j);
+                        break;
+                    }
+                }
+            });
+            selectedData = newData.concat(selectedData); // Add remained
+
+            // Expand shapes for selection
+            if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
+            $$.expandBars(index, null, true);
+
+            // Call event handler
+            $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                config.data_onmouseover.call($$.api, d);
+            });
+        })
+        .on('mouseout', function (d) {
+            var index = d.index;
+            if ($$.hasArcType()) { return; }
+            $$.hideXGridFocus();
+            $$.hideTooltip();
+            // Undo expanded shapes
+            $$.unexpandCircles();
+            $$.unexpandBars();
+            // Call event handler
+            $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                config.data_onmouseout.call($$.api, d);
+            });
+        })
+        .on('mousemove', function (d) {
+            var selectedData, index = d.index,
+                eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
+
+            if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
+            if ($$.hasArcType()) { return; }
+
+            if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                index -= 1;
+            }
+
+            // Show tooltip
+            selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
+                return $$.addName($$.getValueOnIndex(t.values, index));
+            });
+
+            if (config.tooltip_grouped) {
+                $$.showTooltip(selectedData, d3.mouse(this));
+                $$.showXGridFocus(selectedData);
+            }
+
+            if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) {
+                return;
+            }
+
+            $$.main.selectAll('.' + CLASS.shape + '-' + index)
+                .each(function () {
+                    d3.select(this).classed(CLASS.EXPANDED, true);
+                    if (config.data_selection_enabled) {
+                        eventRect.style('cursor', config.data_selection_grouped ? 'pointer' : null);
+                    }
+                    if (!config.tooltip_grouped) {
+                        $$.hideXGridFocus();
+                        $$.hideTooltip();
+                        if (!config.data_selection_grouped) {
+                            $$.unexpandCircles(index);
+                            $$.unexpandBars(index);
+                        }
+                    }
+                })
+                .filter(function (d) {
+                    return $$.isWithinShape(this, d);
+                })
+                .each(function (d) {
+                    if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
+                        eventRect.style('cursor', 'pointer');
+                    }
+                    if (!config.tooltip_grouped) {
+                        $$.showTooltip([d], d3.mouse(this));
+                        $$.showXGridFocus([d]);
+                        if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
+                        $$.expandBars(index, d.id, true);
+                    }
+                });
+        })
+        .on('click', function (d) {
+            var index = d.index;
+            if ($$.hasArcType() || !$$.toggleShape) { return; }
+            if ($$.cancelClick) {
+                $$.cancelClick = false;
+                return;
+            }
+            if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
+                index -= 1;
+            }
+            $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
+                if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
+                    $$.toggleShape(this, d, index);
+                    $$.config.data_onclick.call($$.api, d, this);
+                }
+            });
+        })
+        .call(
+            d3.behavior.drag().origin(Object)
+                .on('drag', function () { $$.drag(d3.mouse(this)); })
+                .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                .on('dragend', function () { $$.dragend(); })
+        );
+};
+
+c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
+    var $$ = this, d3 = $$.d3, config = $$.config;
+
+    function mouseout() {
+        $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
+        $$.hideXGridFocus();
+        $$.hideTooltip();
+        $$.unexpandCircles();
+        $$.unexpandBars();
+    }
+
+    eventRectEnter.append('rect')
+        .attr('x', 0)
+        .attr('y', 0)
+        .attr('width', $$.width)
+        .attr('height', $$.height)
+        .attr('class', CLASS.eventRect)
+        .on('mouseout', function () {
+            if ($$.hasArcType()) { return; }
+            mouseout();
+        })
+        .on('mousemove', function () {
+            var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+            var mouse, closest, sameXData, selectedData;
+
+            if ($$.dragging) { return; } // do nothing when dragging
+            if ($$.hasArcType(targetsToShow)) { return; }
+
+            mouse = d3.mouse(this);
+            closest = $$.findClosestFromTargets(targetsToShow, mouse);
+
+            if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
+                config.data_onmouseout.call($$.api, $$.mouseover);
+                $$.mouseover = undefined;
+            }
+
+            if (! closest) {
+                mouseout();
+                return;
+            }
+
+            if ($$.isScatterType(closest) || !config.tooltip_grouped) {
+                sameXData = [closest];
+            } else {
+                sameXData = $$.filterByX(targetsToShow, closest.x);
+            }
+
+            // show tooltip when cursor is close to some point
+            selectedData = sameXData.map(function (d) {
+                return $$.addName(d);
+            });
+            $$.showTooltip(selectedData, mouse);
+
+            // expand points
+            if (config.point_focus_expand_enabled) {
+                $$.expandCircles(closest.index, closest.id, true);
+            }
+            $$.expandBars(closest.index, closest.id, true);
+
+            // Show xgrid focus line
+            $$.showXGridFocus(selectedData);
+
+            // Show cursor as pointer if point is close to mouse position
+            if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
+                if (!$$.mouseover) {
+                    config.data_onmouseover.call($$.api, closest);
+                    $$.mouseover = closest;
+                }
+            }
+        })
+        .on('click', function () {
+            var targetsToShow = $$.filterTargetsToShow($$.data.targets);
+            var mouse, closest;
+
+            if ($$.hasArcType(targetsToShow)) { return; }
+
+            mouse = d3.mouse(this);
+            closest = $$.findClosestFromTargets(targetsToShow, mouse);
+
+            if (! closest) { return; }
+
+            // select if selection enabled
+            if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
+                $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
+                    if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
+                        $$.toggleShape(this, closest, closest.index);
+                        $$.config.data_onclick.call($$.api, closest, this);
+                    }
+                });
+            }
+        })
+        .call(
+            d3.behavior.drag().origin(Object)
+                .on('drag', function () { $$.drag(d3.mouse(this)); })
+                .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
+                .on('dragend', function () { $$.dragend(); })
+        );
+};
+c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
+    var $$ = this,
+        selector = '.' + CLASS.eventRect + (!$$.isMultipleX() ? '-' + index : ''),
+        eventRect = $$.main.select(selector).node(),
+        box = eventRect.getBoundingClientRect(),
+        x = box.left + (mouse ? mouse[0] : 0),
+        y = box.top + (mouse ? mouse[1] : 0),
+        event = document.createEvent("MouseEvents");
+
+    event.initMouseEvent(type, true, true, window, 0, x, y, x, y,
+                         false, false, false, false, 0, null);
+    eventRect.dispatchEvent(event);
+};
diff --git a/src/legend.js b/src/legend.js
new file mode 100644
index 0000000..0fc1006
--- /dev/null
+++ b/src/legend.js
@@ -0,0 +1,332 @@
+c3_chart_internal_fn.initLegend = function () {
+    var $$ = this;
+    $$.legendHasRendered = false;
+    $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
+    if (!$$.config.legend_show) {
+        $$.legend.style('visibility', 'hidden');
+        $$.hiddenLegendIds = $$.mapToIds($$.data.targets);
+        return;
+    }
+    // MEMO: call here to update legend box and tranlate for all
+    // MEMO: translate will be upated by this, so transform not needed in updateLegend()
+    $$.updateLegendWithDefaults();
+};
+c3_chart_internal_fn.updateLegendWithDefaults = function () {
+    var $$ = this;
+    $$.updateLegend($$.mapToIds($$.data.targets), {withTransform: false, withTransitionForTransform: false, withTransition: false});
+};
+c3_chart_internal_fn.updateSizeForLegend = function (legendHeight, legendWidth) {
+    var $$ = this, config = $$.config, insetLegendPosition = {
+        top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
+        left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
+    };
+
+    $$.margin3 = {
+        top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
+        right: NaN,
+        bottom: 0,
+        left: $$.isLegendRight ? $$.currentWidth - legendWidth : $$.isLegendInset ? insetLegendPosition.left : 0
+    };
+};
+c3_chart_internal_fn.transformLegend = function (withTransition) {
+    var $$ = this;
+    (withTransition ? $$.legend.transition() : $$.legend).attr("transform", $$.getTranslate('legend'));
+};
+c3_chart_internal_fn.updateLegendStep = function (step) {
+    this.legendStep = step;
+};
+c3_chart_internal_fn.updateLegendItemWidth = function (w) {
+    this.legendItemWidth = w;
+};
+c3_chart_internal_fn.updateLegendItemHeight = function (h) {
+    this.legendItemHeight = h;
+};
+c3_chart_internal_fn.getLegendWidth = function () {
+    var $$ = this;
+    return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
+};
+c3_chart_internal_fn.getLegendHeight = function () {
+    var $$ = this, h = 0;
+    if ($$.config.legend_show) {
+        if ($$.isLegendRight) {
+            h = $$.currentHeight;
+        } else {
+            h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
+        }
+    }
+    return h;
+};
+c3_chart_internal_fn.opacityForLegend = function (legendItem) {
+    return legendItem.classed(CLASS.legendItemHidden) ? null : 1;
+};
+c3_chart_internal_fn.opacityForUnfocusedLegend = function (legendItem) {
+    return legendItem.classed(CLASS.legendItemHidden) ? null : 0.3;
+};
+c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
+    var $$ = this;
+    targetIds = $$.mapToTargetIds(targetIds);
+    $$.legend.selectAll('.' + CLASS.legendItem)
+        .filter(function (id) { return targetIds.indexOf(id) >= 0; })
+        .classed(CLASS.legendItemFocused, focus)
+      .transition().duration(100)
+        .style('opacity', function () {
+            var opacity = focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
+            return opacity.call($$, $$.d3.select(this));
+        });
+};
+c3_chart_internal_fn.revertLegend = function () {
+    var $$ = this, d3 = $$.d3;
+    $$.legend.selectAll('.' + CLASS.legendItem)
+        .classed(CLASS.legendItemFocused, false)
+        .transition().duration(100)
+        .style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
+};
+c3_chart_internal_fn.showLegend = function (targetIds) {
+    var $$ = this, config = $$.config;
+    if (!config.legend_show) {
+        config.legend_show = true;
+        $$.legend.style('visibility', 'visible');
+        if (!$$.legendHasRendered) {
+            $$.updateLegendWithDefaults();
+        }
+    }
+    $$.removeHiddenLegendIds(targetIds);
+    $$.legend.selectAll($$.selectorLegends(targetIds))
+        .style('visibility', 'visible')
+        .transition()
+        .style('opacity', function () { return $$.opacityForLegend($$.d3.select(this)); });
+};
+c3_chart_internal_fn.hideLegend = function (targetIds) {
+    var $$ = this, config = $$.config;
+    if (config.legend_show && isEmpty(targetIds)) {
+        config.legend_show = false;
+        $$.legend.style('visibility', 'hidden');
+    }
+    $$.addHiddenLegendIds(targetIds);
+    $$.legend.selectAll($$.selectorLegends(targetIds))
+        .style('opacity', 0)
+        .style('visibility', 'hidden');
+};
+var legendItemTextBox = {};
+c3_chart_internal_fn.clearLegendItemTextBoxCache = function () {
+    legendItemTextBox = {};
+};
+c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
+    var $$ = this, config = $$.config;
+    var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
+    var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
+    var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
+    var withTransition, withTransitionForTransform;
+    var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
+    var texts, rects, tiles, background;
+
+    options = options || {};
+    withTransition = getOption(options, "withTransition", true);
+    withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
+
+    function getTextBox(textElement, id) {
+        if (!legendItemTextBox[id]) {
+            legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
+        }
+        return legendItemTextBox[id];
+    }
+
+    function updatePositions(textElement, id, index) {
+        var reset = index === 0, isLast = index === targetIds.length - 1,
+            box = getTextBox(textElement, id),
+            itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
+            itemHeight = box.height + paddingTop,
+            itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
+            areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
+            margin, maxLength;
+
+        // MEMO: care about condifion of step, totalLength
+        function updateValues(id, withoutStep) {
+            if (!withoutStep) {
+                margin = (areaLength - totalLength - itemLength) / 2;
+                if (margin < posMin) {
+                    margin = (areaLength - itemLength) / 2;
+                    totalLength = 0;
+                    step++;
+                }
+            }
+            steps[id] = step;
+            margins[step] = $$.isLegendInset ? 10 : margin;
+            offsets[id] = totalLength;
+            totalLength += itemLength;
+        }
+
+        if (reset) {
+            totalLength = 0;
+            step = 0;
+            maxWidth = 0;
+            maxHeight = 0;
+        }
+
+        if (config.legend_show && !$$.isLegendToShow(id)) {
+            widths[id] = heights[id] = steps[id] = offsets[id] = 0;
+            return;
+        }
+
+        widths[id] = itemWidth;
+        heights[id] = itemHeight;
+
+        if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; }
+        if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; }
+        maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth;
+
+        if (config.legend_equally) {
+            Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; });
+            Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; });
+            margin = (areaLength - maxLength * targetIds.length) / 2;
+            if (margin < posMin) {
+                totalLength = 0;
+                step = 0;
+                targetIds.forEach(function (id) { updateValues(id); });
+            }
+            else {
+                updateValues(id, true);
+            }
+        } else {
+            updateValues(id);
+        }
+    }
+
+    if ($$.isLegendInset) {
+        step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
+        $$.updateLegendStep(step);
+    }
+
+    if ($$.isLegendRight) {
+        xForLegend = function (id) { return maxWidth * steps[id]; };
+        yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+    } else if ($$.isLegendInset) {
+        xForLegend = function (id) { return maxWidth * steps[id] + 10; };
+        yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+    } else {
+        xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
+        yForLegend = function (id) { return maxHeight * steps[id]; };
+    }
+    xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
+    yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
+    xForLegendRect = function (id, i) { return xForLegend(id, i); };
+    yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
+
+    // Define g for legend area
+    l = $$.legend.selectAll('.' + CLASS.legendItem)
+        .data(targetIds)
+        .enter().append('g')
+        .attr('class', function (id) { return $$.generateClass(CLASS.legendItem, id); })
+        .style('visibility', function (id) { return $$.isLegendToShow(id) ? 'visible' : 'hidden'; })
+        .style('cursor', 'pointer')
+        .on('click', function (id) {
+            if (config.legend_item_onclick) {
+                config.legend_item_onclick.call($$, id);
+            } else {
+                if ($$.d3.event.altKey) {
+                    $$.api.hide();
+                    $$.api.show(id);
+                } else {
+                    $$.api.toggle(id);
+                    $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
+                }
+            }
+        })
+        .on('mouseover', function (id) {
+            $$.d3.select(this).classed(CLASS.legendItemFocused, true);
+            if (!$$.transiting && $$.isTargetToShow(id)) {
+                $$.api.focus(id);
+            }
+            if (config.legend_item_onmouseover) {
+                config.legend_item_onmouseover.call($$, id);
+            }
+        })
+        .on('mouseout', function (id) {
+            $$.d3.select(this).classed(CLASS.legendItemFocused, false);
+            $$.api.revert();
+            if (config.legend_item_onmouseout) {
+                config.legend_item_onmouseout.call($$, id);
+            }
+        });
+    l.append('text')
+        .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
+        .each(function (id, i) { updatePositions(this, id, i); })
+        .style("pointer-events", "none")
+        .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+        .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
+    l.append('rect')
+        .attr("class", CLASS.legendItemEvent)
+        .style('fill-opacity', 0)
+        .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200)
+        .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
+    l.append('rect')
+        .attr("class", CLASS.legendItemTile)
+        .style("pointer-events", "none")
+        .style('fill', $$.color)
+        .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
+        .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
+        .attr('width', 10)
+        .attr('height', 10);
+
+    // Set background for inset legend
+    background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
+    if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
+        background = $$.legend.insert('g', '.' + CLASS.legendItem)
+            .attr("class", CLASS.legendBackground)
+            .append('rect');
+    }
+
+    texts = $$.legend.selectAll('text')
+        .data(targetIds)
+        .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update
+        .each(function (id, i) { updatePositions(this, id, i); });
+    (withTransition ? texts.transition() : texts)
+        .attr('x', xForLegendText)
+        .attr('y', yForLegendText);
+
+    rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent)
+        .data(targetIds);
+    (withTransition ? rects.transition() : rects)
+        .attr('width', function (id) { return widths[id]; })
+        .attr('height', function (id) { return heights[id]; })
+        .attr('x', xForLegendRect)
+        .attr('y', yForLegendRect);
+
+    tiles = $$.legend.selectAll('rect.' + CLASS.legendItemTile)
+        .data(targetIds);
+    (withTransition ? tiles.transition() : tiles)
+        .style('fill', $$.color)
+        .attr('x', xForLegend)
+        .attr('y', yForLegend);
+
+    if (background) {
+        (withTransition ? background.transition() : background)
+            .attr('height', $$.getLegendHeight() - 12)
+            .attr('width', maxWidth * (step + 1) + 10);
+    }
+
+    // toggle legend state
+    $$.legend.selectAll('.' + CLASS.legendItem)
+        .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
+        .transition()
+        .style('opacity', function (id) {
+            var This = $$.d3.select(this);
+            if ($$.isTargetToShow(id)) {
+                return !hasFocused || This.classed(CLASS.legendItemFocused) ? $$.opacityForLegend(This) : $$.opacityForUnfocusedLegend(This);
+            } else {
+                return null; // c3-legend-item-hidden will be applied
+            }
+        });
+
+    // Update all to reflect change of legend
+    $$.updateLegendItemWidth(maxWidth);
+    $$.updateLegendItemHeight(maxHeight);
+    $$.updateLegendStep(step);
+    // Update size and scale
+    $$.updateSizes();
+    $$.updateScales();
+    $$.updateSvgSize();
+    // Update g positions
+    $$.transformAll(withTransitionForTransform, transitions);
+    $$.legendHasRendered = true;
+};
diff --git a/src/region.js b/src/region.js
new file mode 100644
index 0000000..9cb70e6
--- /dev/null
+++ b/src/region.js
@@ -0,0 +1,78 @@
+c3_chart_internal_fn.initRegion = function () {
+    var $$ = this;
+    $$.region = $$.main.append('g')
+        .attr("clip-path", $$.clipPath)
+        .attr("class", CLASS.regions);
+};
+c3_chart_internal_fn.redrawRegion = function (duration) {
+    var $$ = this, config = $$.config;
+
+    // hide if arc type
+    $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
+
+    $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
+        .data(config.regions);
+    $$.mainRegion.enter().append('g')
+        .attr('class', $$.classRegion.bind($$))
+      .append('rect')
+        .style("fill-opacity", 0);
+    $$.mainRegion.exit().transition().duration(duration)
+        .style("opacity", 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForRegion = function (transitions) {
+    var $$ = this,
+        x = $$.regionX.bind($$),
+        y = $$.regionY.bind($$),
+        w = $$.regionWidth.bind($$),
+        h = $$.regionHeight.bind($$);
+    transitions.push($$.mainRegion.selectAll('rect').transition()
+                     .attr("x", x)
+                     .attr("y", y)
+                     .attr("width", w)
+                     .attr("height", h)
+                     .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; }));
+};
+c3_chart_internal_fn.regionX = function (d) {
+    var $$ = this, config = $$.config,
+        xPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+    if (d.axis === 'y' || d.axis === 'y2') {
+        xPos = config.axis_rotated ? ('start' in d ? yScale(d.start) : 0) : 0;
+    } else {
+        xPos = config.axis_rotated ? 0 : ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0);
+    }
+    return xPos;
+};
+c3_chart_internal_fn.regionY = function (d) {
+    var $$ = this, config = $$.config,
+        yPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
+    if (d.axis === 'y' || d.axis === 'y2') {
+        yPos = config.axis_rotated ? 0 : ('end' in d ? yScale(d.end) : 0);
+    } else {
+        yPos = config.axis_rotated ? ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0) : 0;
+    }
+    return yPos;
+};
+c3_chart_internal_fn.regionWidth = function (d) {
+    var $$ = this, config = $$.config,
+        start = $$.regionX(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+    if (d.axis === 'y' || d.axis === 'y2') {
+        end = config.axis_rotated ? ('end' in d ? yScale(d.end) : $$.width) : $$.width;
+    } else {
+        end = config.axis_rotated ? $$.width : ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.width);
+    }
+    return end < start ? 0 : end - start;
+};
+c3_chart_internal_fn.regionHeight = function (d) {
+    var $$ = this, config = $$.config,
+        start = this.regionY(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
+    if (d.axis === 'y' || d.axis === 'y2') {
+        end = config.axis_rotated ? $$.height : ('start' in d ? yScale(d.start) : $$.height);
+    } else {
+        end = config.axis_rotated ? ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.height) : $$.height;
+    }
+    return end < start ? 0 : end - start;
+};
+c3_chart_internal_fn.isRegionOnX = function (d) {
+    return !d.axis || d.axis === 'x';
+};
diff --git a/src/scale.js b/src/scale.js
new file mode 100644
index 0000000..ff4c433
--- /dev/null
+++ b/src/scale.js
@@ -0,0 +1,89 @@
+c3_chart_internal_fn.getScale = function (min, max, forTimeseries) {
+    return (forTimeseries ? this.d3.time.scale() : this.d3.scale.linear()).range([min, max]);
+};
+c3_chart_internal_fn.getX = function (min, max, domain, offset) {
+    var $$ = this,
+        scale = $$.getScale(min, max, $$.isTimeSeries()),
+        _scale = domain ? scale.domain(domain) : scale, key;
+    // Define customized scale if categorized axis
+    if ($$.isCategorized()) {
+        offset = offset || function () { return 0; };
+        scale = function (d, raw) {
+            var v = _scale(d) + offset(d);
+            return raw ? v : Math.ceil(v);
+        };
+    } else {
+        scale = function (d, raw) {
+            var v = _scale(d);
+            return raw ? v : Math.ceil(v);
+        };
+    }
+    // define functions
+    for (key in _scale) {
+        scale[key] = _scale[key];
+    }
+    scale.orgDomain = function () {
+        return _scale.domain();
+    };
+    // define custom domain() for categorized axis
+    if ($$.isCategorized()) {
+        scale.domain = function (domain) {
+            if (!arguments.length) {
+                domain = this.orgDomain();
+                return [domain[0], domain[1] + 1];
+            }
+            _scale.domain(domain);
+            return scale;
+        };
+    }
+    return scale;
+};
+c3_chart_internal_fn.getY = function (min, max, domain) {
+    var scale = this.getScale(min, max, this.isTimeSeriesY());
+    if (domain) { scale.domain(domain); }
+    return scale;
+};
+c3_chart_internal_fn.getYScale = function (id) {
+    return this.getAxisId(id) === 'y2' ? this.y2 : this.y;
+};
+c3_chart_internal_fn.getSubYScale = function (id) {
+    return this.getAxisId(id) === 'y2' ? this.subY2 : this.subY;
+};
+c3_chart_internal_fn.updateScales = function () {
+    var $$ = this, config = $$.config,
+        forInit = !$$.x;
+    // update edges
+    $$.xMin = config.axis_rotated ? 1 : 0;
+    $$.xMax = config.axis_rotated ? $$.height : $$.width;
+    $$.yMin = config.axis_rotated ? 0 : $$.height;
+    $$.yMax = config.axis_rotated ? $$.width : 1;
+    $$.subXMin = $$.xMin;
+    $$.subXMax = $$.xMax;
+    $$.subYMin = config.axis_rotated ? 0 : $$.height2;
+    $$.subYMax = config.axis_rotated ? $$.width2 : 1;
+    // update scales
+    $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () { return $$.xAxis.tickOffset(); });
+    $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
+    $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
+    $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) { return d % 1 ? 0 : $$.subXAxis.tickOffset(); });
+    $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
+    $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
+    // update axes
+    $$.xAxisTickFormat = $$.getXAxisTickFormat();
+    $$.xAxisTickValues = $$.getXAxisTickValues();
+    $$.yAxisTickValues = $$.getYAxisTickValues();
+    $$.y2AxisTickValues = $$.getY2AxisTickValues();
+
+    $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+    $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
+    $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
+    $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
+
+    // Set initialized scales to brush and zoom
+    if (!forInit) {
+        if ($$.brush) { $$.brush.scale($$.subX); }
+        if (config.zoom_enabled) { $$.zoom.scale($$.x); }
+    }
+    // update for arc
+    if ($$.updateArc) { $$.updateArc(); }
+};
diff --git a/src/selection.js b/src/selection.js
new file mode 100644
index 0000000..e9b4ada
--- /dev/null
+++ b/src/selection.js
@@ -0,0 +1,75 @@
+c3_chart_internal_fn.selectPoint = function (target, d, i) {
+    var $$ = this, config = $$.config,
+        cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
+        cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
+        r = $$.pointSelectR.bind($$);
+    config.data_onselected.call($$.api, d, target.node());
+    // add selected-circle on low layer g
+    $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+        .data([d])
+        .enter().append('circle')
+        .attr("class", function () { return $$.generateClass(CLASS.selectedCircle, i); })
+        .attr("cx", cx)
+        .attr("cy", cy)
+        .attr("stroke", function () { return $$.color(d); })
+        .attr("r", function (d) { return $$.pointSelectR(d) * 1.4; })
+        .transition().duration(100)
+        .attr("r", r);
+};
+c3_chart_internal_fn.unselectPoint = function (target, d, i) {
+    var $$ = this;
+    $$.config.data_onunselected(d, target.node());
+    // remove selected-circle from low layer g
+    $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
+        .transition().duration(100).attr('r', 0)
+        .remove();
+};
+c3_chart_internal_fn.togglePoint = function (selected, target, d, i) {
+    selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
+};
+c3_chart_internal_fn.selectPath = function (target, d) {
+    var $$ = this;
+    $$.config.data_onselected.call($$, d, target.node());
+    target.transition().duration(100)
+        .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
+};
+c3_chart_internal_fn.unselectPath = function (target, d) {
+    var $$ = this;
+    $$.config.data_onunselected.call($$, d, target.node());
+    target.transition().duration(100)
+        .style("fill", function () { return $$.color(d); });
+};
+c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
+    selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
+};
+c3_chart_internal_fn.getToggle = function (that, d) {
+    var $$ = this, toggle;
+    if (that.nodeName === 'circle') {
+        if ($$.isStepType(d)) {
+            // circle is hidden in step chart, so treat as within the click area
+            toggle = function () {}; // TODO: how to select step chart?
+        } else {
+            toggle = $$.togglePoint;
+        }
+    }
+    else if (that.nodeName === 'path') {
+        toggle = $$.togglePath;
+    }
+    return toggle;
+};
+c3_chart_internal_fn.toggleShape = function (that, d, i) {
+    var $$ = this, d3 = $$.d3, config = $$.config,
+        shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED),
+        toggle = $$.getToggle(that, d).bind($$);
+
+    if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
+        if (!config.data_selection_multiple) {
+            $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
+                var shape = d3.select(this);
+                if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
+            });
+        }
+        shape.classed(CLASS.SELECTED, !isSelected);
+        toggle(!isSelected, shape, d, i);
+    }
+};
diff --git a/src/shape.bar.js b/src/shape.bar.js
new file mode 100644
index 0000000..714ebb8
--- /dev/null
+++ b/src/shape.bar.js
@@ -0,0 +1,121 @@
+c3_chart_internal_fn.initBar = function () {
+    var $$ = this;
+    $$.main.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartBars);
+};
+c3_chart_internal_fn.updateTargetsForBar = function (targets) {
+    var $$ = this, config = $$.config,
+        mainBarUpdate, mainBarEnter,
+        classChartBar = $$.classChartBar.bind($$),
+        classBars = $$.classBars.bind($$),
+        classFocus = $$.classFocus.bind($$);
+    mainBarUpdate = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+        .data(targets)
+        .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
+    mainBarEnter = mainBarUpdate.enter().append('g')
+        .attr('class', classChartBar)
+        .style('opacity', 0)
+        .style("pointer-events", "none");
+    // Bars for each data
+    mainBarEnter.append('g')
+        .attr("class", classBars)
+        .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
+
+};
+c3_chart_internal_fn.redrawBar = function (durationForExit) {
+    var $$ = this,
+        barData = $$.barData.bind($$),
+        classBar = $$.classBar.bind($$),
+        initialOpacity = $$.initialOpacity.bind($$),
+        color = function (d) { return $$.color(d.id); };
+    $$.mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+        .data(barData);
+    $$.mainBar.enter().append('path')
+        .attr("class", classBar)
+        .style("stroke", color)
+        .style("fill", color);
+    $$.mainBar
+        .style("opacity", initialOpacity);
+    $$.mainBar.exit().transition().duration(durationForExit)
+        .style('opacity', 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForBar = function (transitions, drawBar) {
+    var $$ = this;
+    transitions.push($$.mainBar.transition()
+                     .attr('d', drawBar)
+                     .style("fill", $$.color)
+                     .style("opacity", 1));
+};
+c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
+    var $$ = this, config = $$.config,
+        w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
+    return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
+};
+c3_chart_internal_fn.getBars = function (i, id) {
+    var $$ = this;
+    return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
+};
+c3_chart_internal_fn.expandBars = function (i, id, reset) {
+    var $$ = this;
+    if (reset) { $$.unexpandBars(); }
+    $$.getBars(i, id).classed(CLASS.EXPANDED, true);
+};
+c3_chart_internal_fn.unexpandBars = function (i) {
+    var $$ = this;
+    $$.getBars(i).classed(CLASS.EXPANDED, false);
+};
+c3_chart_internal_fn.generateDrawBar = function (barIndices, isSub) {
+    var $$ = this, config = $$.config,
+        getPoints = $$.generateGetBarPoints(barIndices, isSub);
+    return function (d, i) {
+        // 4 points that make a bar
+        var points = getPoints(d, i);
+
+        // switch points if axis is rotated, not applicable for sub chart
+        var indexX = config.axis_rotated ? 1 : 0;
+        var indexY = config.axis_rotated ? 0 : 1;
+
+        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';
+
+        return path;
+    };
+};
+c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
+    var $$ = this,
+        axis = isSub ? $$.subXAxis : $$.xAxis,
+        barTargetsNum = barIndices.__max__ + 1,
+        barW = $$.getBarW(axis, barTargetsNum),
+        barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
+        barY = $$.getShapeY(!!isSub),
+        barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
+        yScale = isSub ? $$.getSubYScale : $$.getYScale;
+    return function (d, i) {
+        var y0 = yScale.call($$, d.id)(0),
+            offset = barOffset(d, i) || y0, // offset is for stacked bar chart
+            posX = barX(d), posY = barY(d);
+        // fix posY not to overflow opposite quadrant
+        if ($$.config.axis_rotated) {
+            if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+        }
+        // 4 points that make a bar
+        return [
+            [posX, offset],
+            [posX, posY - (y0 - offset)],
+            [posX + barW, posY - (y0 - offset)],
+            [posX + barW, offset]
+        ];
+    };
+};
+c3_chart_internal_fn.isWithinBar = function (that) {
+    var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
+        seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
+        x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
+        w = box.width, h = box.height, offset = 2,
+        sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
+    return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
+};
diff --git a/src/shape.js b/src/shape.js
new file mode 100644
index 0000000..fd40598
--- /dev/null
+++ b/src/shape.js
@@ -0,0 +1,71 @@
+c3_chart_internal_fn.getShapeIndices = function (typeFilter) {
+    var $$ = this, config = $$.config,
+        indices = {}, i = 0, j, k;
+    $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)).forEach(function (d) {
+        for (j = 0; j < config.data_groups.length; j++) {
+            if (config.data_groups[j].indexOf(d.id) < 0) { continue; }
+            for (k = 0; k < config.data_groups[j].length; k++) {
+                if (config.data_groups[j][k] in indices) {
+                    indices[d.id] = indices[config.data_groups[j][k]];
+                    break;
+                }
+            }
+        }
+        if (isUndefined(indices[d.id])) { indices[d.id] = i++; }
+    });
+    indices.__max__ = i - 1;
+    return indices;
+};
+c3_chart_internal_fn.getShapeX = function (offset, targetsNum, indices, isSub) {
+    var $$ = this, scale = isSub ? $$.subX : $$.x;
+    return function (d) {
+        var index = d.id in indices ? indices[d.id] : 0;
+        return d.x || d.x === 0 ? scale(d.x) - offset * (targetsNum / 2 - index) : 0;
+    };
+};
+c3_chart_internal_fn.getShapeY = function (isSub) {
+    var $$ = this;
+    return function (d) {
+        var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id);
+        return scale(d.value);
+    };
+};
+c3_chart_internal_fn.getShapeOffset = function (typeFilter, indices, isSub) {
+    var $$ = this,
+        targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))),
+        targetIds = targets.map(function (t) { return t.id; });
+    return function (d, i) {
+        var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
+            y0 = scale(0), offset = y0;
+        targets.forEach(function (t) {
+            var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
+            if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
+            if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
+                if (values[i].value * d.value >= 0) {
+                    offset += scale(values[i].value) - y0;
+                }
+            }
+        });
+        return offset;
+    };
+};
+c3_chart_internal_fn.isWithinShape = function (that, d) {
+    var $$ = this,
+        shape = $$.d3.select(that), isWithin;
+    if (!$$.isTargetToShow(d.id)) {
+        isWithin = false;
+    }
+    else if (that.nodeName === 'circle') {
+        isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
+    }
+    else if (that.nodeName === 'path') {
+        isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true;
+    }
+    return isWithin;
+};
+
+
+c3_chart_internal_fn.getInterpolate = function (d) {
+    var $$ = this;
+    return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? $$.config.line_step_type : "linear";
+};
diff --git a/src/shape.line.js b/src/shape.line.js
new file mode 100644
index 0000000..454742e
--- /dev/null
+++ b/src/shape.line.js
@@ -0,0 +1,363 @@
+c3_chart_internal_fn.initLine = function () {
+    var $$ = this;
+    $$.main.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartLines);
+};
+c3_chart_internal_fn.updateTargetsForLine = function (targets) {
+    var $$ = this, config = $$.config,
+        mainLineUpdate, mainLineEnter,
+        classChartLine = $$.classChartLine.bind($$),
+        classLines = $$.classLines.bind($$),
+        classAreas = $$.classAreas.bind($$),
+        classCircles = $$.classCircles.bind($$),
+        classFocus = $$.classFocus.bind($$);
+    mainLineUpdate = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+        .data(targets)
+        .attr('class', function (d) { return classChartLine(d) + classFocus(d); });
+    mainLineEnter = mainLineUpdate.enter().append('g')
+        .attr('class', classChartLine)
+        .style('opacity', 0)
+        .style("pointer-events", "none");
+    // Lines for each data
+    mainLineEnter.append('g')
+        .attr("class", classLines);
+    // Areas
+    mainLineEnter.append('g')
+        .attr('class', classAreas);
+    // Circles for each data point on lines
+    mainLineEnter.append('g')
+        .attr("class", function (d) { return $$.generateClass(CLASS.selectedCircles, d.id); });
+    mainLineEnter.append('g')
+        .attr("class", classCircles)
+        .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
+    // Update date for selected circles
+    targets.forEach(function (t) {
+        $$.main.selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d) {
+            d.value = t.values[d.index].value;
+        });
+    });
+    // MEMO: can not keep same color...
+    //mainLineUpdate.exit().remove();
+};
+c3_chart_internal_fn.redrawLine = function (durationForExit) {
+    var $$ = this;
+    $$.mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+        .data($$.lineData.bind($$));
+    $$.mainLine.enter().append('path')
+        .attr('class', $$.classLine.bind($$))
+        .style("stroke", $$.color);
+    $$.mainLine
+        .style("opacity", $$.initialOpacity.bind($$))
+        .style('shape-rendering', function (d) { return $$.isStepType(d) ? 'crispEdges' : ''; })
+        .attr('transform', null);
+    $$.mainLine.exit().transition().duration(durationForExit)
+        .style('opacity', 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForLine = function (transitions, drawLine) {
+    var $$ = this;
+    transitions.push($$.mainLine.transition()
+                     .attr("d", drawLine)
+                     .style("stroke", $$.color)
+                     .style("opacity", 1));
+};
+c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
+    var $$ = this, config = $$.config,
+        line = $$.d3.svg.line(),
+        getPoints = $$.generateGetLinePoints(lineIndices, isSub),
+        yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+        xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+        yValue = function (d, i) {
+            return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
+        };
+
+    line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
+    if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); }
+    return function (d) {
+        var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+            x = isSub ? $$.x : $$.subX, y = yScaleGetter.call($$, d.id), x0 = 0, y0 = 0, path;
+        if ($$.isLineType(d)) {
+            if (config.data_regions[d.id]) {
+                path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
+            } else {
+                if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+                path = line.interpolate($$.getInterpolate(d))(values);
+            }
+        } else {
+            if (values[0]) {
+                x0 = x(values[0].x);
+                y0 = y(values[0].value);
+            }
+            path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+        }
+        return path ? path : "M 0 0";
+    };
+};
+c3_chart_internal_fn.generateGetLinePoints = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
+    var $$ = this, config = $$.config,
+        lineTargetsNum = lineIndices.__max__ + 1,
+        x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
+        y = $$.getShapeY(!!isSub),
+        lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
+        yScale = isSub ? $$.getSubYScale : $$.getYScale;
+    return function (d, i) {
+        var y0 = yScale.call($$, d.id)(0),
+            offset = lineOffset(d, i) || y0, // offset is for stacked area chart
+            posX = x(d), posY = y(d);
+        // fix posY not to overflow opposite quadrant
+        if (config.axis_rotated) {
+            if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+        }
+        // 1 point that marks the line position
+        return [
+            [posX, posY - (y0 - offset)],
+            [posX, posY - (y0 - offset)], // needed for compatibility
+            [posX, posY - (y0 - offset)], // needed for compatibility
+            [posX, posY - (y0 - offset)]  // needed for compatibility
+        ];
+    };
+};
+
+
+c3_chart_internal_fn.lineWithRegions = function (d, x, y, _regions) {
+    var $$ = this, config = $$.config,
+        prev = -1, i, j,
+        s = "M", sWithRegion,
+        xp, yp, dx, dy, dd, diff, diffx2,
+        xValue, yValue,
+        regions = [];
+
+    function isWithinRegions(x, regions) {
+        var i;
+        for (i = 0; i < regions.length; i++) {
+            if (regions[i].start < x && x <= regions[i].end) { return true; }
+        }
+        return false;
+    }
+
+    // Check start/end of regions
+    if (isDefined(_regions)) {
+        for (i = 0; i < _regions.length; i++) {
+            regions[i] = {};
+            if (isUndefined(_regions[i].start)) {
+                regions[i].start = d[0].x;
+            } else {
+                regions[i].start = $$.isTimeSeries() ? $$.parseDate(_regions[i].start) : _regions[i].start;
+            }
+            if (isUndefined(_regions[i].end)) {
+                regions[i].end = d[d.length - 1].x;
+            } else {
+                regions[i].end = $$.isTimeSeries() ? $$.parseDate(_regions[i].end) : _regions[i].end;
+            }
+        }
+    }
+
+    // Set scales
+    xValue = config.axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); };
+    yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
+
+    // Define svg generator function for region
+    if ($$.isTimeSeries()) {
+        sWithRegion = function (d0, d1, j, diff) {
+            var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
+                xv0 = new Date(x0 + x_diff * j),
+                xv1 = new Date(x0 + x_diff * (j + diff));
+            return "M" + x(xv0) + " " + y(yp(j)) + " " + x(xv1) + " " + y(yp(j + diff));
+        };
+    } else {
+        sWithRegion = function (d0, d1, j, diff) {
+            return "M" + x(xp(j), true) + " " + y(yp(j)) + " " + x(xp(j + diff), true) + " " + y(yp(j + diff));
+        };
+    }
+
+    // Generate
+    for (i = 0; i < d.length; i++) {
+
+        // Draw as normal
+        if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) {
+            s += " " + xValue(d[i]) + " " + yValue(d[i]);
+        }
+        // Draw with region // TODO: Fix for horizotal charts
+        else {
+            xp = $$.getScale(d[i - 1].x, d[i].x, $$.isTimeSeries());
+            yp = $$.getScale(d[i - 1].value, d[i].value);
+
+            dx = x(d[i].x) - x(d[i - 1].x);
+            dy = y(d[i].value) - y(d[i - 1].value);
+            dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
+            diff = 2 / dd;
+            diffx2 = diff * 2;
+
+            for (j = diff; j <= 1; j += diffx2) {
+                s += sWithRegion(d[i - 1], d[i], j, diff);
+            }
+        }
+        prev = d[i].x;
+    }
+
+    return s;
+};
+
+
+c3_chart_internal_fn.redrawArea = function (durationForExit) {
+    var $$ = this, d3 = $$.d3;
+    $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+        .data($$.lineData.bind($$));
+    $$.mainArea.enter().append('path')
+        .attr("class", $$.classArea.bind($$))
+        .style("fill", $$.color)
+        .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+    $$.mainArea
+        .style("opacity", $$.orgAreaOpacity);
+    $$.mainArea.exit().transition().duration(durationForExit)
+        .style('opacity', 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForArea = function (transitions, drawArea) {
+    var $$ = this;
+    transitions.push($$.mainArea.transition()
+                     .attr("d", drawArea)
+                     .style("fill", $$.color)
+                     .style("opacity", $$.orgAreaOpacity));
+};
+c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
+    var $$ = this, config = $$.config, area = $$.d3.svg.area(),
+        getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
+        yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
+        xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
+        value0 = function (d, i) {
+            return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
+        },
+        value1 = function (d, i) {
+            return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
+        };
+
+    area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
+    if (!config.line_connectNull) {
+        area = area.defined(function (d) { return d.value !== null; });
+    }
+
+    return function (d) {
+        var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
+            x0 = 0, y0 = 0, path;
+        if ($$.isAreaType(d)) {
+            if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
+            path = area.interpolate($$.getInterpolate(d))(values);
+        } else {
+            if (values[0]) {
+                x0 = $$.x(values[0].x);
+                y0 = $$.getYScale(d.id)(values[0].value);
+            }
+            path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
+        }
+        return path ? path : "M 0 0";
+    };
+};
+
+c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
+    var $$ = this, config = $$.config,
+        areaTargetsNum = areaIndices.__max__ + 1,
+        x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
+        y = $$.getShapeY(!!isSub),
+        areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
+        yScale = isSub ? $$.getSubYScale : $$.getYScale;
+    return function (d, i) {
+        var y0 = yScale.call($$, d.id)(0),
+            offset = areaOffset(d, i) || y0, // offset is for stacked area chart
+            posX = x(d), posY = y(d);
+        // fix posY not to overflow opposite quadrant
+        if (config.axis_rotated) {
+            if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
+        }
+        // 1 point that marks the area position
+        return [
+            [posX, offset],
+            [posX, posY - (y0 - offset)],
+            [posX, posY - (y0 - offset)], // needed for compatibility
+            [posX, offset] // needed for compatibility
+        ];
+    };
+};
+
+
+c3_chart_internal_fn.redrawCircle = function () {
+    var $$ = this;
+    $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
+        .data($$.lineOrScatterData.bind($$));
+    $$.mainCircle.enter().append("circle")
+        .attr("class", $$.classCircle.bind($$))
+        .attr("r", $$.pointR.bind($$))
+        .style("fill", $$.color);
+    $$.mainCircle
+        .style("opacity", $$.initialOpacityForCircle.bind($$));
+    $$.mainCircle.exit().remove();
+};
+c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
+    var $$ = this;
+    transitions.push($$.mainCircle.transition()
+                     .style('opacity', $$.opacityForCircle.bind($$))
+                     .style("fill", $$.color)
+                     .attr("cx", cx)
+                     .attr("cy", cy));
+    transitions.push($$.main.selectAll('.' + CLASS.selectedCircle).transition()
+                     .attr("cx", cx)
+                     .attr("cy", cy));
+};
+c3_chart_internal_fn.circleX = function (d) {
+    return d.x || d.x === 0 ? this.x(d.x) : null;
+};
+c3_chart_internal_fn.updateCircleY = function () {
+    var $$ = this, lineIndices, getPoints;
+    if ($$.config.data_groups.length > 0) {
+        lineIndices = $$.getShapeIndices($$.isLineType),
+        getPoints = $$.generateGetLinePoints(lineIndices);
+        $$.circleY = function (d, i) {
+            return getPoints(d, i)[0][1];
+        };
+    } else {
+        $$.circleY = function (d) {
+            return $$.getYScale(d.id)(d.value);
+        };
+    }
+};
+c3_chart_internal_fn.getCircles = function (i, id) {
+    var $$ = this;
+    return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
+};
+c3_chart_internal_fn.expandCircles = function (i, id, reset) {
+    var $$ = this,
+        r = $$.pointExpandedR.bind($$);
+    if (reset) { $$.unexpandCircles(); }
+    $$.getCircles(i, id)
+        .classed(CLASS.EXPANDED, true)
+        .attr('r', r);
+};
+c3_chart_internal_fn.unexpandCircles = function (i) {
+    var $$ = this,
+        r = $$.pointR.bind($$);
+    $$.getCircles(i)
+        .filter(function () { return $$.d3.select(this).classed(CLASS.EXPANDED); })
+        .classed(CLASS.EXPANDED, false)
+        .attr('r', r);
+};
+c3_chart_internal_fn.pointR = function (d) {
+    var $$ = this, config = $$.config;
+    return $$.isStepType(d) ? 0 : (isFunction(config.point_r) ? config.point_r(d) : config.point_r);
+};
+c3_chart_internal_fn.pointExpandedR = function (d) {
+    var $$ = this, config = $$.config;
+    return config.point_focus_expand_enabled ? (config.point_focus_expand_r ? config.point_focus_expand_r : $$.pointR(d) * 1.75) : $$.pointR(d);
+};
+c3_chart_internal_fn.pointSelectR = function (d) {
+    var $$ = this, config = $$.config;
+    return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
+};
+c3_chart_internal_fn.isWithinCircle = function (that, r) {
+    var d3 = this.d3,
+        mouse = d3.mouse(that), d3_this = d3.select(that),
+        cx = +d3_this.attr("cx"), cy = +d3_this.attr("cy");
+    return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
+};
+c3_chart_internal_fn.isWithinStep = function (that, y) {
+    return Math.abs(y - this.d3.mouse(that)[1]) < 30;
+};
diff --git a/src/size.js b/src/size.js
new file mode 100644
index 0000000..cef3b0f
--- /dev/null
+++ b/src/size.js
@@ -0,0 +1,109 @@
+c3_chart_internal_fn.getCurrentWidth = function () {
+    var $$ = this, config = $$.config;
+    return config.size_width ? config.size_width : $$.getParentWidth();
+};
+c3_chart_internal_fn.getCurrentHeight = function () {
+    var $$ = this, config = $$.config,
+        h = config.size_height ? config.size_height : $$.getParentHeight();
+    return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
+};
+c3_chart_internal_fn.getCurrentPaddingTop = function () {
+    var config = this.config;
+    return isValue(config.padding_top) ? config.padding_top : 0;
+};
+c3_chart_internal_fn.getCurrentPaddingBottom = function () {
+    var config = this.config;
+    return isValue(config.padding_bottom) ? config.padding_bottom : 0;
+};
+c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
+    var $$ = this, config = $$.config;
+    if (isValue(config.padding_left)) {
+        return config.padding_left;
+    } else if (config.axis_rotated) {
+        return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
+    } else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
+        return $$.getYAxisLabelPosition().isOuter ? 30 : 1;
+    } else {
+        return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
+    }
+};
+c3_chart_internal_fn.getCurrentPaddingRight = function () {
+    var $$ = this, config = $$.config,
+        defaultPadding = 10, legendWidthOnRight = $$.isLegendRight ? $$.getLegendWidth() + 20 : 0;
+    if (isValue(config.padding_right)) {
+        return config.padding_right + 1; // 1 is needed not to hide tick line
+    } else if (config.axis_rotated) {
+        return defaultPadding + legendWidthOnRight;
+    } else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
+        return defaultPadding + legendWidthOnRight + ($$.getY2AxisLabelPosition().isOuter ? 20 : 0);
+    } else {
+        return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
+    }
+};
+
+c3_chart_internal_fn.getParentRectValue = function (key) {
+    var parent = this.selectChart.node(), v;
+    while (parent && parent.tagName !== 'BODY') {
+        v = parent.getBoundingClientRect()[key];
+        if (v) {
+            break;
+        }
+        parent = parent.parentNode;
+    }
+    return v;
+};
+c3_chart_internal_fn.getParentWidth = function () {
+    return this.getParentRectValue('width');
+};
+c3_chart_internal_fn.getParentHeight = function () {
+    var h = this.selectChart.style('height');
+    return h.indexOf('px') > 0 ? +h.replace('px', '') : 0;
+};
+
+
+c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
+    var $$ = this, config = $$.config,
+        leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
+        leftAxis = $$.main.select('.' + leftAxisClass).node(),
+        svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
+        chartRect = $$.selectChart.node().getBoundingClientRect(),
+        hasArc = $$.hasArcType(),
+        svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
+    return svgLeft > 0 ? svgLeft : 0;
+};
+
+
+c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
+    var $$ = this, position = $$.getAxisLabelPositionById(id);
+    return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
+};
+c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
+    var $$ = this, config = $$.config, h = 30;
+    if (axisId === 'x' && !config.axis_x_show) { return 8; }
+    if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
+    if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
+    if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
+    // Calculate x axis height when tick rotated
+    if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
+        h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
+    }
+    return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
+};
+
+c3_chart_internal_fn.getEventRectWidth = function () {
+    var $$ = this;
+    var target = $$.getMaxDataCountTarget($$.data.targets),
+        firstData, lastData, base, maxDataCount, ratio, w;
+    if (!target) {
+        return 0;
+    }
+    firstData = target.values[0], lastData = target.values[target.values.length - 1];
+    base = $$.x(lastData.x) - $$.x(firstData.x);
+    if (base === 0) {
+        return $$.config.axis_rotated ? $$.height : $$.width;
+    }
+    maxDataCount = $$.getMaxDataCount();
+    ratio = ($$.hasType('bar') ? (maxDataCount - ($$.isCategorized() ? 0.25 : 1)) / maxDataCount : 1);
+    w = maxDataCount > 1 ? (base * ratio) / (maxDataCount - 1) : base;
+    return w < 1 ? 1 : w;
+};
diff --git a/src/subchart.js b/src/subchart.js
new file mode 100644
index 0000000..d5f1fbe
--- /dev/null
+++ b/src/subchart.js
@@ -0,0 +1,187 @@
+c3_chart_internal_fn.initBrush = function () {
+    var $$ = this, d3 = $$.d3;
+    $$.brush = d3.svg.brush().on("brush", function () { $$.redrawForBrush(); });
+    $$.brush.update = function () {
+        if ($$.context) { $$.context.select('.' + CLASS.brush).call(this); }
+        return this;
+    };
+    $$.brush.scale = function (scale) {
+        return $$.config.axis_rotated ? this.y(scale) : this.x(scale);
+    };
+};
+c3_chart_internal_fn.initSubchart = function () {
+    var $$ = this, config = $$.config,
+        context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context'));
+
+    if (!config.subchart_show) {
+        context.style('visibility', 'hidden');
+    }
+
+    // Define g for chart area
+    context.append('g')
+        .attr("clip-path", $$.clipPathForSubchart)
+        .attr('class', CLASS.chart);
+
+    // Define g for bar chart area
+    context.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartBars);
+
+    // Define g for line chart area
+    context.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartLines);
+
+    // Add extent rect for Brush
+    context.append("g")
+        .attr("clip-path", $$.clipPath)
+        .attr("class", CLASS.brush)
+        .call($$.brush)
+        .selectAll("rect")
+        .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
+
+    // ATTENTION: This must be called AFTER chart added
+    // Add Axis
+    $$.axes.subx = context.append("g")
+        .attr("class", CLASS.axisX)
+        .attr("transform", $$.getTranslate('subx'))
+        .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis);
+};
+c3_chart_internal_fn.updateTargetsForSubchart = function (targets) {
+    var $$ = this, context = $$.context, config = $$.config,
+        contextLineEnter, contextLineUpdate, contextBarEnter, contextBarUpdate,
+        classChartBar = $$.classChartBar.bind($$),
+        classBars = $$.classBars.bind($$),
+        classChartLine = $$.classChartLine.bind($$),
+        classLines = $$.classLines.bind($$),
+        classAreas = $$.classAreas.bind($$);
+
+    if (config.subchart_show) {
+        contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
+            .data(targets)
+            .attr('class', classChartBar);
+        contextBarEnter = contextBarUpdate.enter().append('g')
+            .style('opacity', 0)
+            .attr('class', classChartBar);
+        // Bars for each data
+        contextBarEnter.append('g')
+            .attr("class", classBars);
+
+        //-- Line --//
+        contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
+            .data(targets)
+            .attr('class', classChartLine);
+        contextLineEnter = contextLineUpdate.enter().append('g')
+            .style('opacity', 0)
+            .attr('class', classChartLine);
+        // Lines for each data
+        contextLineEnter.append("g")
+            .attr("class", classLines);
+        // Area
+        contextLineEnter.append("g")
+            .attr("class", classAreas);
+    }
+};
+c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
+    var $$ = this, d3 = $$.d3, context = $$.context, config = $$.config,
+        contextLine,  contextArea, contextBar, drawAreaOnSub, drawBarOnSub, drawLineOnSub,
+        barData = $$.barData.bind($$),
+        lineData = $$.lineData.bind($$),
+        classBar = $$.classBar.bind($$),
+        classLine = $$.classLine.bind($$),
+        classArea = $$.classArea.bind($$),
+        initialOpacity = $$.initialOpacity.bind($$);
+
+    // subchart
+    if (config.subchart_show) {
+        // reflect main chart to extent on subchart if zoomed
+        if (d3.event && d3.event.type === 'zoom') {
+            $$.brush.extent($$.x.orgDomain()).update();
+        }
+        // update subchart elements if needed
+        if (withSubchart) {
+
+            // extent rect
+            if (!$$.brush.empty()) {
+                $$.brush.extent($$.x.orgDomain()).update();
+            }
+            // setup drawer - MEMO: this must be called after axis updated
+            drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
+            drawBarOnSub = $$.generateDrawBar(barIndices, true);
+            drawLineOnSub = $$.generateDrawLine(lineIndices, true);
+            // bars
+            contextBar = context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
+                .data(barData);
+            contextBar.enter().append('path')
+                .attr("class", classBar)
+                .style("stroke", 'none')
+                .style("fill", $$.color);
+            contextBar
+                .style("opacity", initialOpacity)
+                .transition().duration(duration)
+                .attr('d', drawBarOnSub)
+                .style('opacity', 1);
+            contextBar.exit().transition().duration(duration)
+                .style('opacity', 0)
+                .remove();
+            // lines
+            contextLine = context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
+                .data(lineData);
+            contextLine.enter().append('path')
+                .attr('class', classLine)
+                .style('stroke', $$.color);
+            contextLine
+                .style("opacity", initialOpacity)
+                .transition().duration(duration)
+                .attr("d", drawLineOnSub)
+                .style('opacity', 1);
+            contextLine.exit().transition().duration(duration)
+                .style('opacity', 0)
+                .remove();
+            // area
+            contextArea = context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
+                .data(lineData);
+            contextArea.enter().append('path')
+                .attr("class", classArea)
+                .style("fill", $$.color)
+                .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
+            contextArea
+                .style("opacity", 0)
+                .transition().duration(duration)
+                .attr("d", drawAreaOnSub)
+                .style("fill", $$.color)
+                .style("opacity", $$.orgAreaOpacity);
+            contextArea.exit().transition().duration(durationForExit)
+                .style('opacity', 0)
+                .remove();
+        }
+    }
+};
+c3_chart_internal_fn.redrawForBrush = function () {
+    var $$ = this, x = $$.x;
+    $$.redraw({
+        withTransition: false,
+        withY: $$.config.zoom_rescale,
+        withSubchart: false,
+        withUpdateXDomain: true,
+        withDimension: false
+    });
+    $$.config.subchart_onbrush.call($$.api, x.orgDomain());
+};
+c3_chart_internal_fn.transformContext = function (withTransition, transitions) {
+    var $$ = this, subXAxis;
+    if (transitions && transitions.axisSubX) {
+        subXAxis = transitions.axisSubX;
+    } else {
+        subXAxis = $$.context.select('.' + CLASS.axisX);
+        if (withTransition) { subXAxis = subXAxis.transition(); }
+    }
+    $$.context.attr("transform", $$.getTranslate('context'));
+    subXAxis.attr("transform", $$.getTranslate('subx'));
+};
+c3_chart_internal_fn.getDefaultExtent = function () {
+    var $$ = this, config = $$.config,
+        extent = isFunction(config.axis_x_extent) ? config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
+    if ($$.isTimeSeries()) {
+        extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
+    }
+    return extent;
+};
diff --git a/src/tail.js b/src/tail.js
new file mode 100644
index 0000000..7e78a25
--- /dev/null
+++ b/src/tail.js
@@ -0,0 +1,9 @@
+    if (typeof define === 'function' && define.amd) {
+        define("c3", ["d3"], c3);
+    } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
+        module.exports = c3;
+    } else {
+        window.c3 = c3;
+    }
+
+})(window);
diff --git a/src/text.js b/src/text.js
new file mode 100644
index 0000000..b1e70ca
--- /dev/null
+++ b/src/text.js
@@ -0,0 +1,94 @@
+c3_chart_internal_fn.initText = function () {
+    var $$ = this;
+    $$.main.select('.' + CLASS.chart).append("g")
+        .attr("class", CLASS.chartTexts);
+    $$.mainText = $$.d3.selectAll([]);
+};
+c3_chart_internal_fn.updateTargetsForText = function (targets) {
+    var $$ = this, mainTextUpdate, mainTextEnter,
+        classChartText = $$.classChartText.bind($$),
+        classTexts = $$.classTexts.bind($$),
+        classFocus = $$.classFocus.bind($$);
+    mainTextUpdate = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
+        .data(targets)
+        .attr('class', function (d) { return classChartText(d) + classFocus(d); });
+    mainTextEnter = mainTextUpdate.enter().append('g')
+        .attr('class', classChartText)
+        .style('opacity', 0)
+        .style("pointer-events", "none");
+    mainTextEnter.append('g')
+        .attr('class', classTexts);
+};
+c3_chart_internal_fn.redrawText = function (durationForExit) {
+    var $$ = this, config = $$.config,
+        barOrLineData = $$.barOrLineData.bind($$),
+        classText = $$.classText.bind($$);
+    $$.mainText = $$.main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text)
+        .data(barOrLineData);
+    $$.mainText.enter().append('text')
+        .attr("class", classText)
+        .attr('text-anchor', function (d) { return config.axis_rotated ? (d.value < 0 ? 'end' : 'start') : 'middle'; })
+        .style("stroke", 'none')
+        .style("fill", function (d) { return $$.color(d); })
+        .style("fill-opacity", 0);
+    $$.mainText
+        .text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
+    $$.mainText.exit()
+        .transition().duration(durationForExit)
+        .style('fill-opacity', 0)
+        .remove();
+};
+c3_chart_internal_fn.addTransitionForText = function (transitions, xForText, yForText, forFlow) {
+    var $$ = this,
+        opacityForText = forFlow ? 0 : $$.opacityForText.bind($$);
+    transitions.push($$.mainText.transition()
+                     .attr('x', xForText)
+                     .attr('y', yForText)
+                     .style("fill", $$.color)
+                     .style("fill-opacity", opacityForText));
+};
+c3_chart_internal_fn.getTextRect = function (text, cls) {
+    var body = this.d3.select('body').classed('c3', true),
+        svg = body.append("svg").style('visibility', 'hidden'), rect;
+    svg.selectAll('.dummy')
+        .data([text])
+      .enter().append('text')
+        .classed(cls ? cls : "", true)
+        .text(text)
+      .each(function () { rect = this.getBoundingClientRect(); });
+    svg.remove();
+    body.classed('c3', false);
+    return rect;
+};
+c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
+    var $$ = this,
+        getAreaPoints = $$.generateGetAreaPoints(barIndices, false),
+        getBarPoints = $$.generateGetBarPoints(barIndices, false),
+        getLinePoints = $$.generateGetLinePoints(lineIndices, false),
+        getter = forX ? $$.getXForText : $$.getYForText;
+    return function (d, i) {
+        var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
+        return getter.call($$, getPoints(d, i), d, this);
+    };
+};
+c3_chart_internal_fn.getXForText = function (points, d, textElement) {
+    var $$ = this,
+        box = textElement.getBoundingClientRect(), xPos, padding;
+    if ($$.config.axis_rotated) {
+        padding = $$.isBarType(d) ? 4 : 6;
+        xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
+    } else {
+        xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
+    }
+    return d.value !== null ? xPos : xPos > $$.width ? $$.width - box.width : xPos;
+};
+c3_chart_internal_fn.getYForText = function (points, d, textElement) {
+    var $$ = this,
+        box = textElement.getBoundingClientRect(), yPos;
+    if ($$.config.axis_rotated) {
+        yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
+    } else {
+        yPos = points[2][1] + (d.value < 0 ? box.height : $$.isBarType(d) ? -3 : -6);
+    }
+    return d.value !== null ? yPos : yPos < box.height ? box.height : yPos;
+};
diff --git a/src/tooltip.js b/src/tooltip.js
new file mode 100644
index 0000000..d4bad52
--- /dev/null
+++ b/src/tooltip.js
@@ -0,0 +1,100 @@
+c3_chart_internal_fn.initTooltip = function () {
+    var $$ = this, config = $$.config, i;
+    $$.tooltip = $$.selectChart
+        .style("position", "relative")
+      .append("div")
+        .attr('class', CLASS.tooltipContainer)
+        .style("position", "absolute")
+        .style("pointer-events", "none")
+        .style("display", "none");
+    // Show tooltip if needed
+    if (config.tooltip_init_show) {
+        if ($$.isTimeSeries() && isString(config.tooltip_init_x)) {
+            config.tooltip_init_x = $$.parseDate(config.tooltip_init_x);
+            for (i = 0; i < $$.data.targets[0].values.length; i++) {
+                if (($$.data.targets[0].values[i].x - config.tooltip_init_x) === 0) { break; }
+            }
+            config.tooltip_init_x = i;
+        }
+        $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
+            return $$.addName(d.values[config.tooltip_init_x]);
+        }), $$.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
+        $$.tooltip.style("top", config.tooltip_init_position.top)
+            .style("left", config.tooltip_init_position.left)
+            .style("display", "block");
+    }
+};
+c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
+    var $$ = this, config = $$.config,
+        titleFormat = config.tooltip_format_title || defaultTitleFormat,
+        nameFormat = config.tooltip_format_name || function (name) { return name; },
+        valueFormat = config.tooltip_format_value || defaultValueFormat,
+        text, i, title, value, name, bgcolor;
+    for (i = 0; i < d.length; i++) {
+        if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
+
+        if (! text) {
+            title = titleFormat ? titleFormat(d[i].x) : d[i].x;
+            text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
+        }
+
+        name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
+        value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
+        bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
+
+        text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
+        text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
+        text += "<td class='value'>" + value + "</td>";
+        text += "</tr>";
+    }
+    return text + "</table>";
+};
+c3_chart_internal_fn.showTooltip = function (selectedData, mouse) {
+    var $$ = this, config = $$.config;
+    var tWidth, tHeight, svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
+    var forArc = $$.hasArcType(),
+        dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
+    if (dataToShow.length === 0 || !config.tooltip_show) {
+        return;
+    }
+    $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
+
+    // Get tooltip dimensions
+    tWidth = $$.tooltip.property('offsetWidth');
+    tHeight = $$.tooltip.property('offsetHeight');
+    // Determin tooltip position
+    if (forArc) {
+        tooltipLeft = ($$.width / 2) + mouse[0];
+        tooltipTop = ($$.height / 2) + mouse[1] + 20;
+    } else {
+        svgLeft = $$.getSvgLeft(true);
+        if (config.axis_rotated) {
+            tooltipLeft = svgLeft + mouse[0] + 100;
+            tooltipRight = tooltipLeft + tWidth;
+            chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
+            tooltipTop = $$.x(dataToShow[0].x) + 20;
+        } else {
+            tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
+            tooltipRight = tooltipLeft + tWidth;
+            chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
+            tooltipTop = mouse[1] + 15;
+        }
+
+        if (tooltipRight > chartRight) {
+            tooltipLeft -= tooltipRight - chartRight;
+        }
+        if (tooltipTop + tHeight > $$.currentHeight) {
+            tooltipTop -= tHeight + 30;
+        }
+    }
+    if (tooltipTop < 0) {
+        tooltipTop = 0;
+    }
+    // Set tooltip
+    $$.tooltip
+        .style("top", tooltipTop + "px")
+        .style("left", tooltipLeft + 'px');
+};
+c3_chart_internal_fn.hideTooltip = function () {
+    this.tooltip.style("display", "none");
+};
diff --git a/src/type.js b/src/type.js
new file mode 100644
index 0000000..51511a5
--- /dev/null
+++ b/src/type.js
@@ -0,0 +1,91 @@
+c3_chart_internal_fn.setTargetType = function (targetIds, type) {
+    var $$ = this, config = $$.config;
+    $$.mapToTargetIds(targetIds).forEach(function (id) {
+        $$.withoutFadeIn[id] = (type === config.data_types[id]);
+        config.data_types[id] = type;
+    });
+    if (!targetIds) {
+        config.data_type = type;
+    }
+};
+c3_chart_internal_fn.hasType = function (type, targets) {
+    var $$ = this, types = $$.config.data_types, has = false;
+    targets = targets || $$.data.targets;
+    if (targets && targets.length) {
+        targets.forEach(function (target) {
+            var t = types[target.id];
+            if ((t && t.indexOf(type) >= 0) || (!t && type === 'line')) {
+                has = true;
+            }
+        });
+    } else if (Object.keys(types).length) {
+        Object.keys(types).forEach(function (id) {
+            if (types[id] === type) { has = true; }
+        });
+    } else {
+        has = $$.config.data_type === type;
+    }
+    return has;
+};
+c3_chart_internal_fn.hasArcType = function (targets) {
+    return this.hasType('pie', targets) || this.hasType('donut', targets) || this.hasType('gauge', targets);
+};
+c3_chart_internal_fn.isLineType = function (d) {
+    var config = this.config, id = isString(d) ? d : d.id;
+    return !config.data_types[id] || ['line', 'spline', 'area', 'area-spline', 'step', 'area-step'].indexOf(config.data_types[id]) >= 0;
+};
+c3_chart_internal_fn.isStepType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return ['step', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+};
+c3_chart_internal_fn.isSplineType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return ['spline', 'area-spline'].indexOf(this.config.data_types[id]) >= 0;
+};
+c3_chart_internal_fn.isAreaType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return ['area', 'area-spline', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
+};
+c3_chart_internal_fn.isBarType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return this.config.data_types[id] === 'bar';
+};
+c3_chart_internal_fn.isScatterType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return this.config.data_types[id] === 'scatter';
+};
+c3_chart_internal_fn.isPieType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return this.config.data_types[id] === 'pie';
+};
+c3_chart_internal_fn.isGaugeType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return this.config.data_types[id] === 'gauge';
+};
+c3_chart_internal_fn.isDonutType = function (d) {
+    var id = isString(d) ? d : d.id;
+    return this.config.data_types[id] === 'donut';
+};
+c3_chart_internal_fn.isArcType = function (d) {
+    return this.isPieType(d) || this.isDonutType(d) || this.isGaugeType(d);
+};
+c3_chart_internal_fn.lineData = function (d) {
+    return this.isLineType(d) ? [d] : [];
+};
+c3_chart_internal_fn.arcData = function (d) {
+    return this.isArcType(d.data) ? [d] : [];
+};
+/* not used
+ function scatterData(d) {
+ return isScatterType(d) ? d.values : [];
+ }
+ */
+c3_chart_internal_fn.barData = function (d) {
+    return this.isBarType(d) ? d.values : [];
+};
+c3_chart_internal_fn.lineOrScatterData = function (d) {
+    return this.isLineType(d) || this.isScatterType(d) ? d.values : [];
+};
+c3_chart_internal_fn.barOrLineData = function (d) {
+    return this.isBarType(d) || this.isLineType(d) ? d.values : [];
+};
diff --git a/src/util.js b/src/util.js
new file mode 100644
index 0000000..91cb48b
--- /dev/null
+++ b/src/util.js
@@ -0,0 +1,46 @@
+var isValue = c3_chart_internal_fn.isValue = function (v) {
+    return v || v === 0;
+},
+    isFunction = c3_chart_internal_fn.isFunction = function (o) {
+        return typeof o === 'function';
+    },
+    isString = c3_chart_internal_fn.isString = function (o) {
+        return typeof o === 'string';
+    },
+    isUndefined = c3_chart_internal_fn.isUndefined = function (v) {
+        return typeof v === 'undefined';
+    },
+    isDefined = c3_chart_internal_fn.isDefined = function (v) {
+        return typeof v !== 'undefined';
+    },
+    ceil10 = c3_chart_internal_fn.ceil10 = function (v) {
+        return Math.ceil(v / 10) * 10;
+    },
+    asHalfPixel = c3_chart_internal_fn.asHalfPixel = function (n) {
+        return Math.ceil(n) + 0.5;
+    },
+    diffDomain = c3_chart_internal_fn.diffDomain = function (d) {
+        return d[1] - d[0];
+    },
+    isEmpty = c3_chart_internal_fn.isEmpty = function (o) {
+        return !o || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
+    },
+    notEmpty = c3_chart_internal_fn.notEmpty = function (o) {
+        return Object.keys(o).length > 0;
+    },
+    getOption = c3_chart_internal_fn.getOption = function (options, key, defaultValue) {
+        return isDefined(options[key]) ? options[key] : defaultValue;
+    },
+    hasValue = c3_chart_internal_fn.hasValue = function (dict, value) {
+        var found = false;
+        Object.keys(dict).forEach(function (key) {
+            if (dict[key] === value) { found = true; }
+        });
+        return found;
+    },
+    getPathBox = c3_chart_internal_fn.getPathBox = function (path) {
+        var box = path.getBoundingClientRect(),
+            items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
+            minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
+        return {x: minX, y: minY, width: box.width, height: box.height};
+    };
diff --git a/src/zoom.js b/src/zoom.js
new file mode 100644
index 0000000..b46a0b1
--- /dev/null
+++ b/src/zoom.js
@@ -0,0 +1,69 @@
+c3_chart_internal_fn.initZoom = function () {
+    var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
+
+    $$.zoom = d3.behavior.zoom()
+        .on("zoomstart", function () {
+            startEvent = d3.event.sourceEvent;
+            $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
+            config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
+        })
+        .on("zoom", function () {
+            $$.redrawForZoom.call($$);
+        })
+        .on('zoomend', function () {
+            var event = d3.event.sourceEvent;
+            // if click, do nothing. otherwise, click interaction will be canceled.
+            if (event && startEvent.clientX === event.clientX && startEvent.clientY === event.clientY) {
+                return;
+            }
+            $$.redrawEventRect();
+            $$.updateZoom();
+            config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
+        });
+    $$.zoom.scale = function (scale) {
+        return config.axis_rotated ? this.y(scale) : this.x(scale);
+    };
+    $$.zoom.orgScaleExtent = function () {
+        var extent = config.zoom_extent ? config.zoom_extent : [1, 10];
+        return [extent[0], Math.max($$.getMaxDataCount() / extent[1], extent[1])];
+    };
+    $$.zoom.updateScaleExtent = function () {
+        var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.orgXDomain),
+            extent = this.orgScaleExtent();
+        this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
+        return this;
+    };
+};
+c3_chart_internal_fn.updateZoom = function () {
+    var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
+    $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
+    $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
+};
+c3_chart_internal_fn.redrawForZoom = function () {
+    var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
+    if (!config.zoom_enabled) {
+        return;
+    }
+    if ($$.filterTargetsToShow($$.data.targets).length === 0) {
+        return;
+    }
+    if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) {
+        x.domain(zoom.altDomain);
+        zoom.scale(x).updateScaleExtent();
+        return;
+    }
+    if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
+        x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
+    }
+    $$.redraw({
+        withTransition: false,
+        withY: config.zoom_rescale,
+        withSubchart: false,
+        withEventRect: false,
+        withDimension: false
+    });
+    if (d3.event.sourceEvent.type === 'mousemove') {
+        $$.cancelClick = true;
+    }
+    config.zoom_onzoom.call($$.api, x.orgDomain());
+};