c3-rails 0.4.8 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,9 +3,30 @@
3
3
 
4
4
  /*global define, module, exports, require */
5
5
 
6
- var c3 = { version: "0.4.8" };
6
+ var c3 = { version: "0.4.10" };
7
7
 
8
- var c3_chart_fn, c3_chart_internal_fn;
8
+ var c3_chart_fn,
9
+ c3_chart_internal_fn,
10
+ c3_chart_internal_axis_fn;
11
+
12
+ function API(owner) {
13
+ this.owner = owner;
14
+ }
15
+
16
+ function inherit(base, derived) {
17
+
18
+ if (Object.create) {
19
+ derived.prototype = Object.create(base.prototype);
20
+ } else {
21
+ var f = function f() {};
22
+ f.prototype = base.prototype;
23
+ derived.prototype = new f();
24
+ }
25
+
26
+ derived.prototype.constructor = derived;
27
+
28
+ return derived;
29
+ }
9
30
 
10
31
  function Chart(config) {
11
32
  var $$ = this.internal = new ChartInternal(this);
@@ -40,12 +61,15 @@
40
61
  c3.chart = {
41
62
  fn: Chart.prototype,
42
63
  internal: {
43
- fn: ChartInternal.prototype
64
+ fn: ChartInternal.prototype,
65
+ axis: {
66
+ fn: Axis.prototype
67
+ }
44
68
  }
45
69
  };
46
70
  c3_chart_fn = c3.chart.fn;
47
71
  c3_chart_internal_fn = c3.chart.internal.fn;
48
-
72
+ c3_chart_internal_axis_fn = c3.chart.internal.axis.fn;
49
73
 
50
74
  c3_chart_internal_fn.init = function () {
51
75
  var $$ = this, config = $$.config;
@@ -154,11 +178,21 @@
154
178
  var $$ = this, d3 = $$.d3, config = $$.config;
155
179
  var defs, main, binding = true;
156
180
 
181
+ $$.axis = new Axis($$);
182
+
157
183
  if ($$.initPie) { $$.initPie(); }
158
184
  if ($$.initBrush) { $$.initBrush(); }
159
185
  if ($$.initZoom) { $$.initZoom(); }
160
186
 
161
- $$.selectChart = typeof config.bindto.node === 'function' ? config.bindto : d3.select(config.bindto);
187
+ if (!config.bindto) {
188
+ $$.selectChart = d3.selectAll([]);
189
+ }
190
+ else if (typeof config.bindto.node === 'function') {
191
+ $$.selectChart = config.bindto;
192
+ }
193
+ else {
194
+ $$.selectChart = d3.select(config.bindto);
195
+ }
162
196
  if ($$.selectChart.empty()) {
163
197
  $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
164
198
  $$.observeInserted($$.selectChart);
@@ -271,7 +305,7 @@
271
305
  if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
272
306
 
273
307
  // Add Axis
274
- $$.initAxis();
308
+ $$.axis.init();
275
309
 
276
310
  // Set targets
277
311
  $$.updateTargets($$.data.targets);
@@ -281,6 +315,7 @@
281
315
  $$.updateDimension();
282
316
  $$.config.oninit.call($$);
283
317
  $$.redraw({
318
+ withTransition: false,
284
319
  withTransform: true,
285
320
  withUpdateXDomain: true,
286
321
  withUpdateOrgXDomain: true,
@@ -399,7 +434,7 @@
399
434
  };
400
435
 
401
436
  c3_chart_internal_fn.updateTargets = function (targets) {
402
- var $$ = this, config = $$.config;
437
+ var $$ = this;
403
438
 
404
439
  /*-- Main --*/
405
440
 
@@ -413,14 +448,19 @@
413
448
  $$.updateTargetsForLine(targets);
414
449
 
415
450
  //-- Arc --//
416
- if ($$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
417
- if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
451
+ if ($$.hasArcType() && $$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
418
452
 
419
- /*-- Show --*/
453
+ /*-- Sub --*/
454
+
455
+ if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
420
456
 
421
457
  // Fade-in each chart
458
+ $$.showTargets();
459
+ };
460
+ c3_chart_internal_fn.showTargets = function () {
461
+ var $$ = this;
422
462
  $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); })
423
- .transition().duration(config.transition_duration)
463
+ .transition().duration($$.config.transition_duration)
424
464
  .style("opacity", 1);
425
465
  };
426
466
 
@@ -456,7 +496,7 @@
456
496
  durationForExit = withTransitionForExit ? duration : 0;
457
497
  durationForAxis = withTransitionForAxis ? duration : 0;
458
498
 
459
- transitions = transitions || $$.generateAxisTransitions(durationForAxis);
499
+ transitions = transitions || $$.axis.generateTransitions(durationForAxis);
460
500
 
461
501
  // update legend and transform each g
462
502
  if (withLegend && config.legend_show) {
@@ -475,13 +515,7 @@
475
515
  if (targetsToShow.length) {
476
516
  $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
477
517
  if (!config.axis_x_tick_values) {
478
- if (config.axis_x_tick_fit || config.axis_x_tick_count) {
479
- tickValues = $$.generateTickValues($$.mapTargetsToUniqueXs(targetsToShow), config.axis_x_tick_count, $$.isTimeSeries());
480
- } else {
481
- tickValues = undefined;
482
- }
483
- $$.xAxis.tickValues(tickValues);
484
- $$.subXAxis.tickValues(tickValues);
518
+ tickValues = $$.axis.updateXAxisTickValues(targetsToShow);
485
519
  }
486
520
  } else {
487
521
  $$.xAxis.tickValues([]);
@@ -496,17 +530,17 @@
496
530
  $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
497
531
 
498
532
  if (!config.axis_y_tick_values && config.axis_y_tick_count) {
499
- $$.yAxis.tickValues($$.generateTickValues($$.y.domain(), config.axis_y_tick_count));
533
+ $$.yAxis.tickValues($$.axis.generateTickValues($$.y.domain(), config.axis_y_tick_count));
500
534
  }
501
535
  if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
502
- $$.y2Axis.tickValues($$.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
536
+ $$.y2Axis.tickValues($$.axis.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
503
537
  }
504
538
 
505
539
  // axes
506
- $$.redrawAxis(transitions, hideAxis);
540
+ $$.axis.redraw(transitions, hideAxis);
507
541
 
508
542
  // Update axis label
509
- $$.updateAxisLabels(withTransition);
543
+ $$.axis.updateLabels(withTransition);
510
544
 
511
545
  // show/hide if manual culling needed
512
546
  if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
@@ -556,22 +590,22 @@
556
590
  .style('opacity', targetsToShow.length ? 0 : 1);
557
591
 
558
592
  // grid
559
- $$.redrawGrid(duration);
593
+ $$.updateGrid(duration);
560
594
 
561
595
  // rect for regions
562
- $$.redrawRegion(duration);
596
+ $$.updateRegion(duration);
563
597
 
564
598
  // bars
565
- $$.redrawBar(durationForExit);
599
+ $$.updateBar(durationForExit);
566
600
 
567
601
  // lines, areas and cricles
568
- $$.redrawLine(durationForExit);
569
- $$.redrawArea(durationForExit);
570
- $$.redrawCircle();
602
+ $$.updateLine(durationForExit);
603
+ $$.updateArea(durationForExit);
604
+ $$.updateCircle();
571
605
 
572
606
  // text
573
607
  if ($$.hasDataLabel()) {
574
- $$.redrawText(durationForExit);
608
+ $$.updateText(durationForExit);
575
609
  }
576
610
 
577
611
  // arc
@@ -601,40 +635,69 @@
601
635
  cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
602
636
  cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
603
637
 
604
- // transition should be derived from one transition
605
- d3.transition().duration(duration).each(function () {
606
- var transitions = [];
638
+ if (options.flow) {
639
+ flow = $$.generateFlow({
640
+ targets: targetsToShow,
641
+ flow: options.flow,
642
+ duration: options.flow.duration,
643
+ drawBar: drawBar,
644
+ drawLine: drawLine,
645
+ drawArea: drawArea,
646
+ cx: cx,
647
+ cy: cy,
648
+ xv: xv,
649
+ xForText: xForText,
650
+ yForText: yForText
651
+ });
652
+ }
607
653
 
608
- $$.addTransitionForBar(transitions, drawBar);
609
- $$.addTransitionForLine(transitions, drawLine);
610
- $$.addTransitionForArea(transitions, drawArea);
611
- $$.addTransitionForCircle(transitions, cx, cy);
612
- $$.addTransitionForText(transitions, xForText, yForText, options.flow);
613
- $$.addTransitionForRegion(transitions);
614
- $$.addTransitionForGrid(transitions);
654
+ if ((duration || flow) && $$.isTabVisible()) { // Only use transition if tab visible. See #938.
655
+ // transition should be derived from one transition
656
+ d3.transition().duration(duration).each(function () {
657
+ var transitionsToWait = [];
658
+
659
+ // redraw and gather transitions
660
+ [
661
+ $$.redrawBar(drawBar, true),
662
+ $$.redrawLine(drawLine, true),
663
+ $$.redrawArea(drawArea, true),
664
+ $$.redrawCircle(cx, cy, true),
665
+ $$.redrawText(xForText, yForText, options.flow, true),
666
+ $$.redrawRegion(true),
667
+ $$.redrawGrid(true),
668
+ ].forEach(function (transitions) {
669
+ transitions.forEach(function (transition) {
670
+ transitionsToWait.push(transition);
671
+ });
672
+ });
615
673
 
616
- // Wait for end of transitions if called from flow API
617
- if (options.flow) {
674
+ // Wait for end of transitions to call flow and onrendered callback
618
675
  waitForDraw = $$.generateWait();
619
- transitions.forEach(function (t) {
676
+ transitionsToWait.forEach(function (t) {
620
677
  waitForDraw.add(t);
621
678
  });
622
- flow = $$.generateFlow({
623
- targets: targetsToShow,
624
- flow: options.flow,
625
- duration: duration,
626
- drawBar: drawBar,
627
- drawLine: drawLine,
628
- drawArea: drawArea,
629
- cx: cx,
630
- cy: cy,
631
- xv: xv,
632
- xForText: xForText,
633
- yForText: yForText
634
- });
679
+ })
680
+ .call(waitForDraw, function () {
681
+ if (flow) {
682
+ flow();
683
+ }
684
+ if (config.onrendered) {
685
+ config.onrendered.call($$);
686
+ }
687
+ });
688
+ }
689
+ else {
690
+ $$.redrawBar(drawBar);
691
+ $$.redrawLine(drawLine);
692
+ $$.redrawArea(drawArea);
693
+ $$.redrawCircle(cx, cy);
694
+ $$.redrawText(xForText, yForText, options.flow);
695
+ $$.redrawRegion();
696
+ $$.redrawGrid();
697
+ if (config.onrendered) {
698
+ config.onrendered.call($$);
635
699
  }
636
- })
637
- .call(waitForDraw || function () {}, flow || function () {});
700
+ }
638
701
 
639
702
  // update fadein condition
640
703
  $$.mapToIds($$.data.targets).forEach(function (id) {
@@ -658,7 +721,7 @@
658
721
  $$.updateSizes();
659
722
  // MEMO: called in updateLegend in redraw if withLegend
660
723
  if (!(options.withLegend && config.legend_show)) {
661
- transitions = $$.generateAxisTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
724
+ transitions = $$.axis.generateTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
662
725
  // Update scales
663
726
  $$.updateScales();
664
727
  $$.updateSvgSize();
@@ -836,7 +899,12 @@
836
899
  };
837
900
 
838
901
  c3_chart_internal_fn.observeInserted = function (selection) {
839
- var $$ = this, observer = new MutationObserver(function (mutations) {
902
+ var $$ = this, observer;
903
+ if (typeof MutationObserver === 'undefined') {
904
+ window.console.error("MutationObserver not defined.");
905
+ return;
906
+ }
907
+ observer= new MutationObserver(function (mutations) {
840
908
  mutations.forEach(function (mutation) {
841
909
  if (mutation.type === 'childList' && mutation.previousSibling) {
842
910
  observer.disconnect();
@@ -918,10 +986,10 @@
918
986
  var $$ = this, parsedDate;
919
987
  if (date instanceof Date) {
920
988
  parsedDate = date;
989
+ } else if (typeof date === 'string') {
990
+ parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
921
991
  } else if (typeof date === 'number' || !isNaN(date)) {
922
992
  parsedDate = new Date(+date);
923
- } else {
924
- parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
925
993
  }
926
994
  if (!parsedDate || isNaN(+parsedDate)) {
927
995
  window.console.error("Failed to parse x '" + date + "' to Date object");
@@ -929,6 +997,21 @@
929
997
  return parsedDate;
930
998
  };
931
999
 
1000
+ c3_chart_internal_fn.isTabVisible = function () {
1001
+ var hidden;
1002
+ if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
1003
+ hidden = "hidden";
1004
+ } else if (typeof document.mozHidden !== "undefined") {
1005
+ hidden = "mozHidden";
1006
+ } else if (typeof document.msHidden !== "undefined") {
1007
+ hidden = "msHidden";
1008
+ } else if (typeof document.webkitHidden !== "undefined") {
1009
+ hidden = "webkitHidden";
1010
+ }
1011
+
1012
+ return document[hidden] ? false : true;
1013
+ };
1014
+
932
1015
  c3_chart_internal_fn.getDefaultConfig = function () {
933
1016
  var config = {
934
1017
  bindto: '#chart',
@@ -951,6 +1034,7 @@
951
1034
  onresize: function () {},
952
1035
  onresized: function () {},
953
1036
  oninit: function () {},
1037
+ onrendered: function () {},
954
1038
  transition_duration: 350,
955
1039
  data_x: undefined,
956
1040
  data_xs: {},
@@ -975,13 +1059,12 @@
975
1059
  data_selection_grouped: false,
976
1060
  data_selection_isselectable: function () { return true; },
977
1061
  data_selection_multiple: true,
1062
+ data_selection_draggable: false,
978
1063
  data_onclick: function () {},
979
1064
  data_onmouseover: function () {},
980
1065
  data_onmouseout: function () {},
981
1066
  data_onselected: function () {},
982
1067
  data_onunselected: function () {},
983
- data_ondragstart: function () {},
984
- data_ondragend: function () {},
985
1068
  data_url: undefined,
986
1069
  data_json: undefined,
987
1070
  data_rows: undefined,
@@ -1036,6 +1119,7 @@
1036
1119
  axis_y_type: undefined,
1037
1120
  axis_y_max: undefined,
1038
1121
  axis_y_min: undefined,
1122
+ axis_y_inverted: false,
1039
1123
  axis_y_center: undefined,
1040
1124
  axis_y_inner: undefined,
1041
1125
  axis_y_label: {},
@@ -1050,6 +1134,7 @@
1050
1134
  axis_y2_show: false,
1051
1135
  axis_y2_max: undefined,
1052
1136
  axis_y2_min: undefined,
1137
+ axis_y2_inverted: false,
1053
1138
  axis_y2_center: undefined,
1054
1139
  axis_y2_inner: undefined,
1055
1140
  axis_y2_label: {},
@@ -1114,6 +1199,7 @@
1114
1199
  tooltip_format_title: undefined,
1115
1200
  tooltip_format_name: undefined,
1116
1201
  tooltip_format_value: undefined,
1202
+ tooltip_position: undefined,
1117
1203
  tooltip_contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
1118
1204
  return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
1119
1205
  },
@@ -1203,10 +1289,10 @@
1203
1289
  return scale;
1204
1290
  };
1205
1291
  c3_chart_internal_fn.getYScale = function (id) {
1206
- return this.getAxisId(id) === 'y2' ? this.y2 : this.y;
1292
+ return this.axis.getId(id) === 'y2' ? this.y2 : this.y;
1207
1293
  };
1208
1294
  c3_chart_internal_fn.getSubYScale = function (id) {
1209
- return this.getAxisId(id) === 'y2' ? this.subY2 : this.subY;
1295
+ return this.axis.getId(id) === 'y2' ? this.subY2 : this.subY;
1210
1296
  };
1211
1297
  c3_chart_internal_fn.updateScales = function () {
1212
1298
  var $$ = this, config = $$.config,
@@ -1228,15 +1314,15 @@
1228
1314
  $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
1229
1315
  $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
1230
1316
  // update axes
1231
- $$.xAxisTickFormat = $$.getXAxisTickFormat();
1232
- $$.xAxisTickValues = $$.getXAxisTickValues();
1233
- $$.yAxisTickValues = $$.getYAxisTickValues();
1234
- $$.y2AxisTickValues = $$.getY2AxisTickValues();
1317
+ $$.xAxisTickFormat = $$.axis.getXAxisTickFormat();
1318
+ $$.xAxisTickValues = $$.axis.getXAxisTickValues();
1319
+ $$.yAxisTickValues = $$.axis.getYAxisTickValues();
1320
+ $$.y2AxisTickValues = $$.axis.getY2AxisTickValues();
1235
1321
 
1236
- $$.xAxis = $$.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1237
- $$.subXAxis = $$.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1238
- $$.yAxis = $$.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
1239
- $$.y2Axis = $$.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
1322
+ $$.xAxis = $$.axis.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1323
+ $$.subXAxis = $$.axis.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
1324
+ $$.yAxis = $$.axis.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
1325
+ $$.y2Axis = $$.axis.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
1240
1326
 
1241
1327
  // Set initialized scales to brush and zoom
1242
1328
  if (!forInit) {
@@ -1269,7 +1355,7 @@
1269
1355
  id = idsInGroup[k];
1270
1356
  if (! ys[id]) { continue; }
1271
1357
  ys[id].forEach(function (v, i) {
1272
- if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
1358
+ if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
1273
1359
  ys[baseId][i] += +v;
1274
1360
  }
1275
1361
  });
@@ -1300,7 +1386,7 @@
1300
1386
  id = idsInGroup[k];
1301
1387
  if (! ys[id]) { continue; }
1302
1388
  ys[id].forEach(function (v, i) {
1303
- if ($$.getAxisId(id) === $$.getAxisId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
1389
+ if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
1304
1390
  ys[baseId][i] += +v;
1305
1391
  }
1306
1392
  });
@@ -1311,26 +1397,23 @@
1311
1397
  };
1312
1398
  c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
1313
1399
  var $$ = this, config = $$.config,
1314
- targetsByAxisId = targets.filter(function (t) { return $$.getAxisId(t.id) === axisId; }),
1400
+ targetsByAxisId = targets.filter(function (t) { return $$.axis.getId(t.id) === axisId; }),
1315
1401
  yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
1316
1402
  yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
1317
1403
  yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
1318
- yDomainMin = isValue(yMin) ? yMin : $$.getYDomainMin(yTargets),
1319
- yDomainMax = isValue(yMax) ? yMax : $$.getYDomainMax(yTargets),
1320
- domainLength, padding, padding_top, padding_bottom,
1404
+ yDomainMin = $$.getYDomainMin(yTargets),
1405
+ yDomainMax = $$.getYDomainMax(yTargets),
1406
+ domain, domainLength, padding, padding_top, padding_bottom,
1321
1407
  center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
1322
1408
  yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative,
1323
1409
  isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
1410
+ isInverted = axisId === 'y2' ? config.axis_y2_inverted : config.axis_y_inverted,
1324
1411
  showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
1325
1412
  showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
1326
1413
 
1327
- if (yDomainMax < yDomainMin) {
1328
- if (isValue(yMin)) {
1329
- yDomainMax = yDomainMin + 10; // TODO: introduce axis.y.maxMin
1330
- } else {
1331
- yDomainMin = yDomainMax - 10; // TODO: introduce axis.y.minMax
1332
- }
1333
- }
1414
+ // MEMO: avoid inverting domain unexpectedly
1415
+ yDomainMin = isValue(yMin) ? yMin : isValue(yMax) ? (yDomainMin < yMax ? yDomainMin : yMax - 10) : yDomainMin;
1416
+ yDomainMax = isValue(yMax) ? yMax : isValue(yMin) ? (yMin < yDomainMax ? yDomainMax : yMin + 10) : yDomainMax;
1334
1417
 
1335
1418
  if (yTargets.length === 0) { // use current domain if target of axisId is none
1336
1419
  return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
@@ -1368,30 +1451,31 @@
1368
1451
  }
1369
1452
  // add padding for data label
1370
1453
  if (showHorizontalDataLabel) {
1371
- lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'width');
1454
+ lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'width');
1372
1455
  diff = diffDomain($$.y.range());
1373
1456
  ratio = [lengths[0] / diff, lengths[1] / diff];
1374
1457
  padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
1375
1458
  padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
1376
1459
  } else if (showVerticalDataLabel) {
1377
- lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, axisId, 'height');
1378
- padding_top += this.convertPixelsToAxisPadding(lengths[1], domainLength);
1379
- padding_bottom += this.convertPixelsToAxisPadding(lengths[0], domainLength);
1460
+ lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'height');
1461
+ padding_top += $$.axis.convertPixelsToAxisPadding(lengths[1], domainLength);
1462
+ padding_bottom += $$.axis.convertPixelsToAxisPadding(lengths[0], domainLength);
1380
1463
  }
1381
1464
  if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
1382
- padding_top = $$.getAxisPadding(config.axis_y_padding, 'top', padding_top, domainLength);
1383
- padding_bottom = $$.getAxisPadding(config.axis_y_padding, 'bottom', padding_bottom, domainLength);
1465
+ padding_top = $$.axis.getPadding(config.axis_y_padding, 'top', padding_top, domainLength);
1466
+ padding_bottom = $$.axis.getPadding(config.axis_y_padding, 'bottom', padding_bottom, domainLength);
1384
1467
  }
1385
1468
  if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
1386
- padding_top = $$.getAxisPadding(config.axis_y2_padding, 'top', padding_top, domainLength);
1387
- padding_bottom = $$.getAxisPadding(config.axis_y2_padding, 'bottom', padding_bottom, domainLength);
1469
+ padding_top = $$.axis.getPadding(config.axis_y2_padding, 'top', padding_top, domainLength);
1470
+ padding_bottom = $$.axis.getPadding(config.axis_y2_padding, 'bottom', padding_bottom, domainLength);
1388
1471
  }
1389
1472
  // Bar/Area chart should be 0-based if all positive|negative
1390
1473
  if (isZeroBased) {
1391
1474
  if (isAllPositive) { padding_bottom = yDomainMin; }
1392
1475
  if (isAllNegative) { padding_top = -yDomainMax; }
1393
1476
  }
1394
- return [yDomainMin - padding_bottom, yDomainMax + padding_top];
1477
+ domain = [yDomainMin - padding_bottom, yDomainMax + padding_top];
1478
+ return isInverted ? domain.reverse() : domain;
1395
1479
  };
1396
1480
  c3_chart_internal_fn.getXDomainMin = function (targets) {
1397
1481
  var $$ = this, config = $$.config;
@@ -1747,13 +1831,13 @@
1747
1831
  }
1748
1832
  return false;
1749
1833
  };
1750
- c3_chart_internal_fn.getDataLabelLength = function (min, max, axisId, key) {
1834
+ c3_chart_internal_fn.getDataLabelLength = function (min, max, key) {
1751
1835
  var $$ = this,
1752
1836
  lengths = [0, 0], paddingCoef = 1.3;
1753
1837
  $$.selectChart.select('svg').selectAll('.dummy')
1754
1838
  .data([min, max])
1755
1839
  .enter().append('text')
1756
- .text(function (d) { return $$.formatByAxisId(axisId)(d); })
1840
+ .text(function (d) { return $$.dataLabelFormat(d.id)(d); })
1757
1841
  .each(function (d, i) {
1758
1842
  lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
1759
1843
  })
@@ -1858,6 +1942,9 @@
1858
1942
  var $$ = this, type = mimeType ? mimeType : 'csv';
1859
1943
  $$.d3.xhr(url, function (error, data) {
1860
1944
  var d;
1945
+ if (!data) {
1946
+ throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')');
1947
+ }
1861
1948
  if (type === 'json') {
1862
1949
  d = $$.convertJsonToData(JSON.parse(data.response), keys);
1863
1950
  } else if (type === 'tsv') {
@@ -1890,10 +1977,11 @@
1890
1977
  var $$ = this,
1891
1978
  new_rows = [], targetKeys, data;
1892
1979
  if (keys) { // when keys specified, json would be an array that includes objects
1893
- targetKeys = keys.value;
1894
1980
  if (keys.x) {
1895
- targetKeys.push(keys.x);
1981
+ targetKeys = keys.value.concat(keys.x);
1896
1982
  $$.config.data_x = keys.x;
1983
+ } else {
1984
+ targetKeys = keys.value;
1897
1985
  }
1898
1986
  new_rows.push(targetKeys);
1899
1987
  json.forEach(function (o) {
@@ -2052,7 +2140,8 @@
2052
2140
  // set type if args.types || args.type specified
2053
2141
  if (args.type || args.types) {
2054
2142
  targets.forEach(function (t) {
2055
- $$.setTargetType(t.id, args.types ? args.types[t.id] : args.type);
2143
+ var type = args.types && args.types[t.id] ? args.types[t.id] : args.type;
2144
+ $$.setTargetType(t.id, type);
2056
2145
  });
2057
2146
  }
2058
2147
  // Update/Add data
@@ -2251,28 +2340,11 @@
2251
2340
  .attr("class", $$.classEvent.bind($$))
2252
2341
  .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
2253
2342
  .on('mouseover', function (d) {
2254
- var index = d.index, selectedData, newData;
2343
+ var index = d.index;
2255
2344
 
2256
2345
  if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
2257
2346
  if ($$.hasArcType()) { return; }
2258
2347
 
2259
- selectedData = $$.data.targets.map(function (t) {
2260
- return $$.addName($$.getValueOnIndex(t.values, index));
2261
- });
2262
-
2263
- // Sort selectedData as names order
2264
- newData = [];
2265
- Object.keys(config.data_names).forEach(function (id) {
2266
- for (var j = 0; j < selectedData.length; j++) {
2267
- if (selectedData[j] && selectedData[j].id === id) {
2268
- newData.push(selectedData[j]);
2269
- selectedData.shift(j);
2270
- break;
2271
- }
2272
- }
2273
- });
2274
- selectedData = newData.concat(selectedData); // Add remained
2275
-
2276
2348
  // Expand shapes for selection
2277
2349
  if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
2278
2350
  $$.expandBars(index, null, true);
@@ -2284,6 +2356,7 @@
2284
2356
  })
2285
2357
  .on('mouseout', function (d) {
2286
2358
  var index = d.index;
2359
+ if (!$$.config) { return; } // chart is destroyed
2287
2360
  if ($$.hasArcType()) { return; }
2288
2361
  $$.hideXGridFocus();
2289
2362
  $$.hideTooltip();
@@ -2312,7 +2385,7 @@
2312
2385
  });
2313
2386
 
2314
2387
  if (config.tooltip_grouped) {
2315
- $$.showTooltip(selectedData, d3.mouse(this));
2388
+ $$.showTooltip(selectedData, this);
2316
2389
  $$.showXGridFocus(selectedData);
2317
2390
  }
2318
2391
 
@@ -2343,7 +2416,7 @@
2343
2416
  eventRect.style('cursor', 'pointer');
2344
2417
  }
2345
2418
  if (!config.tooltip_grouped) {
2346
- $$.showTooltip([d], d3.mouse(this));
2419
+ $$.showTooltip([d], this);
2347
2420
  $$.showXGridFocus([d]);
2348
2421
  if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
2349
2422
  $$.expandBars(index, d.id, true);
@@ -2368,10 +2441,12 @@
2368
2441
  });
2369
2442
  })
2370
2443
  .call(
2371
- d3.behavior.drag().origin(Object)
2372
- .on('drag', function () { $$.drag(d3.mouse(this)); })
2373
- .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2374
- .on('dragend', function () { $$.dragend(); })
2444
+ config.data_selection_draggable && $$.drag ? (
2445
+ d3.behavior.drag().origin(Object)
2446
+ .on('drag', function () { $$.drag(d3.mouse(this)); })
2447
+ .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2448
+ .on('dragend', function () { $$.dragend(); })
2449
+ ) : function () {}
2375
2450
  );
2376
2451
  };
2377
2452
 
@@ -2393,6 +2468,7 @@
2393
2468
  .attr('height', $$.height)
2394
2469
  .attr('class', CLASS.eventRect)
2395
2470
  .on('mouseout', function () {
2471
+ if (!$$.config) { return; } // chart is destroyed
2396
2472
  if ($$.hasArcType()) { return; }
2397
2473
  mouseout();
2398
2474
  })
@@ -2426,7 +2502,7 @@
2426
2502
  selectedData = sameXData.map(function (d) {
2427
2503
  return $$.addName(d);
2428
2504
  });
2429
- $$.showTooltip(selectedData, mouse);
2505
+ $$.showTooltip(selectedData, this);
2430
2506
 
2431
2507
  // expand points
2432
2508
  if (config.point_focus_expand_enabled) {
@@ -2459,7 +2535,7 @@
2459
2535
 
2460
2536
  // select if selection enabled
2461
2537
  if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
2462
- $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).select('.' + CLASS.shape + '-' + closest.index).each(function () {
2538
+ $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).selectAll('.' + CLASS.shape + '-' + closest.index).each(function () {
2463
2539
  if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
2464
2540
  $$.toggleShape(this, closest, closest.index);
2465
2541
  $$.config.data_onclick.call($$.api, closest, this);
@@ -2468,10 +2544,12 @@
2468
2544
  }
2469
2545
  })
2470
2546
  .call(
2471
- d3.behavior.drag().origin(Object)
2472
- .on('drag', function () { $$.drag(d3.mouse(this)); })
2473
- .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2474
- .on('dragend', function () { $$.dragend(); })
2547
+ config.data_selection_draggable && $$.drag ? (
2548
+ d3.behavior.drag().origin(Object)
2549
+ .on('drag', function () { $$.drag(d3.mouse(this)); })
2550
+ .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
2551
+ .on('dragend', function () { $$.dragend(); })
2552
+ ) : function () {}
2475
2553
  );
2476
2554
  };
2477
2555
  c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
@@ -2512,7 +2590,7 @@
2512
2590
  } else if (config.axis_rotated) {
2513
2591
  return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
2514
2592
  } else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
2515
- return $$.getYAxisLabelPosition().isOuter ? 30 : 1;
2593
+ return $$.axis.getYAxisLabelPosition().isOuter ? 30 : 1;
2516
2594
  } else {
2517
2595
  return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
2518
2596
  }
@@ -2525,7 +2603,7 @@
2525
2603
  } else if (config.axis_rotated) {
2526
2604
  return defaultPadding + legendWidthOnRight;
2527
2605
  } else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
2528
- return 2 + legendWidthOnRight + ($$.getY2AxisLabelPosition().isOuter ? 20 : 0);
2606
+ return 2 + legendWidthOnRight + ($$.axis.getY2AxisLabelPosition().isOuter ? 20 : 0);
2529
2607
  } else {
2530
2608
  return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
2531
2609
  }
@@ -2534,7 +2612,15 @@
2534
2612
  c3_chart_internal_fn.getParentRectValue = function (key) {
2535
2613
  var parent = this.selectChart.node(), v;
2536
2614
  while (parent && parent.tagName !== 'BODY') {
2537
- v = parent.getBoundingClientRect()[key];
2615
+ try {
2616
+ v = parent.getBoundingClientRect()[key];
2617
+ } catch(e) {
2618
+ if (key === 'width') {
2619
+ // In IE in certain cases getBoundingClientRect
2620
+ // will cause an "unspecified error"
2621
+ v = parent.offsetWidth;
2622
+ }
2623
+ }
2538
2624
  if (v) {
2539
2625
  break;
2540
2626
  }
@@ -2565,8 +2651,8 @@
2565
2651
 
2566
2652
 
2567
2653
  c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
2568
- var $$ = this, position = $$.getAxisLabelPositionById(id);
2569
- return $$.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
2654
+ var $$ = this, position = $$.axis.getLabelPositionById(id);
2655
+ return $$.axis.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
2570
2656
  };
2571
2657
  c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
2572
2658
  var $$ = this, config = $$.config, h = 30;
@@ -2576,27 +2662,13 @@
2576
2662
  if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
2577
2663
  // Calculate x axis height when tick rotated
2578
2664
  if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
2579
- h = $$.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
2665
+ h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
2580
2666
  }
2581
- return h + ($$.getAxisLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
2667
+ return h + ($$.axis.getLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
2582
2668
  };
2583
2669
 
2584
2670
  c3_chart_internal_fn.getEventRectWidth = function () {
2585
- var $$ = this;
2586
- var target = $$.getMaxDataCountTarget($$.data.targets),
2587
- firstData, lastData, base, maxDataCount, ratio, w;
2588
- if (!target) {
2589
- return 0;
2590
- }
2591
- firstData = target.values[0], lastData = target.values[target.values.length - 1];
2592
- base = $$.x(lastData.x) - $$.x(firstData.x);
2593
- if (base === 0) {
2594
- return $$.config.axis_rotated ? $$.height : $$.width;
2595
- }
2596
- maxDataCount = $$.getMaxDataCount();
2597
- ratio = ($$.hasType('bar') ? (maxDataCount - ($$.isCategorized() ? 0.25 : 1)) / maxDataCount : 1);
2598
- w = maxDataCount > 1 ? (base * ratio) / (maxDataCount - 1) : base;
2599
- return w < 1 ? 1 : w;
2671
+ return Math.max(0, this.xAxis.tickInterval());
2600
2672
  };
2601
2673
 
2602
2674
  c3_chart_internal_fn.getShapeIndices = function (typeFilter) {
@@ -2712,7 +2784,7 @@
2712
2784
  // MEMO: can not keep same color...
2713
2785
  //mainLineUpdate.exit().remove();
2714
2786
  };
2715
- c3_chart_internal_fn.redrawLine = function (durationForExit) {
2787
+ c3_chart_internal_fn.updateLine = function (durationForExit) {
2716
2788
  var $$ = this;
2717
2789
  $$.mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
2718
2790
  .data($$.lineData.bind($$));
@@ -2727,12 +2799,13 @@
2727
2799
  .style('opacity', 0)
2728
2800
  .remove();
2729
2801
  };
2730
- c3_chart_internal_fn.addTransitionForLine = function (transitions, drawLine) {
2731
- var $$ = this;
2732
- transitions.push($$.mainLine.transition()
2733
- .attr("d", drawLine)
2734
- .style("stroke", $$.color)
2735
- .style("opacity", 1));
2802
+ c3_chart_internal_fn.redrawLine = function (drawLine, withTransition) {
2803
+ return [
2804
+ (withTransition ? this.mainLine.transition() : this.mainLine)
2805
+ .attr("d", drawLine)
2806
+ .style("stroke", this.color)
2807
+ .style("opacity", 1)
2808
+ ];
2736
2809
  };
2737
2810
  c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
2738
2811
  var $$ = this, config = $$.config,
@@ -2797,6 +2870,7 @@
2797
2870
  prev = -1, i, j,
2798
2871
  s = "M", sWithRegion,
2799
2872
  xp, yp, dx, dy, dd, diff, diffx2,
2873
+ xOffset = $$.isCategorized() ? 0.5 : 0,
2800
2874
  xValue, yValue,
2801
2875
  regions = [];
2802
2876
 
@@ -2830,16 +2904,31 @@
2830
2904
  yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
2831
2905
 
2832
2906
  // Define svg generator function for region
2907
+ function generateM(points) {
2908
+ return 'M' + points[0][0] + ' ' + points[0][1] + ' ' + points[1][0] + ' ' + points[1][1];
2909
+ }
2833
2910
  if ($$.isTimeSeries()) {
2834
2911
  sWithRegion = function (d0, d1, j, diff) {
2835
2912
  var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
2836
2913
  xv0 = new Date(x0 + x_diff * j),
2837
- xv1 = new Date(x0 + x_diff * (j + diff));
2838
- return "M" + x(xv0) + " " + y(yp(j)) + " " + x(xv1) + " " + y(yp(j + diff));
2914
+ xv1 = new Date(x0 + x_diff * (j + diff)),
2915
+ points;
2916
+ if (config.axis_rotated) {
2917
+ points = [[y(yp(j)), x(xv0)], [y(yp(j + diff)), x(xv1)]];
2918
+ } else {
2919
+ points = [[x(xv0), y(yp(j))], [x(xv1), y(yp(j + diff))]];
2920
+ }
2921
+ return generateM(points);
2839
2922
  };
2840
2923
  } else {
2841
2924
  sWithRegion = function (d0, d1, j, diff) {
2842
- return "M" + x(xp(j), true) + " " + y(yp(j)) + " " + x(xp(j + diff), true) + " " + y(yp(j + diff));
2925
+ var points;
2926
+ if (config.axis_rotated) {
2927
+ points = [[y(yp(j), true), x(xp(j))], [y(yp(j + diff), true), x(xp(j + diff))]];
2928
+ } else {
2929
+ points = [[x(xp(j), true), y(yp(j))], [x(xp(j + diff), true), y(yp(j + diff))]];
2930
+ }
2931
+ return generateM(points);
2843
2932
  };
2844
2933
  }
2845
2934
 
@@ -2852,7 +2941,7 @@
2852
2941
  }
2853
2942
  // Draw with region // TODO: Fix for horizotal charts
2854
2943
  else {
2855
- xp = $$.getScale(d[i - 1].x, d[i].x, $$.isTimeSeries());
2944
+ xp = $$.getScale(d[i - 1].x + xOffset, d[i].x + xOffset, $$.isTimeSeries());
2856
2945
  yp = $$.getScale(d[i - 1].value, d[i].value);
2857
2946
 
2858
2947
  dx = x(d[i].x) - x(d[i - 1].x);
@@ -2872,7 +2961,7 @@
2872
2961
  };
2873
2962
 
2874
2963
 
2875
- c3_chart_internal_fn.redrawArea = function (durationForExit) {
2964
+ c3_chart_internal_fn.updateArea = function (durationForExit) {
2876
2965
  var $$ = this, d3 = $$.d3;
2877
2966
  $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
2878
2967
  .data($$.lineData.bind($$));
@@ -2886,12 +2975,13 @@
2886
2975
  .style('opacity', 0)
2887
2976
  .remove();
2888
2977
  };
2889
- c3_chart_internal_fn.addTransitionForArea = function (transitions, drawArea) {
2890
- var $$ = this;
2891
- transitions.push($$.mainArea.transition()
2892
- .attr("d", drawArea)
2893
- .style("fill", $$.color)
2894
- .style("opacity", $$.orgAreaOpacity));
2978
+ c3_chart_internal_fn.redrawArea = function (drawArea, withTransition) {
2979
+ return [
2980
+ (withTransition ? this.mainArea.transition() : this.mainArea)
2981
+ .attr("d", drawArea)
2982
+ .style("fill", this.color)
2983
+ .style("opacity", this.orgAreaOpacity)
2984
+ ];
2895
2985
  };
2896
2986
  c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
2897
2987
  var $$ = this, config = $$.config, area = $$.d3.svg.area(),
@@ -2899,7 +2989,7 @@
2899
2989
  yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
2900
2990
  xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
2901
2991
  value0 = function (d, i) {
2902
- return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(0);
2992
+ return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)($$.getAreaBaseValue(d.id));
2903
2993
  },
2904
2994
  value1 = function (d, i) {
2905
2995
  return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
@@ -2926,7 +3016,9 @@
2926
3016
  return path ? path : "M 0 0";
2927
3017
  };
2928
3018
  };
2929
-
3019
+ c3_chart_internal_fn.getAreaBaseValue = function () {
3020
+ return 0;
3021
+ };
2930
3022
  c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
2931
3023
  var $$ = this, config = $$.config,
2932
3024
  areaTargetsNum = areaIndices.__max__ + 1,
@@ -2953,7 +3045,7 @@
2953
3045
  };
2954
3046
 
2955
3047
 
2956
- c3_chart_internal_fn.redrawCircle = function () {
3048
+ c3_chart_internal_fn.updateCircle = function () {
2957
3049
  var $$ = this;
2958
3050
  $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
2959
3051
  .data($$.lineOrScatterData.bind($$));
@@ -2965,16 +3057,18 @@
2965
3057
  .style("opacity", $$.initialOpacityForCircle.bind($$));
2966
3058
  $$.mainCircle.exit().remove();
2967
3059
  };
2968
- c3_chart_internal_fn.addTransitionForCircle = function (transitions, cx, cy) {
2969
- var $$ = this;
2970
- transitions.push($$.mainCircle.transition()
2971
- .style('opacity', $$.opacityForCircle.bind($$))
2972
- .style("fill", $$.color)
2973
- .attr("cx", cx)
2974
- .attr("cy", cy));
2975
- transitions.push($$.main.selectAll('.' + CLASS.selectedCircle).transition()
2976
- .attr("cx", cx)
2977
- .attr("cy", cy));
3060
+ c3_chart_internal_fn.redrawCircle = function (cx, cy, withTransition) {
3061
+ var selectedCircles = this.main.selectAll('.' + CLASS.selectedCircle);
3062
+ return [
3063
+ (withTransition ? this.mainCircle.transition() : this.mainCircle)
3064
+ .style('opacity', this.opacityForCircle.bind(this))
3065
+ .style("fill", this.color)
3066
+ .attr("cx", cx)
3067
+ .attr("cy", cy),
3068
+ (withTransition ? selectedCircles.transition() : selectedCircles)
3069
+ .attr("cx", cx)
3070
+ .attr("cy", cy)
3071
+ ];
2978
3072
  };
2979
3073
  c3_chart_internal_fn.circleX = function (d) {
2980
3074
  return d.x || d.x === 0 ? this.x(d.x) : null;
@@ -3059,7 +3153,7 @@
3059
3153
  .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
3060
3154
 
3061
3155
  };
3062
- c3_chart_internal_fn.redrawBar = function (durationForExit) {
3156
+ c3_chart_internal_fn.updateBar = function (durationForExit) {
3063
3157
  var $$ = this,
3064
3158
  barData = $$.barData.bind($$),
3065
3159
  classBar = $$.classBar.bind($$),
@@ -3077,16 +3171,17 @@
3077
3171
  .style('opacity', 0)
3078
3172
  .remove();
3079
3173
  };
3080
- c3_chart_internal_fn.addTransitionForBar = function (transitions, drawBar) {
3081
- var $$ = this;
3082
- transitions.push($$.mainBar.transition()
3083
- .attr('d', drawBar)
3084
- .style("fill", $$.color)
3085
- .style("opacity", 1));
3174
+ c3_chart_internal_fn.redrawBar = function (drawBar, withTransition) {
3175
+ return [
3176
+ (withTransition ? this.mainBar.transition() : this.mainBar)
3177
+ .attr('d', drawBar)
3178
+ .style("fill", this.color)
3179
+ .style("opacity", 1)
3180
+ ];
3086
3181
  };
3087
3182
  c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
3088
3183
  var $$ = this, config = $$.config,
3089
- w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickOffset() * 2 * config.bar_width_ratio) / barTargetsNum : 0;
3184
+ w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickInterval() * config.bar_width_ratio) / barTargetsNum : 0;
3090
3185
  return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
3091
3186
  };
3092
3187
  c3_chart_internal_fn.getBars = function (i, id) {
@@ -3178,7 +3273,7 @@
3178
3273
  mainTextEnter.append('g')
3179
3274
  .attr('class', classTexts);
3180
3275
  };
3181
- c3_chart_internal_fn.redrawText = function (durationForExit) {
3276
+ c3_chart_internal_fn.updateText = function (durationForExit) {
3182
3277
  var $$ = this, config = $$.config,
3183
3278
  barOrLineData = $$.barOrLineData.bind($$),
3184
3279
  classText = $$.classText.bind($$);
@@ -3191,37 +3286,37 @@
3191
3286
  .style("fill", function (d) { return $$.color(d); })
3192
3287
  .style("fill-opacity", 0);
3193
3288
  $$.mainText
3194
- .text(function (d, i, j) { return $$.formatByAxisId($$.getAxisId(d.id))(d.value, d.id, i, j); });
3289
+ .text(function (d, i, j) { return $$.dataLabelFormat(d.id)(d.value, d.id, i, j); });
3195
3290
  $$.mainText.exit()
3196
3291
  .transition().duration(durationForExit)
3197
3292
  .style('fill-opacity', 0)
3198
3293
  .remove();
3199
3294
  };
3200
- c3_chart_internal_fn.addTransitionForText = function (transitions, xForText, yForText, forFlow) {
3201
- var $$ = this,
3202
- opacityForText = forFlow ? 0 : $$.opacityForText.bind($$);
3203
- transitions.push($$.mainText.transition()
3204
- .attr('x', xForText)
3205
- .attr('y', yForText)
3206
- .style("fill", $$.color)
3207
- .style("fill-opacity", opacityForText));
3295
+ c3_chart_internal_fn.redrawText = function (xForText, yForText, forFlow, withTransition) {
3296
+ return [
3297
+ (withTransition ? this.mainText.transition() : this.mainText)
3298
+ .attr('x', xForText)
3299
+ .attr('y', yForText)
3300
+ .style("fill", this.color)
3301
+ .style("fill-opacity", forFlow ? 0 : this.opacityForText.bind(this))
3302
+ ];
3208
3303
  };
3209
3304
  c3_chart_internal_fn.getTextRect = function (text, cls) {
3210
- var body = this.d3.select('body').classed('c3', true),
3211
- svg = body.append("svg").style('visibility', 'hidden'), rect;
3305
+ var dummy = this.d3.select('body').append('div').classed('c3', true),
3306
+ svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
3307
+ rect;
3212
3308
  svg.selectAll('.dummy')
3213
3309
  .data([text])
3214
3310
  .enter().append('text')
3215
3311
  .classed(cls ? cls : "", true)
3216
3312
  .text(text)
3217
3313
  .each(function () { rect = this.getBoundingClientRect(); });
3218
- svg.remove();
3219
- body.classed('c3', false);
3314
+ dummy.remove();
3220
3315
  return rect;
3221
3316
  };
3222
3317
  c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
3223
3318
  var $$ = this,
3224
- getAreaPoints = $$.generateGetAreaPoints(barIndices, false),
3319
+ getAreaPoints = $$.generateGetAreaPoints(areaIndices, false),
3225
3320
  getBarPoints = $$.generateGetBarPoints(barIndices, false),
3226
3321
  getLinePoints = $$.generateGetLinePoints(lineIndices, false),
3227
3322
  getter = forX ? $$.getXForText : $$.getYForText;
@@ -3251,11 +3346,23 @@
3251
3346
  };
3252
3347
  c3_chart_internal_fn.getYForText = function (points, d, textElement) {
3253
3348
  var $$ = this,
3254
- box = textElement.getBoundingClientRect(), yPos;
3349
+ box = textElement.getBoundingClientRect(),
3350
+ yPos;
3255
3351
  if ($$.config.axis_rotated) {
3256
3352
  yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
3257
3353
  } else {
3258
- yPos = points[2][1] + (d.value < 0 ? box.height : $$.isBarType(d) ? -3 : -6);
3354
+ yPos = points[2][1];
3355
+ if (d.value < 0) {
3356
+ yPos += box.height;
3357
+ if ($$.isBarType(d) && $$.isSafari()) {
3358
+ yPos -= 3;
3359
+ }
3360
+ else if (!$$.isBarType(d) && $$.isChrome()) {
3361
+ yPos += 3;
3362
+ }
3363
+ } else {
3364
+ yPos += $$.isBarType(d) ? -3 : -6;
3365
+ }
3259
3366
  }
3260
3367
  // show labels regardless of the domain if value is null
3261
3368
  if (d.value === null && !$$.config.axis_rotated) {
@@ -3431,8 +3538,19 @@
3431
3538
  $$.smoothLines($$.ygrid, 'grid');
3432
3539
  };
3433
3540
 
3434
-
3435
- c3_chart_internal_fn.redrawGrid = function (duration) {
3541
+ c3_chart_internal_fn.gridTextAnchor = function (d) {
3542
+ return d.position ? d.position : "end";
3543
+ };
3544
+ c3_chart_internal_fn.gridTextDx = function (d) {
3545
+ return d.position === 'start' ? 4 : d.position === 'middle' ? 0 : -4;
3546
+ };
3547
+ c3_chart_internal_fn.xGridTextX = function (d) {
3548
+ return d.position === 'start' ? -this.height : d.position === 'middle' ? -this.height / 2 : 0;
3549
+ };
3550
+ c3_chart_internal_fn.yGridTextX = function (d) {
3551
+ return d.position === 'start' ? 0 : d.position === 'middle' ? this.width / 2 : this.width;
3552
+ };
3553
+ c3_chart_internal_fn.updateGrid = function (duration) {
3436
3554
  var $$ = this, main = $$.main, config = $$.config,
3437
3555
  xgridLine, ygridLine, yv;
3438
3556
 
@@ -3451,9 +3569,9 @@
3451
3569
  xgridLine.append('line')
3452
3570
  .style("opacity", 0);
3453
3571
  xgridLine.append('text')
3454
- .attr("text-anchor", "end")
3572
+ .attr("text-anchor", $$.gridTextAnchor)
3455
3573
  .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
3456
- .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
3574
+ .attr('dx', $$.gridTextDx)
3457
3575
  .attr('dy', -5)
3458
3576
  .style("opacity", 0);
3459
3577
  // udpate
@@ -3475,9 +3593,9 @@
3475
3593
  ygridLine.append('line')
3476
3594
  .style("opacity", 0);
3477
3595
  ygridLine.append('text')
3478
- .attr("text-anchor", "end")
3596
+ .attr("text-anchor", $$.gridTextAnchor)
3479
3597
  .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
3480
- .attr('dx', config.axis_rotated ? 0 : -$$.margin.top)
3598
+ .attr('dx', $$.gridTextDx)
3481
3599
  .attr('dy', -5)
3482
3600
  .style("opacity", 0);
3483
3601
  // update
@@ -3491,7 +3609,7 @@
3491
3609
  .style("opacity", 1);
3492
3610
  $$.ygridLines.select('text')
3493
3611
  .transition().duration(duration)
3494
- .attr("x", config.axis_rotated ? 0 : $$.width)
3612
+ .attr("x", config.axis_rotated ? $$.xGridTextX.bind($$) : $$.yGridTextX.bind($$))
3495
3613
  .attr("y", yv)
3496
3614
  .text(function (d) { return d.text; })
3497
3615
  .style("opacity", 1);
@@ -3500,19 +3618,23 @@
3500
3618
  .style("opacity", 0)
3501
3619
  .remove();
3502
3620
  };
3503
- c3_chart_internal_fn.addTransitionForGrid = function (transitions) {
3504
- var $$ = this, config = $$.config, xv = $$.xv.bind($$);
3505
- transitions.push($$.xgridLines.select('line').transition()
3506
- .attr("x1", config.axis_rotated ? 0 : xv)
3507
- .attr("x2", config.axis_rotated ? $$.width : xv)
3508
- .attr("y1", config.axis_rotated ? xv : $$.margin.top)
3509
- .attr("y2", config.axis_rotated ? xv : $$.height)
3510
- .style("opacity", 1));
3511
- transitions.push($$.xgridLines.select('text').transition()
3512
- .attr("x", config.axis_rotated ? $$.width : 0)
3513
- .attr("y", xv)
3514
- .text(function (d) { return d.text; })
3515
- .style("opacity", 1));
3621
+ c3_chart_internal_fn.redrawGrid = function (withTransition) {
3622
+ var $$ = this, config = $$.config, xv = $$.xv.bind($$),
3623
+ lines = $$.xgridLines.select('line'),
3624
+ texts = $$.xgridLines.select('text');
3625
+ return [
3626
+ (withTransition ? lines.transition() : lines)
3627
+ .attr("x1", config.axis_rotated ? 0 : xv)
3628
+ .attr("x2", config.axis_rotated ? $$.width : xv)
3629
+ .attr("y1", config.axis_rotated ? xv : 0)
3630
+ .attr("y2", config.axis_rotated ? xv : $$.height)
3631
+ .style("opacity", 1),
3632
+ (withTransition ? texts.transition() : texts)
3633
+ .attr("x", config.axis_rotated ? $$.yGridTextX.bind($$) : $$.xGridTextX.bind($$))
3634
+ .attr("y", xv)
3635
+ .text(function (d) { return d.text; })
3636
+ .style("opacity", 1)
3637
+ ];
3516
3638
  };
3517
3639
  c3_chart_internal_fn.showXGridFocus = function (selectedData) {
3518
3640
  var $$ = this, config = $$.config,
@@ -3606,7 +3728,7 @@
3606
3728
  }
3607
3729
  $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
3608
3730
  return $$.addName(d.values[config.tooltip_init_x]);
3609
- }), $$.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
3731
+ }), $$.axis.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
3610
3732
  $$.tooltip.style("top", config.tooltip_init_position.top)
3611
3733
  .style("left", config.tooltip_init_position.left)
3612
3734
  .style("display", "block");
@@ -3626,33 +3748,27 @@
3626
3748
  text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
3627
3749
  }
3628
3750
 
3629
- name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
3630
3751
  value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
3631
- bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
3632
-
3633
- text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
3634
- text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
3635
- text += "<td class='value'>" + value + "</td>";
3636
- text += "</tr>";
3752
+ if (value !== undefined) {
3753
+ name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
3754
+ bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
3755
+
3756
+ text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
3757
+ text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
3758
+ text += "<td class='value'>" + value + "</td>";
3759
+ text += "</tr>";
3760
+ }
3637
3761
  }
3638
3762
  return text + "</table>";
3639
3763
  };
3640
- c3_chart_internal_fn.showTooltip = function (selectedData, mouse) {
3641
- var $$ = this, config = $$.config;
3642
- var tWidth, tHeight, svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
3764
+ c3_chart_internal_fn.tooltipPosition = function (dataToShow, tWidth, tHeight, element) {
3765
+ var $$ = this, config = $$.config, d3 = $$.d3;
3766
+ var svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
3643
3767
  var forArc = $$.hasArcType(),
3644
- dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); });
3645
- if (dataToShow.length === 0 || !config.tooltip_show) {
3646
- return;
3647
- }
3648
- $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
3649
-
3650
- // Get tooltip dimensions
3651
- tWidth = $$.tooltip.property('offsetWidth');
3652
- tHeight = $$.tooltip.property('offsetHeight');
3653
- // Determin tooltip position
3768
+ mouse = d3.mouse(element);
3769
+ // Determin tooltip position
3654
3770
  if (forArc) {
3655
- tooltipLeft = ($$.width / 2) + mouse[0];
3771
+ tooltipLeft = (($$.width - ($$.isLegendRight ? $$.getLegendWidth() : 0)) / 2) + mouse[0];
3656
3772
  tooltipTop = ($$.height / 2) + mouse[1] + 20;
3657
3773
  } else {
3658
3774
  svgLeft = $$.getSvgLeft(true);
@@ -3669,7 +3785,8 @@
3669
3785
  }
3670
3786
 
3671
3787
  if (tooltipRight > chartRight) {
3672
- tooltipLeft -= tooltipRight - chartRight;
3788
+ // 20 is needed for Firefox to keep tooletip width
3789
+ tooltipLeft -= tooltipRight - chartRight + 20;
3673
3790
  }
3674
3791
  if (tooltipTop + tHeight > $$.currentHeight) {
3675
3792
  tooltipTop -= tHeight + 30;
@@ -3678,10 +3795,28 @@
3678
3795
  if (tooltipTop < 0) {
3679
3796
  tooltipTop = 0;
3680
3797
  }
3798
+ return {top: tooltipTop, left: tooltipLeft};
3799
+ };
3800
+ c3_chart_internal_fn.showTooltip = function (selectedData, element) {
3801
+ var $$ = this, config = $$.config;
3802
+ var tWidth, tHeight, position;
3803
+ var forArc = $$.hasArcType(),
3804
+ dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
3805
+ positionFunction = config.tooltip_position || c3_chart_internal_fn.tooltipPosition;
3806
+ if (dataToShow.length === 0 || !config.tooltip_show) {
3807
+ return;
3808
+ }
3809
+ $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.axis.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
3810
+
3811
+ // Get tooltip dimensions
3812
+ tWidth = $$.tooltip.property('offsetWidth');
3813
+ tHeight = $$.tooltip.property('offsetHeight');
3814
+
3815
+ position = positionFunction.call(this, dataToShow, tWidth, tHeight, element);
3681
3816
  // Set tooltip
3682
3817
  $$.tooltip
3683
- .style("top", tooltipTop + "px")
3684
- .style("left", tooltipLeft + 'px');
3818
+ .style("top", position.top + "px")
3819
+ .style("left", position.left + 'px');
3685
3820
  };
3686
3821
  c3_chart_internal_fn.hideTooltip = function () {
3687
3822
  this.tooltip.style("display", "none");
@@ -3689,6 +3824,7 @@
3689
3824
 
3690
3825
  c3_chart_internal_fn.initLegend = function () {
3691
3826
  var $$ = this;
3827
+ $$.legendItemTextBox = {};
3692
3828
  $$.legendHasRendered = false;
3693
3829
  $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
3694
3830
  if (!$$.config.legend_show) {
@@ -3796,9 +3932,8 @@
3796
3932
  .style('opacity', 0)
3797
3933
  .style('visibility', 'hidden');
3798
3934
  };
3799
- var legendItemTextBox = {};
3800
3935
  c3_chart_internal_fn.clearLegendItemTextBoxCache = function () {
3801
- legendItemTextBox = {};
3936
+ this.legendItemTextBox = {};
3802
3937
  };
3803
3938
  c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
3804
3939
  var $$ = this, config = $$.config;
@@ -3806,7 +3941,6 @@
3806
3941
  var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
3807
3942
  var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
3808
3943
  var withTransition, withTransitionForTransform;
3809
- var hasFocused = $$.legend.selectAll('.' + CLASS.legendItemFocused).size();
3810
3944
  var texts, rects, tiles, background;
3811
3945
 
3812
3946
  options = options || {};
@@ -3814,10 +3948,10 @@
3814
3948
  withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
3815
3949
 
3816
3950
  function getTextBox(textElement, id) {
3817
- if (!legendItemTextBox[id]) {
3818
- legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
3951
+ if (!$$.legendItemTextBox[id]) {
3952
+ $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
3819
3953
  }
3820
- return legendItemTextBox[id];
3954
+ return $$.legendItemTextBox[id];
3821
3955
  }
3822
3956
 
3823
3957
  function updatePositions(textElement, id, index) {
@@ -3996,16 +4130,7 @@
3996
4130
 
3997
4131
  // toggle legend state
3998
4132
  $$.legend.selectAll('.' + CLASS.legendItem)
3999
- .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); })
4000
- .transition()
4001
- .style('opacity', function (id) {
4002
- var This = $$.d3.select(this);
4003
- if ($$.isTargetToShow(id)) {
4004
- return !hasFocused || This.classed(CLASS.legendItemFocused) ? $$.opacityForLegend(This) : $$.opacityForUnfocusedLegend(This);
4005
- } else {
4006
- return null; // c3-legend-item-hidden will be applied
4007
- }
4008
- });
4133
+ .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); });
4009
4134
 
4010
4135
  // Update all to reflect change of legend
4011
4136
  $$.updateLegendItemWidth(maxWidth);
@@ -4020,8 +4145,15 @@
4020
4145
  $$.legendHasRendered = true;
4021
4146
  };
4022
4147
 
4023
- c3_chart_internal_fn.initAxis = function () {
4024
- var $$ = this, config = $$.config, main = $$.main;
4148
+ function Axis(owner) {
4149
+ API.call(this, owner);
4150
+ }
4151
+
4152
+ inherit(API, Axis);
4153
+
4154
+ Axis.prototype.init = function init() {
4155
+
4156
+ var $$ = this.owner, config = $$.config, main = $$.main;
4025
4157
  $$.axes.x = main.append("g")
4026
4158
  .attr("class", CLASS.axis + ' ' + CLASS.axisX)
4027
4159
  .attr("clip-path", $$.clipPathForXAxis)
@@ -4030,8 +4162,7 @@
4030
4162
  $$.axes.x.append("text")
4031
4163
  .attr("class", CLASS.axisXLabel)
4032
4164
  .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
4033
- .style("text-anchor", $$.textAnchorForXAxisLabel.bind($$));
4034
-
4165
+ .style("text-anchor", this.textAnchorForXAxisLabel.bind(this));
4035
4166
  $$.axes.y = main.append("g")
4036
4167
  .attr("class", CLASS.axis + ' ' + CLASS.axisY)
4037
4168
  .attr("clip-path", config.axis_y_inner ? "" : $$.clipPathForYAxis)
@@ -4040,7 +4171,7 @@
4040
4171
  $$.axes.y.append("text")
4041
4172
  .attr("class", CLASS.axisYLabel)
4042
4173
  .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
4043
- .style("text-anchor", $$.textAnchorForYAxisLabel.bind($$));
4174
+ .style("text-anchor", this.textAnchorForYAxisLabel.bind(this));
4044
4175
 
4045
4176
  $$.axes.y2 = main.append("g")
4046
4177
  .attr("class", CLASS.axis + ' ' + CLASS.axisY2)
@@ -4050,15 +4181,17 @@
4050
4181
  $$.axes.y2.append("text")
4051
4182
  .attr("class", CLASS.axisY2Label)
4052
4183
  .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
4053
- .style("text-anchor", $$.textAnchorForY2AxisLabel.bind($$));
4184
+ .style("text-anchor", this.textAnchorForY2AxisLabel.bind(this));
4054
4185
  };
4055
- c3_chart_internal_fn.getXAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
4056
- var $$ = this, config = $$.config,
4186
+ Axis.prototype.getXAxis = function getXAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
4187
+ var $$ = this.owner, config = $$.config,
4057
4188
  axisParams = {
4058
4189
  isCategory: $$.isCategorized(),
4059
4190
  withOuterTick: withOuterTick,
4060
4191
  tickMultiline: config.axis_x_tick_multiline,
4061
- tickWidth: config.axis_x_tick_width
4192
+ tickWidth: config.axis_x_tick_width,
4193
+ tickTextRotate: withoutRotateTickText ? 0 : config.axis_x_tick_rotate,
4194
+ withoutTransition: withoutTransition,
4062
4195
  },
4063
4196
  axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
4064
4197
 
@@ -4073,34 +4206,45 @@
4073
4206
  if (isEmpty(config.axis_x_tick_culling)) {
4074
4207
  config.axis_x_tick_culling = false;
4075
4208
  }
4076
- } else {
4077
- // TODO: move this to c3_axis
4078
- axis.tickOffset = function () {
4079
- var scale = this.scale(),
4080
- edgeX = $$.getEdgeX($$.data.targets), diff = scale(edgeX[1]) - scale(edgeX[0]),
4081
- base = diff ? diff : (config.axis_rotated ? $$.height : $$.width);
4082
- return (base / $$.getMaxDataCount()) / 2;
4083
- };
4084
4209
  }
4085
4210
 
4086
4211
  return axis;
4087
4212
  };
4088
- c3_chart_internal_fn.getYAxis = function (scale, orient, tickFormat, tickValues, withOuterTick) {
4089
- var axisParams = {withOuterTick: withOuterTick},
4090
- axis = c3_axis(this.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
4091
- if (this.isTimeSeriesY()) {
4092
- axis.ticks(this.d3.time[this.config.axis_y_tick_time_value], this.config.axis_y_tick_time_interval);
4213
+ Axis.prototype.updateXAxisTickValues = function updateXAxisTickValues(targets, axis) {
4214
+ var $$ = this.owner, config = $$.config, tickValues;
4215
+ if (config.axis_x_tick_fit || config.axis_x_tick_count) {
4216
+ tickValues = this.generateTickValues($$.mapTargetsToUniqueXs(targets), config.axis_x_tick_count, $$.isTimeSeries());
4217
+ }
4218
+ if (axis) {
4219
+ axis.tickValues(tickValues);
4220
+ } else {
4221
+ $$.xAxis.tickValues(tickValues);
4222
+ $$.subXAxis.tickValues(tickValues);
4223
+ }
4224
+ return tickValues;
4225
+ };
4226
+ Axis.prototype.getYAxis = function getYAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition) {
4227
+ var axisParams = {
4228
+ withOuterTick: withOuterTick,
4229
+ withoutTransition: withoutTransition,
4230
+ },
4231
+ $$ = this.owner,
4232
+ d3 = $$.d3,
4233
+ config = $$.config,
4234
+ axis = c3_axis(d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
4235
+ if ($$.isTimeSeriesY()) {
4236
+ axis.ticks(d3.time[config.axis_y_tick_time_value], config.axis_y_tick_time_interval);
4093
4237
  } else {
4094
4238
  axis.tickValues(tickValues);
4095
4239
  }
4096
4240
  return axis;
4097
4241
  };
4098
- c3_chart_internal_fn.getAxisId = function (id) {
4099
- var config = this.config;
4242
+ Axis.prototype.getId = function getId(id) {
4243
+ var config = this.owner.config;
4100
4244
  return id in config.data_axes ? config.data_axes[id] : 'y';
4101
4245
  };
4102
- c3_chart_internal_fn.getXAxisTickFormat = function () {
4103
- var $$ = this, config = $$.config,
4246
+ Axis.prototype.getXAxisTickFormat = function getXAxisTickFormat() {
4247
+ var $$ = this.owner, config = $$.config,
4104
4248
  format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
4105
4249
  if (config.axis_x_tick_format) {
4106
4250
  if (isFunction(config.axis_x_tick_format)) {
@@ -4113,20 +4257,20 @@
4113
4257
  }
4114
4258
  return isFunction(format) ? function (v) { return format.call($$, v); } : format;
4115
4259
  };
4116
- c3_chart_internal_fn.getAxisTickValues = function (tickValues, axis) {
4260
+ Axis.prototype.getTickValues = function getTickValues(tickValues, axis) {
4117
4261
  return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
4118
4262
  };
4119
- c3_chart_internal_fn.getXAxisTickValues = function () {
4120
- return this.getAxisTickValues(this.config.axis_x_tick_values, this.xAxis);
4263
+ Axis.prototype.getXAxisTickValues = function getXAxisTickValues() {
4264
+ return this.getTickValues(this.owner.config.axis_x_tick_values, this.owner.xAxis);
4121
4265
  };
4122
- c3_chart_internal_fn.getYAxisTickValues = function () {
4123
- return this.getAxisTickValues(this.config.axis_y_tick_values, this.yAxis);
4266
+ Axis.prototype.getYAxisTickValues = function getYAxisTickValues() {
4267
+ return this.getTickValues(this.owner.config.axis_y_tick_values, this.owner.yAxis);
4124
4268
  };
4125
- c3_chart_internal_fn.getY2AxisTickValues = function () {
4126
- return this.getAxisTickValues(this.config.axis_y2_tick_values, this.y2Axis);
4269
+ Axis.prototype.getY2AxisTickValues = function getY2AxisTickValues() {
4270
+ return this.getTickValues(this.owner.config.axis_y2_tick_values, this.owner.y2Axis);
4127
4271
  };
4128
- c3_chart_internal_fn.getAxisLabelOptionByAxisId = function (axisId) {
4129
- var $$ = this, config = $$.config, option;
4272
+ Axis.prototype.getLabelOptionByAxisId = function getLabelOptionByAxisId(axisId) {
4273
+ var $$ = this.owner, config = $$.config, option;
4130
4274
  if (axisId === 'y') {
4131
4275
  option = config.axis_y_label;
4132
4276
  } else if (axisId === 'y2') {
@@ -4136,13 +4280,13 @@
4136
4280
  }
4137
4281
  return option;
4138
4282
  };
4139
- c3_chart_internal_fn.getAxisLabelText = function (axisId) {
4140
- var option = this.getAxisLabelOptionByAxisId(axisId);
4283
+ Axis.prototype.getLabelText = function getLabelText(axisId) {
4284
+ var option = this.getLabelOptionByAxisId(axisId);
4141
4285
  return isString(option) ? option : option ? option.text : null;
4142
4286
  };
4143
- c3_chart_internal_fn.setAxisLabelText = function (axisId, text) {
4144
- var $$ = this, config = $$.config,
4145
- option = $$.getAxisLabelOptionByAxisId(axisId);
4287
+ Axis.prototype.setLabelText = function setLabelText(axisId, text) {
4288
+ var $$ = this.owner, config = $$.config,
4289
+ option = this.getLabelOptionByAxisId(axisId);
4146
4290
  if (isString(option)) {
4147
4291
  if (axisId === 'y') {
4148
4292
  config.axis_y_label = text;
@@ -4155,8 +4299,8 @@
4155
4299
  option.text = text;
4156
4300
  }
4157
4301
  };
4158
- c3_chart_internal_fn.getAxisLabelPosition = function (axisId, defaultPosition) {
4159
- var option = this.getAxisLabelOptionByAxisId(axisId),
4302
+ Axis.prototype.getLabelPosition = function getLabelPosition(axisId, defaultPosition) {
4303
+ var option = this.getLabelOptionByAxisId(axisId),
4160
4304
  position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
4161
4305
  return {
4162
4306
  isInner: position.indexOf('inner') >= 0,
@@ -4169,126 +4313,109 @@
4169
4313
  isBottom: position.indexOf('bottom') >= 0
4170
4314
  };
4171
4315
  };
4172
- c3_chart_internal_fn.getXAxisLabelPosition = function () {
4173
- return this.getAxisLabelPosition('x', this.config.axis_rotated ? 'inner-top' : 'inner-right');
4316
+ Axis.prototype.getXAxisLabelPosition = function getXAxisLabelPosition() {
4317
+ return this.getLabelPosition('x', this.owner.config.axis_rotated ? 'inner-top' : 'inner-right');
4174
4318
  };
4175
- c3_chart_internal_fn.getYAxisLabelPosition = function () {
4176
- return this.getAxisLabelPosition('y', this.config.axis_rotated ? 'inner-right' : 'inner-top');
4319
+ Axis.prototype.getYAxisLabelPosition = function getYAxisLabelPosition() {
4320
+ return this.getLabelPosition('y', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
4177
4321
  };
4178
- c3_chart_internal_fn.getY2AxisLabelPosition = function () {
4179
- return this.getAxisLabelPosition('y2', this.config.axis_rotated ? 'inner-right' : 'inner-top');
4322
+ Axis.prototype.getY2AxisLabelPosition = function getY2AxisLabelPosition() {
4323
+ return this.getLabelPosition('y2', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
4180
4324
  };
4181
- c3_chart_internal_fn.getAxisLabelPositionById = function (id) {
4325
+ Axis.prototype.getLabelPositionById = function getLabelPositionById(id) {
4182
4326
  return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
4183
4327
  };
4184
- c3_chart_internal_fn.textForXAxisLabel = function () {
4185
- return this.getAxisLabelText('x');
4328
+ Axis.prototype.textForXAxisLabel = function textForXAxisLabel() {
4329
+ return this.getLabelText('x');
4186
4330
  };
4187
- c3_chart_internal_fn.textForYAxisLabel = function () {
4188
- return this.getAxisLabelText('y');
4331
+ Axis.prototype.textForYAxisLabel = function textForYAxisLabel() {
4332
+ return this.getLabelText('y');
4189
4333
  };
4190
- c3_chart_internal_fn.textForY2AxisLabel = function () {
4191
- return this.getAxisLabelText('y2');
4334
+ Axis.prototype.textForY2AxisLabel = function textForY2AxisLabel() {
4335
+ return this.getLabelText('y2');
4192
4336
  };
4193
- c3_chart_internal_fn.xForAxisLabel = function (forHorizontal, position) {
4194
- var $$ = this;
4337
+ Axis.prototype.xForAxisLabel = function xForAxisLabel(forHorizontal, position) {
4338
+ var $$ = this.owner;
4195
4339
  if (forHorizontal) {
4196
4340
  return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
4197
4341
  } else {
4198
4342
  return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
4199
4343
  }
4200
4344
  };
4201
- c3_chart_internal_fn.dxForAxisLabel = function (forHorizontal, position) {
4345
+ Axis.prototype.dxForAxisLabel = function dxForAxisLabel(forHorizontal, position) {
4202
4346
  if (forHorizontal) {
4203
4347
  return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
4204
4348
  } else {
4205
4349
  return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
4206
4350
  }
4207
4351
  };
4208
- c3_chart_internal_fn.textAnchorForAxisLabel = function (forHorizontal, position) {
4352
+ Axis.prototype.textAnchorForAxisLabel = function textAnchorForAxisLabel(forHorizontal, position) {
4209
4353
  if (forHorizontal) {
4210
4354
  return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
4211
4355
  } else {
4212
4356
  return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
4213
4357
  }
4214
4358
  };
4215
- c3_chart_internal_fn.xForXAxisLabel = function () {
4216
- return this.xForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
4359
+ Axis.prototype.xForXAxisLabel = function xForXAxisLabel() {
4360
+ return this.xForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
4217
4361
  };
4218
- c3_chart_internal_fn.xForYAxisLabel = function () {
4219
- return this.xForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
4362
+ Axis.prototype.xForYAxisLabel = function xForYAxisLabel() {
4363
+ return this.xForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
4220
4364
  };
4221
- c3_chart_internal_fn.xForY2AxisLabel = function () {
4222
- return this.xForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
4365
+ Axis.prototype.xForY2AxisLabel = function xForY2AxisLabel() {
4366
+ return this.xForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
4223
4367
  };
4224
- c3_chart_internal_fn.dxForXAxisLabel = function () {
4225
- return this.dxForAxisLabel(!this.config.axis_rotated, this.getXAxisLabelPosition());
4368
+ Axis.prototype.dxForXAxisLabel = function dxForXAxisLabel() {
4369
+ return this.dxForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
4226
4370
  };
4227
- c3_chart_internal_fn.dxForYAxisLabel = function () {
4228
- return this.dxForAxisLabel(this.config.axis_rotated, this.getYAxisLabelPosition());
4371
+ Axis.prototype.dxForYAxisLabel = function dxForYAxisLabel() {
4372
+ return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
4229
4373
  };
4230
- c3_chart_internal_fn.dxForY2AxisLabel = function () {
4231
- return this.dxForAxisLabel(this.config.axis_rotated, this.getY2AxisLabelPosition());
4374
+ Axis.prototype.dxForY2AxisLabel = function dxForY2AxisLabel() {
4375
+ return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
4232
4376
  };
4233
- c3_chart_internal_fn.dyForXAxisLabel = function () {
4234
- var $$ = this, config = $$.config,
4235
- position = $$.getXAxisLabelPosition();
4377
+ Axis.prototype.dyForXAxisLabel = function dyForXAxisLabel() {
4378
+ var $$ = this.owner, config = $$.config,
4379
+ position = this.getXAxisLabelPosition();
4236
4380
  if (config.axis_rotated) {
4237
- return position.isInner ? "1.2em" : -25 - $$.getMaxTickWidth('x');
4381
+ return position.isInner ? "1.2em" : -25 - this.getMaxTickWidth('x');
4238
4382
  } else {
4239
4383
  return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
4240
4384
  }
4241
4385
  };
4242
- c3_chart_internal_fn.dyForYAxisLabel = function () {
4243
- var $$ = this,
4244
- position = $$.getYAxisLabelPosition();
4386
+ Axis.prototype.dyForYAxisLabel = function dyForYAxisLabel() {
4387
+ var $$ = this.owner,
4388
+ position = this.getYAxisLabelPosition();
4245
4389
  if ($$.config.axis_rotated) {
4246
4390
  return position.isInner ? "-0.5em" : "3em";
4247
4391
  } else {
4248
- return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : ($$.getMaxTickWidth('y') + 10));
4392
+ return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : (this.getMaxTickWidth('y') + 10));
4249
4393
  }
4250
4394
  };
4251
- c3_chart_internal_fn.dyForY2AxisLabel = function () {
4252
- var $$ = this,
4253
- position = $$.getY2AxisLabelPosition();
4395
+ Axis.prototype.dyForY2AxisLabel = function dyForY2AxisLabel() {
4396
+ var $$ = this.owner,
4397
+ position = this.getY2AxisLabelPosition();
4254
4398
  if ($$.config.axis_rotated) {
4255
4399
  return position.isInner ? "1.2em" : "-2.2em";
4256
4400
  } else {
4257
4401
  return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth('y2') + 15));
4258
4402
  }
4259
4403
  };
4260
- c3_chart_internal_fn.textAnchorForXAxisLabel = function () {
4261
- var $$ = this;
4262
- return $$.textAnchorForAxisLabel(!$$.config.axis_rotated, $$.getXAxisLabelPosition());
4404
+ Axis.prototype.textAnchorForXAxisLabel = function textAnchorForXAxisLabel() {
4405
+ var $$ = this.owner;
4406
+ return this.textAnchorForAxisLabel(!$$.config.axis_rotated, this.getXAxisLabelPosition());
4263
4407
  };
4264
- c3_chart_internal_fn.textAnchorForYAxisLabel = function () {
4265
- var $$ = this;
4266
- return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getYAxisLabelPosition());
4267
- };
4268
- c3_chart_internal_fn.textAnchorForY2AxisLabel = function () {
4269
- var $$ = this;
4270
- return $$.textAnchorForAxisLabel($$.config.axis_rotated, $$.getY2AxisLabelPosition());
4408
+ Axis.prototype.textAnchorForYAxisLabel = function textAnchorForYAxisLabel() {
4409
+ var $$ = this.owner;
4410
+ return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getYAxisLabelPosition());
4271
4411
  };
4272
-
4273
- c3_chart_internal_fn.xForRotatedTickText = function (r) {
4274
- return 8 * Math.sin(Math.PI * (r / 180));
4412
+ Axis.prototype.textAnchorForY2AxisLabel = function textAnchorForY2AxisLabel() {
4413
+ var $$ = this.owner;
4414
+ return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getY2AxisLabelPosition());
4275
4415
  };
4276
- c3_chart_internal_fn.yForRotatedTickText = function (r) {
4277
- return 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1);
4278
- };
4279
- c3_chart_internal_fn.rotateTickText = function (axis, transition, rotate) {
4280
- axis.selectAll('.tick text')
4281
- .style("text-anchor", rotate > 0 ? "start" : "end");
4282
- transition.selectAll('.tick text')
4283
- .attr("y", this.yForRotatedTickText(rotate))
4284
- .attr("transform", "rotate(" + rotate + ")")
4285
- .selectAll('tspan')
4286
- .attr('dx', this.xForRotatedTickText(rotate));
4287
- };
4288
-
4289
- c3_chart_internal_fn.getMaxTickWidth = function (id, withoutRecompute) {
4290
- var $$ = this, config = $$.config,
4291
- maxWidth = 0, targetsToShow, scale, axis;
4416
+ Axis.prototype.getMaxTickWidth = function getMaxTickWidth(id, withoutRecompute) {
4417
+ var $$ = this.owner, config = $$.config,
4418
+ maxWidth = 0, targetsToShow, scale, axis, dummy, svg;
4292
4419
  if (withoutRecompute && $$.currentMaxTickWidths[id]) {
4293
4420
  return $$.currentMaxTickWidths[id];
4294
4421
  }
@@ -4296,48 +4423,51 @@
4296
4423
  targetsToShow = $$.filterTargetsToShow($$.data.targets);
4297
4424
  if (id === 'y') {
4298
4425
  scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
4299
- axis = $$.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues);
4426
+ axis = this.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, false, true);
4300
4427
  } else if (id === 'y2') {
4301
4428
  scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
4302
- axis = $$.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues);
4429
+ axis = this.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, false, true);
4303
4430
  } else {
4304
4431
  scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
4305
- axis = $$.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues);
4432
+ axis = this.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, false, true, true);
4433
+ this.updateXAxisTickValues(targetsToShow, axis);
4306
4434
  }
4307
- $$.d3.select('body').append("g").style('visibility', 'hidden').call(axis).each(function () {
4308
- $$.d3.select(this).selectAll('text tspan').each(function () {
4435
+ dummy = $$.d3.select('body').append('div').classed('c3', true);
4436
+ svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
4437
+ svg.append('g').call(axis).each(function () {
4438
+ $$.d3.select(this).selectAll('text').each(function () {
4309
4439
  var box = this.getBoundingClientRect();
4310
- if (box.left > 0 && maxWidth < box.width) { maxWidth = box.width; }
4440
+ if (maxWidth < box.width) { maxWidth = box.width; }
4311
4441
  });
4312
- }).remove();
4442
+ dummy.remove();
4443
+ });
4313
4444
  }
4314
4445
  $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
4315
4446
  return $$.currentMaxTickWidths[id];
4316
4447
  };
4317
4448
 
4318
- c3_chart_internal_fn.updateAxisLabels = function (withTransition) {
4319
- var $$ = this;
4449
+ Axis.prototype.updateLabels = function updateLabels(withTransition) {
4450
+ var $$ = this.owner;
4320
4451
  var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
4321
4452
  axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
4322
4453
  axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
4323
4454
  (withTransition ? axisXLabel.transition() : axisXLabel)
4324
- .attr("x", $$.xForXAxisLabel.bind($$))
4325
- .attr("dx", $$.dxForXAxisLabel.bind($$))
4326
- .attr("dy", $$.dyForXAxisLabel.bind($$))
4327
- .text($$.textForXAxisLabel.bind($$));
4455
+ .attr("x", this.xForXAxisLabel.bind(this))
4456
+ .attr("dx", this.dxForXAxisLabel.bind(this))
4457
+ .attr("dy", this.dyForXAxisLabel.bind(this))
4458
+ .text(this.textForXAxisLabel.bind(this));
4328
4459
  (withTransition ? axisYLabel.transition() : axisYLabel)
4329
- .attr("x", $$.xForYAxisLabel.bind($$))
4330
- .attr("dx", $$.dxForYAxisLabel.bind($$))
4331
- .attr("dy", $$.dyForYAxisLabel.bind($$))
4332
- .text($$.textForYAxisLabel.bind($$));
4460
+ .attr("x", this.xForYAxisLabel.bind(this))
4461
+ .attr("dx", this.dxForYAxisLabel.bind(this))
4462
+ .attr("dy", this.dyForYAxisLabel.bind(this))
4463
+ .text(this.textForYAxisLabel.bind(this));
4333
4464
  (withTransition ? axisY2Label.transition() : axisY2Label)
4334
- .attr("x", $$.xForY2AxisLabel.bind($$))
4335
- .attr("dx", $$.dxForY2AxisLabel.bind($$))
4336
- .attr("dy", $$.dyForY2AxisLabel.bind($$))
4337
- .text($$.textForY2AxisLabel.bind($$));
4465
+ .attr("x", this.xForY2AxisLabel.bind(this))
4466
+ .attr("dx", this.dxForY2AxisLabel.bind(this))
4467
+ .attr("dy", this.dyForY2AxisLabel.bind(this))
4468
+ .text(this.textForY2AxisLabel.bind(this));
4338
4469
  };
4339
-
4340
- c3_chart_internal_fn.getAxisPadding = function (padding, key, defaultValue, domainLength) {
4470
+ Axis.prototype.getPadding = function getPadding(padding, key, defaultValue, domainLength) {
4341
4471
  if (!isValue(padding[key])) {
4342
4472
  return defaultValue;
4343
4473
  }
@@ -4347,12 +4477,12 @@
4347
4477
  // assume padding is pixels if unit is not specified
4348
4478
  return this.convertPixelsToAxisPadding(padding[key], domainLength);
4349
4479
  };
4350
- c3_chart_internal_fn.convertPixelsToAxisPadding = function (pixels, domainLength) {
4351
- var length = this.config.axis_rotated ? this.width : this.height;
4480
+ Axis.prototype.convertPixelsToAxisPadding = function convertPixelsToAxisPadding(pixels, domainLength) {
4481
+ var $$ = this.owner,
4482
+ length = $$.config.axis_rotated ? $$.width : $$.height;
4352
4483
  return domainLength * (pixels / length);
4353
4484
  };
4354
-
4355
- c3_chart_internal_fn.generateTickValues = function (values, tickCount, forTimeSeries) {
4485
+ Axis.prototype.generateTickValues = function generateTickValues(values, tickCount, forTimeSeries) {
4356
4486
  var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
4357
4487
  if (tickCount) {
4358
4488
  targetCount = isFunction(tickCount) ? tickCount() : tickCount;
@@ -4378,8 +4508,8 @@
4378
4508
  if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
4379
4509
  return tickValues;
4380
4510
  };
4381
- c3_chart_internal_fn.generateAxisTransitions = function (duration) {
4382
- var $$ = this, axes = $$.axes;
4511
+ Axis.prototype.generateTransitions = function generateTransitions(duration) {
4512
+ var $$ = this.owner, axes = $$.axes;
4383
4513
  return {
4384
4514
  axisX: duration ? axes.x.transition().duration(duration) : axes.x,
4385
4515
  axisY: duration ? axes.y.transition().duration(duration) : axes.y,
@@ -4387,8 +4517,8 @@
4387
4517
  axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
4388
4518
  };
4389
4519
  };
4390
- c3_chart_internal_fn.redrawAxis = function (transitions, isHidden) {
4391
- var $$ = this, config = $$.config;
4520
+ Axis.prototype.redraw = function redraw(transitions, isHidden) {
4521
+ var $$ = this.owner;
4392
4522
  $$.axes.x.style("opacity", isHidden ? 0 : 1);
4393
4523
  $$.axes.y.style("opacity", isHidden ? 0 : 1);
4394
4524
  $$.axes.y2.style("opacity", isHidden ? 0 : 1);
@@ -4397,11 +4527,6 @@
4397
4527
  transitions.axisY.call($$.yAxis);
4398
4528
  transitions.axisY2.call($$.y2Axis);
4399
4529
  transitions.axisSubX.call($$.subXAxis);
4400
- // rotate tick text if needed
4401
- if (!config.axis_rotated && config.axis_x_tick_rotate) {
4402
- $$.rotateTickText($$.axes.x, transitions.axisX, config.axis_x_tick_rotate);
4403
- $$.rotateTickText($$.axes.subx, transitions.axisSubX, config.axis_x_tick_rotate);
4404
- }
4405
4530
  };
4406
4531
 
4407
4532
  c3_chart_internal_fn.getClipPath = function (id) {
@@ -4501,6 +4626,9 @@
4501
4626
  }
4502
4627
  index++;
4503
4628
  });
4629
+ if (isNaN(d.startAngle)) {
4630
+ d.startAngle = 0;
4631
+ }
4504
4632
  if (isNaN(d.endAngle)) {
4505
4633
  d.endAngle = d.startAngle;
4506
4634
  }
@@ -4738,7 +4866,7 @@
4738
4866
  var updated = $$.updateAngle(d),
4739
4867
  arcData = $$.convertToArcData(updated),
4740
4868
  selectedData = [arcData];
4741
- $$.showTooltip(selectedData, d3.mouse(this));
4869
+ $$.showTooltip(selectedData, this);
4742
4870
  } : null)
4743
4871
  .on('mouseout', config.interaction_enabled ? function (d) {
4744
4872
  var updated, arcData;
@@ -4773,6 +4901,9 @@
4773
4901
  // endAngle: Math.PI*2,
4774
4902
  // };
4775
4903
  // }
4904
+ if (isNaN(this._current.startAngle)) {
4905
+ this._current.startAngle = 0;
4906
+ }
4776
4907
  if (isNaN(this._current.endAngle)) {
4777
4908
  this._current.endAngle = this._current.startAngle;
4778
4909
  }
@@ -4858,7 +4989,7 @@
4858
4989
  .attr("clip-path", $$.clipPath)
4859
4990
  .attr("class", CLASS.regions);
4860
4991
  };
4861
- c3_chart_internal_fn.redrawRegion = function (duration) {
4992
+ c3_chart_internal_fn.updateRegion = function (duration) {
4862
4993
  var $$ = this, config = $$.config;
4863
4994
 
4864
4995
  // hide if arc type
@@ -4874,18 +5005,21 @@
4874
5005
  .style("opacity", 0)
4875
5006
  .remove();
4876
5007
  };
4877
- c3_chart_internal_fn.addTransitionForRegion = function (transitions) {
5008
+ c3_chart_internal_fn.redrawRegion = function (withTransition) {
4878
5009
  var $$ = this,
5010
+ regions = $$.mainRegion.selectAll('rect'),
4879
5011
  x = $$.regionX.bind($$),
4880
5012
  y = $$.regionY.bind($$),
4881
5013
  w = $$.regionWidth.bind($$),
4882
5014
  h = $$.regionHeight.bind($$);
4883
- transitions.push($$.mainRegion.selectAll('rect').transition()
4884
- .attr("x", x)
4885
- .attr("y", y)
4886
- .attr("width", w)
4887
- .attr("height", h)
4888
- .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; }));
5015
+ return [
5016
+ (withTransition ? regions.transition() : regions)
5017
+ .attr("x", x)
5018
+ .attr("y", y)
5019
+ .attr("width", w)
5020
+ .attr("height", h)
5021
+ .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; })
5022
+ ];
4889
5023
  };
4890
5024
  c3_chart_internal_fn.regionX = function (d) {
4891
5025
  var $$ = this, config = $$.config,
@@ -4998,7 +5132,6 @@
4998
5132
  .attr('class', CLASS.dragarea)
4999
5133
  .style('opacity', 0.1);
5000
5134
  $$.dragging = true;
5001
- $$.config.data_ondragstart.call($$.api);
5002
5135
  };
5003
5136
 
5004
5137
  c3_chart_internal_fn.dragend = function () {
@@ -5012,10 +5145,8 @@
5012
5145
  $$.main.selectAll('.' + CLASS.shape)
5013
5146
  .classed(CLASS.INCLUDED, false);
5014
5147
  $$.dragging = false;
5015
- $$.config.data_ondragend.call($$.api);
5016
5148
  };
5017
5149
 
5018
-
5019
5150
  c3_chart_internal_fn.selectPoint = function (target, d, i) {
5020
5151
  var $$ = this, config = $$.config,
5021
5152
  cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
@@ -5107,9 +5238,7 @@
5107
5238
  var $$ = this, config = $$.config,
5108
5239
  context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context'));
5109
5240
 
5110
- if (!config.subchart_show) {
5111
- context.style('visibility', 'hidden');
5112
- }
5241
+ context.style('visibility', config.subchart_show ? 'visible' : 'hidden');
5113
5242
 
5114
5243
  // Define g for chart area
5115
5244
  context.append('g')
@@ -5128,9 +5257,7 @@
5128
5257
  context.append("g")
5129
5258
  .attr("clip-path", $$.clipPath)
5130
5259
  .attr("class", CLASS.brush)
5131
- .call($$.brush)
5132
- .selectAll("rect")
5133
- .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
5260
+ .call($$.brush);
5134
5261
 
5135
5262
  // ATTENTION: This must be called AFTER chart added
5136
5263
  // Add Axis
@@ -5149,6 +5276,7 @@
5149
5276
  classAreas = $$.classAreas.bind($$);
5150
5277
 
5151
5278
  if (config.subchart_show) {
5279
+ //-- Bar --//
5152
5280
  contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
5153
5281
  .data(targets)
5154
5282
  .attr('class', classChartBar);
@@ -5172,17 +5300,74 @@
5172
5300
  // Area
5173
5301
  contextLineEnter.append("g")
5174
5302
  .attr("class", classAreas);
5303
+
5304
+ //-- Brush --//
5305
+ context.selectAll('.' + CLASS.brush + ' rect')
5306
+ .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
5175
5307
  }
5176
5308
  };
5309
+ c3_chart_internal_fn.updateBarForSubchart = function (durationForExit) {
5310
+ var $$ = this;
5311
+ $$.contextBar = $$.context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
5312
+ .data($$.barData.bind($$));
5313
+ $$.contextBar.enter().append('path')
5314
+ .attr("class", $$.classBar.bind($$))
5315
+ .style("stroke", 'none')
5316
+ .style("fill", $$.color);
5317
+ $$.contextBar
5318
+ .style("opacity", $$.initialOpacity.bind($$));
5319
+ $$.contextBar.exit().transition().duration(durationForExit)
5320
+ .style('opacity', 0)
5321
+ .remove();
5322
+ };
5323
+ c3_chart_internal_fn.redrawBarForSubchart = function (drawBarOnSub, withTransition, duration) {
5324
+ (withTransition ? this.contextBar.transition().duration(duration) : this.contextBar)
5325
+ .attr('d', drawBarOnSub)
5326
+ .style('opacity', 1);
5327
+ };
5328
+ c3_chart_internal_fn.updateLineForSubchart = function (durationForExit) {
5329
+ var $$ = this;
5330
+ $$.contextLine = $$.context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
5331
+ .data($$.lineData.bind($$));
5332
+ $$.contextLine.enter().append('path')
5333
+ .attr('class', $$.classLine.bind($$))
5334
+ .style('stroke', $$.color);
5335
+ $$.contextLine
5336
+ .style("opacity", $$.initialOpacity.bind($$));
5337
+ $$.contextLine.exit().transition().duration(durationForExit)
5338
+ .style('opacity', 0)
5339
+ .remove();
5340
+ };
5341
+ c3_chart_internal_fn.redrawLineForSubchart = function (drawLineOnSub, withTransition, duration) {
5342
+ (withTransition ? this.contextLine.transition().duration(duration) : this.contextLine)
5343
+ .attr("d", drawLineOnSub)
5344
+ .style('opacity', 1);
5345
+ };
5346
+ c3_chart_internal_fn.updateAreaForSubchart = function (durationForExit) {
5347
+ var $$ = this, d3 = $$.d3;
5348
+ $$.contextArea = $$.context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
5349
+ .data($$.lineData.bind($$));
5350
+ $$.contextArea.enter().append('path')
5351
+ .attr("class", $$.classArea.bind($$))
5352
+ .style("fill", $$.color)
5353
+ .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
5354
+ $$.contextArea
5355
+ .style("opacity", 0);
5356
+ $$.contextArea.exit().transition().duration(durationForExit)
5357
+ .style('opacity', 0)
5358
+ .remove();
5359
+ };
5360
+ c3_chart_internal_fn.redrawAreaForSubchart = function (drawAreaOnSub, withTransition, duration) {
5361
+ (withTransition ? this.contextArea.transition().duration(duration) : this.contextArea)
5362
+ .attr("d", drawAreaOnSub)
5363
+ .style("fill", this.color)
5364
+ .style("opacity", this.orgAreaOpacity);
5365
+ };
5177
5366
  c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
5178
- var $$ = this, d3 = $$.d3, context = $$.context, config = $$.config,
5179
- contextLine, contextArea, contextBar, drawAreaOnSub, drawBarOnSub, drawLineOnSub,
5180
- barData = $$.barData.bind($$),
5181
- lineData = $$.lineData.bind($$),
5182
- classBar = $$.classBar.bind($$),
5183
- classLine = $$.classLine.bind($$),
5184
- classArea = $$.classArea.bind($$),
5185
- initialOpacity = $$.initialOpacity.bind($$);
5367
+ var $$ = this, d3 = $$.d3, config = $$.config,
5368
+ drawAreaOnSub, drawBarOnSub, drawLineOnSub;
5369
+
5370
+ $$.context.style('visibility', config.subchart_show ? 'visible' : 'hidden');
5186
5371
 
5187
5372
  // subchart
5188
5373
  if (config.subchart_show) {
@@ -5201,51 +5386,14 @@
5201
5386
  drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
5202
5387
  drawBarOnSub = $$.generateDrawBar(barIndices, true);
5203
5388
  drawLineOnSub = $$.generateDrawLine(lineIndices, true);
5204
- // bars
5205
- contextBar = context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
5206
- .data(barData);
5207
- contextBar.enter().append('path')
5208
- .attr("class", classBar)
5209
- .style("stroke", 'none')
5210
- .style("fill", $$.color);
5211
- contextBar
5212
- .style("opacity", initialOpacity)
5213
- .transition().duration(duration)
5214
- .attr('d', drawBarOnSub)
5215
- .style('opacity', 1);
5216
- contextBar.exit().transition().duration(duration)
5217
- .style('opacity', 0)
5218
- .remove();
5219
- // lines
5220
- contextLine = context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
5221
- .data(lineData);
5222
- contextLine.enter().append('path')
5223
- .attr('class', classLine)
5224
- .style('stroke', $$.color);
5225
- contextLine
5226
- .style("opacity", initialOpacity)
5227
- .transition().duration(duration)
5228
- .attr("d", drawLineOnSub)
5229
- .style('opacity', 1);
5230
- contextLine.exit().transition().duration(duration)
5231
- .style('opacity', 0)
5232
- .remove();
5233
- // area
5234
- contextArea = context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
5235
- .data(lineData);
5236
- contextArea.enter().append('path')
5237
- .attr("class", classArea)
5238
- .style("fill", $$.color)
5239
- .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
5240
- contextArea
5241
- .style("opacity", 0)
5242
- .transition().duration(duration)
5243
- .attr("d", drawAreaOnSub)
5244
- .style("fill", $$.color)
5245
- .style("opacity", $$.orgAreaOpacity);
5246
- contextArea.exit().transition().duration(durationForExit)
5247
- .style('opacity', 0)
5248
- .remove();
5389
+
5390
+ $$.updateBarForSubchart(duration);
5391
+ $$.updateLineForSubchart(duration);
5392
+ $$.updateAreaForSubchart(duration);
5393
+
5394
+ $$.redrawBarForSubchart(drawBarOnSub, duration, duration);
5395
+ $$.redrawLineForSubchart(drawLineOnSub, duration, duration);
5396
+ $$.redrawAreaForSubchart(drawAreaOnSub, duration, duration);
5249
5397
  }
5250
5398
  }
5251
5399
  };
@@ -5358,7 +5506,7 @@
5358
5506
  ids = [];
5359
5507
 
5360
5508
  return function (d) {
5361
- var id = d.id || d, color;
5509
+ var id = d.id || (d.data && d.data.id) || d, color;
5362
5510
 
5363
5511
  // if callback function is provided
5364
5512
  if (colors[id] instanceof Function) {
@@ -5402,7 +5550,7 @@
5402
5550
  formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
5403
5551
  formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
5404
5552
  return function (v, ratio, id) {
5405
- var format = $$.getAxisId(id) === 'y2' ? formatForY2 : formatForY;
5553
+ var format = $$.axis.getId(id) === 'y2' ? formatForY2 : formatForY;
5406
5554
  return format.call($$, v, ratio);
5407
5555
  };
5408
5556
  };
@@ -5422,16 +5570,20 @@
5422
5570
  c3_chart_internal_fn.defaultArcValueFormat = function (v, ratio) {
5423
5571
  return (ratio * 100).toFixed(1) + '%';
5424
5572
  };
5425
- c3_chart_internal_fn.formatByAxisId = function (axisId) {
5573
+ c3_chart_internal_fn.dataLabelFormat = function (targetId) {
5426
5574
  var $$ = this, data_labels = $$.config.data_labels,
5427
- format = function (v) { return isValue(v) ? +v : ""; };
5575
+ format, defaultFormat = function (v) { return isValue(v) ? +v : ""; };
5428
5576
  // find format according to axis id
5429
5577
  if (typeof data_labels.format === 'function') {
5430
5578
  format = data_labels.format;
5431
5579
  } else if (typeof data_labels.format === 'object') {
5432
- if (data_labels.format[axisId]) {
5433
- format = data_labels.format[axisId];
5580
+ if (data_labels.format[targetId]) {
5581
+ format = data_labels.format[targetId] === true ? defaultFormat : data_labels.format[targetId];
5582
+ } else {
5583
+ format = function () { return ''; };
5434
5584
  }
5585
+ } else {
5586
+ format = defaultFormat;
5435
5587
  }
5436
5588
  return format;
5437
5589
  };
@@ -5701,7 +5853,6 @@
5701
5853
  targetIds = $$.mapToTargetIds(targetIds);
5702
5854
  candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
5703
5855
 
5704
- this.revert();
5705
5856
  candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
5706
5857
  if ($$.hasArcType()) {
5707
5858
  $$.unexpandArc(targetIds);
@@ -5726,6 +5877,11 @@
5726
5877
  }
5727
5878
  if ($$.config.legend_show) {
5728
5879
  $$.showLegend(targetIds.filter($$.isLegendToShow.bind($$)));
5880
+ $$.legend.selectAll($$.selectorLegends(targetIds))
5881
+ .filter(function () {
5882
+ return $$.d3.select(this).classed(CLASS.legendItemFocused);
5883
+ })
5884
+ .classed(CLASS.legendItemFocused, false);
5729
5885
  }
5730
5886
 
5731
5887
  $$.focusedTargetIds = [];
@@ -5776,10 +5932,10 @@
5776
5932
  $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
5777
5933
  };
5778
5934
 
5779
- c3_chart_fn.toggle = function (targetIds) {
5935
+ c3_chart_fn.toggle = function (targetIds, options) {
5780
5936
  var that = this, $$ = this.internal;
5781
5937
  $$.mapToTargetIds(targetIds).forEach(function (targetId) {
5782
- $$.isTargetToShow(targetId) ? that.hide(targetId) : that.show(targetId);
5938
+ $$.isTargetToShow(targetId) ? that.hide(targetId, options) : that.show(targetId, options);
5783
5939
  });
5784
5940
  };
5785
5941
 
@@ -5828,6 +5984,12 @@
5828
5984
  config.data_axes[id] = args.axes[id];
5829
5985
  });
5830
5986
  }
5987
+ // update colors if exists
5988
+ if ('colors' in args) {
5989
+ Object.keys(args.colors).forEach(function (id) {
5990
+ config.data_colors[id] = args.colors[id];
5991
+ });
5992
+ }
5831
5993
  // use cache if exists
5832
5994
  if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
5833
5995
  $$.load($$.getCaches(args.cacheIds), args.done);
@@ -6221,6 +6383,7 @@
6221
6383
  options.withTransitionForTransform = false;
6222
6384
  $$.transiting = false;
6223
6385
  $$.setTargetType(targetIds, type);
6386
+ $$.updateTargets($$.data.targets); // this is needed when transforming to arc
6224
6387
  $$.updateAndRedraw(options);
6225
6388
  };
6226
6389
 
@@ -6377,9 +6540,9 @@
6377
6540
  var $$ = this.internal;
6378
6541
  if (arguments.length) {
6379
6542
  Object.keys(labels).forEach(function (axisId) {
6380
- $$.setAxisLabelText(axisId, labels[axisId]);
6543
+ $$.axis.setLabelText(axisId, labels[axisId]);
6381
6544
  });
6382
- $$.updateAxisLabels();
6545
+ $$.axis.updateLabels();
6383
6546
  }
6384
6547
  // TODO: return some values?
6385
6548
  };
@@ -6459,11 +6622,18 @@
6459
6622
 
6460
6623
  c3_chart_fn.destroy = function () {
6461
6624
  var $$ = this.internal;
6462
- $$.data.targets = undefined;
6463
- $$.data.xs = {};
6464
- $$.selectChart.classed('c3', false).html("");
6625
+
6465
6626
  window.clearInterval($$.intervalForObserveInserted);
6466
6627
  window.onresize = null;
6628
+
6629
+ $$.selectChart.classed('c3', false).html("");
6630
+
6631
+ // MEMO: this is needed because the reference of some elements will not be released, then memory leak will happen.
6632
+ Object.keys($$).forEach(function (key) {
6633
+ $$[key] = null;
6634
+ });
6635
+
6636
+ return null;
6467
6637
  };
6468
6638
 
6469
6639
  c3_chart_fn.tooltip = function () {};
@@ -6552,7 +6722,8 @@
6552
6722
  return newScale;
6553
6723
  }
6554
6724
  function textFormatted(v) {
6555
- return tickFormat ? tickFormat(v) : v;
6725
+ var formatted = tickFormat ? tickFormat(v) : v;
6726
+ return typeof formatted !== 'undefined' ? formatted : '';
6556
6727
  }
6557
6728
  function getSizeFor1Char(tick) {
6558
6729
  if (tickTextCharSize) {
@@ -6575,9 +6746,13 @@
6575
6746
  tickTextCharSize = size;
6576
6747
  return size;
6577
6748
  }
6749
+ function transitionise(selection) {
6750
+ return params.withoutTransition ? selection : d3.transition(selection);
6751
+ }
6578
6752
  function axis(g) {
6579
6753
  g.each(function () {
6580
- var g = d3.select(this);
6754
+ var g = axis.g = d3.select(this);
6755
+
6581
6756
  var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale();
6582
6757
 
6583
6758
  var ticks = tickValues ? tickValues : generateTicks(scale1),
@@ -6585,12 +6760,12 @@
6585
6760
  tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
6586
6761
  // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
6587
6762
  tickExit = tick.exit().remove(),
6588
- tickUpdate = d3.transition(tick).style("opacity", 1),
6763
+ tickUpdate = transitionise(tick).style("opacity", 1),
6589
6764
  tickTransform, tickX, tickY;
6590
6765
 
6591
6766
  var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
6592
6767
  path = g.selectAll(".domain").data([ 0 ]),
6593
- pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path));
6768
+ pathUpdate = (path.enter().append("path").attr("class", "domain"), transitionise(path));
6594
6769
  tickEnter.append("line");
6595
6770
  tickEnter.append("text");
6596
6771
 
@@ -6676,6 +6851,33 @@
6676
6851
  tspan.exit().remove();
6677
6852
  tspan.text(function (d) { return d.splitted; });
6678
6853
 
6854
+ var rotate = params.tickTextRotate;
6855
+
6856
+ function textAnchorForText(rotate) {
6857
+ if (!rotate) {
6858
+ return 'middle';
6859
+ }
6860
+ return rotate > 0 ? "start" : "end";
6861
+ }
6862
+ function textTransform(rotate) {
6863
+ if (!rotate) {
6864
+ return '';
6865
+ }
6866
+ return "rotate(" + rotate + ")";
6867
+ }
6868
+ function dxForText(rotate) {
6869
+ if (!rotate) {
6870
+ return 0;
6871
+ }
6872
+ return 8 * Math.sin(Math.PI * (rotate / 180));
6873
+ }
6874
+ function yForText(rotate) {
6875
+ if (!rotate) {
6876
+ return tickLength;
6877
+ }
6878
+ return 11.5 - 2.5 * (rotate / 15) * (rotate > 0 ? 1 : -1);
6879
+ }
6880
+
6679
6881
  switch (orient) {
6680
6882
  case "bottom":
6681
6883
  {
@@ -6683,14 +6885,16 @@
6683
6885
  lineEnter.attr("y2", innerTickSize);
6684
6886
  textEnter.attr("y", tickLength);
6685
6887
  lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
6686
- textUpdate.attr("x", 0).attr("y", tickLength);
6687
- text.style("text-anchor", "middle");
6688
- tspan.attr('x', 0).attr("dy", tspanDy);
6888
+ textUpdate.attr("x", 0).attr("y", yForText(rotate))
6889
+ .style("text-anchor", textAnchorForText(rotate))
6890
+ .attr("transform", textTransform(rotate));
6891
+ tspan.attr('x', 0).attr("dy", tspanDy).attr('dx', dxForText(rotate));
6689
6892
  pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
6690
6893
  break;
6691
6894
  }
6692
6895
  case "top":
6693
6896
  {
6897
+ // TODO: rotated tick text
6694
6898
  tickTransform = axisX;
6695
6899
  lineEnter.attr("y2", -innerTickSize);
6696
6900
  textEnter.attr("y", -tickLength);
@@ -6760,9 +6964,20 @@
6760
6964
  tickCentered = isCentered;
6761
6965
  return axis;
6762
6966
  };
6763
- axis.tickOffset = function () { // This will be overwritten when normal x axis
6967
+ axis.tickOffset = function () {
6764
6968
  return tickOffset;
6765
6969
  };
6970
+ axis.tickInterval = function () {
6971
+ var interval, length;
6972
+ if (params.isCategory) {
6973
+ interval = tickOffset * 2;
6974
+ }
6975
+ else {
6976
+ length = axis.g.select('path.domain').node().getTotalLength() - outerTickSize * 2;
6977
+ interval = length / axis.g.selectAll('line').size();
6978
+ }
6979
+ return interval === Infinity ? 0 : interval;
6980
+ };
6766
6981
  axis.ticks = function () {
6767
6982
  if (!arguments.length) { return tickArguments; }
6768
6983
  tickArguments = arguments;
@@ -6788,6 +7003,41 @@
6788
7003
  return axis;
6789
7004
  }
6790
7005
 
7006
+ c3_chart_internal_fn.isSafari = function () {
7007
+ var ua = window.navigator.userAgent;
7008
+ return ua.indexOf('Safari') >= 0 && ua.indexOf('Chrome') < 0;
7009
+ };
7010
+ c3_chart_internal_fn.isChrome = function () {
7011
+ var ua = window.navigator.userAgent;
7012
+ return ua.indexOf('Chrome') >= 0;
7013
+ };
7014
+
7015
+ // PhantomJS doesn't have support for Function.prototype.bind, which has caused confusion. Use
7016
+ // this polyfill to avoid the confusion.
7017
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill
7018
+
7019
+ if (!Function.prototype.bind) {
7020
+ Function.prototype.bind = function(oThis) {
7021
+ if (typeof this !== 'function') {
7022
+ // closest thing possible to the ECMAScript 5
7023
+ // internal IsCallable function
7024
+ throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
7025
+ }
7026
+
7027
+ var aArgs = Array.prototype.slice.call(arguments, 1),
7028
+ fToBind = this,
7029
+ fNOP = function() {},
7030
+ fBound = function() {
7031
+ return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
7032
+ };
7033
+
7034
+ fNOP.prototype = this.prototype;
7035
+ fBound.prototype = new fNOP();
7036
+
7037
+ return fBound;
7038
+ };
7039
+ }
7040
+
6791
7041
  if (typeof define === 'function' && define.amd) {
6792
7042
  define("c3", ["d3"], c3);
6793
7043
  } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {