c3-rails 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }