c3-rails 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
 
4
4
  /*global define, module, exports, require */
5
5
 
6
- var c3 = { version: "0.3.0" };
6
+ var c3 = { version: "0.4.0" };
7
7
 
8
8
  var c3_chart_fn, c3_chart_internal_fn;
9
9
 
@@ -14,12 +14,12 @@
14
14
 
15
15
  // bind "this" to nested API
16
16
  (function bindThis(fn, target, argThis) {
17
- for (var key in fn) {
17
+ Object.keys(fn).forEach(function (key) {
18
18
  target[key] = fn[key].bind(argThis);
19
19
  if (Object.keys(fn[key]).length > 0) {
20
20
  bindThis(fn[key], target[key], argThis);
21
21
  }
22
- }
22
+ });
23
23
  })(c3_chart_fn, this, this);
24
24
  }
25
25
 
@@ -76,12 +76,17 @@
76
76
  $$.clipId = "c3-" + (+new Date()) + '-clip',
77
77
  $$.clipIdForXAxis = $$.clipId + '-xaxis',
78
78
  $$.clipIdForYAxis = $$.clipId + '-yaxis',
79
+ $$.clipIdForGrid = $$.clipId + '-grid',
80
+ $$.clipIdForSubchart = $$.clipId + '-subchart',
79
81
  $$.clipPath = $$.getClipPath($$.clipId),
80
82
  $$.clipPathForXAxis = $$.getClipPath($$.clipIdForXAxis),
81
83
  $$.clipPathForYAxis = $$.getClipPath($$.clipIdForYAxis);
84
+ $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid),
85
+ $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart),
82
86
 
83
87
  $$.dragStart = null;
84
88
  $$.dragging = false;
89
+ $$.flowing = false;
85
90
  $$.cancelClick = false;
86
91
  $$.mouseover = false;
87
92
  $$.transiting = false;
@@ -104,6 +109,8 @@
104
109
 
105
110
  $$.hiddenTargetIds = [];
106
111
  $$.hiddenLegendIds = [];
112
+ $$.focusedTargetIds = [];
113
+ $$.defocusedTargetIds = [];
107
114
 
108
115
  $$.xOrient = config.axis_rotated ? "left" : "bottom";
109
116
  $$.yOrient = config.axis_rotated ? "bottom" : "left";
@@ -119,7 +126,11 @@
119
126
  $$.legendItemHeight = 0;
120
127
  $$.legendOpacityForHidden = 0.15;
121
128
 
122
- $$.currentMaxTickWidth = 0;
129
+ $$.currentMaxTickWidths = {
130
+ x: 0,
131
+ y: 0,
132
+ y2: 0
133
+ };
123
134
 
124
135
  $$.rotated_padding_left = 30;
125
136
  $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
@@ -127,18 +138,20 @@
127
138
 
128
139
  $$.withoutFadeIn = {};
129
140
 
141
+ $$.intervalForObserveInserted = undefined;
142
+
130
143
  $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
131
144
  };
132
145
 
133
146
  c3_chart_internal_fn.initWithData = function (data) {
134
147
  var $$ = this, d3 = $$.d3, config = $$.config;
135
- var main, binding = true;
148
+ var defs, main, binding = true;
136
149
 
137
150
  if ($$.initPie) { $$.initPie(); }
138
151
  if ($$.initBrush) { $$.initBrush(); }
139
152
  if ($$.initZoom) { $$.initZoom(); }
140
153
 
141
- $$.selectChart = d3.select(config.bindto);
154
+ $$.selectChart = typeof config.bindto.node === 'function' ? config.bindto : d3.select(config.bindto);
142
155
  if ($$.selectChart.empty()) {
143
156
  $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
144
157
  $$.observeInserted($$.selectChart);
@@ -192,10 +205,12 @@
192
205
  .on('mouseleave', function () { return config.onmouseout.call($$); });
193
206
 
194
207
  // Define defs
195
- $$.defs = $$.svg.append("defs");
196
- $$.defs.append("clipPath").attr("id", $$.clipId).append("rect");
197
- $$.defs.append("clipPath").attr("id", $$.clipIdForXAxis).append("rect");
198
- $$.defs.append("clipPath").attr("id", $$.clipIdForYAxis).append("rect");
208
+ defs = $$.svg.append("defs");
209
+ $$.clipChart = $$.appendClip(defs, $$.clipId);
210
+ $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
211
+ $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
212
+ $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
213
+ $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
199
214
  $$.updateSvgSize();
200
215
 
201
216
  // Define regions
@@ -224,6 +239,9 @@
224
239
  .attr("clip-path", $$.clipPath)
225
240
  .attr('class', CLASS.chart);
226
241
 
242
+ // Grid lines
243
+ if (config.grid_lines_front) { $$.initGridLines(); }
244
+
227
245
  // Cover whole with rects for events
228
246
  $$.initEventRect();
229
247
 
@@ -250,9 +268,7 @@
250
268
  .on("dblclick.zoom", null);
251
269
 
252
270
  // Set default extent if defined
253
- if (config.axis_x_default) {
254
- $$.brush.extent(isFunction(config.axis_x_default) ? config.axis_x_default($$.getXDomain()) : config.axis_x_default);
255
- }
271
+ if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
256
272
 
257
273
  // Add Axis
258
274
  $$.initAxis();
@@ -263,6 +279,7 @@
263
279
  // Draw with targets
264
280
  if (binding) {
265
281
  $$.updateDimension();
282
+ $$.config.oninit.call($$);
266
283
  $$.redraw({
267
284
  withTransform: true,
268
285
  withUpdateXDomain: true,
@@ -371,6 +388,9 @@
371
388
  // for arc
372
389
  $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
373
390
  $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
391
+ if ($$.hasType('gauge')) {
392
+ $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
393
+ }
374
394
  if ($$.updateRadius) { $$.updateRadius(); }
375
395
 
376
396
  if ($$.isLegendRight && hasArc) {
@@ -407,15 +427,13 @@
407
427
  c3_chart_internal_fn.redraw = function (options, transitions) {
408
428
  var $$ = this, main = $$.main, d3 = $$.d3, config = $$.config;
409
429
  var areaIndices = $$.getShapeIndices($$.isAreaType), barIndices = $$.getShapeIndices($$.isBarType), lineIndices = $$.getShapeIndices($$.isLineType);
410
- var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis, withTransform, withUpdateXDomain, withUpdateOrgXDomain, withLegend;
430
+ var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis, withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend, withEventRect;
411
431
  var hideAxis = $$.hasArcType();
412
432
  var drawArea, drawBar, drawLine, xForText, yForText;
413
433
  var duration, durationForExit, durationForAxis;
414
434
  var waitForDraw, flow;
415
- var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling;
416
- var xv = $$.xv.bind($$),
417
- cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
418
- cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
435
+ var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling, xDomainForZoom;
436
+ var xv = $$.xv.bind($$), cx, cy;
419
437
 
420
438
  options = options || {};
421
439
  withY = getOption(options, "withY", true);
@@ -424,7 +442,9 @@
424
442
  withTransform = getOption(options, "withTransform", false);
425
443
  withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
426
444
  withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
445
+ withTrimXDomain = getOption(options, "withTrimXDomain", true);
427
446
  withLegend = getOption(options, "withLegend", false);
447
+ withEventRect = getOption(options, "withEventRect", true);
428
448
  withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
429
449
  withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
430
450
 
@@ -437,6 +457,10 @@
437
457
  // update legend and transform each g
438
458
  if (withLegend && config.legend_show) {
439
459
  $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
460
+ } else if ((!config.axis_rotated && withY) || (config.axis_rotated && withUpdateXDomain)) {
461
+ // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
462
+ // no need to update axis in it because they will be updated in redraw()
463
+ $$.updateDimension(true);
440
464
  }
441
465
 
442
466
  // MEMO: needed for grids calculation
@@ -445,10 +469,13 @@
445
469
  }
446
470
 
447
471
  if (targetsToShow.length) {
448
- $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain);
449
- // update axis tick values according to options
450
- if (!config.axis_x_tick_values && (config.axis_x_tick_fit || config.axis_x_tick_count)) {
451
- tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count);
472
+ $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
473
+ if (!config.axis_x_tick_values) {
474
+ if (config.axis_x_tick_fit || config.axis_x_tick_count) {
475
+ tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count, $$.isTimeSeries());
476
+ } else {
477
+ tickValues = undefined;
478
+ }
452
479
  $$.xAxis.tickValues(tickValues);
453
480
  $$.subXAxis.tickValues(tickValues);
454
481
  }
@@ -457,8 +484,19 @@
457
484
  $$.subXAxis.tickValues([]);
458
485
  }
459
486
 
460
- $$.y.domain($$.getYDomain(targetsToShow, 'y'));
461
- $$.y2.domain($$.getYDomain(targetsToShow, 'y2'));
487
+ if (withY && !options.flow) {
488
+ xDomainForZoom = $$.x.orgDomain();
489
+ }
490
+
491
+ $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
492
+ $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
493
+
494
+ if (!config.axis_y_tick_values && config.axis_y_tick_count) {
495
+ $$.yAxis.tickValues($$.generateTickValues($$.y.domain(), config.axis_y_tick_count));
496
+ }
497
+ if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
498
+ $$.y2Axis.tickValues($$.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
499
+ }
462
500
 
463
501
  // axes
464
502
  $$.redrawAxis(transitions, hideAxis);
@@ -486,21 +524,18 @@
486
524
  }
487
525
  }
488
526
 
489
- // rotate tick text if needed
490
- if (!config.axis_rotated && config.axis_x_tick_rotate) {
491
- $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
492
- }
493
-
494
527
  // setup drawer - MEMO: these must be called after axis updated
495
528
  drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
496
529
  drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
497
530
  drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
498
- xForText = $$.generateXYForText(barIndices, true);
499
- yForText = $$.generateXYForText(barIndices, false);
531
+ xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
532
+ yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false);
500
533
 
501
534
  // Update sub domain
502
- $$.subY.domain($$.y.domain());
503
- $$.subY2.domain($$.y2.domain());
535
+ if (withY) {
536
+ $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
537
+ $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
538
+ }
504
539
 
505
540
  // tooltip
506
541
  $$.tooltip.style("display", "none");
@@ -528,7 +563,7 @@
528
563
  // lines, areas and cricles
529
564
  $$.redrawLine(durationForExit);
530
565
  $$.redrawArea(durationForExit);
531
- if (config.point_show) { $$.redrawCircle(); }
566
+ $$.redrawCircle();
532
567
 
533
568
  // text
534
569
  if ($$.hasDataLabel()) {
@@ -549,11 +584,16 @@
549
584
  .selectAll('circle')
550
585
  .remove();
551
586
 
552
- // event rect
553
- if (config.interaction_enabled) {
587
+ // event rects will redrawn when flow called
588
+ if (config.interaction_enabled && !options.flow && withEventRect) {
554
589
  $$.redrawEventRect();
590
+ if ($$.updateZoom) { $$.updateZoom(); }
555
591
  }
556
592
 
593
+ // generate circle x/y functions depending on updated params
594
+ cx = ($$.config.axis_rotated ? $$.generateCircleY() : $$.circleX).bind($$);
595
+ cy = ($$.config.axis_rotated ? $$.circleX : $$.generateCircleY()).bind($$);
596
+
557
597
  // transition should be derived from one transition
558
598
  d3.transition().duration(duration).each(function () {
559
599
  var transitions = [];
@@ -561,7 +601,7 @@
561
601
  $$.addTransitionForBar(transitions, drawBar);
562
602
  $$.addTransitionForLine(transitions, drawLine);
563
603
  $$.addTransitionForArea(transitions, drawArea);
564
- if (config.point_show) { $$.addTransitionForCircle(transitions, cx, cy); }
604
+ $$.addTransitionForCircle(transitions, cx, cy);
565
605
  $$.addTransitionForText(transitions, xForText, yForText, options.flow);
566
606
  $$.addTransitionForRegion(transitions);
567
607
  $$.addTransitionForGrid(transitions);
@@ -593,8 +633,6 @@
593
633
  $$.mapToIds($$.data.targets).forEach(function (id) {
594
634
  $$.withoutFadeIn[id] = true;
595
635
  });
596
-
597
- if ($$.updateZoom) { $$.updateZoom(); }
598
636
  };
599
637
 
600
638
  c3_chart_internal_fn.updateAndRedraw = function (options) {
@@ -635,6 +673,10 @@
635
673
  return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
636
674
  };
637
675
 
676
+ c3_chart_internal_fn.isTimeSeriesY = function () {
677
+ return this.config.axis_y_type === 'timeseries';
678
+ };
679
+
638
680
  c3_chart_internal_fn.getTranslate = function (target) {
639
681
  var $$ = this, config = $$.config, x, y;
640
682
  if (target === 'main') {
@@ -667,9 +709,11 @@
667
709
  c3_chart_internal_fn.initialOpacity = function (d) {
668
710
  return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
669
711
  };
712
+ c3_chart_internal_fn.initialOpacityForCircle = function (d) {
713
+ return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
714
+ };
670
715
  c3_chart_internal_fn.opacityForCircle = function (d) {
671
- var $$ = this;
672
- return isValue(d.value) ? $$.isScatterType(d) ? 0.5 : 1 : 0;
716
+ return isValue(d.value) && this.config.point_show ? (this.isScatterType(d) ? 0.5 : 1) : 0;
673
717
  };
674
718
  c3_chart_internal_fn.opacityForText = function () {
675
719
  return this.hasDataLabel() ? 1 : 0;
@@ -725,9 +769,10 @@
725
769
  };
726
770
 
727
771
  c3_chart_internal_fn.updateSvgSize = function () {
728
- var $$ = this;
772
+ var $$ = this,
773
+ brush = $$.svg.select(".c3-brush .background");
729
774
  $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
730
- $$.svg.select('#' + $$.clipId).select('rect')
775
+ $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect')
731
776
  .attr('width', $$.width)
732
777
  .attr('height', $$.height);
733
778
  $$.svg.select('#' + $$.clipIdForXAxis).select('rect')
@@ -740,6 +785,9 @@
740
785
  .attr('y', $$.getYAxisClipY.bind($$))
741
786
  .attr('width', $$.getYAxisClipWidth.bind($$))
742
787
  .attr('height', $$.getYAxisClipHeight.bind($$));
788
+ $$.svg.select('#' + $$.clipIdForSubchart).select('rect')
789
+ .attr('width', $$.width)
790
+ .attr('height', brush.size() ? brush.attr('height') : 0);
743
791
  $$.svg.select('.' + CLASS.zoomRect)
744
792
  .attr('width', $$.width)
745
793
  .attr('height', $$.height);
@@ -748,14 +796,16 @@
748
796
  };
749
797
 
750
798
 
751
- c3_chart_internal_fn.updateDimension = function () {
799
+ c3_chart_internal_fn.updateDimension = function (withoutAxis) {
752
800
  var $$ = this;
753
- if ($$.config.axis_rotated) {
754
- $$.axes.x.call($$.xAxis);
755
- $$.axes.subx.call($$.subXAxis);
756
- } else {
757
- $$.axes.y.call($$.yAxis);
758
- $$.axes.y2.call($$.y2Axis);
801
+ if (!withoutAxis) {
802
+ if ($$.config.axis_rotated) {
803
+ $$.axes.x.call($$.xAxis);
804
+ $$.axes.subx.call($$.subXAxis);
805
+ } else {
806
+ $$.axes.y.call($$.yAxis);
807
+ $$.axes.y2.call($$.y2Axis);
808
+ }
759
809
  }
760
810
  $$.updateSizes();
761
811
  $$.updateScales();
@@ -769,11 +819,12 @@
769
819
  if (mutation.type === 'childList' && mutation.previousSibling) {
770
820
  observer.disconnect();
771
821
  // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
772
- var interval = window.setInterval(function () {
822
+ $$.intervalForObserveInserted = window.setInterval(function () {
773
823
  // parentNode will NOT be null when completed
774
824
  if (selection.node().parentNode) {
775
- window.clearInterval(interval);
825
+ window.clearInterval($$.intervalForObserveInserted);
776
826
  $$.updateDimension();
827
+ $$.config.oninit.call($$);
777
828
  $$.redraw({
778
829
  withTransform: true,
779
830
  withUpdateXDomain: true,
@@ -868,17 +919,22 @@
868
919
  zoom_enabled: false,
869
920
  zoom_extent: undefined,
870
921
  zoom_privileged: false,
922
+ zoom_rescale: false,
871
923
  zoom_onzoom: function () {},
924
+ zoom_onzoomstart: function () {},
925
+ zoom_onzoomend: function () {},
872
926
  interaction_enabled: true,
873
927
  onmouseover: function () {},
874
928
  onmouseout: function () {},
875
929
  onresize: function () {},
876
930
  onresized: function () {},
931
+ oninit: function () {},
877
932
  transition_duration: 350,
878
933
  data_x: undefined,
879
934
  data_xs: {},
880
935
  data_xFormat: '%Y-%m-%d',
881
936
  data_xLocaltime: true,
937
+ data_xSort: true,
882
938
  data_idConverter: function (id) { return id; },
883
939
  data_names: {},
884
940
  data_classes: {},
@@ -943,23 +999,30 @@
943
999
  axis_x_tick_count: undefined,
944
1000
  axis_x_tick_fit: true,
945
1001
  axis_x_tick_values: null,
946
- axis_x_tick_rotate: undefined,
1002
+ axis_x_tick_rotate: 0,
947
1003
  axis_x_tick_outer: true,
948
- axis_x_max: null,
949
- axis_x_min: null,
1004
+ axis_x_tick_multiline: true,
1005
+ axis_x_tick_width: null,
1006
+ axis_x_max: undefined,
1007
+ axis_x_min: undefined,
950
1008
  axis_x_padding: {},
951
1009
  axis_x_height: undefined,
952
- axis_x_default: undefined,
1010
+ axis_x_extent: undefined,
953
1011
  axis_x_label: {},
954
1012
  axis_y_show: true,
1013
+ axis_y_type: undefined,
955
1014
  axis_y_max: undefined,
956
1015
  axis_y_min: undefined,
957
1016
  axis_y_center: undefined,
958
1017
  axis_y_label: {},
959
1018
  axis_y_tick_format: undefined,
960
1019
  axis_y_tick_outer: true,
961
- axis_y_padding: undefined,
962
- axis_y_ticks: 10,
1020
+ axis_y_tick_values: null,
1021
+ axis_y_tick_count: undefined,
1022
+ axis_y_tick_time_value: undefined,
1023
+ axis_y_tick_time_interval: undefined,
1024
+ axis_y_padding: {},
1025
+ axis_y_default: undefined,
963
1026
  axis_y2_show: false,
964
1027
  axis_y2_max: undefined,
965
1028
  axis_y2_min: undefined,
@@ -967,8 +1030,10 @@
967
1030
  axis_y2_label: {},
968
1031
  axis_y2_tick_format: undefined,
969
1032
  axis_y2_tick_outer: true,
970
- axis_y2_padding: undefined,
971
- axis_y2_ticks: 10,
1033
+ axis_y2_tick_values: null,
1034
+ axis_y2_tick_count: undefined,
1035
+ axis_y2_padding: {},
1036
+ axis_y2_default: undefined,
972
1037
  // grid
973
1038
  grid_x_show: false,
974
1039
  grid_x_type: 'tick',
@@ -979,13 +1044,16 @@
979
1044
  grid_y_lines: [],
980
1045
  grid_y_ticks: 10,
981
1046
  grid_focus_show: true,
1047
+ grid_lines_front: true,
982
1048
  // point - point of each data
983
1049
  point_show: true,
984
1050
  point_r: 2.5,
985
1051
  point_focus_expand_enabled: true,
986
1052
  point_focus_expand_r: undefined,
987
1053
  point_select_r: undefined,
988
- line_connect_null: false,
1054
+ // line
1055
+ line_connectNull: false,
1056
+ line_step_type: 'step',
989
1057
  // bar
990
1058
  bar_width: undefined,
991
1059
  bar_width_ratio: 0.6,
@@ -997,7 +1065,6 @@
997
1065
  pie_label_show: true,
998
1066
  pie_label_format: undefined,
999
1067
  pie_label_threshold: 0.05,
1000
- pie_sort: true,
1001
1068
  pie_expand: true,
1002
1069
  // gauge
1003
1070
  gauge_label_show: true,
@@ -1012,7 +1079,6 @@
1012
1079
  donut_label_format: undefined,
1013
1080
  donut_label_threshold: 0.05,
1014
1081
  donut_width: undefined,
1015
- donut_sort: true,
1016
1082
  donut_expand: true,
1017
1083
  donut_title: "",
1018
1084
  // region - region to change style
@@ -1107,7 +1173,7 @@
1107
1173
  return scale;
1108
1174
  };
1109
1175
  c3_chart_internal_fn.getY = function (min, max, domain) {
1110
- var scale = this.getScale(min, max);
1176
+ var scale = this.getScale(min, max, this.isTimeSeriesY());
1111
1177
  if (domain) { scale.domain(domain); }
1112
1178
  return scale;
1113
1179
  };
@@ -1131,18 +1197,22 @@
1131
1197
  $$.subYMax = config.axis_rotated ? $$.width2 : 1;
1132
1198
  // update scales
1133
1199
  $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () { return $$.xAxis.tickOffset(); });
1134
- $$.y = $$.getY($$.yMin, $$.yMax, forInit ? undefined : $$.y.domain());
1135
- $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? undefined : $$.y2.domain());
1200
+ $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
1201
+ $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
1136
1202
  $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) { return d % 1 ? 0 : $$.subXAxis.tickOffset(); });
1137
- $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? undefined : $$.subY.domain());
1138
- $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? undefined : $$.subY2.domain());
1203
+ $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
1204
+ $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
1139
1205
  // update axes
1140
1206
  $$.xAxisTickFormat = $$.getXAxisTickFormat();
1141
- $$.xAxisTickValues = config.axis_x_tick_values ? config.axis_x_tick_values : (forInit ? undefined : $$.xAxis.tickValues());
1142
- $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
1143
- $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
1144
- $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, config.axis_y_ticks);
1145
- $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, config.axis_y2_ticks);
1207
+ $$.xAxisTickValues = $$.getXAxisTickValues();
1208
+ $$.yAxisTickValues = $$.getYAxisTickValues();
1209
+ $$.y2AxisTickValues = $$.getY2AxisTickValues();
1210
+
1211
+ $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1212
+ $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1213
+ $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
1214
+ $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
1215
+
1146
1216
  // Set initialized scales to brush and zoom
1147
1217
  if (!forInit) {
1148
1218
  if ($$.brush) { $$.brush.scale($$.subX); }
@@ -1214,9 +1284,10 @@
1214
1284
  }
1215
1285
  return $$.d3.max(Object.keys(ys).map(function (key) { return $$.d3.max(ys[key]); }));
1216
1286
  };
1217
- c3_chart_internal_fn.getYDomain = function (targets, axisId) {
1287
+ c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
1218
1288
  var $$ = this, config = $$.config,
1219
- yTargets = targets.filter(function (d) { return $$.getAxisId(d.id) === axisId; }),
1289
+ targetsByAxisId = targets.filter(function (t) { return $$.getAxisId(t.id) === axisId; }),
1290
+ yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
1220
1291
  yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
1221
1292
  yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
1222
1293
  yDomainMin = isValue(yMin) ? yMin : $$.getYDomainMin(yTargets),
@@ -1227,15 +1298,35 @@
1227
1298
  isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
1228
1299
  showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
1229
1300
  showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
1301
+
1302
+ if (yDomainMax < yDomainMin) {
1303
+ if (isValue(yMin)) {
1304
+ yDomainMax = yDomainMin + 10; // TODO: introduce axis.y.maxMin
1305
+ } else {
1306
+ yDomainMin = yDomainMax - 10; // TODO: introduce axis.y.minMax
1307
+ }
1308
+ }
1309
+
1230
1310
  if (yTargets.length === 0) { // use current domain if target of axisId is none
1231
1311
  return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
1232
1312
  }
1313
+ if (isNaN(yDomainMin)) { // set minimum to zero when not number
1314
+ yDomainMin = 0;
1315
+ }
1316
+ if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin
1317
+ yDomainMax = yDomainMin;
1318
+ }
1233
1319
  if (yDomainMin === yDomainMax) {
1234
1320
  yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
1235
1321
  }
1236
1322
  isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
1237
1323
  isAllNegative = yDomainMin <= 0 && yDomainMax <= 0;
1238
1324
 
1325
+ // Cancel zerobased if axis_*_min / axis_*_max specified
1326
+ if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) {
1327
+ isZeroBased = false;
1328
+ }
1329
+
1239
1330
  // Bar/Area chart should be 0-based if all positive|negative
1240
1331
  if (isZeroBased) {
1241
1332
  if (isAllPositive) { yDomainMin = 0; }
@@ -1262,11 +1353,11 @@
1262
1353
  padding_top += lengths[1];
1263
1354
  padding_bottom += lengths[0];
1264
1355
  }
1265
- if (axisId === 'y' && config.axis_y_padding) {
1356
+ if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
1266
1357
  padding_top = $$.getAxisPadding(config.axis_y_padding, 'top', padding, domainLength);
1267
1358
  padding_bottom = $$.getAxisPadding(config.axis_y_padding, 'bottom', padding, domainLength);
1268
1359
  }
1269
- if (axisId === 'y2' && config.axis_y2_padding) {
1360
+ if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
1270
1361
  padding_top = $$.getAxisPadding(config.axis_y2_padding, 'top', padding, domainLength);
1271
1362
  padding_bottom = $$.getAxisPadding(config.axis_y2_padding, 'bottom', padding, domainLength);
1272
1363
  }
@@ -1279,23 +1370,23 @@
1279
1370
  };
1280
1371
  c3_chart_internal_fn.getXDomainMin = function (targets) {
1281
1372
  var $$ = this, config = $$.config;
1282
- return config.axis_x_min ?
1373
+ return isDefined(config.axis_x_min) ?
1283
1374
  ($$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min) :
1284
1375
  $$.d3.min(targets, function (t) { return $$.d3.min(t.values, function (v) { return v.x; }); });
1285
1376
  };
1286
1377
  c3_chart_internal_fn.getXDomainMax = function (targets) {
1287
1378
  var $$ = this, config = $$.config;
1288
- return config.axis_x_max ?
1379
+ return isDefined(config.axis_x_max) ?
1289
1380
  ($$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max) :
1290
1381
  $$.d3.max(targets, function (t) { return $$.d3.max(t.values, function (v) { return v.x; }); });
1291
1382
  };
1292
- c3_chart_internal_fn.getXDomainPadding = function (targets) {
1383
+ c3_chart_internal_fn.getXDomainPadding = function (domain) {
1293
1384
  var $$ = this, config = $$.config,
1294
- edgeX = this.getEdgeX(targets), diff = edgeX[1] - edgeX[0],
1385
+ diff = domain[1] - domain[0],
1295
1386
  maxDataCount, padding, paddingLeft, paddingRight;
1296
1387
  if ($$.isCategorized()) {
1297
1388
  padding = 0;
1298
- } else if ($$.hasType('bar', targets)) {
1389
+ } else if ($$.hasType('bar')) {
1299
1390
  maxDataCount = $$.getMaxDataCount();
1300
1391
  padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
1301
1392
  } else {
@@ -1315,12 +1406,17 @@
1315
1406
  var $$ = this,
1316
1407
  xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
1317
1408
  firstX = xDomain[0], lastX = xDomain[1],
1318
- padding = $$.getXDomainPadding(targets),
1409
+ padding = $$.getXDomainPadding(xDomain),
1319
1410
  min = 0, max = 0;
1320
1411
  // show center of x domain if min and max are the same
1321
1412
  if ((firstX - lastX) === 0 && !$$.isCategorized()) {
1322
- firstX = $$.isTimeSeries() ? new Date(firstX.getTime() * 0.5) : -0.5;
1323
- lastX = $$.isTimeSeries() ? new Date(lastX.getTime() * 1.5) : 0.5;
1413
+ if ($$.isTimeSeries()) {
1414
+ firstX = new Date(firstX.getTime() * 0.5);
1415
+ lastX = new Date(lastX.getTime() * 1.5);
1416
+ } else {
1417
+ firstX = firstX === 0 ? 1 : (firstX * 0.5);
1418
+ lastX = lastX === 0 ? -1 : (lastX * 1.5);
1419
+ }
1324
1420
  }
1325
1421
  if (firstX || firstX === 0) {
1326
1422
  min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
@@ -1330,8 +1426,9 @@
1330
1426
  }
1331
1427
  return [min, max];
1332
1428
  };
1333
- c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, domain) {
1429
+ c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
1334
1430
  var $$ = this, config = $$.config;
1431
+
1335
1432
  if (withUpdateOrgXDomain) {
1336
1433
  $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
1337
1434
  $$.orgXDomain = $$.x.domain();
@@ -1343,8 +1440,24 @@
1343
1440
  $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent());
1344
1441
  if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
1345
1442
  }
1443
+
1444
+ // Trim domain when too big by zoom mousemove event
1445
+ if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); }
1446
+
1346
1447
  return $$.x.domain();
1347
1448
  };
1449
+ c3_chart_internal_fn.trimXDomain = function (domain) {
1450
+ var $$ = this;
1451
+ if (domain[0] <= $$.orgXDomain[0]) {
1452
+ domain[1] = +domain[1] + ($$.orgXDomain[0] - domain[0]);
1453
+ domain[0] = $$.orgXDomain[0];
1454
+ }
1455
+ if ($$.orgXDomain[1] <= domain[1]) {
1456
+ domain[0] = +domain[0] - (domain[1] - $$.orgXDomain[1]);
1457
+ domain[1] = $$.orgXDomain[1];
1458
+ }
1459
+ return domain;
1460
+ };
1348
1461
 
1349
1462
  c3_chart_internal_fn.isX = function (key) {
1350
1463
  var $$ = this, config = $$.config;
@@ -1367,6 +1480,11 @@
1367
1480
  });
1368
1481
  return xValues;
1369
1482
  };
1483
+ c3_chart_internal_fn.getIndexByX = function (x) {
1484
+ var $$ = this,
1485
+ data = $$.filterByX($$.data.targets, x);
1486
+ return data.length ? data[0].index : null;
1487
+ };
1370
1488
  c3_chart_internal_fn.getXValue = function (id, i) {
1371
1489
  var $$ = this;
1372
1490
  return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
@@ -1390,8 +1508,7 @@
1390
1508
  return this.d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() > 1;
1391
1509
  };
1392
1510
  c3_chart_internal_fn.isMultipleX = function () {
1393
- var $$ = this, config = $$.config;
1394
- return notEmpty(config.data_xs) && $$.hasMultipleX(config.data_xs);
1511
+ return notEmpty(this.config.data_xs) || !this.config.data_xSort || this.hasType('scatter');
1395
1512
  };
1396
1513
  c3_chart_internal_fn.addName = function (data) {
1397
1514
  var $$ = this, name;
@@ -1471,12 +1588,11 @@
1471
1588
  return maxTarget;
1472
1589
  };
1473
1590
  c3_chart_internal_fn.getEdgeX = function (targets) {
1474
- var target = this.getMaxDataCountTarget(targets), firstData, lastData;
1475
- if (!target) {
1476
- return [0, 0];
1477
- }
1478
- firstData = target.values[0], lastData = target.values[target.values.length - 1];
1479
- return [firstData.x, lastData.x];
1591
+ var $$ = this;
1592
+ return !targets.length ? [0, 0] : [
1593
+ $$.d3.min(targets, function (t) { return t.values[0].x; }),
1594
+ $$.d3.max(targets, function (t) { return t.values[t.values.length - 1].x; })
1595
+ ];
1480
1596
  };
1481
1597
  c3_chart_internal_fn.mapToIds = function (targets) {
1482
1598
  return targets.map(function (d) { return d.id; });
@@ -1506,8 +1622,8 @@
1506
1622
  };
1507
1623
  c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
1508
1624
  var $$ = this;
1509
- var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return v.x; }); }))).values();
1510
- return $$.isTimeSeries() ? xs.map(function (x) { return new Date(x); }) : xs.map(function (x) { return +x; });
1625
+ var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
1626
+ return $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
1511
1627
  };
1512
1628
  c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
1513
1629
  this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
@@ -1551,11 +1667,11 @@
1551
1667
  };
1552
1668
  c3_chart_internal_fn.isOrderDesc = function () {
1553
1669
  var config = this.config;
1554
- return config.data_order && config.data_order.toLowerCase() === 'desc';
1670
+ return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'desc';
1555
1671
  };
1556
1672
  c3_chart_internal_fn.isOrderAsc = function () {
1557
1673
  var config = this.config;
1558
- return config.data_order && config.data_order.toLowerCase() === 'asc';
1674
+ return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'asc';
1559
1675
  };
1560
1676
  c3_chart_internal_fn.orderTargets = function (targets) {
1561
1677
  var $$ = this, config = $$.config, orderAsc = $$.isOrderAsc(), orderDesc = $$.isOrderDesc();
@@ -1571,12 +1687,23 @@
1571
1687
  } // TODO: accept name array for order
1572
1688
  return targets;
1573
1689
  };
1574
- c3_chart_internal_fn.filterSameX = function (targets, x) {
1690
+ c3_chart_internal_fn.filterByX = function (targets, x) {
1575
1691
  return this.d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
1576
1692
  };
1577
1693
  c3_chart_internal_fn.filterRemoveNull = function (data) {
1578
1694
  return data.filter(function (d) { return isValue(d.value); });
1579
1695
  };
1696
+ c3_chart_internal_fn.filterByXDomain = function (targets, xDomain) {
1697
+ return targets.map(function (t) {
1698
+ return {
1699
+ id: t.id,
1700
+ id_org: t.id_org,
1701
+ values: t.values.filter(function (v) {
1702
+ return xDomain[0] <= v.x && v.x <= xDomain[1];
1703
+ })
1704
+ };
1705
+ });
1706
+ };
1580
1707
  c3_chart_internal_fn.hasDataLabel = function () {
1581
1708
  var config = this.config;
1582
1709
  if (typeof config.data_labels === 'boolean' && config.data_labels) {
@@ -1618,56 +1745,37 @@
1618
1745
  return sames;
1619
1746
  };
1620
1747
 
1621
- c3_chart_internal_fn.findClosestOfValues = function (values, pos, _min, _max) { // MEMO: values must be sorted by x
1622
- var $$ = this,
1623
- min = _min ? _min : 0,
1624
- max = _max ? _max : values.length - 1,
1625
- med = Math.floor((max - min) / 2) + min,
1626
- value = values[med],
1627
- diff = $$.x(value.x) - pos[$$.config.axis_rotated ? 1 : 0],
1628
- candidates;
1629
-
1630
- // Update range for search
1631
- diff > 0 ? max = med : min = med;
1632
-
1633
- // if candidates are two closest min and max, stop recursive call
1634
- if ((max - min) === 1 || (min === 0 && max === 0)) {
1635
-
1636
- // Get candidates that has same min and max index
1637
- candidates = [];
1638
- if (values[min].x || values[min].x === 0) {
1639
- candidates = candidates.concat($$.findSameXOfValues(values, min));
1640
- }
1641
- if (values[max].x || values[max].x === 0) {
1642
- candidates = candidates.concat($$.findSameXOfValues(values, max));
1643
- }
1644
-
1645
- // Determine the closest and return
1646
- return $$.findClosest(candidates, pos);
1647
- }
1648
-
1649
- return $$.findClosestOfValues(values, pos, min, max);
1650
- };
1651
1748
  c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
1652
1749
  var $$ = this, candidates;
1653
1750
 
1654
1751
  // map to array of closest points of each target
1655
1752
  candidates = targets.map(function (target) {
1656
- return $$.findClosestOfValues(target.values, pos);
1753
+ return $$.findClosest(target.values, pos);
1657
1754
  });
1658
1755
 
1659
1756
  // decide closest point and return
1660
1757
  return $$.findClosest(candidates, pos);
1661
1758
  };
1662
1759
  c3_chart_internal_fn.findClosest = function (values, pos) {
1663
- var $$ = this, minDist, closest;
1664
- values.forEach(function (v) {
1760
+ var $$ = this, minDist = 100, closest;
1761
+
1762
+ // find mouseovering bar
1763
+ values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
1764
+ var shape = $$.d3.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
1765
+ if ($$.isWithinBar(shape)) {
1766
+ closest = v;
1767
+ }
1768
+ });
1769
+
1770
+ // find closest point from non-bar
1771
+ values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
1665
1772
  var d = $$.dist(v, pos);
1666
- if (d < minDist || ! minDist) {
1773
+ if (d < minDist) {
1667
1774
  minDist = d;
1668
1775
  closest = v;
1669
1776
  }
1670
1777
  });
1778
+
1671
1779
  return closest;
1672
1780
  };
1673
1781
  c3_chart_internal_fn.dist = function (data, pos) {
@@ -1677,6 +1785,39 @@
1677
1785
  yIndex = config.axis_rotated ? 0 : 1;
1678
1786
  return Math.pow($$.x(data.x) - pos[xIndex], 2) + Math.pow(yScale(data.value) - pos[yIndex], 2);
1679
1787
  };
1788
+ c3_chart_internal_fn.convertValuesToStep = function (values) {
1789
+ var converted = [].concat(values), i;
1790
+
1791
+ if (!this.isCategorized()) {
1792
+ return values;
1793
+ }
1794
+
1795
+ for (i = values.length + 1; 0 < i; i--) {
1796
+ converted[i] = converted[i - 1];
1797
+ }
1798
+
1799
+ converted[0] = {
1800
+ x: converted[0].x - 1,
1801
+ value: converted[0].value,
1802
+ id: converted[0].id
1803
+ };
1804
+ converted[values.length + 1] = {
1805
+ x: converted[values.length].x + 1,
1806
+ value: converted[values.length].value,
1807
+ id: converted[values.length].id
1808
+ };
1809
+
1810
+ return converted;
1811
+ };
1812
+ c3_chart_internal_fn.updateDataAttributes = function (name, attrs) {
1813
+ var $$ = this, config = $$.config, current = config['data_' + name];
1814
+ if (typeof attrs === 'undefined') { return current; }
1815
+ Object.keys(attrs).forEach(function (id) {
1816
+ current[id] = attrs[id];
1817
+ });
1818
+ $$.redraw({withLegend: true});
1819
+ return current;
1820
+ };
1680
1821
 
1681
1822
  c3_chart_internal_fn.convertUrlToData = function (url, mimeType, keys, done) {
1682
1823
  var $$ = this, type = mimeType ? mimeType : 'csv';
@@ -1684,24 +1825,32 @@
1684
1825
  var d;
1685
1826
  if (type === 'json') {
1686
1827
  d = $$.convertJsonToData(JSON.parse(data.response), keys);
1828
+ } else if (type === 'tsv') {
1829
+ d = $$.convertTsvToData(data.response);
1687
1830
  } else {
1688
1831
  d = $$.convertCsvToData(data.response);
1689
1832
  }
1690
1833
  done.call($$, d);
1691
1834
  });
1692
1835
  };
1693
- c3_chart_internal_fn.convertCsvToData = function (csv) {
1694
- var d3 = this.d3, rows = d3.csv.parseRows(csv), d;
1836
+ c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
1837
+ var rows = parser.parseRows(xsv), d;
1695
1838
  if (rows.length === 1) {
1696
1839
  d = [{}];
1697
1840
  rows[0].forEach(function (id) {
1698
1841
  d[0][id] = null;
1699
1842
  });
1700
1843
  } else {
1701
- d = d3.csv.parse(csv);
1844
+ d = parser.parse(xsv);
1702
1845
  }
1703
1846
  return d;
1704
1847
  };
1848
+ c3_chart_internal_fn.convertCsvToData = function (csv) {
1849
+ return this.convertXsvToData(csv, this.d3.csv);
1850
+ };
1851
+ c3_chart_internal_fn.convertTsvToData = function (tsv) {
1852
+ return this.convertXsvToData(tsv, this.d3.tsv);
1853
+ };
1705
1854
  c3_chart_internal_fn.convertJsonToData = function (json, keys) {
1706
1855
  var $$ = this,
1707
1856
  new_rows = [], targetKeys, data;
@@ -1827,11 +1976,13 @@
1827
1976
  targets.forEach(function (t) {
1828
1977
  var i;
1829
1978
  // sort values by its x
1830
- t.values = t.values.sort(function (v1, v2) {
1831
- var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
1832
- x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
1833
- return x1 - x2;
1834
- });
1979
+ if (config.data_xSort) {
1980
+ t.values = t.values.sort(function (v1, v2) {
1981
+ var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
1982
+ x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
1983
+ return x1 - x2;
1984
+ });
1985
+ }
1835
1986
  // indexing each value
1836
1987
  i = 0;
1837
1988
  t.values.forEach(function (v) {
@@ -2011,13 +2162,30 @@
2011
2162
  else {
2012
2163
  if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
2013
2164
  rectW = function (d) {
2014
- var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index), dx = $$.data.xs[d.id][d.index],
2015
- w = ($$.x(nextX ? nextX : dx) - $$.x(prevX ? prevX : dx)) / 2;
2016
- return w < 0 ? 0 : w;
2165
+ var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
2166
+
2167
+ // if there this is a single data point make the eventRect full width (or height)
2168
+ if (prevX === null && nextX === null) {
2169
+ return config.axis_rotated ? $$.height : $$.width;
2170
+ }
2171
+
2172
+ if (prevX === null) { prevX = $$.x.domain()[0]; }
2173
+ if (nextX === null) { nextX = $$.x.domain()[1]; }
2174
+
2175
+ return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
2017
2176
  };
2018
2177
  rectX = function (d) {
2019
- var prevX = $$.getPrevX(d.index), dx = $$.data.xs[d.id][d.index];
2020
- return ($$.x(dx) + $$.x(prevX ? prevX : dx)) / 2;
2178
+ var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
2179
+ thisX = $$.data.xs[d.id][d.index];
2180
+
2181
+ // if there this is a single data point position the eventRect at 0
2182
+ if (prevX === null && nextX === null) {
2183
+ return 0;
2184
+ }
2185
+
2186
+ if (prevX === null) { prevX = $$.x.domain()[0]; }
2187
+
2188
+ return ($$.x(thisX) + $$.x(prevX)) / 2;
2021
2189
  };
2022
2190
  } else {
2023
2191
  rectW = $$.getEventRectWidth();
@@ -2046,7 +2214,7 @@
2046
2214
  .on('mouseover', function (d) {
2047
2215
  var index = d.index, selectedData, newData;
2048
2216
 
2049
- if ($$.dragging) { return; } // do nothing if dragging
2217
+ if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
2050
2218
  if ($$.hasArcType()) { return; }
2051
2219
 
2052
2220
  selectedData = $$.data.targets.map(function (t) {
@@ -2067,8 +2235,8 @@
2067
2235
  selectedData = newData.concat(selectedData); // Add remained
2068
2236
 
2069
2237
  // Expand shapes for selection
2070
- if (config.point_focus_expand_enabled) { $$.expandCircles(index); }
2071
- $$.expandBars(index);
2238
+ if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
2239
+ $$.expandBars(index, null, true);
2072
2240
 
2073
2241
  // Call event handler
2074
2242
  $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
@@ -2081,7 +2249,7 @@
2081
2249
  $$.hideXGridFocus();
2082
2250
  $$.hideTooltip();
2083
2251
  // Undo expanded shapes
2084
- $$.unexpandCircles(index);
2252
+ $$.unexpandCircles();
2085
2253
  $$.unexpandBars();
2086
2254
  // Call event handler
2087
2255
  $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
@@ -2092,9 +2260,13 @@
2092
2260
  var selectedData, index = d.index,
2093
2261
  eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
2094
2262
 
2095
- if ($$.dragging) { return; } // do nothing when dragging
2263
+ if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
2096
2264
  if ($$.hasArcType()) { return; }
2097
2265
 
2266
+ if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
2267
+ index -= 1;
2268
+ }
2269
+
2098
2270
  // Show tooltip
2099
2271
  selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
2100
2272
  return $$.addName($$.getValueOnIndex(t.values, index));
@@ -2120,17 +2292,12 @@
2120
2292
  $$.hideTooltip();
2121
2293
  if (!config.data_selection_grouped) {
2122
2294
  $$.unexpandCircles(index);
2123
- $$.unexpandBars();
2295
+ $$.unexpandBars(index);
2124
2296
  }
2125
2297
  }
2126
2298
  })
2127
2299
  .filter(function (d) {
2128
- if (this.nodeName === 'circle') {
2129
- return $$.isWithinCircle(this, $$.pointSelectR(d));
2130
- }
2131
- else if (this.nodeName === 'path') {
2132
- return $$.isWithinBar(this);
2133
- }
2300
+ return $$.isWithinShape(this, d);
2134
2301
  })
2135
2302
  .each(function (d) {
2136
2303
  if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
@@ -2139,8 +2306,8 @@
2139
2306
  if (!config.tooltip_grouped) {
2140
2307
  $$.showTooltip([d], d3.mouse(this));
2141
2308
  $$.showXGridFocus([d]);
2142
- if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id); }
2143
- $$.expandBars(index, d.id);
2309
+ if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
2310
+ $$.expandBars(index, d.id, true);
2144
2311
  }
2145
2312
  });
2146
2313
  })
@@ -2151,8 +2318,14 @@
2151
2318
  $$.cancelClick = false;
2152
2319
  return;
2153
2320
  }
2321
+ if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
2322
+ index -= 1;
2323
+ }
2154
2324
  $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
2155
- $$.toggleShape(this, d, index);
2325
+ if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
2326
+ $$.toggleShape(this, d, index);
2327
+ $$.config.data_onclick.call($$.api, d, this);
2328
+ }
2156
2329
  });
2157
2330
  })
2158
2331
  .call(
@@ -2160,12 +2333,20 @@
2160
2333
  .on('drag', function () { $$.drag(d3.mouse(this)); })
2161
2334
  .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2162
2335
  .on('dragend', function () { $$.dragend(); })
2163
- )
2164
- .on("dblclick.zoom", null);
2336
+ );
2165
2337
  };
2166
2338
 
2167
2339
  c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
2168
2340
  var $$ = this, d3 = $$.d3, config = $$.config;
2341
+
2342
+ function mouseout() {
2343
+ $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
2344
+ $$.hideXGridFocus();
2345
+ $$.hideTooltip();
2346
+ $$.unexpandCircles();
2347
+ $$.unexpandBars();
2348
+ }
2349
+
2169
2350
  eventRectEnter.append('rect')
2170
2351
  .attr('x', 0)
2171
2352
  .attr('y', 0)
@@ -2174,9 +2355,7 @@
2174
2355
  .attr('class', CLASS.eventRect)
2175
2356
  .on('mouseout', function () {
2176
2357
  if ($$.hasArcType()) { return; }
2177
- $$.hideXGridFocus();
2178
- $$.hideTooltip();
2179
- $$.unexpandCircles();
2358
+ mouseout();
2180
2359
  })
2181
2360
  .on('mousemove', function () {
2182
2361
  var targetsToShow = $$.filterTargetsToShow($$.data.targets);
@@ -2188,12 +2367,20 @@
2188
2367
  mouse = d3.mouse(this);
2189
2368
  closest = $$.findClosestFromTargets(targetsToShow, mouse);
2190
2369
 
2191
- if (! closest) { return; }
2370
+ if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
2371
+ config.data_onmouseout.call($$, $$.mouseover);
2372
+ $$.mouseover = undefined;
2373
+ }
2192
2374
 
2193
- if ($$.isScatterType(closest)) {
2375
+ if (! closest) {
2376
+ mouseout();
2377
+ return;
2378
+ }
2379
+
2380
+ if ($$.isScatterType(closest) || !config.tooltip_grouped) {
2194
2381
  sameXData = [closest];
2195
2382
  } else {
2196
- sameXData = $$.filterSameX(targetsToShow, closest.x);
2383
+ sameXData = $$.filterByX(targetsToShow, closest.x);
2197
2384
  }
2198
2385
 
2199
2386
  // show tooltip when cursor is close to some point
@@ -2204,24 +2391,20 @@
2204
2391
 
2205
2392
  // expand points
2206
2393
  if (config.point_focus_expand_enabled) {
2207
- $$.unexpandCircles();
2208
- $$.expandCircles(closest.index, closest.id);
2394
+ $$.expandCircles(closest.index, closest.id, true);
2209
2395
  }
2396
+ $$.expandBars(closest.index, closest.id, true);
2210
2397
 
2211
2398
  // Show xgrid focus line
2212
2399
  $$.showXGridFocus(selectedData);
2213
2400
 
2214
2401
  // Show cursor as pointer if point is close to mouse position
2215
- if ($$.dist(closest, mouse) < 100) {
2402
+ if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
2216
2403
  $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
2217
2404
  if (!$$.mouseover) {
2218
2405
  config.data_onmouseover.call($$, closest);
2219
- $$.mouseover = true;
2406
+ $$.mouseover = closest;
2220
2407
  }
2221
- } else if ($$.mouseover) {
2222
- $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
2223
- config.data_onmouseout.call($$, closest);
2224
- $$.mouseover = false;
2225
2408
  }
2226
2409
  })
2227
2410
  .on('click', function () {
@@ -2236,9 +2419,12 @@
2236
2419
  if (! closest) { return; }
2237
2420
 
2238
2421
  // select if selection enabled
2239
- if ($$.dist(closest, mouse) < 100 && $$.toggleShape) {
2240
- $$.main.select('.' + CLASS.circles + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.circle + '-' + closest.index).each(function () {
2241
- $$.toggleShape(this, closest, closest.index);
2422
+ if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
2423
+ $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
2424
+ if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
2425
+ $$.toggleShape(this, closest, closest.index);
2426
+ $$.config.data_onclick.call($$.api, closest, this);
2427
+ }
2242
2428
  });
2243
2429
  }
2244
2430
  })
@@ -2247,8 +2433,20 @@
2247
2433
  .on('drag', function () { $$.drag(d3.mouse(this)); })
2248
2434
  .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2249
2435
  .on('dragend', function () { $$.dragend(); })
2250
- )
2251
- .on("dblclick.zoom", null);
2436
+ );
2437
+ };
2438
+ c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
2439
+ var $$ = this,
2440
+ selector = '.' + CLASS.eventRect + (!$$.isMultipleX() ? '-' + index : ''),
2441
+ eventRect = $$.main.select(selector).node(),
2442
+ box = eventRect.getBoundingClientRect(),
2443
+ x = box.left + (mouse ? mouse[0] : 0),
2444
+ y = box.top + (mouse ? mouse[1] : 0),
2445
+ event = document.createEvent("MouseEvents");
2446
+
2447
+ event.initMouseEvent(type, true, true, window, 0, x, y, x, y,
2448
+ false, false, false, false, 0, null);
2449
+ eventRect.dispatchEvent(event);
2252
2450
  };
2253
2451
 
2254
2452
  c3_chart_internal_fn.getCurrentWidth = function () {
@@ -2258,7 +2456,7 @@
2258
2456
  c3_chart_internal_fn.getCurrentHeight = function () {
2259
2457
  var $$ = this, config = $$.config,
2260
2458
  h = config.size_height ? config.size_height : $$.getParentHeight();
2261
- return h > 0 ? h : 320;
2459
+ return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
2262
2460
  };
2263
2461
  c3_chart_internal_fn.getCurrentPaddingTop = function () {
2264
2462
  var config = this.config;
@@ -2268,14 +2466,14 @@
2268
2466
  var config = this.config;
2269
2467
  return isValue(config.padding_bottom) ? config.padding_bottom : 0;
2270
2468
  };
2271
- c3_chart_internal_fn.getCurrentPaddingLeft = function () {
2469
+ c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
2272
2470
  var $$ = this, config = $$.config;
2273
2471
  if (isValue(config.padding_left)) {
2274
2472
  return config.padding_left;
2275
2473
  } else if (config.axis_rotated) {
2276
- return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x')), 40);
2474
+ return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
2277
2475
  } else {
2278
- return !config.axis_y_show ? 1 : ceil10($$.getAxisWidthByAxisId('y'));
2476
+ return !config.axis_y_show ? 1 : ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
2279
2477
  }
2280
2478
  };
2281
2479
  c3_chart_internal_fn.getCurrentPaddingRight = function () {
@@ -2310,29 +2508,33 @@
2310
2508
  };
2311
2509
 
2312
2510
 
2313
- c3_chart_internal_fn.getSvgLeft = function () {
2511
+ c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
2314
2512
  var $$ = this, config = $$.config,
2315
2513
  leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
2316
2514
  leftAxis = $$.main.select('.' + leftAxisClass).node(),
2317
2515
  svgRect = leftAxis ? leftAxis.getBoundingClientRect() : {right: 0},
2318
2516
  chartRect = $$.selectChart.node().getBoundingClientRect(),
2319
2517
  hasArc = $$.hasArcType(),
2320
- svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft());
2518
+ svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
2321
2519
  return svgLeft > 0 ? svgLeft : 0;
2322
2520
  };
2323
2521
 
2324
2522
 
2325
- c3_chart_internal_fn.getAxisWidthByAxisId = function (id) {
2523
+ c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
2326
2524
  var $$ = this, position = $$.getAxisLabelPositionById(id);
2327
- return position.isInner ? 20 + $$.getMaxTickWidth(id) : 40 + $$.getMaxTickWidth(id);
2525
+ return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
2328
2526
  };
2329
2527
  c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
2330
- var $$ = this, config = $$.config;
2331
- if (axisId === 'x' && !config.axis_x_show) { return 0; }
2528
+ var $$ = this, config = $$.config, h = 30;
2529
+ if (axisId === 'x' && !config.axis_x_show) { return 8; }
2332
2530
  if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
2333
2531
  if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
2334
2532
  if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
2335
- return ($$.getAxisLabelPositionById(axisId).isInner ? 30 : 40) + (axisId === 'y2' ? -10 : 0);
2533
+ // Calculate x axis height when tick rotated
2534
+ if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
2535
+ h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
2536
+ }
2537
+ return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
2336
2538
  };
2337
2539
 
2338
2540
  c3_chart_internal_fn.getEventRectWidth = function () {
@@ -2393,18 +2595,36 @@
2393
2595
  var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
2394
2596
  y0 = scale(0), offset = y0;
2395
2597
  targets.forEach(function (t) {
2598
+ var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
2396
2599
  if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
2397
- if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id) && t.values[i].value * d.value >= 0) {
2398
- offset += scale(t.values[i].value) - y0;
2600
+ if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
2601
+ if (values[i].value * d.value >= 0) {
2602
+ offset += scale(values[i].value) - y0;
2603
+ }
2399
2604
  }
2400
2605
  });
2401
2606
  return offset;
2402
2607
  };
2403
2608
  };
2609
+ c3_chart_internal_fn.isWithinShape = function (that, d) {
2610
+ var $$ = this,
2611
+ shape = $$.d3.select(that), isWithin;
2612
+ if (!$$.isTargetToShow(d.id)) {
2613
+ isWithin = false;
2614
+ }
2615
+ else if (that.nodeName === 'circle') {
2616
+ isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
2617
+ }
2618
+ else if (that.nodeName === 'path') {
2619
+ isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true;
2620
+ }
2621
+ return isWithin;
2622
+ };
2623
+
2404
2624
 
2405
2625
  c3_chart_internal_fn.getInterpolate = function (d) {
2406
2626
  var $$ = this;
2407
- return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? "step-after" : "linear";
2627
+ return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? $$.config.line_step_type : "linear";
2408
2628
  };
2409
2629
 
2410
2630
  c3_chart_internal_fn.initLine = function () {
@@ -2418,10 +2638,11 @@
2418
2638
  classChartLine = $$.classChartLine.bind($$),
2419
2639
  classLines = $$.classLines.bind($$),
2420
2640
  classAreas = $$.classAreas.bind($$),
2421
- classCircles = $$.classCircles.bind($$);
2641
+ classCircles = $$.classCircles.bind($$),
2642
+ classFocus = $$.classFocus.bind($$);
2422
2643
  mainLineUpdate = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
2423
2644
  .data(targets)
2424
- .attr('class', classChartLine);
2645
+ .attr('class', function (d) { return classChartLine(d) + classFocus(d); });
2425
2646
  mainLineEnter = mainLineUpdate.enter().append('g')
2426
2647
  .attr('class', classChartLine)
2427
2648
  .style('opacity', 0)
@@ -2456,6 +2677,7 @@
2456
2677
  .style("stroke", $$.color);
2457
2678
  $$.mainLine
2458
2679
  .style("opacity", $$.initialOpacity.bind($$))
2680
+ .style('shape-rendering', function (d) { return $$.isStepType(d) ? 'crispEdges' : ''; })
2459
2681
  .attr('transform', null);
2460
2682
  $$.mainLine.exit().transition().duration(durationForExit)
2461
2683
  .style('opacity', 0)
@@ -2471,35 +2693,36 @@
2471
2693
  c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
2472
2694
  var $$ = this, config = $$.config,
2473
2695
  line = $$.d3.svg.line(),
2474
- getPoint = $$.generateGetLinePoint(lineIndices, isSub),
2696
+ getPoints = $$.generateGetLinePoints(lineIndices, isSub),
2475
2697
  yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
2476
2698
  xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
2477
2699
  yValue = function (d, i) {
2478
- return config.data_groups.length > 0 ? getPoint(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
2700
+ return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
2479
2701
  };
2480
2702
 
2481
2703
  line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
2482
- if (!config.line_connect_null) { line = line.defined(function (d) { return d.value != null; }); }
2704
+ if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); }
2483
2705
  return function (d) {
2484
- var data = config.line_connect_null ? $$.filterRemoveNull(d.values) : d.values,
2706
+ var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
2485
2707
  x = isSub ? $$.x : $$.subX, y = yScaleGetter.call($$, d.id), x0 = 0, y0 = 0, path;
2486
2708
  if ($$.isLineType(d)) {
2487
2709
  if (config.data_regions[d.id]) {
2488
- path = $$.lineWithRegions(data, x, y, config.data_regions[d.id]);
2710
+ path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
2489
2711
  } else {
2490
- path = line.interpolate($$.getInterpolate(d))(data);
2712
+ if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
2713
+ path = line.interpolate($$.getInterpolate(d))(values);
2491
2714
  }
2492
2715
  } else {
2493
- if (data[0]) {
2494
- x0 = x(data[0].x);
2495
- y0 = y(data[0].value);
2716
+ if (values[0]) {
2717
+ x0 = x(values[0].x);
2718
+ y0 = y(values[0].value);
2496
2719
  }
2497
2720
  path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
2498
2721
  }
2499
2722
  return path ? path : "M 0 0";
2500
2723
  };
2501
2724
  };
2502
- c3_chart_internal_fn.generateGetLinePoint = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
2725
+ c3_chart_internal_fn.generateGetLinePoints = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
2503
2726
  var $$ = this, config = $$.config,
2504
2727
  lineTargetsNum = lineIndices.__max__ + 1,
2505
2728
  x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
@@ -2516,7 +2739,10 @@
2516
2739
  }
2517
2740
  // 1 point that marks the line position
2518
2741
  return [
2519
- [posX, posY - (y0 - offset)]
2742
+ [posX, posY - (y0 - offset)],
2743
+ [posX, posY - (y0 - offset)], // needed for compatibility
2744
+ [posX, posY - (y0 - offset)], // needed for compatibility
2745
+ [posX, posY - (y0 - offset)] // needed for compatibility
2520
2746
  ];
2521
2747
  };
2522
2748
  };
@@ -2625,29 +2851,31 @@
2625
2851
  };
2626
2852
  c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
2627
2853
  var $$ = this, config = $$.config, area = $$.d3.svg.area(),
2628
- getPoint = $$.generateGetAreaPoint(areaIndices, isSub),
2854
+ getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
2629
2855
  yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
2630
2856
  xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
2631
2857
  value0 = function (d, i) {
2632
- return config.data_groups.length > 0 ? getPoint(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
2858
+ return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
2633
2859
  },
2634
2860
  value1 = function (d, i) {
2635
- return config.data_groups.length > 0 ? getPoint(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
2861
+ return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
2636
2862
  };
2637
2863
 
2638
2864
  area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
2639
- if (!config.line_connect_null) {
2865
+ if (!config.line_connectNull) {
2640
2866
  area = area.defined(function (d) { return d.value !== null; });
2641
2867
  }
2642
2868
 
2643
2869
  return function (d) {
2644
- var data = config.line_connect_null ? $$.filterRemoveNull(d.values) : d.values, x0 = 0, y0 = 0, path;
2870
+ var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
2871
+ x0 = 0, y0 = 0, path;
2645
2872
  if ($$.isAreaType(d)) {
2646
- path = area.interpolate($$.getInterpolate(d))(data);
2873
+ if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
2874
+ path = area.interpolate($$.getInterpolate(d))(values);
2647
2875
  } else {
2648
- if (data[0]) {
2649
- x0 = $$.x(data[0].x);
2650
- y0 = $$.getYScale(d.id)(data[0].value);
2876
+ if (values[0]) {
2877
+ x0 = $$.x(values[0].x);
2878
+ y0 = $$.getYScale(d.id)(values[0].value);
2651
2879
  }
2652
2880
  path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
2653
2881
  }
@@ -2655,7 +2883,7 @@
2655
2883
  };
2656
2884
  };
2657
2885
 
2658
- c3_chart_internal_fn.generateGetAreaPoint = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
2886
+ c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
2659
2887
  var $$ = this, config = $$.config,
2660
2888
  areaTargetsNum = areaIndices.__max__ + 1,
2661
2889
  x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
@@ -2673,7 +2901,9 @@
2673
2901
  // 1 point that marks the area position
2674
2902
  return [
2675
2903
  [posX, offset],
2676
- [posX, posY - (y0 - offset)]
2904
+ [posX, posY - (y0 - offset)],
2905
+ [posX, posY - (y0 - offset)], // needed for compatibility
2906
+ [posX, offset] // needed for compatibility
2677
2907
  ];
2678
2908
  };
2679
2909
  };
@@ -2688,7 +2918,7 @@
2688
2918
  .attr("r", $$.pointR.bind($$))
2689
2919
  .style("fill", $$.color);
2690
2920
  $$.mainCircle
2691
- .style("opacity", $$.initialOpacity.bind($$));
2921
+ .style("opacity", $$.initialOpacityForCircle.bind($$));
2692
2922
  $$.mainCircle.exit().remove();
2693
2923
  };
2694
2924
  c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
@@ -2705,18 +2935,28 @@
2705
2935
  c3_chart_internal_fn.circleX = function (d) {
2706
2936
  return d.x || d.x === 0 ? this.x(d.x) : null;
2707
2937
  };
2708
- c3_chart_internal_fn.circleY = function (d, i) {
2709
- var $$ = this,
2710
- lineIndices = $$.getShapeIndices($$.isLineType), getPoint = $$.generateGetLinePoint(lineIndices);
2711
- return $$.config.data_groups.length > 0 ? getPoint(d, i)[0][1] : $$.getYScale(d.id)(d.value);
2938
+ c3_chart_internal_fn.generateCircleY = function () {
2939
+ var $$ = this, lineIndices, getPoints;
2940
+ if ($$.config.data_groups.length > 0) {
2941
+ lineIndices = $$.getShapeIndices($$.isLineType),
2942
+ getPoints = $$.generateGetLinePoints(lineIndices);
2943
+ return function (d, i) {
2944
+ return getPoints(d, i)[0][1];
2945
+ };
2946
+ } else {
2947
+ return function (d) {
2948
+ return $$.getYScale(d.id)(d.value);
2949
+ };
2950
+ }
2712
2951
  };
2713
2952
  c3_chart_internal_fn.getCircles = function (i, id) {
2714
2953
  var $$ = this;
2715
2954
  return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
2716
2955
  };
2717
- c3_chart_internal_fn.expandCircles = function (i, id) {
2956
+ c3_chart_internal_fn.expandCircles = function (i, id, reset) {
2718
2957
  var $$ = this,
2719
2958
  r = $$.pointExpandedR.bind($$);
2959
+ if (reset) { $$.unexpandCircles(); }
2720
2960
  $$.getCircles(i, id)
2721
2961
  .classed(CLASS.EXPANDED, true)
2722
2962
  .attr('r', r);
@@ -2731,7 +2971,7 @@
2731
2971
  };
2732
2972
  c3_chart_internal_fn.pointR = function (d) {
2733
2973
  var $$ = this, config = $$.config;
2734
- return config.point_show && !$$.isStepType(d) ? (isFunction(config.point_r) ? config.point_r(d) : config.point_r) : 0;
2974
+ return $$.isStepType(d) ? 0 : (isFunction(config.point_r) ? config.point_r(d) : config.point_r);
2735
2975
  };
2736
2976
  c3_chart_internal_fn.pointExpandedR = function (d) {
2737
2977
  var $$ = this, config = $$.config;
@@ -2741,11 +2981,14 @@
2741
2981
  var $$ = this, config = $$.config;
2742
2982
  return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
2743
2983
  };
2744
- c3_chart_internal_fn.isWithinCircle = function (_this, _r) {
2984
+ c3_chart_internal_fn.isWithinCircle = function (that, r) {
2745
2985
  var d3 = this.d3,
2746
- mouse = d3.mouse(_this), d3_this = d3.select(_this),
2747
- cx = d3_this.attr("cx") * 1, cy = d3_this.attr("cy") * 1;
2748
- return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < _r;
2986
+ mouse = d3.mouse(that), d3_this = d3.select(that),
2987
+ cx = +d3_this.attr("cx"), cy = +d3_this.attr("cy");
2988
+ return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
2989
+ };
2990
+ c3_chart_internal_fn.isWithinStep = function (that, y) {
2991
+ return Math.abs(y - this.d3.mouse(that)[1]) < 30;
2749
2992
  };
2750
2993
 
2751
2994
  c3_chart_internal_fn.initBar = function () {
@@ -2757,10 +3000,11 @@
2757
3000
  var $$ = this, config = $$.config,
2758
3001
  mainBarUpdate, mainBarEnter,
2759
3002
  classChartBar = $$.classChartBar.bind($$),
2760
- classBars = $$.classBars.bind($$);
3003
+ classBars = $$.classBars.bind($$),
3004
+ classFocus = $$.classFocus.bind($$);
2761
3005
  mainBarUpdate = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
2762
3006
  .data(targets)
2763
- .attr('class', classChartBar);
3007
+ .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
2764
3008
  mainBarEnter = mainBarUpdate.enter().append('g')
2765
3009
  .attr('class', classChartBar)
2766
3010
  .style('opacity', 0)
@@ -2801,13 +3045,14 @@
2801
3045
  w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
2802
3046
  return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
2803
3047
  };
2804
- c3_chart_internal_fn.getBars = function (i) {
3048
+ c3_chart_internal_fn.getBars = function (i, id) {
2805
3049
  var $$ = this;
2806
- return $$.main.selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
3050
+ return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
2807
3051
  };
2808
- c3_chart_internal_fn.expandBars = function (i) {
3052
+ c3_chart_internal_fn.expandBars = function (i, id, reset) {
2809
3053
  var $$ = this;
2810
- $$.getBars(i).classed(CLASS.EXPANDED, true);
3054
+ if (reset) { $$.unexpandBars(); }
3055
+ $$.getBars(i, id).classed(CLASS.EXPANDED, true);
2811
3056
  };
2812
3057
  c3_chart_internal_fn.unexpandBars = function (i) {
2813
3058
  var $$ = this;
@@ -2835,8 +3080,9 @@
2835
3080
  };
2836
3081
  c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
2837
3082
  var $$ = this,
3083
+ axis = isSub ? $$.subXAxis : $$.xAxis,
2838
3084
  barTargetsNum = barIndices.__max__ + 1,
2839
- barW = $$.getBarW($$.xAxis, barTargetsNum),
3085
+ barW = $$.getBarW(axis, barTargetsNum),
2840
3086
  barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
2841
3087
  barY = $$.getShapeY(!!isSub),
2842
3088
  barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
@@ -2858,11 +3104,11 @@
2858
3104
  ];
2859
3105
  };
2860
3106
  };
2861
- c3_chart_internal_fn.isWithinBar = function (_this) {
2862
- var d3 = this.d3,
2863
- mouse = d3.mouse(_this), box = _this.getBoundingClientRect(),
2864
- seg0 = _this.pathSegList.getItem(0), seg1 = _this.pathSegList.getItem(1),
2865
- x = seg0.x, y = Math.min(seg0.y, seg1.y), w = box.width, h = box.height, offset = 2,
3107
+ c3_chart_internal_fn.isWithinBar = function (that) {
3108
+ var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
3109
+ seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
3110
+ x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
3111
+ w = box.width, h = box.height, offset = 2,
2866
3112
  sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
2867
3113
  return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
2868
3114
  };
@@ -2876,10 +3122,11 @@
2876
3122
  c3_chart_internal_fn.updateTargetsForText = function (targets) {
2877
3123
  var $$ = this, mainTextUpdate, mainTextEnter,
2878
3124
  classChartText = $$.classChartText.bind($$),
2879
- classTexts = $$.classTexts.bind($$);
3125
+ classTexts = $$.classTexts.bind($$),
3126
+ classFocus = $$.classFocus.bind($$);
2880
3127
  mainTextUpdate = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
2881
3128
  .data(targets)
2882
- .attr('class', classChartText);
3129
+ .attr('class', function (d) { return classChartText(d) + classFocus(d); });
2883
3130
  mainTextEnter = mainTextUpdate.enter().append('g')
2884
3131
  .attr('class', classChartText)
2885
3132
  .style('opacity', 0)
@@ -2900,7 +3147,7 @@
2900
3147
  .style("fill", function (d) { return $$.color(d); })
2901
3148
  .style("fill-opacity", 0);
2902
3149
  $$.mainText
2903
- .text(function (d) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id); });
3150
+ .text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
2904
3151
  $$.mainText.exit()
2905
3152
  .transition().duration(durationForExit)
2906
3153
  .style('fill-opacity', 0)
@@ -2916,21 +3163,26 @@
2916
3163
  .style("fill-opacity", opacityForText));
2917
3164
  };
2918
3165
  c3_chart_internal_fn.getTextRect = function (text, cls) {
2919
- var rect;
2920
- this.d3.select('body').selectAll('.dummy')
3166
+ var body = this.d3.select('body').classed('c3', true),
3167
+ svg = body.append("svg").style('visibility', 'hidden'), rect;
3168
+ svg.selectAll('.dummy')
2921
3169
  .data([text])
2922
3170
  .enter().append('text')
2923
3171
  .classed(cls ? cls : "", true)
2924
3172
  .text(text)
2925
- .each(function () { rect = this.getBoundingClientRect(); })
2926
- .remove();
3173
+ .each(function () { rect = this.getBoundingClientRect(); });
3174
+ svg.remove();
3175
+ body.classed('c3', false);
2927
3176
  return rect;
2928
3177
  };
2929
- c3_chart_internal_fn.generateXYForText = function (barIndices, forX) {
3178
+ c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
2930
3179
  var $$ = this,
2931
- getPoints = $$.generateGetBarPoints(barIndices, false),
3180
+ getAreaPoints = $$.generateGetAreaPoints(barIndices, false),
3181
+ getBarPoints = $$.generateGetBarPoints(barIndices, false),
3182
+ getLinePoints = $$.generateGetLinePoints(lineIndices, false),
2932
3183
  getter = forX ? $$.getXForText : $$.getYForText;
2933
3184
  return function (d, i) {
3185
+ var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
2934
3186
  return getter.call($$, getPoints(d, i), d, this);
2935
3187
  };
2936
3188
  };
@@ -2943,7 +3195,7 @@
2943
3195
  } else {
2944
3196
  xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
2945
3197
  }
2946
- return xPos > $$.width ? $$.width - box.width : xPos;
3198
+ return d.value !== null ? xPos : xPos > $$.width ? $$.width - box.width : xPos;
2947
3199
  };
2948
3200
  c3_chart_internal_fn.getYForText = function (points, d, textElement) {
2949
3201
  var $$ = this,
@@ -2953,7 +3205,7 @@
2953
3205
  } else {
2954
3206
  yPos = points[2][1] + (d.value < 0 ? box.height : $$.isBarType(d) ? -3 : -6);
2955
3207
  }
2956
- return yPos < box.height ? box.height : yPos;
3208
+ return d.value !== null ? yPos : yPos < box.height ? box.height : yPos;
2957
3209
  };
2958
3210
 
2959
3211
  c3_chart_internal_fn.setTargetType = function (targetIds, type) {
@@ -2968,11 +3220,19 @@
2968
3220
  };
2969
3221
  c3_chart_internal_fn.hasType = function (type, targets) {
2970
3222
  var $$ = this, types = $$.config.data_types, has = false;
2971
- (targets || $$.data.targets).forEach(function (t) {
2972
- if ((types[t.id] && types[t.id].indexOf(type) >= 0) || (!(t.id in types) && type === 'line')) {
2973
- has = true;
2974
- }
2975
- });
3223
+ targets = targets || $$.data.targets;
3224
+ if (targets && targets.length) {
3225
+ targets.forEach(function (target) {
3226
+ var t = types[target.id];
3227
+ if ((t && t.indexOf(type) >= 0) || (!t && type === 'line')) {
3228
+ has = true;
3229
+ }
3230
+ });
3231
+ } else {
3232
+ Object.keys(types).forEach(function (id) {
3233
+ if (types[id] === type) { has = true; }
3234
+ });
3235
+ }
2976
3236
  return has;
2977
3237
  };
2978
3238
  c3_chart_internal_fn.hasArcType = function (targets) {
@@ -3041,7 +3301,7 @@
3041
3301
  c3_chart_internal_fn.initGrid = function () {
3042
3302
  var $$ = this, config = $$.config, d3 = $$.d3;
3043
3303
  $$.grid = $$.main.append('g')
3044
- .attr("clip-path", $$.clipPath)
3304
+ .attr("clip-path", $$.clipPathForGrid)
3045
3305
  .attr('class', CLASS.grid);
3046
3306
  if (config.grid_x_show) {
3047
3307
  $$.grid.append("g").attr("class", CLASS.xgrids);
@@ -3049,8 +3309,6 @@
3049
3309
  if (config.grid_y_show) {
3050
3310
  $$.grid.append('g').attr('class', CLASS.ygrids);
3051
3311
  }
3052
- $$.grid.append('g').attr("class", CLASS.xgridLines);
3053
- $$.grid.append('g').attr('class', CLASS.ygridLines);
3054
3312
  if (config.grid_focus_show) {
3055
3313
  $$.grid.append('g')
3056
3314
  .attr("class", CLASS.xgridFocus)
@@ -3058,9 +3316,17 @@
3058
3316
  .attr('class', CLASS.xgridFocus);
3059
3317
  }
3060
3318
  $$.xgrid = d3.selectAll([]);
3319
+ if (!config.grid_lines_front) { $$.initGridLines(); }
3320
+ };
3321
+ c3_chart_internal_fn.initGridLines = function () {
3322
+ var $$ = this, d3 = $$.d3;
3323
+ $$.gridLines = $$.main.append('g')
3324
+ .attr("clip-path", $$.clipPathForGrid)
3325
+ .attr('class', CLASS.grid + ' ' + CLASS.gridLines);
3326
+ $$.gridLines.append('g').attr("class", CLASS.xgridLines);
3327
+ $$.gridLines.append('g').attr('class', CLASS.ygridLines);
3061
3328
  $$.xgridLines = d3.selectAll([]);
3062
3329
  };
3063
-
3064
3330
  c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
3065
3331
  var $$ = this, config = $$.config, d3 = $$.d3,
3066
3332
  xgridData = $$.generateGridData(config.grid_x_type, $$.x),
@@ -3089,9 +3355,10 @@
3089
3355
  };
3090
3356
 
3091
3357
  c3_chart_internal_fn.updateYGrid = function () {
3092
- var $$ = this, config = $$.config;
3358
+ var $$ = this, config = $$.config,
3359
+ gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
3093
3360
  $$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
3094
- .data($$.y.ticks(config.grid_y_ticks));
3361
+ .data(gridValues);
3095
3362
  $$.ygrid.enter().append('line')
3096
3363
  .attr('class', CLASS.ygrid);
3097
3364
  $$.ygrid.attr("x1", config.axis_rotated ? $$.y : 0)
@@ -3106,6 +3373,10 @@
3106
3373
  c3_chart_internal_fn.redrawGrid = function (duration, withY) {
3107
3374
  var $$ = this, main = $$.main, config = $$.config,
3108
3375
  xgridLine, ygridLine, yv;
3376
+
3377
+ // hide if arc type
3378
+ $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
3379
+
3109
3380
  main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
3110
3381
  if (config.grid_x_show) {
3111
3382
  $$.updateXGrid();
@@ -3114,7 +3385,7 @@
3114
3385
  .data(config.grid_x_lines);
3115
3386
  // enter
3116
3387
  xgridLine = $$.xgridLines.enter().append('g')
3117
- .attr("class", function (d) { return CLASS.xgridLine + (d.class ? ' ' + d.class : ''); });
3388
+ .attr("class", function (d) { return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : ''); });
3118
3389
  xgridLine.append('line')
3119
3390
  .style("opacity", 0);
3120
3391
  xgridLine.append('text')
@@ -3139,7 +3410,7 @@
3139
3410
  .data(config.grid_y_lines);
3140
3411
  // enter
3141
3412
  ygridLine = $$.ygridLines.enter().append('g')
3142
- .attr("class", function (d) { return CLASS.ygridLine + (d.class ? ' ' + d.class : ''); });
3413
+ .attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
3143
3414
  ygridLine.append('line')
3144
3415
  .style("opacity", 0);
3145
3416
  ygridLine.append('text')
@@ -3232,7 +3503,7 @@
3232
3503
  return params ? function (line) {
3233
3504
  var found = false;
3234
3505
  [].concat(params).forEach(function (param) {
3235
- if ((('value' in param && line.value === params.value) || ('class' in param && line.class === params.class))) {
3506
+ if ((('value' in param && line.value === params.value) || ('class' in param && line['class'] === params['class']))) {
3236
3507
  found = true;
3237
3508
  }
3238
3509
  });
@@ -3259,10 +3530,10 @@
3259
3530
  var $$ = this, config = $$.config, i;
3260
3531
  $$.tooltip = $$.selectChart
3261
3532
  .style("position", "relative")
3262
- .append("div")
3533
+ .append("div")
3534
+ .attr('class', CLASS.tooltipContainer)
3263
3535
  .style("position", "absolute")
3264
3536
  .style("pointer-events", "none")
3265
- .style("z-index", "10")
3266
3537
  .style("display", "none");
3267
3538
  // Show tooltip if needed
3268
3539
  if (config.tooltip_init_show) {
@@ -3295,7 +3566,7 @@
3295
3566
  text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
3296
3567
  }
3297
3568
 
3298
- name = nameFormat(d[i].name);
3569
+ name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
3299
3570
  value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
3300
3571
  bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
3301
3572
 
@@ -3324,27 +3595,29 @@
3324
3595
  tooltipLeft = ($$.width / 2) + mouse[0];
3325
3596
  tooltipTop = ($$.height / 2) + mouse[1] + 20;
3326
3597
  } else {
3598
+ svgLeft = $$.getSvgLeft(true);
3327
3599
  if (config.axis_rotated) {
3328
- svgLeft = $$.getSvgLeft();
3329
3600
  tooltipLeft = svgLeft + mouse[0] + 100;
3330
3601
  tooltipRight = tooltipLeft + tWidth;
3331
- chartRight = $$.getCurrentWidth() - $$.getCurrentPaddingRight();
3602
+ chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
3332
3603
  tooltipTop = $$.x(dataToShow[0].x) + 20;
3333
3604
  } else {
3334
- svgLeft = $$.getSvgLeft();
3335
- tooltipLeft = svgLeft + $$.getCurrentPaddingLeft() + $$.x(dataToShow[0].x) + 20;
3605
+ tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
3336
3606
  tooltipRight = tooltipLeft + tWidth;
3337
- chartRight = svgLeft + $$.getCurrentWidth() - $$.getCurrentPaddingRight();
3607
+ chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
3338
3608
  tooltipTop = mouse[1] + 15;
3339
3609
  }
3340
3610
 
3341
3611
  if (tooltipRight > chartRight) {
3342
3612
  tooltipLeft -= tooltipRight - chartRight;
3343
3613
  }
3344
- if (tooltipTop + tHeight > $$.getCurrentHeight() && tooltipTop > tHeight + 30) {
3614
+ if (tooltipTop + tHeight > $$.currentHeight) {
3345
3615
  tooltipTop -= tHeight + 30;
3346
3616
  }
3347
3617
  }
3618
+ if (tooltipTop < 0) {
3619
+ tooltipTop = 0;
3620
+ }
3348
3621
  // Set tooltip
3349
3622
  $$.tooltip
3350
3623
  .style("top", tooltipTop + "px")
@@ -3370,6 +3643,7 @@
3370
3643
  top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
3371
3644
  left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
3372
3645
  };
3646
+
3373
3647
  $$.margin3 = {
3374
3648
  top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
3375
3649
  right: NaN,
@@ -3395,12 +3669,10 @@
3395
3669
  return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
3396
3670
  };
3397
3671
  c3_chart_internal_fn.getLegendHeight = function () {
3398
- var $$ = this, config = $$.config, h = 0;
3399
- if (config.legend_show) {
3672
+ var $$ = this, h = 0;
3673
+ if ($$.config.legend_show) {
3400
3674
  if ($$.isLegendRight) {
3401
3675
  h = $$.currentHeight;
3402
- } else if ($$.isLegendInset) {
3403
- h = config.legend_inset_step ? Math.max(20, $$.legendItemHeight) * (config.legend_inset_step + 1) : $$.height;
3404
3676
  } else {
3405
3677
  h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
3406
3678
  }
@@ -3415,22 +3687,23 @@
3415
3687
  var $$ = this;
3416
3688
  return legendItem.classed(CLASS.legendItemHidden) ? $$.legendOpacityForHidden : 0.3;
3417
3689
  };
3418
- c3_chart_internal_fn.toggleFocusLegend = function (id, focus) {
3690
+ c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
3419
3691
  var $$ = this;
3692
+ targetIds = $$.mapToTargetIds(targetIds);
3420
3693
  $$.legend.selectAll('.' + CLASS.legendItem)
3694
+ .classed(CLASS.legendItemFocused, function (id) {
3695
+ return targetIds.indexOf(id) >= 0 && focus;
3696
+ })
3421
3697
  .transition().duration(100)
3422
- .style('opacity', function (_id) {
3423
- var This = $$.d3.select(this);
3424
- if (id && _id !== id) {
3425
- return focus ? $$.opacityForUnfocusedLegend(This) : $$.opacityForLegend(This);
3426
- } else {
3427
- return focus ? $$.opacityForLegend(This) : $$.opacityForUnfocusedLegend(This);
3428
- }
3698
+ .style('opacity', function (id) {
3699
+ var opacity = targetIds.indexOf(id) >= 0 && focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
3700
+ return opacity.call($$, $$.d3.select(this));
3429
3701
  });
3430
3702
  };
3431
3703
  c3_chart_internal_fn.revertLegend = function () {
3432
3704
  var $$ = this, d3 = $$.d3;
3433
3705
  $$.legend.selectAll('.' + CLASS.legendItem)
3706
+ .classed(CLASS.legendItemFocused, false)
3434
3707
  .transition().duration(100)
3435
3708
  .style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
3436
3709
  };
@@ -3460,20 +3733,21 @@
3460
3733
  c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
3461
3734
  var $$ = this, config = $$.config;
3462
3735
  var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
3463
- var paddingTop = 4, paddingRight = 36, maxWidth = 0, maxHeight = 0, posMin = 10;
3736
+ var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
3464
3737
  var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
3465
3738
  var withTransition, withTransitionForTransform;
3466
3739
  var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
3467
- var texts, rects, tiles;
3740
+ var texts, rects, tiles, background;
3468
3741
 
3469
3742
  options = options || {};
3470
3743
  withTransition = getOption(options, "withTransition", true);
3471
3744
  withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
3472
3745
 
3473
- function updatePositions(textElement, id, reset) {
3474
- var box = $$.getTextRect(textElement.textContent, CLASS.legendItem),
3475
- itemWidth = Math.ceil((box.width + paddingRight) / 10) * 10,
3476
- itemHeight = Math.ceil((box.height + paddingTop) / 10) * 10,
3746
+ function updatePositions(textElement, id, index) {
3747
+ var reset = index === 0, isLast = index === targetIds.length - 1,
3748
+ box = $$.getTextRect(textElement.textContent, CLASS.legendItem),
3749
+ itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
3750
+ itemHeight = box.height + paddingTop,
3477
3751
  itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
3478
3752
  areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
3479
3753
  margin, maxLength;
@@ -3530,6 +3804,11 @@
3530
3804
  }
3531
3805
  }
3532
3806
 
3807
+ if ($$.isLegendInset) {
3808
+ step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
3809
+ $$.updateLegendStep(step);
3810
+ }
3811
+
3533
3812
  if ($$.isLegendRight) {
3534
3813
  xForLegend = function (id) { return maxWidth * steps[id]; };
3535
3814
  yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
@@ -3542,8 +3821,8 @@
3542
3821
  }
3543
3822
  xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
3544
3823
  yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
3545
- xForLegendRect = function (id, i) { return xForLegend(id, i) - 4; };
3546
- yForLegendRect = function (id, i) { return yForLegend(id, i) - 7; };
3824
+ xForLegendRect = function (id, i) { return xForLegend(id, i); };
3825
+ yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
3547
3826
 
3548
3827
  // Define g for legend area
3549
3828
  l = $$.legend.selectAll('.' + CLASS.legendItem)
@@ -3553,11 +3832,21 @@
3553
3832
  .style('visibility', function (id) { return $$.isLegendToShow(id) ? 'visible' : 'hidden'; })
3554
3833
  .style('cursor', 'pointer')
3555
3834
  .on('click', function (id) {
3556
- config.legend_item_onclick ? config.legend_item_onclick.call($$, id) : $$.api.toggle(id);
3835
+ if (config.legend_item_onclick) {
3836
+ config.legend_item_onclick.call($$, id);
3837
+ } else {
3838
+ if ($$.d3.event.altKey) {
3839
+ $$.api.hide();
3840
+ $$.api.show(id);
3841
+ } else {
3842
+ $$.api.toggle(id);
3843
+ $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
3844
+ }
3845
+ }
3557
3846
  })
3558
3847
  .on('mouseover', function (id) {
3559
3848
  $$.d3.select(this).classed(CLASS.legendItemFocused, true);
3560
- if (!$$.transiting) {
3849
+ if (!$$.transiting && $$.isTargetToShow(id)) {
3561
3850
  $$.api.focus(id);
3562
3851
  }
3563
3852
  if (config.legend_item_onmouseover) {
@@ -3566,16 +3855,14 @@
3566
3855
  })
3567
3856
  .on('mouseout', function (id) {
3568
3857
  $$.d3.select(this).classed(CLASS.legendItemFocused, false);
3569
- if (!$$.transiting) {
3570
- $$.api.revert();
3571
- }
3858
+ $$.api.revert();
3572
3859
  if (config.legend_item_onmouseout) {
3573
3860
  config.legend_item_onmouseout.call($$, id);
3574
3861
  }
3575
3862
  });
3576
3863
  l.append('text')
3577
3864
  .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
3578
- .each(function (id, i) { updatePositions(this, id, i === 0); })
3865
+ .each(function (id, i) { updatePositions(this, id, i); })
3579
3866
  .style("pointer-events", "none")
3580
3867
  .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
3581
3868
  .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
@@ -3592,19 +3879,19 @@
3592
3879
  .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
3593
3880
  .attr('width', 10)
3594
3881
  .attr('height', 10);
3882
+
3595
3883
  // Set background for inset legend
3596
- if ($$.isLegendInset && maxWidth !== 0) {
3597
- $$.legend.insert('g', '.' + CLASS.legendItem)
3884
+ background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
3885
+ if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
3886
+ background = $$.legend.insert('g', '.' + CLASS.legendItem)
3598
3887
  .attr("class", CLASS.legendBackground)
3599
- .append('rect')
3600
- .attr('height', $$.getLegendHeight() - 10)
3601
- .attr('width', maxWidth * (step + 1) + 10);
3888
+ .append('rect');
3602
3889
  }
3603
3890
 
3604
3891
  texts = $$.legend.selectAll('text')
3605
3892
  .data(targetIds)
3606
3893
  .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update
3607
- .each(function (id, i) { updatePositions(this, id, i === 0); });
3894
+ .each(function (id, i) { updatePositions(this, id, i); });
3608
3895
  (withTransition ? texts.transition() : texts)
3609
3896
  .attr('x', xForLegendText)
3610
3897
  .attr('y', yForLegendText);
@@ -3624,6 +3911,12 @@
3624
3911
  .attr('x', xForLegend)
3625
3912
  .attr('y', yForLegend);
3626
3913
 
3914
+ if (background) {
3915
+ (withTransition ? background.transition() : background)
3916
+ .attr('height', $$.getLegendHeight() - 12)
3917
+ .attr('width', maxWidth * (step + 1) + 10);
3918
+ }
3919
+
3627
3920
  // toggle legend state
3628
3921
  $$.legend.selectAll('.' + CLASS.legendItem)
3629
3922
  .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
@@ -3681,9 +3974,19 @@
3681
3974
  .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
3682
3975
  .style("text-anchor", $$.textAnchorForY2AxisLabel.bind($$));
3683
3976
  };
3684
- c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues) {
3977
+ c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
3685
3978
  var $$ = this, config = $$.config,
3686
- axis = c3_axis($$.d3, $$.isCategorized()).scale(scale).orient(orient);
3979
+ axisParams = {
3980
+ isCategory: $$.isCategorized(),
3981
+ withOuterTick: withOuterTick,
3982
+ tickMultiline: config.axis_x_tick_multiline,
3983
+ tickWidth: config.axis_x_tick_width
3984
+ },
3985
+ axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
3986
+
3987
+ if ($$.isTimeSeries() && tickValues) {
3988
+ tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
3989
+ }
3687
3990
 
3688
3991
  // Set tick
3689
3992
  axis.tickFormat(tickFormat).tickValues(tickValues);
@@ -3695,7 +3998,8 @@
3695
3998
  } else {
3696
3999
  // TODO: move this to c3_axis
3697
4000
  axis.tickOffset = function () {
3698
- var edgeX = $$.getEdgeX($$.data.targets), diff = $$.x(edgeX[1]) - $$.x(edgeX[0]),
4001
+ var scale = this.scale(),
4002
+ edgeX = $$.getEdgeX($$.data.targets), diff = scale(edgeX[1]) - scale(edgeX[0]),
3699
4003
  base = diff ? diff : (config.axis_rotated ? $$.height : $$.width);
3700
4004
  return (base / $$.getMaxDataCount()) / 2;
3701
4005
  };
@@ -3703,8 +4007,15 @@
3703
4007
 
3704
4008
  return axis;
3705
4009
  };
3706
- c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, ticks) {
3707
- return c3_axis(this.d3).scale(scale).orient(orient).tickFormat(tickFormat).ticks(ticks);
4010
+ c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
4011
+ var axisParams = {withOuterTick: withOuterTick},
4012
+ axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
4013
+ if (this.isTimeSeriesY()) {
4014
+ axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
4015
+ } else {
4016
+ axis.tickValues(tickValues);
4017
+ }
4018
+ return axis;
3708
4019
  };
3709
4020
  c3_chart_internal_fn.getAxisId = function (id) {
3710
4021
  var config = this.config;
@@ -3724,6 +4035,18 @@
3724
4035
  }
3725
4036
  return isFunction(format) ? function (v) { return format.call($$, v); } : format;
3726
4037
  };
4038
+ c3_chart_internal_fn.getAxisTickValues = function (tickValues, axis) {
4039
+ return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
4040
+ };
4041
+ c3_chart_internal_fn.getXAxisTickValues = function () {
4042
+ return this.getAxisTickValues(this.config.axis_x_tick_values, this.xAxis);
4043
+ };
4044
+ c3_chart_internal_fn.getYAxisTickValues = function () {
4045
+ return this.getAxisTickValues(this.config.axis_y_tick_values, this.yAxis);
4046
+ };
4047
+ c3_chart_internal_fn.getY2AxisTickValues = function () {
4048
+ return this.getAxisTickValues(this.config.axis_y2_tick_values, this.y2Axis);
4049
+ };
3727
4050
  c3_chart_internal_fn.getAxisLabelOptionByAxisId = function (axisId) {
3728
4051
  var $$ = this, config = $$.config, option;
3729
4052
  if (axisId === 'y') {
@@ -3870,44 +4193,48 @@
3870
4193
  };
3871
4194
 
3872
4195
  c3_chart_internal_fn.xForRotatedTickText = function (r) {
3873
- return 10 * Math.sin(Math.PI * (r / 180));
4196
+ return 8 * Math.sin(Math.PI * (r / 180));
3874
4197
  };
3875
4198
  c3_chart_internal_fn.yForRotatedTickText = function (r) {
3876
- return 11.5 - 2.5 * (r / 15);
4199
+ return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
3877
4200
  };
3878
4201
  c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
3879
4202
  axis.selectAll('.tick text')
3880
- .style("text-anchor", "start");
4203
+ .style("text-anchor", rotate > 0 ? "start" : "end");
3881
4204
  transition.selectAll('.tick text')
3882
4205
  .attr("y", this.yForRotatedTickText(rotate))
3883
- .attr("x", this.xForRotatedTickText(rotate))
3884
- .attr("transform", "rotate(" + rotate + ")");
4206
+ .attr("transform", "rotate(" + rotate + ")")
4207
+ .selectAll('tspan')
4208
+ .attr('dx', this.xForRotatedTickText(rotate));
3885
4209
  };
3886
4210
 
3887
- c3_chart_internal_fn.getMaxTickWidth = function (id) {
4211
+ c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
3888
4212
  var $$ = this, config = $$.config,
3889
4213
  maxWidth = 0, targetsToShow, scale, axis;
4214
+ if (withoutRecompute && $$.currentMaxTickWidths[id]) {
4215
+ return $$.currentMaxTickWidths[id];
4216
+ }
3890
4217
  if ($$.svg) {
3891
4218
  targetsToShow = $$.filterTargetsToShow($$.data.targets);
3892
4219
  if (id === 'y') {
3893
4220
  scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
3894
- axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, config.axis_y_ticks);
4221
+ axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
3895
4222
  } else if (id === 'y2') {
3896
4223
  scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
3897
- axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, config.axis_y2_ticks);
4224
+ axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
3898
4225
  } else {
3899
4226
  scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
3900
- axis = $$.getXAxis(scale, $$.xOrient, $$.getXAxisTickFormat(), config.axis_x_tick_values ? config.axis_x_tick_values : $$.xAxis.tickValues());
4227
+ axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
3901
4228
  }
3902
- $$.main.append("g").call(axis).each(function () {
3903
- $$.d3.select(this).selectAll('text').each(function () {
4229
+ $$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
4230
+ $$.d3.select(this).selectAll('text tspan').each(function () {
3904
4231
  var box = this.getBoundingClientRect();
3905
- if (maxWidth < box.width) { maxWidth = box.width; }
4232
+ if (box.left > 0 && maxWidth < box.width) { maxWidth = box.width; }
3906
4233
  });
3907
4234
  }).remove();
3908
4235
  }
3909
- $$.currentMaxTickWidth = maxWidth <= 0 ? $$.currentMaxTickWidth : maxWidth;
3910
- return $$.currentMaxTickWidth;
4236
+ $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
4237
+ return $$.currentMaxTickWidths[id];
3911
4238
  };
3912
4239
 
3913
4240
  c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
@@ -3937,31 +4264,30 @@
3937
4264
  return isValue(padding[key]) ? padding[key] * ratio : defaultValue;
3938
4265
  };
3939
4266
 
3940
- c3_chart_internal_fn.generateTickValues = function (xs, tickCount) {
3941
- var $$ = this;
3942
- var tickValues = xs, targetCount, start, end, count, interval, i, tickValue;
4267
+ c3_chart_internal_fn.generateTickValues = function (values, tickCount, forTimeSeries) {
4268
+ var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
3943
4269
  if (tickCount) {
3944
4270
  targetCount = isFunction(tickCount) ? tickCount() : tickCount;
3945
- // compute ticks according to $$.config.axis_x_tick_count
4271
+ // compute ticks according to tickCount
3946
4272
  if (targetCount === 1) {
3947
- tickValues = [xs[0]];
4273
+ tickValues = [values[0]];
3948
4274
  } else if (targetCount === 2) {
3949
- tickValues = [xs[0], xs[xs.length - 1]];
4275
+ tickValues = [values[0], values[values.length - 1]];
3950
4276
  } else if (targetCount > 2) {
3951
4277
  count = targetCount - 2;
3952
- start = xs[0];
3953
- end = xs[xs.length - 1];
4278
+ start = values[0];
4279
+ end = values[values.length - 1];
3954
4280
  interval = (end - start) / (count + 1);
3955
- // re-construct uniqueXs
4281
+ // re-construct unique values
3956
4282
  tickValues = [start];
3957
4283
  for (i = 0; i < count; i++) {
3958
4284
  tickValue = +start + interval * (i + 1);
3959
- tickValues.push($$.isTimeSeries() ? new Date(tickValue) : tickValue);
4285
+ tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
3960
4286
  }
3961
4287
  tickValues.push(end);
3962
4288
  }
3963
4289
  }
3964
- if (!$$.isTimeSeries()) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
4290
+ if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
3965
4291
  return tickValues;
3966
4292
  };
3967
4293
  c3_chart_internal_fn.generateAxisTransitions = function (duration) {
@@ -3974,7 +4300,7 @@
3974
4300
  };
3975
4301
  };
3976
4302
  c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
3977
- var $$ = this;
4303
+ var $$ = this, config = $$.config;
3978
4304
  $$.axes.x.style("opacity", isHidden ? 0 : 1);
3979
4305
  $$.axes.y.style("opacity", isHidden ? 0 : 1);
3980
4306
  $$.axes.y2.style("opacity", isHidden ? 0 : 1);
@@ -3983,15 +4309,23 @@
3983
4309
  transitions.axisY.call($$.yAxis);
3984
4310
  transitions.axisY2.call($$.y2Axis);
3985
4311
  transitions.axisSubX.call($$.subXAxis);
4312
+ // rotate tick text if needed
4313
+ if (!config.axis_rotated && config.axis_x_tick_rotate) {
4314
+ $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
4315
+ }
3986
4316
  };
3987
4317
 
3988
4318
  c3_chart_internal_fn.getClipPath = function (id) {
3989
4319
  var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
3990
4320
  return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
3991
4321
  };
4322
+ c3_chart_internal_fn.appendClip = function (parent, id) {
4323
+ return parent.append("clipPath").attr("id", id).append("rect");
4324
+ };
3992
4325
  c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
3993
4326
  // axis line width + padding for left
3994
- return forHorizontal ? -(1 + 30) : -(this.margin.left - 1);
4327
+ var left = Math.max(30, this.margin.left);
4328
+ return forHorizontal ? -(1 + left) : -(left - 1);
3995
4329
  };
3996
4330
  c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
3997
4331
  return forHorizontal ? -20 : -4;
@@ -4013,13 +4347,14 @@
4013
4347
  return $$.getAxisClipY($$.config.axis_rotated);
4014
4348
  };
4015
4349
  c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
4016
- var $$ = this;
4350
+ var $$ = this,
4351
+ left = Math.max(30, $$.margin.left),
4352
+ right = Math.max(30, $$.margin.right);
4017
4353
  // width + axis line width + padding for left/right
4018
- return forHorizontal ? $$.width + 2 + 30 + 30 : $$.margin.left + 20;
4354
+ return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
4019
4355
  };
4020
4356
  c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
4021
- var $$ = this, config = $$.config;
4022
- return forHorizontal ? (config.axis_x_height ? config.axis_x_height : 0) + 80 : $$.height + 8;
4357
+ return (forHorizontal ? this.margin.bottom : this.height) + 8;
4023
4358
  };
4024
4359
  c3_chart_internal_fn.getXAxisClipWidth = function () {
4025
4360
  var $$ = this;
@@ -4043,7 +4378,7 @@
4043
4378
  $$.pie = d3.layout.pie().value(function (d) {
4044
4379
  return d.values.reduce(function (a, b) { return a + b.value; }, 0);
4045
4380
  });
4046
- if (!config.data_order || !config.pie_sort || !config.donut_sort) {
4381
+ if (!config.data_order) {
4047
4382
  $$.pie.sort(null);
4048
4383
  }
4049
4384
  };
@@ -4066,8 +4401,9 @@
4066
4401
 
4067
4402
  c3_chart_internal_fn.updateAngle = function (d) {
4068
4403
  var $$ = this, config = $$.config,
4069
- found = false, index = 0;
4070
- $$.pie($$.filterTargetsToShow($$.data.targets)).sort($$.descByStartAngle).forEach(function (t) {
4404
+ found = false, index = 0,
4405
+ gMin = config.gauge_min, gMax = config.gauge_max, gTic, gValue;
4406
+ $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
4071
4407
  if (! found && t.data.id === d.data.id) {
4072
4408
  found = true;
4073
4409
  d = t;
@@ -4079,11 +4415,10 @@
4079
4415
  d.endAngle = d.startAngle;
4080
4416
  }
4081
4417
  if ($$.isGaugeType(d.data)) {
4082
- var gMin = config.gauge_min, gMax = config.gauge_max,
4083
- gF = Math.abs(gMin) + gMax,
4084
- aTic = (Math.PI) / gF;
4085
- d.startAngle = (-1 * (Math.PI / 2)) + (aTic * Math.abs(gMin));
4086
- d.endAngle = d.startAngle + (aTic * ((d.value > gMax) ? gMax : d.value));
4418
+ gTic = (Math.PI) / (gMax - gMin);
4419
+ gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
4420
+ d.startAngle = -1 * (Math.PI / 2);
4421
+ d.endAngle = d.startAngle + gTic * gValue;
4087
4422
  }
4088
4423
  return found ? d : null;
4089
4424
  };
@@ -4148,23 +4483,38 @@
4148
4483
 
4149
4484
  c3_chart_internal_fn.textForArcLabel = function (d) {
4150
4485
  var $$ = this,
4151
- updated, value, ratio, format;
4486
+ updated, value, ratio, id, format;
4152
4487
  if (! $$.shouldShowArcLabel()) { return ""; }
4153
4488
  updated = $$.updateAngle(d);
4154
4489
  value = updated ? updated.value : null;
4155
4490
  ratio = $$.getArcRatio(updated);
4491
+ id = d.data.id;
4156
4492
  if (! $$.hasType('gauge') && ! $$.meetsArcLabelThreshold(ratio)) { return ""; }
4157
4493
  format = $$.getArcLabelFormat();
4158
- return format ? format(value, ratio) : $$.defaultArcValueFormat(value, ratio);
4494
+ return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
4159
4495
  };
4160
4496
 
4161
- c3_chart_internal_fn.expandArc = function (id, withoutFadeOut) {
4162
- var $$ = this,
4163
- target = $$.svg.selectAll('.' + CLASS.chartArc + $$.selectorTarget(id)),
4164
- noneTargets = $$.svg.selectAll('.' + CLASS.arc).filter(function (data) { return data.data.id !== id; });
4497
+ c3_chart_internal_fn.expandArc = function (targetIds) {
4498
+ var $$ = this, interval;
4499
+
4500
+ // MEMO: avoid to cancel transition
4501
+ if ($$.transiting) {
4502
+ interval = window.setInterval(function () {
4503
+ if (!$$.transiting) {
4504
+ window.clearInterval(interval);
4505
+ if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
4506
+ $$.expandArc(targetIds);
4507
+ }
4508
+ }
4509
+ }, 10);
4510
+ return;
4511
+ }
4512
+
4513
+ targetIds = $$.mapToTargetIds(targetIds);
4165
4514
 
4166
- if ($$.shouldExpand(id)) {
4167
- target.selectAll('path')
4515
+ $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
4516
+ if (! $$.shouldExpand(d.data.id)) { return; }
4517
+ $$.d3.select(this).selectAll('path')
4168
4518
  .transition().duration(50)
4169
4519
  .attr("d", $$.svgArcExpanded)
4170
4520
  .transition().duration(100)
@@ -4174,16 +4524,17 @@
4174
4524
  // callback here
4175
4525
  }
4176
4526
  });
4177
- }
4178
- if (!withoutFadeOut) {
4179
- noneTargets.style("opacity", 0.3);
4180
- }
4527
+ });
4181
4528
  };
4182
4529
 
4183
- c3_chart_internal_fn.unexpandArc = function (id) {
4184
- var $$ = this,
4185
- target = $$.svg.selectAll('.' + CLASS.chartArc + $$.selectorTarget(id));
4186
- target.selectAll('path.' + CLASS.arc)
4530
+ c3_chart_internal_fn.unexpandArc = function (targetIds) {
4531
+ var $$ = this;
4532
+
4533
+ if ($$.transiting) { return; }
4534
+
4535
+ targetIds = $$.mapToTargetIds(targetIds);
4536
+
4537
+ $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
4187
4538
  .transition().duration(50)
4188
4539
  .attr("d", $$.svgArc);
4189
4540
  $$.svg.selectAll('.' + CLASS.arc)
@@ -4228,24 +4579,21 @@
4228
4579
  return $$.hasType('donut') ? $$.config.donut_title : "";
4229
4580
  };
4230
4581
 
4231
- c3_chart_internal_fn.descByStartAngle = function (a, b) {
4232
- return a.startAngle - b.startAngle;
4233
- };
4234
-
4235
4582
  c3_chart_internal_fn.updateTargetsForArc = function (targets) {
4236
4583
  var $$ = this, main = $$.main,
4237
4584
  mainPieUpdate, mainPieEnter,
4238
4585
  classChartArc = $$.classChartArc.bind($$),
4239
- classArcs = $$.classArcs.bind($$);
4586
+ classArcs = $$.classArcs.bind($$),
4587
+ classFocus = $$.classFocus.bind($$);
4240
4588
  mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
4241
4589
  .data($$.pie(targets))
4242
- .attr("class", classChartArc);
4590
+ .attr("class", function (d) { return classChartArc(d) + classFocus(d.data); });
4243
4591
  mainPieEnter = mainPieUpdate.enter().append("g")
4244
4592
  .attr("class", classChartArc);
4245
4593
  mainPieEnter.append('g')
4246
4594
  .attr('class', classArcs);
4247
4595
  mainPieEnter.append("text")
4248
- .attr("dy", $$.hasType('gauge') ? "-0.35em" : ".35em")
4596
+ .attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
4249
4597
  .style("opacity", 0)
4250
4598
  .style("text-anchor", "middle")
4251
4599
  .style("pointer-events", "none");
@@ -4289,6 +4637,7 @@
4289
4637
  arcData = $$.convertToArcData(updated);
4290
4638
  // transitions
4291
4639
  $$.expandArc(updated.data.id);
4640
+ $$.api.focus(updated.data.id);
4292
4641
  $$.toggleFocusLegend(updated.data.id, true);
4293
4642
  $$.config.data_onmouseover(arcData, this);
4294
4643
  })
@@ -4307,18 +4656,16 @@
4307
4656
  arcData = $$.convertToArcData(updated);
4308
4657
  // transitions
4309
4658
  $$.unexpandArc(updated.data.id);
4659
+ $$.api.revert();
4310
4660
  $$.revertLegend();
4311
4661
  $$.hideTooltip();
4312
4662
  $$.config.data_onmouseout(arcData, this);
4313
4663
  })
4314
4664
  .on('click', function (d, i) {
4315
- var updated, arcData;
4316
- if (!$$.toggleShape) {
4317
- return;
4318
- }
4319
- updated = $$.updateAngle(d);
4320
- arcData = $$.convertToArcData(updated);
4321
- $$.toggleShape(this, arcData, i); // onclick called in toogleShape()
4665
+ var updated = $$.updateAngle(d),
4666
+ arcData = $$.convertToArcData(updated);
4667
+ if ($$.toggleShape) { $$.toggleShape(this, arcData, i); }
4668
+ $$.config.data_onclick.call($$.api, arcData, this);
4322
4669
  });
4323
4670
  mainArc
4324
4671
  .attr("transform", function (d) { return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : ""; })
@@ -4341,7 +4688,11 @@
4341
4688
  }
4342
4689
  interpolate = d3.interpolate(this._current, updated);
4343
4690
  this._current = interpolate(0);
4344
- return function (t) { return $$.getArc(interpolate(t), true); };
4691
+ return function (t) {
4692
+ var interpolated = interpolate(t);
4693
+ interpolated.data = d.data; // data.id will be updated by interporator
4694
+ return $$.getArc(interpolated, true);
4695
+ };
4345
4696
  })
4346
4697
  .attr("transform", withTransform ? "scale(1)" : "")
4347
4698
  .style("fill", function (d) {
@@ -4359,17 +4710,14 @@
4359
4710
  .attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
4360
4711
  .text($$.textForArcLabel.bind($$))
4361
4712
  .attr("transform", $$.transformForArcLabel.bind($$))
4362
- .transition().duration(duration)
4713
+ .style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
4714
+ .transition().duration(duration)
4363
4715
  .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
4364
4716
  main.select('.' + CLASS.chartArcsTitle)
4365
4717
  .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
4366
4718
 
4367
- };
4368
- c3_chart_internal_fn.initGauge = function () {
4369
- var $$ = this, config = $$.config, arcs = $$.arcs;
4370
4719
  if ($$.hasType('gauge')) {
4371
- arcs.append('path')
4372
- .attr("class", CLASS.chartArcsBackground)
4720
+ $$.arcs.select('.' + CLASS.chartArcsBackground)
4373
4721
  .attr("d", function () {
4374
4722
  var d = {
4375
4723
  data: [{value: config.gauge_max}],
@@ -4378,37 +4726,54 @@
4378
4726
  };
4379
4727
  return $$.getArc(d, true, true);
4380
4728
  });
4381
- arcs.append("text")
4729
+ $$.arcs.select('.' + CLASS.chartArcsGaugeUnit)
4382
4730
  .attr("dy", ".75em")
4383
- .attr("class", CLASS.chartArcsGaugeUnit)
4384
- .style("text-anchor", "middle")
4385
- .style("pointer-events", "none")
4386
4731
  .text(config.gauge_label_show ? config.gauge_units : '');
4387
- arcs.append("text")
4732
+ $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
4388
4733
  .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
4389
4734
  .attr("dy", "1.2em")
4390
- .attr("class", CLASS.chartArcsGaugeMin)
4391
- .style("text-anchor", "middle")
4392
- .style("pointer-events", "none")
4393
4735
  .text(config.gauge_label_show ? config.gauge_min : '');
4394
- arcs.append("text")
4736
+ $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
4395
4737
  .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
4396
4738
  .attr("dy", "1.2em")
4739
+ .text(config.gauge_label_show ? config.gauge_max : '');
4740
+ }
4741
+ };
4742
+ c3_chart_internal_fn.initGauge = function () {
4743
+ var arcs = this.arcs;
4744
+ if (this.hasType('gauge')) {
4745
+ arcs.append('path')
4746
+ .attr("class", CLASS.chartArcsBackground);
4747
+ arcs.append("text")
4748
+ .attr("class", CLASS.chartArcsGaugeUnit)
4749
+ .style("text-anchor", "middle")
4750
+ .style("pointer-events", "none");
4751
+ arcs.append("text")
4752
+ .attr("class", CLASS.chartArcsGaugeMin)
4753
+ .style("text-anchor", "middle")
4754
+ .style("pointer-events", "none");
4755
+ arcs.append("text")
4397
4756
  .attr("class", CLASS.chartArcsGaugeMax)
4398
4757
  .style("text-anchor", "middle")
4399
- .style("pointer-events", "none")
4400
- .text(config.gauge_label_show ? config.gauge_max : '');
4758
+ .style("pointer-events", "none");
4401
4759
  }
4402
4760
  };
4761
+ c3_chart_internal_fn.getGaugeLabelHeight = function () {
4762
+ return this.config.gauge_label_show ? 20 : 0;
4763
+ };
4403
4764
 
4404
4765
  c3_chart_internal_fn.initRegion = function () {
4405
4766
  var $$ = this;
4406
- $$.main.append('g')
4767
+ $$.region = $$.main.append('g')
4407
4768
  .attr("clip-path", $$.clipPath)
4408
4769
  .attr("class", CLASS.regions);
4409
4770
  };
4410
4771
  c3_chart_internal_fn.redrawRegion = function (duration) {
4411
4772
  var $$ = this, config = $$.config;
4773
+
4774
+ // hide if arc type
4775
+ $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
4776
+
4412
4777
  $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
4413
4778
  .data(config.regions);
4414
4779
  $$.mainRegion.enter().append('g')
@@ -4519,7 +4884,7 @@
4519
4884
  _y = box.y;
4520
4885
  _w = box.width;
4521
4886
  _h = box.height;
4522
- toggle = $$.toggleBar;
4887
+ toggle = $$.togglePath;
4523
4888
  isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
4524
4889
  } else {
4525
4890
  // line/area selection not supported yet
@@ -4563,8 +4928,8 @@
4563
4928
 
4564
4929
  c3_chart_internal_fn.selectPoint = function (target, d, i) {
4565
4930
  var $$ = this, config = $$.config,
4566
- cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
4567
- cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
4931
+ cx = (config.axis_rotated ? $$.generateCircleY() : $$.circleX).bind($$),
4932
+ cy = (config.axis_rotated ? $$.circleX : $$.generateCircleY()).bind($$),
4568
4933
  r = $$.pointSelectR.bind($$);
4569
4934
  config.data_onselected.call($$.api, d, target.node());
4570
4935
  // add selected-circle on low layer g
@@ -4590,57 +4955,50 @@
4590
4955
  c3_chart_internal_fn.togglePoint = function (selected, target, d, i) {
4591
4956
  selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
4592
4957
  };
4593
- c3_chart_internal_fn.selectBar = function (target, d) {
4958
+ c3_chart_internal_fn.selectPath = function (target, d) {
4594
4959
  var $$ = this;
4595
4960
  $$.config.data_onselected.call($$, d, target.node());
4596
4961
  target.transition().duration(100)
4597
4962
  .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
4598
4963
  };
4599
- c3_chart_internal_fn.unselectBar = function (target, d) {
4964
+ c3_chart_internal_fn.unselectPath = function (target, d) {
4600
4965
  var $$ = this;
4601
4966
  $$.config.data_onunselected.call($$, d, target.node());
4602
4967
  target.transition().duration(100)
4603
4968
  .style("fill", function () { return $$.color(d); });
4604
4969
  };
4605
- c3_chart_internal_fn.toggleBar = function (selected, target, d, i) {
4606
- selected ? this.selectBar(target, d, i) : this.unselectBar(target, d, i);
4607
- };
4608
- c3_chart_internal_fn.toggleArc = function (selected, target, d, i) {
4609
- this.toggleBar(selected, target, d.data, i);
4610
- };
4611
- c3_chart_internal_fn.getToggle = function (that) {
4612
- var $$ = this;
4613
- // path selection not supported yet
4614
- return that.nodeName === 'circle' ? $$.togglePoint : ($$.d3.select(that).classed(CLASS.bar) ? $$.toggleBar : $$.toggleArc);
4970
+ c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
4971
+ selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
4615
4972
  };
4616
- c3_chart_internal_fn.toggleShape = function (that, d, i) {
4617
- var $$ = this, d3 = $$.d3, config = $$.config,
4618
- shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED), isWithin, toggle;
4973
+ c3_chart_internal_fn.getToggle = function (that, d) {
4974
+ var $$ = this, toggle;
4619
4975
  if (that.nodeName === 'circle') {
4620
- isWithin = $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
4621
- toggle = $$.togglePoint;
4976
+ if ($$.isStepType(d)) {
4977
+ // circle is hidden in step chart, so treat as within the click area
4978
+ toggle = function () {}; // TODO: how to select step chart?
4979
+ } else {
4980
+ toggle = $$.togglePoint;
4981
+ }
4622
4982
  }
4623
4983
  else if (that.nodeName === 'path') {
4624
- if (shape.classed(CLASS.bar)) {
4625
- isWithin = $$.isWithinBar(that);
4626
- toggle = $$.toggleBar;
4627
- } else { // would be arc
4628
- isWithin = true;
4629
- toggle = $$.toggleArc;
4630
- }
4984
+ toggle = $$.togglePath;
4631
4985
  }
4632
- if (config.data_selection_grouped || isWithin) {
4633
- if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
4634
- if (!config.data_selection_multiple) {
4635
- $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
4636
- var shape = d3.select(this);
4637
- if (shape.classed(CLASS.SELECTED)) { toggle.call($$, false, shape.classed(CLASS.SELECTED, false), d, i); }
4638
- });
4639
- }
4640
- shape.classed(CLASS.SELECTED, !isSelected);
4641
- toggle.call($$, !isSelected, shape, d, i);
4986
+ return toggle;
4987
+ };
4988
+ c3_chart_internal_fn.toggleShape = function (that, d, i) {
4989
+ var $$ = this, d3 = $$.d3, config = $$.config,
4990
+ shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED),
4991
+ toggle = $$.getToggle(that, d).bind($$);
4992
+
4993
+ if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
4994
+ if (!config.data_selection_multiple) {
4995
+ $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
4996
+ var shape = d3.select(this);
4997
+ if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
4998
+ });
4642
4999
  }
4643
- $$.config.data_onclick.call($$.api, d, that);
5000
+ shape.classed(CLASS.SELECTED, !isSelected);
5001
+ toggle(!isSelected, shape, d, i);
4644
5002
  }
4645
5003
  };
4646
5004
 
@@ -4665,7 +5023,7 @@
4665
5023
 
4666
5024
  // Define g for chart area
4667
5025
  context.append('g')
4668
- .attr("clip-path", $$.clipPath)
5026
+ .attr("clip-path", $$.clipPathForSubchart)
4669
5027
  .attr('class', CLASS.chart);
4670
5028
 
4671
5029
  // Define g for bar chart area
@@ -4810,7 +5168,7 @@
4810
5168
  var $$ = this, x = $$.x;
4811
5169
  $$.redraw({
4812
5170
  withTransition: false,
4813
- withY: false,
5171
+ withY: $$.config.zoom_rescale,
4814
5172
  withSubchart: false,
4815
5173
  withUpdateXDomain: true
4816
5174
  });
@@ -4827,14 +5185,37 @@
4827
5185
  $$.context.attr("transform", $$.getTranslate('context'));
4828
5186
  subXAxis.attr("transform", $$.getTranslate('subx'));
4829
5187
  };
5188
+ c3_chart_internal_fn.getDefaultExtent = function () {
5189
+ var $$ = this, config = $$.config,
5190
+ extent = isFunction(config.axis_x_extent) ? config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
5191
+ if ($$.isTimeSeries()) {
5192
+ extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
5193
+ }
5194
+ return extent;
5195
+ };
4830
5196
 
4831
5197
  c3_chart_internal_fn.initZoom = function () {
4832
- var $$ = this, d3 = $$.d3, config = $$.config;
5198
+ var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
5199
+
4833
5200
  $$.zoom = d3.behavior.zoom()
4834
5201
  .on("zoomstart", function () {
5202
+ startEvent = d3.event.sourceEvent;
4835
5203
  $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
5204
+ config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
4836
5205
  })
4837
- .on("zoom", function () { $$.redrawForZoom.call($$); });
5206
+ .on("zoom", function () {
5207
+ $$.redrawForZoom.call($$);
5208
+ })
5209
+ .on('zoomend', function () {
5210
+ var event = d3.event.sourceEvent;
5211
+ // if click, do nothing. otherwise, click interaction will be canceled.
5212
+ if (event && startEvent.x === event.x && startEvent.y === event.y) {
5213
+ return;
5214
+ }
5215
+ $$.redrawEventRect();
5216
+ $$.updateZoom();
5217
+ config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
5218
+ });
4838
5219
  $$.zoom.scale = function (scale) {
4839
5220
  return config.axis_rotated ? this.y(scale) : this.x(scale);
4840
5221
  };
@@ -4851,11 +5232,11 @@
4851
5232
  };
4852
5233
  c3_chart_internal_fn.updateZoom = function () {
4853
5234
  var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
4854
- $$.main.select('.' + CLASS.zoomRect).call(z);
4855
- $$.main.selectAll('.' + CLASS.eventRect).call(z);
5235
+ $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
5236
+ $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
4856
5237
  };
4857
5238
  c3_chart_internal_fn.redrawForZoom = function () {
4858
- var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x, orgXDomain = $$.orgXDomain;
5239
+ var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
4859
5240
  if (!config.zoom_enabled) {
4860
5241
  return;
4861
5242
  }
@@ -4867,13 +5248,14 @@
4867
5248
  zoom.scale(x).updateScaleExtent();
4868
5249
  return;
4869
5250
  }
4870
- if ($$.isCategorized() && x.orgDomain()[0] === orgXDomain[0]) {
4871
- x.domain([orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
5251
+ if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
5252
+ x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
4872
5253
  }
4873
5254
  $$.redraw({
4874
5255
  withTransition: false,
4875
- withY: false,
4876
- withSubchart: false
5256
+ withY: config.zoom_rescale,
5257
+ withSubchart: false,
5258
+ withEventRect: false
4877
5259
  });
4878
5260
  if (d3.event.sourceEvent.type === 'mousemove') {
4879
5261
  $$.cancelClick = true;
@@ -5009,8 +5391,10 @@
5009
5391
  zoomRect: 'c3-zoom-rect',
5010
5392
  brush: 'c3-brush',
5011
5393
  focused: 'c3-focused',
5394
+ defocused: 'c3-defocused',
5012
5395
  region: 'c3-region',
5013
5396
  regions: 'c3-regions',
5397
+ tooltipContainer: 'c3-tooltip-container',
5014
5398
  tooltip: 'c3-tooltip',
5015
5399
  tooltipName: 'c3-tooltip-name',
5016
5400
  shape: 'c3-shape',
@@ -5030,6 +5414,7 @@
5030
5414
  texts: 'c3-texts',
5031
5415
  gaugeValue: 'c3-gauge-value',
5032
5416
  grid: 'c3-grid',
5417
+ gridLines: 'c3-grid-lines',
5033
5418
  xgrid: 'c3-xgrid',
5034
5419
  xgrids: 'c3-xgrids',
5035
5420
  xgridLine: 'c3-xgrid-line',
@@ -5103,7 +5488,7 @@
5103
5488
  return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
5104
5489
  };
5105
5490
  c3_chart_internal_fn.classRegion = function (d, i) {
5106
- return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d.class : '');
5491
+ return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
5107
5492
  };
5108
5493
  c3_chart_internal_fn.classEvent = function (d) {
5109
5494
  return this.generateClass(CLASS.eventRect, d.index);
@@ -5116,6 +5501,15 @@
5116
5501
  }
5117
5502
  return $$.generateClass(CLASS.target, id) + additionalClass;
5118
5503
  };
5504
+ c3_chart_internal_fn.classFocus = function (d) {
5505
+ return this.classFocused(d) + this.classDefocused(d);
5506
+ };
5507
+ c3_chart_internal_fn.classFocused = function (d) {
5508
+ return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
5509
+ };
5510
+ c3_chart_internal_fn.classDefocused = function (d) {
5511
+ return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
5512
+ };
5119
5513
  c3_chart_internal_fn.classChartText = function (d) {
5120
5514
  return CLASS.chartText + this.classTarget(d.id);
5121
5515
  };
@@ -5129,14 +5523,15 @@
5129
5523
  return CLASS.chartArc + this.classTarget(d.data.id);
5130
5524
  };
5131
5525
  c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
5132
- return targetId || targetId === 0 ? '-' + (targetId.replace ? targetId.replace(/([^a-zA-Z0-9-_])/g, '-') : targetId) : '';
5526
+ return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s!@#$%^&*()_+,.<>'":;\[\]]/g, '-') : '';
5133
5527
  };
5134
- c3_chart_internal_fn.selectorTarget = function (id) {
5135
- return '.' + CLASS.target + this.getTargetSelectorSuffix(id);
5528
+ c3_chart_internal_fn.selectorTarget = function (id, prefix) {
5529
+ return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
5136
5530
  };
5137
- c3_chart_internal_fn.selectorTargets = function (ids) {
5531
+ c3_chart_internal_fn.selectorTargets = function (ids, prefix) {
5138
5532
  var $$ = this;
5139
- return ids.length ? ids.map(function (id) { return $$.selectorTarget(id); }) : null;
5533
+ ids = ids || [];
5534
+ return ids.length ? ids.map(function (id) { return $$.selectorTarget(id, prefix); }) : null;
5140
5535
  };
5141
5536
  c3_chart_internal_fn.selectorLegend = function (id) {
5142
5537
  return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
@@ -5193,67 +5588,75 @@
5193
5588
  return {x: minX, y: minY, width: box.width, height: box.height};
5194
5589
  };
5195
5590
 
5196
- c3_chart_fn.focus = function (targetId) {
5197
- var $$ = this.internal,
5198
- candidates = $$.svg.selectAll($$.selectorTarget(targetId)),
5199
- candidatesForNoneArc = candidates.filter($$.isNoneArc.bind($$)),
5200
- candidatesForArc = candidates.filter($$.isArc.bind($$));
5201
- function focus(targets) {
5202
- $$.filterTargetsToShow(targets).transition().duration(100).style('opacity', 1);
5203
- }
5591
+ c3_chart_fn.focus = function (targetIds) {
5592
+ var $$ = this.internal, candidates;
5593
+
5594
+ targetIds = $$.mapToTargetIds(targetIds);
5595
+ candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
5596
+
5204
5597
  this.revert();
5205
5598
  this.defocus();
5206
- focus(candidatesForNoneArc.classed(CLASS.focused, true));
5207
- focus(candidatesForArc);
5599
+ candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
5208
5600
  if ($$.hasArcType()) {
5209
- $$.expandArc(targetId, true);
5601
+ $$.expandArc(targetIds);
5210
5602
  }
5211
- $$.toggleFocusLegend(targetId, true);
5603
+ $$.toggleFocusLegend(targetIds, true);
5604
+
5605
+ $$.focusedTargetIds = targetIds;
5606
+ $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
5607
+ return targetIds.indexOf(id) < 0;
5608
+ });
5212
5609
  };
5213
5610
 
5214
- c3_chart_fn.defocus = function (targetId) {
5215
- var $$ = this.internal,
5216
- candidates = $$.svg.selectAll($$.selectorTarget(targetId)),
5217
- candidatesForNoneArc = candidates.filter($$.isNoneArc.bind($$)),
5218
- candidatesForArc = candidates.filter($$.isArc.bind($$));
5219
- function defocus(targets) {
5220
- $$.filterTargetsToShow(targets).transition().duration(100).style('opacity', 0.3);
5221
- }
5611
+ c3_chart_fn.defocus = function (targetIds) {
5612
+ var $$ = this.internal, candidates;
5613
+
5614
+ targetIds = $$.mapToTargetIds(targetIds);
5615
+ candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
5616
+
5222
5617
  this.revert();
5223
- defocus(candidatesForNoneArc.classed(CLASS.focused, false));
5224
- defocus(candidatesForArc);
5618
+ candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
5225
5619
  if ($$.hasArcType()) {
5226
- $$.unexpandArc(targetId);
5620
+ $$.unexpandArc(targetIds);
5227
5621
  }
5228
- $$.toggleFocusLegend(targetId, false);
5622
+ $$.toggleFocusLegend(targetIds, false);
5623
+
5624
+ $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
5625
+ return targetIds.indexOf(id) < 0;
5626
+ });
5627
+ $$.defocusedTargetIds = targetIds;
5229
5628
  };
5230
5629
 
