c3-rails 0.4.8 → 0.4.10

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