5231
- c3_chart_fn.revert = function (targetId) {
5232
- var $$ = this.internal,
5233
- candidates = $$.svg.selectAll($$.selectorTarget(targetId)),
5234
- candidatesForNoneArc = candidates.filter($$.isNoneArc.bind($$)),
5235
- candidatesForArc = candidates.filter($$.isArc.bind($$));
5236
- function revert(targets) {
5237
- $$.filterTargetsToShow(targets).transition().duration(100).style('opacity', 1);
5238
- }
5239
- revert(candidatesForNoneArc.classed(CLASS.focused, false));
5240
- revert(candidatesForArc);
5630
+ c3_chart_fn.revert = function (targetIds) {
5631
+ var $$ = this.internal, candidates;
5632
+
5633
+ targetIds = $$.mapToTargetIds(targetIds);
5634
+ candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
5635
+
5636
+ candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
5241
5637
  if ($$.hasArcType()) {
5242
- $$.unexpandArc(targetId);
5638
+ $$.unexpandArc(targetIds);
5243
5639
  }
5244
5640
  $$.revertLegend();
5641
+
5642
+ $$.focusedTargetIds = [];
5643
+ $$.defocusedTargetIds = [];
5245
5644
  };
5246
5645
 
5247
5646
  c3_chart_fn.show = function (targetIds, options) {
5248
- var $$ = this.internal;
5647
+ var $$ = this.internal, targets;
5249
5648
 
5250
5649
  targetIds = $$.mapToTargetIds(targetIds);
5251
5650
  options = options || {};
5252
5651
 
5253
5652
  $$.removeHiddenTargetIds(targetIds);
5254
- $$.svg.selectAll($$.selectorTargets(targetIds))
5255
- .transition()
5256
- .style('opacity', 1);
5653
+ targets = $$.svg.selectAll($$.selectorTargets(targetIds));
5654
+
5655
+ targets.transition()
5656
+ .style('opacity', 1, 'important')
5657
+ .call($$.endall, function () {
5658
+ targets.style('opacity', null).style('opacity', 1);
5659
+ });
5257
5660
 
5258
5661
  if (options.withLegend) {
5259
5662
  $$.showLegend(targetIds);
@@ -5263,15 +5666,19 @@
5263
5666
  };
5264
5667
 
5265
5668
  c3_chart_fn.hide = function (targetIds, options) {
5266
- var $$ = this.internal;
5669
+ var $$ = this.internal, targets;
5267
5670
 
5268
5671
  targetIds = $$.mapToTargetIds(targetIds);
5269
5672
  options = options || {};
5270
5673
 
5271
5674
  $$.addHiddenTargetIds(targetIds);
5272
- $$.svg.selectAll($$.selectorTargets(targetIds))
5273
- .transition()
5274
- .style('opacity', 0);
5675
+ targets = $$.svg.selectAll($$.selectorTargets(targetIds));
5676
+
5677
+ targets.transition()
5678
+ .style('opacity', 0, 'important')
5679
+ .call($$.endall, function () {
5680
+ targets.style('opacity', null).style('opacity', 0);
5681
+ });
5275
5682
 
5276
5683
  if (options.withLegend) {
5277
5684
  $$.hideLegend(targetIds);
@@ -5285,7 +5692,16 @@
5285
5692
  $$.isTargetToShow(targetId) ? this.hide(targetId) : this.show(targetId);
5286
5693
  };
5287
5694
 
5288
- c3_chart_fn.zoom = function () {
5695
+ c3_chart_fn.zoom = function (domain) {
5696
+ var $$ = this.internal;
5697
+ if (domain) {
5698
+ if ($$.isTimeSeries()) {
5699
+ domain = domain.map(function (x) { return $$.parseDate(x); });
5700
+ }
5701
+ $$.brush.extent(domain);
5702
+ $$.redraw({withUpdateXDomain: true});
5703
+ }
5704
+ return $$.brush.extent();
5289
5705
  };
5290
5706
  c3_chart_fn.zoom.enable = function (enabled) {
5291
5707
  var $$ = this.internal;
@@ -5314,6 +5730,12 @@
5314
5730
  if ('categories' in args && $$.isCategorized()) {
5315
5731
  config.axis_x_categories = args.categories;
5316
5732
  }
5733
+ // update axes if exists
5734
+ if ('axes' in args) {
5735
+ Object.keys(args.axes).forEach(function (id) {
5736
+ config.data_axes[id] = args.axes[id];
5737
+ });
5738
+ }
5317
5739
  // use cache if exists
5318
5740
  if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
5319
5741
  $$.load($$.getCaches(args.cacheIds), args.done);
@@ -5333,6 +5755,11 @@
5333
5755
  c3_chart_fn.unload = function (args) {
5334
5756
  var $$ = this.internal;
5335
5757
  args = args || {};
5758
+ if (args instanceof Array) {
5759
+ args = {ids: args};
5760
+ } else if (typeof args === 'string') {
5761
+ args = {ids: [args]};
5762
+ }
5336
5763
  $$.unload($$.mapToTargetIds(args.ids), function () {
5337
5764
  $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
5338
5765
  if (args.done) { args.done(); }
@@ -5454,12 +5881,12 @@
5454
5881
  diff = 1;
5455
5882
  }
5456
5883
  domain = [baseValue.x - diff, baseValue.x];
5457
- $$.updateXDomain(null, true, true, domain);
5884
+ $$.updateXDomain(null, true, true, false, domain);
5458
5885
  } else if (orgDataCount === 1) {
5459
5886
  if ($$.isTimeSeries()) {
5460
5887
  diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
5461
5888
  domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
5462
- $$.updateXDomain(null, true, true, domain);
5889
+ $$.updateXDomain(null, true, true, false, domain);
5463
5890
  }
5464
5891
  }
5465
5892
 
@@ -5477,6 +5904,7 @@
5477
5904
  },
5478
5905
  withLegend: true,
5479
5906
  withTransition: orgDataCount > 1,
5907
+ withTrimXDomain: false
5480
5908
  });
5481
5909
  };
5482
5910
 
@@ -5515,6 +5943,9 @@
5515
5943
  mainArea = $$.mainArea || d3.selectAll([]),
5516
5944
  mainCircle = $$.mainCircle || d3.selectAll([]);
5517
5945
 
5946
+ // set flag
5947
+ $$.flowing = true;
5948
+
5518
5949
  // remove head data after rendered
5519
5950
  $$.data.targets.forEach(function (d) {
5520
5951
  d.values.splice(0, flowLength);
@@ -5550,6 +5981,10 @@
5550
5981
  scaleX = (diffDomain(orgDomain) / diffDomain(domain));
5551
5982
  transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
5552
5983
 
5984
+ // hide tooltip
5985
+ $$.hideXGridFocus();
5986
+ $$.hideTooltip();
5987
+
5553
5988
  d3.transition().ease('linear').duration(durationForFlow).each(function () {
5554
5989
  wait.add($$.axes.x.transition().call($$.xAxis));
5555
5990
  wait.add(mainBar.transition().attr('transform', transform));
@@ -5612,10 +6047,15 @@
5612
6047
  mainRegion.select('rect').filter($$.isRegionOnX)
5613
6048
  .attr("x", $$.regionX.bind($$))
5614
6049
  .attr("width", $$.regionWidth.bind($$));
5615
- $$.updateEventRect();
6050
+
6051
+ if (config.interaction_enabled) {
6052
+ $$.redrawEventRect();
6053
+ }
5616
6054
 
5617
6055
  // callback for end of flow
5618
6056
  done();
6057
+
6058
+ $$.flowing = false;
5619
6059
  });
5620
6060
  };
5621
6061
  };
@@ -5633,7 +6073,7 @@
5633
6073
  if (! config.data_selection_enabled) { return; }
5634
6074
  $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
5635
6075
  var shape = d3.select(this), id = d.data ? d.data.id : d.id,
5636
- toggle = $$.getToggle(this).bind($$),
6076
+ toggle = $$.getToggle(this, d).bind($$),
5637
6077
  isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
5638
6078
  isTargetIndex = !indices || indices.indexOf(i) >= 0,
5639
6079
  isSelected = shape.classed(CLASS.SELECTED);
@@ -5657,7 +6097,7 @@
5657
6097
  if (! config.data_selection_enabled) { return; }
5658
6098
  $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
5659
6099
  var shape = d3.select(this), id = d.data ? d.data.id : d.id,
5660
- toggle = $$.getToggle(this).bind($$),
6100
+ toggle = $$.getToggle(this, d).bind($$),
5661
6101
  isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
5662
6102
  isTargetIndex = !indices || indices.indexOf(i) >= 0,
5663
6103
  isSelected = shape.classed(CLASS.SELECTED);
@@ -5760,10 +6200,10 @@
5760
6200
 
5761
6201
  config.regions = config.regions.filter(function (region) {
5762
6202
  var found = false;
5763
- if (!region.class) {
6203
+ if (!region['class']) {
5764
6204
  return true;
5765
6205
  }
5766
- region.class.split(' ').forEach(function (c) {
6206
+ region['class'].split(' ').forEach(function (c) {
5767
6207
  if (classes.indexOf(c) >= 0) { found = true; }
5768
6208
  });
5769
6209
  return !found;
@@ -5772,32 +6212,27 @@
5772
6212
  return config.regions;
5773
6213
  };
5774
6214
 
5775
- c3_chart_fn.data = function () {};
5776
- c3_chart_fn.data.get = function (targetId) {
5777
- var target = this.data.getAsTarget(targetId);
5778
- return isDefined(target) ? target.values.map(function (d) { return d.value; }) : undefined;
6215
+ c3_chart_fn.data = function (targetIds) {
6216
+ var targets = this.internal.data.targets;
6217
+ return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
6218
+ return [].concat(targetIds).indexOf(t.id) >= 0;
6219
+ });
6220
+ };
6221
+ c3_chart_fn.data.shown = function (targetId) {
6222
+ return this.internal.filterTargetsToShow(this.data(targetId));
5779
6223
  };
5780
- c3_chart_fn.data.getAsTarget = function (targetId) {
5781
- var targets = this.data.targets.filter(function (t) { return t.id === targetId; });
5782
- return targets.length > 0 ? targets[0] : undefined;
6224
+ c3_chart_fn.data.values = function (targetId) {
6225
+ var target = this.data(targetId);
6226
+ return target ? target.values.map(function (d) { return d.value; }) : null;
5783
6227
  };
5784
6228
  c3_chart_fn.data.names = function (names) {
5785
- var $$ = this.internal, config = $$.config;
5786
- if (!arguments.length) { return config.data_names; }
5787
- Object.keys(names).forEach(function (id) {
5788
- config.data_names[id] = names[id];
5789
- });
5790
- $$.redraw({withLegend: true});
5791
- return config.data_names;
6229
+ return this.internal.updateDataAttributes('names', names);
5792
6230
  };
5793
6231
  c3_chart_fn.data.colors = function (colors) {
5794
- var $$ = this.internal, config = $$.config;
5795
- if (!arguments.length) { return config.data_colors; }
5796
- Object.keys(colors).forEach(function (id) {
5797
- config.data_colors[id] = colors[id];
5798
- });
5799
- $$.redraw({withLegend: true});
5800
- return config.data_colors;
6232
+ return this.internal.updateDataAttributes('colors', colors);
6233
+ };
6234
+ c3_chart_fn.data.axes = function (axes) {
6235
+ return this.internal.updateDataAttributes('axes', axes);
5801
6236
  };
5802
6237
 
5803
6238
  c3_chart_fn.category = function (i, category) {
@@ -5861,6 +6296,12 @@
5861
6296
  config.axis_y_max = config.axis_y2_max = max;
5862
6297
  }
5863
6298
  $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
6299
+ } else {
6300
+ return {
6301
+ x: config.axis_x_max,
6302
+ y: config.axis_y_max,
6303
+ y2: config.axis_y2_max
6304
+ };
5864
6305
  }
5865
6306
  };
5866
6307
  c3_chart_fn.axis.min = function (min) {
@@ -5874,12 +6315,23 @@
5874
6315
  config.axis_y_min = config.axis_y2_min = min;
5875
6316
  }
5876
6317
  $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
6318
+ } else {
6319
+ return {
6320
+ x: config.axis_x_min,
6321
+ y: config.axis_y_min,
6322
+ y2: config.axis_y2_min
6323
+ };
5877
6324
  }
5878
6325
  };
5879
6326
  c3_chart_fn.axis.range = function (range) {
5880
6327
  if (arguments.length) {
5881
6328
  if (isDefined(range.max)) { this.axis.max(range.max); }
5882
6329
  if (isDefined(range.min)) { this.axis.min(range.min); }
6330
+ } else {
6331
+ return {
6332
+ max: this.axis.max(),
6333
+ min: this.axis.min()
6334
+ };
5883
6335
  }
5884
6336
  };
5885
6337
 
@@ -5912,17 +6364,57 @@
5912
6364
  $$.data.targets = undefined;
5913
6365
  $$.data.xs = {};
5914
6366
  $$.selectChart.classed('c3', false).html("");
6367
+ window.clearInterval($$.intervalForObserveInserted);
5915
6368
  window.onresize = null;
5916
6369
  };
5917
6370
 
6371
+ c3_chart_fn.tooltip = function () {};
6372
+ c3_chart_fn.tooltip.show = function (args) {
6373
+ var $$ = this.internal, index, mouse;
6374
+
6375
+ // determine mouse position on the chart
6376
+ if (args.mouse) {
6377
+ mouse = args.mouse;
6378
+ }
6379
+
6380
+ // determine focus data
6381
+ if (args.data) {
6382
+ if ($$.isMultipleX()) {
6383
+ // if multiple xs, target point will be determined by mouse
6384
+ mouse = [$$.x(args.data.x), $$.getYScale(args.data.id)(args.data.value)];
6385
+ index = null;
6386
+ } else {
6387
+ // TODO: when tooltip_grouped = false
6388
+ index = isValue(args.data.index) ? args.data.index : $$.getIndexByX(args.data.x);
6389
+ }
6390
+ }
6391
+ else if (typeof args.x !== 'undefined') {
6392
+ index = $$.getIndexByX(args.x);
6393
+ }
6394
+ else if (typeof args.index !== 'undefined') {
6395
+ index = args.index;
6396
+ }
6397
+
6398
+ // emulate mouse events to show
6399
+ $$.dispatchEvent('mouseover', index, mouse);
6400
+ $$.dispatchEvent('mousemove', index, mouse);
6401
+ };
6402
+ c3_chart_fn.tooltip.hide = function () {
6403
+ // TODO: get target data by checking the state of focus
6404
+ this.internal.dispatchEvent('mouseout', 0);
6405
+ };
6406
+
5918
6407
  // Features:
5919
6408
  // 1. category axis
5920
6409
  // 2. ceil values of translate/x/y to int for half pixel antialiasing
5921
- function c3_axis(d3, isCategory) {
5922
- var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
6410
+ function c3_axis(d3, params) {
6411
+ var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
5923
6412
 
5924
6413
  var tickOffset = 0, tickCulling = true, tickCentered;
5925
6414
 
6415
+ params = params || {};
6416
+ outerTickSize = params.withOuterTick ? 6 : 0;
6417
+
5926
6418
  function axisX(selection, x) {
5927
6419
  selection.attr("transform", function (d) {
5928
6420
  return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
@@ -5953,7 +6445,7 @@
5953
6445
  }
5954
6446
  function copyScale() {
5955
6447
  var newScale = scale.copy(), domain;
5956
- if (isCategory) {
6448
+ if (params.isCategory) {
5957
6449
  domain = scale.domain();
5958
6450
  newScale.domain([domain[0], domain[1] - 1]);
5959
6451
  }
@@ -5962,6 +6454,23 @@
5962
6454
  function textFormatted(v) {
5963
6455
  return tickFormat ? tickFormat(v) : v;
5964
6456
  }
6457
+ function getSizeFor1Char(tick) {
6458
+ var size = {
6459
+ h: 11.5,
6460
+ w: 5.5
6461
+ };
6462
+ tick.select('text').text(textFormatted).each(function (d) {
6463
+ var box = this.getBoundingClientRect(),
6464
+ text = textFormatted(d),
6465
+ h = box.height,
6466
+ w = text ? (box.width / text.length) : undefined;
6467
+ if (h && w) {
6468
+ size.h = h;
6469
+ size.w = w;
6470
+ }
6471
+ }).text('');
6472
+ return size;
6473
+ }
5965
6474
  function axis(g) {
5966
6475
  g.each(function () {
5967
6476
  var g = d3.select(this);
@@ -5973,7 +6482,7 @@
5973
6482
  // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
5974
6483
  tickExit = tick.exit().remove(),
5975
6484
  tickUpdate = d3.transition(tick).style("opacity", 1),
5976
- tickTransform, tickX;
6485
+ tickTransform, tickX, tickY;
5977
6486
 
5978
6487
  var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
5979
6488
  path = g.selectAll(".domain").data([ 0 ]),
@@ -5983,31 +6492,95 @@
5983
6492
 
5984
6493
  var lineEnter = tickEnter.select("line"),
5985
6494
  lineUpdate = tickUpdate.select("line"),
5986
- text = tick.select("text").text(textFormatted),
5987
6495
  textEnter = tickEnter.select("text"),
5988
6496
  textUpdate = tickUpdate.select("text");
5989
6497
 
5990
- if (isCategory) {
6498
+ if (params.isCategory) {
5991
6499
  tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
5992
6500
  tickX = tickCentered ? 0 : tickOffset;
6501
+ tickY = tickCentered ? tickOffset : 0;
5993
6502
  } else {
5994
6503
  tickOffset = tickX = 0;
5995
6504
  }
5996
6505
 
6506
+ var text, tspan, sizeFor1Char = getSizeFor1Char(tick), counts = [];
6507
+ var tickLength = Math.max(innerTickSize, 0) + tickPadding,
6508
+ isVertical = orient === 'left' || orient === 'right';
6509
+
6510
+ // this should be called only when category axis
6511
+ function splitTickText(d, maxWidth) {
6512
+ var tickText = textFormatted(d),
6513
+ subtext, spaceIndex, textWidth, splitted = [];
6514
+
6515
+ if (Object.prototype.toString.call(tickText) === "[object Array]") {
6516
+ return tickText;
6517
+ }
6518
+
6519
+ if (!maxWidth || maxWidth <= 0) {
6520
+ maxWidth = isVertical ? 95 : params.isCategory ? (tickOffset * 2 - 10) : 110;
6521
+ }
6522
+
6523
+ function split(splitted, text) {
6524
+ spaceIndex = undefined;
6525
+ for (var i = 1; i < text.length; i++) {
6526
+ if (text.charAt(i) === ' ') {
6527
+ spaceIndex = i;
6528
+ }
6529
+ subtext = text.substr(0, i + 1);
6530
+ textWidth = sizeFor1Char.w * subtext.length;
6531
+ // if text width gets over tick width, split by space index or crrent index
6532
+ if (maxWidth < textWidth) {
6533
+ return split(
6534
+ splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)),
6535
+ text.slice(spaceIndex ? spaceIndex + 1 : i)
6536
+ );
6537
+ }
6538
+ }
6539
+ return splitted.concat(text);
6540
+ }
6541
+
6542
+ return split(splitted, tickText + "");
6543
+ }
6544
+
6545
+ function tspanDy(d, i) {
6546
+ var dy = sizeFor1Char.h;
6547
+ if (i === 0) {
6548
+ if (orient === 'left' || orient === 'right') {
6549
+ dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - (params.isCategory ? 2 : 3));
6550
+ } else {
6551
+ dy = params.isCategory ? ".40em" : ".71em";
6552
+ }
6553
+ }
6554
+ return dy;
6555
+ }
6556
+
5997
6557
  function tickSize(d) {
5998
6558
  var tickPosition = scale(d) + tickOffset;
5999
6559
  return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0;
6000
6560
  }
6001
6561
 
6562
+ text = tick.select("text");
6563
+ tspan = text.selectAll('tspan')
6564
+ .data(function (d, i) {
6565
+ var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
6566
+ counts[i] = splitted.length;
6567
+ return splitted.map(function (s) {
6568
+ return { index: i, splitted: s };
6569
+ });
6570
+ })
6571
+ .enter().append('tspan')
6572
+ .text(function (d) { return d.splitted; });
6573
+
6002
6574
  switch (orient) {
6003
6575
  case "bottom":
6004
6576
  {
6005
6577
  tickTransform = axisX;
6006
6578
  lineEnter.attr("y2", innerTickSize);
6007
- textEnter.attr("y", Math.max(innerTickSize, 0) + tickPadding);
6579
+ textEnter.attr("y", tickLength);
6008
6580
  lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
6009
- textUpdate.attr("x", 0).attr("y", Math.max(innerTickSize, 0) + tickPadding);
6010
- text.attr("dy", ".71em").style("text-anchor", "middle");
6581
+ textUpdate.attr("x", 0).attr("y", tickLength);
6582
+ text.style("text-anchor", "middle");
6583
+ tspan.attr('x', 0).attr("dy", tspanDy);
6011
6584
  pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
6012
6585
  break;
6013
6586
  }
@@ -6015,10 +6588,11 @@
6015
6588
  {
6016
6589
  tickTransform = axisX;
6017
6590
  lineEnter.attr("y2", -innerTickSize);
6018
- textEnter.attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
6591
+ textEnter.attr("y", -tickLength);
6019
6592
  lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
6020
- textUpdate.attr("x", 0).attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
6021
- text.attr("dy", "0em").style("text-anchor", "middle");
6593
+ textUpdate.attr("x", 0).attr("y", -tickLength);
6594
+ text.style("text-anchor", "middle");
6595
+ tspan.attr('x', 0).attr("dy", "0em");
6022
6596
  pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
6023
6597
  break;
6024
6598
  }
@@ -6026,10 +6600,11 @@
6026
6600
  {
6027
6601
  tickTransform = axisY;
6028
6602
  lineEnter.attr("x2", -innerTickSize);
6029
- textEnter.attr("x", -(Math.max(innerTickSize, 0) + tickPadding));
6030
- lineUpdate.attr("x2", -innerTickSize).attr("y2", 0);
6031
- textUpdate.attr("x", -(Math.max(innerTickSize, 0) + tickPadding)).attr("y", tickOffset);
6032
- text.attr("dy", ".32em").style("text-anchor", "end");
6603
+ textEnter.attr("x", -tickLength);
6604
+ lineUpdate.attr("x2", -innerTickSize).attr("y1", tickY).attr("y2", tickY);
6605
+ textUpdate.attr("x", -tickLength).attr("y", tickOffset);
6606
+ text.style("text-anchor", "end");
6607
+ tspan.attr('x', -tickLength).attr("dy", tspanDy);
6033
6608
  pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
6034
6609
  break;
6035
6610
  }
@@ -6037,10 +6612,11 @@
6037
6612
  {
6038
6613
  tickTransform = axisY;
6039
6614
  lineEnter.attr("x2", innerTickSize);
6040
- textEnter.attr("x", Math.max(innerTickSize, 0) + tickPadding);
6615
+ textEnter.attr("x", tickLength);
6041
6616
  lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
6042
- textUpdate.attr("x", Math.max(innerTickSize, 0) + tickPadding).attr("y", 0);
6043
- text.attr("dy", ".32em").style("text-anchor", "start");
6617
+ textUpdate.attr("x", tickLength).attr("y", 0);
6618
+ text.style("text-anchor", "start");
6619
+ tspan.attr('x', tickLength).attr("dy", tspanDy);
6044
6620
  pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
6045
6621
  break;
6046
6622
  }