c3-rails 0.4.10 → 0.4.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24d96a8fc04f0ac3635181db7bbad6b37188e22e
4
- data.tar.gz: 904a53199c8d8d71b11e10b071d3fc10db15285d
3
+ metadata.gz: 90162db1f8f150165ac442b177dc27844ddc85f3
4
+ data.tar.gz: 544bc6b27a93230f0110bf05f9eab6d395e89411
5
5
  SHA512:
6
- metadata.gz: 5ba9d6b81fd23e849392cf3f70caba53bb8384e493d2612d030ac9459cc30a0b5f986ded6f75d9a828fb0a156ec83e62db92c5f555c3ced59bce27207dfea86f
7
- data.tar.gz: dc495fa5f394efba86f1b12d7111f832821b11c7e3570788035d6a9db49387e713b1cdc10b1ddd605fc2496c659bba71a73d8f6a1abdeb64f093bc6b831f0e8f
6
+ metadata.gz: 91430d5a404bb35170b53cf769c84f3f630bfb72ced49842a4f039b03f8b3f7dd80737bab1cd1c000412bff5b9c3d6ad2aa719f25a7393cc389ed3c1bf094cf9
7
+ data.tar.gz: 0c610b66c7606a3c912688ec43c8e3b9f1893e020e92d0eb7beaca5ecf4ad246afe9b607777641ac6feb2d26551c6cd816bb5b79d71827c7d3d58f463876cc1b
data/.gitmodules CHANGED
@@ -1,4 +1,4 @@
1
1
  [submodule "vendor/assets/javascripts/c3"]
2
2
  path = vendor/assets/javascripts/c3
3
- url = git://github.com/masayuki0812/c3.git
3
+ url = git://github.com/c3js/c3.git
4
4
  branch = master
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # c3-rails
2
2
 
3
- [c3](https://github.com/masayuki0812/c3) is a D3-based reusable chart library
3
+ [c3](https://github.com/c3js/c3) is a D3-based reusable chart library
4
4
  that enables deeper integration of charts into web applications.
5
5
 
6
6
  c3-rails provides c3 for Rails 4 (it might work with Rails 3)
@@ -77,6 +77,6 @@ include bootstrap into your project this way..
77
77
 
78
78
  ## License
79
79
 
80
- Both [c3](https://github.com/masayuki0812/c3/blob/master/LICENSE)
80
+ Both [c3](https://github.com/c3js/c3/blob/master/LICENSE)
81
81
  and [c3-rails](https://github.com/SunnyLi/c3-rails/blob/master/LICENSE)
82
82
  are licensed under the MIT license
@@ -1,5 +1,5 @@
1
1
  module C3
2
2
  module Rails
3
- VERSION = "0.4.10"
3
+ VERSION = "0.4.11"
4
4
  end
5
5
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  /*global define, module, exports, require */
5
5
 
6
- var c3 = { version: "0.4.10" };
6
+ var c3 = { version: "0.4.11" };
7
7
 
8
8
  var c3_chart_fn,
9
9
  c3_chart_internal_fn,
@@ -31,7 +31,10 @@
31
31
  function Chart(config) {
32
32
  var $$ = this.internal = new ChartInternal(this);
33
33
  $$.loadConfig(config);
34
+
35
+ $$.beforeInit(config);
34
36
  $$.init();
37
+ $$.afterInit(config);
35
38
 
36
39
  // bind "this" to nested API
37
40
  (function bindThis(fn, target, argThis) {
@@ -71,13 +74,19 @@
71
74
  c3_chart_internal_fn = c3.chart.internal.fn;
72
75
  c3_chart_internal_axis_fn = c3.chart.internal.axis.fn;
73
76
 
77
+ c3_chart_internal_fn.beforeInit = function () {
78
+ // can do something
79
+ };
80
+ c3_chart_internal_fn.afterInit = function () {
81
+ // can do something
82
+ };
74
83
  c3_chart_internal_fn.init = function () {
75
84
  var $$ = this, config = $$.config;
76
85
 
77
86
  $$.initParams();
78
87
 
79
88
  if (config.data_url) {
80
- $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_keys, $$.initWithData);
89
+ $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_headers, config.data_keys, $$.initWithData);
81
90
  }
82
91
  else if (config.data_json) {
83
92
  $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
@@ -248,6 +257,10 @@
248
257
  .on('mouseenter', function () { return config.onmouseover.call($$); })
249
258
  .on('mouseleave', function () { return config.onmouseout.call($$); });
250
259
 
260
+ if ($$.config.svg_classname) {
261
+ $$.svg.attr('class', $$.config.svg_classname);
262
+ }
263
+
251
264
  // Define defs
252
265
  defs = $$.svg.append("defs");
253
266
  $$.clipChart = $$.appendClip(defs, $$.clipId);
@@ -263,6 +276,7 @@
263
276
  if ($$.initSubchart) { $$.initSubchart(); }
264
277
  if ($$.initTooltip) { $$.initTooltip(); }
265
278
  if ($$.initLegend) { $$.initLegend(); }
279
+ if ($$.initTitle) { $$.initTitle(); }
266
280
 
267
281
  /*-- Main Region --*/
268
282
 
@@ -324,20 +338,7 @@
324
338
  }
325
339
 
326
340
  // Bind resize event
327
- if (window.onresize == null) {
328
- window.onresize = $$.generateResize();
329
- }
330
- if (window.onresize.add) {
331
- window.onresize.add(function () {
332
- config.onresize.call($$);
333
- });
334
- window.onresize.add(function () {
335
- $$.api.flush();
336
- });
337
- window.onresize.add(function () {
338
- config.onresized.call($$);
339
- });
340
- }
341
+ $$.bindResize();
341
342
 
342
343
  // export element of the chart
343
344
  $$.api.element = $$.selectChart.node();
@@ -423,7 +424,7 @@
423
424
  // for arc
424
425
  $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
425
426
  $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
426
- if ($$.hasType('gauge')) {
427
+ if ($$.hasType('gauge') && !config.gauge_fullCircle) {
427
428
  $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
428
429
  }
429
430
  if ($$.updateRadius) { $$.updateRadius(); }
@@ -575,9 +576,6 @@
575
576
  $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
576
577
  }
577
578
 
578
- // tooltip
579
- $$.tooltip.style("display", "none");
580
-
581
579
  // xgrid focus
582
580
  $$.updateXgridFocus();
583
581
 
@@ -608,6 +606,9 @@
608
606
  $$.updateText(durationForExit);
609
607
  }
610
608
 
609
+ // title
610
+ if ($$.redrawTitle) { $$.redrawTitle(); }
611
+
611
612
  // arc
612
613
  if ($$.redrawArc) { $$.redrawArc(duration, durationForExit, withTransform); }
613
614
 
@@ -914,6 +915,7 @@
914
915
  if (selection.node().parentNode) {
915
916
  window.clearInterval($$.intervalForObserveInserted);
916
917
  $$.updateDimension();
918
+ if ($$.brush) { $$.brush.update(); }
917
919
  $$.config.oninit.call($$);
918
920
  $$.redraw({
919
921
  withTransform: true,
@@ -932,6 +934,49 @@
932
934
  observer.observe(selection.node(), {attributes: true, childList: true, characterData: true});
933
935
  };
934
936
 
937
+ c3_chart_internal_fn.bindResize = function () {
938
+ var $$ = this, config = $$.config;
939
+
940
+ $$.resizeFunction = $$.generateResize();
941
+
942
+ $$.resizeFunction.add(function () {
943
+ config.onresize.call($$);
944
+ });
945
+ if (config.resize_auto) {
946
+ $$.resizeFunction.add(function () {
947
+ if ($$.resizeTimeout !== undefined) {
948
+ window.clearTimeout($$.resizeTimeout);
949
+ }
950
+ $$.resizeTimeout = window.setTimeout(function () {
951
+ delete $$.resizeTimeout;
952
+ $$.api.flush();
953
+ }, 100);
954
+ });
955
+ }
956
+ $$.resizeFunction.add(function () {
957
+ config.onresized.call($$);
958
+ });
959
+
960
+ if (window.attachEvent) {
961
+ window.attachEvent('onresize', $$.resizeFunction);
962
+ } else if (window.addEventListener) {
963
+ window.addEventListener('resize', $$.resizeFunction, false);
964
+ } else {
965
+ // fallback to this, if this is a very old browser
966
+ var wrapper = window.onresize;
967
+ if (!wrapper) {
968
+ // create a wrapper that will call all charts
969
+ wrapper = $$.generateResize();
970
+ } else if (!wrapper.add || !wrapper.remove) {
971
+ // there is already a handler registered, make sure we call it too
972
+ wrapper = $$.generateResize();
973
+ wrapper.add(window.onresize);
974
+ }
975
+ // add this graph to the wrapper, we will be removed if the user calls destroy
976
+ wrapper.add($$.resizeFunction);
977
+ window.onresize = wrapper;
978
+ }
979
+ };
935
980
 
936
981
  c3_chart_internal_fn.generateResize = function () {
937
982
  var resizeFunctions = [];
@@ -943,6 +988,14 @@
943
988
  callResizeFunctions.add = function (f) {
944
989
  resizeFunctions.push(f);
945
990
  };
991
+ callResizeFunctions.remove = function (f) {
992
+ for (var i = 0; i < resizeFunctions.length; i++) {
993
+ if (resizeFunctions[i] === f) {
994
+ resizeFunctions.splice(i, 1);
995
+ break;
996
+ }
997
+ }
998
+ };
946
999
  return callResizeFunctions;
947
1000
  };
948
1001
 
@@ -988,7 +1041,7 @@
988
1041
  parsedDate = date;
989
1042
  } else if (typeof date === 'string') {
990
1043
  parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
991
- } else if (typeof date === 'number' || !isNaN(date)) {
1044
+ } else if (typeof date === 'number' && !isNaN(date)) {
992
1045
  parsedDate = new Date(+date);
993
1046
  }
994
1047
  if (!parsedDate || isNaN(+parsedDate)) {
@@ -1015,12 +1068,14 @@
1015
1068
  c3_chart_internal_fn.getDefaultConfig = function () {
1016
1069
  var config = {
1017
1070
  bindto: '#chart',
1071
+ svg_classname: undefined,
1018
1072
  size_width: undefined,
1019
1073
  size_height: undefined,
1020
1074
  padding_left: undefined,
1021
1075
  padding_right: undefined,
1022
1076
  padding_top: undefined,
1023
1077
  padding_bottom: undefined,
1078
+ resize_auto: true,
1024
1079
  zoom_enabled: false,
1025
1080
  zoom_extent: undefined,
1026
1081
  zoom_privileged: false,
@@ -1028,6 +1083,9 @@
1028
1083
  zoom_onzoom: function () {},
1029
1084
  zoom_onzoomstart: function () {},
1030
1085
  zoom_onzoomend: function () {},
1086
+ zoom_x_min: undefined,
1087
+ zoom_x_max: undefined,
1088
+ interaction_brighten: true,
1031
1089
  interaction_enabled: true,
1032
1090
  onmouseover: function () {},
1033
1091
  onmouseout: function () {},
@@ -1066,6 +1124,7 @@
1066
1124
  data_onselected: function () {},
1067
1125
  data_onunselected: function () {},
1068
1126
  data_url: undefined,
1127
+ data_headers: undefined,
1069
1128
  data_json: undefined,
1070
1129
  data_rows: undefined,
1071
1130
  data_columns: undefined,
@@ -1076,6 +1135,7 @@
1076
1135
  // subchart
1077
1136
  subchart_show: false,
1078
1137
  subchart_size_height: 60,
1138
+ subchart_axis_x_show: true,
1079
1139
  subchart_onbrush: function () {},
1080
1140
  // color
1081
1141
  color_pattern: [],
@@ -1092,6 +1152,9 @@
1092
1152
  legend_item_onmouseover: undefined,
1093
1153
  legend_item_onmouseout: undefined,
1094
1154
  legend_equally: false,
1155
+ legend_padding: 0,
1156
+ legend_item_tile_width: 10,
1157
+ legend_item_tile_height: 10,
1095
1158
  // axis
1096
1159
  axis_rotated: false,
1097
1160
  axis_x_show: true,
@@ -1125,7 +1188,8 @@
1125
1188
  axis_y_label: {},
1126
1189
  axis_y_tick_format: undefined,
1127
1190
  axis_y_tick_outer: true,
1128
- axis_y_tick_values: null,
1191
+ axis_y_tick_values: null,
1192
+ axis_y_tick_rotate: 0,
1129
1193
  axis_y_tick_count: undefined,
1130
1194
  axis_y_tick_time_value: undefined,
1131
1195
  axis_y_tick_time_interval: undefined,
@@ -1158,6 +1222,7 @@
1158
1222
  // point - point of each data
1159
1223
  point_show: true,
1160
1224
  point_r: 2.5,
1225
+ point_sensitivity: 10,
1161
1226
  point_focus_expand_enabled: true,
1162
1227
  point_focus_expand_r: undefined,
1163
1228
  point_select_r: undefined,
@@ -1171,26 +1236,36 @@
1171
1236
  bar_zerobased: true,
1172
1237
  // area
1173
1238
  area_zerobased: true,
1239
+ area_above: false,
1174
1240
  // pie
1175
1241
  pie_label_show: true,
1176
1242
  pie_label_format: undefined,
1177
1243
  pie_label_threshold: 0.05,
1178
- pie_expand: true,
1244
+ pie_label_ratio: undefined,
1245
+ pie_expand: {},
1246
+ pie_expand_duration: 50,
1179
1247
  // gauge
1248
+ gauge_fullCircle: false,
1180
1249
  gauge_label_show: true,
1181
1250
  gauge_label_format: undefined,
1182
- gauge_expand: true,
1183
1251
  gauge_min: 0,
1184
1252
  gauge_max: 100,
1253
+ gauge_startingAngle: -1 * Math.PI/2,
1185
1254
  gauge_units: undefined,
1186
1255
  gauge_width: undefined,
1256
+ gauge_expand: {},
1257
+ gauge_expand_duration: 50,
1187
1258
  // donut
1188
1259
  donut_label_show: true,
1189
1260
  donut_label_format: undefined,
1190
1261
  donut_label_threshold: 0.05,
1262
+ donut_label_ratio: undefined,
1191
1263
  donut_width: undefined,
1192
- donut_expand: true,
1193
1264
  donut_title: "",
1265
+ donut_expand: {},
1266
+ donut_expand_duration: 50,
1267
+ // spline
1268
+ spline_interpolation_type: 'cardinal',
1194
1269
  // region - region to change style
1195
1270
  regions: [],
1196
1271
  // tooltip - show when mouseover on each data
@@ -1205,7 +1280,18 @@
1205
1280
  },
1206
1281
  tooltip_init_show: false,
1207
1282
  tooltip_init_x: 0,
1208
- tooltip_init_position: {top: '0px', left: '50px'}
1283
+ tooltip_init_position: {top: '0px', left: '50px'},
1284
+ tooltip_onshow: function () {},
1285
+ tooltip_onhide: function () {},
1286
+ // title
1287
+ title_text: undefined,
1288
+ title_padding: {
1289
+ top: 0,
1290
+ right: 0,
1291
+ bottom: 0,
1292
+ left: 0
1293
+ },
1294
+ title_position: 'top-center',
1209
1295
  };
1210
1296
 
1211
1297
  Object.keys(this.additionalConfig).forEach(function (key) {
@@ -1556,14 +1642,15 @@
1556
1642
  return $$.x.domain();
1557
1643
  };
1558
1644
  c3_chart_internal_fn.trimXDomain = function (domain) {
1559
- var $$ = this;
1560
- if (domain[0] <= $$.orgXDomain[0]) {
1561
- domain[1] = +domain[1] + ($$.orgXDomain[0] - domain[0]);
1562
- domain[0] = $$.orgXDomain[0];
1645
+ var zoomDomain = this.getZoomDomain(),
1646
+ min = zoomDomain[0], max = zoomDomain[1];
1647
+ if (domain[0] <= min) {
1648
+ domain[1] = +domain[1] + (min - domain[0]);
1649
+ domain[0] = min;
1563
1650
  }
1564
- if ($$.orgXDomain[1] <= domain[1]) {
1565
- domain[0] = +domain[0] - (domain[1] - $$.orgXDomain[1]);
1566
- domain[1] = $$.orgXDomain[1];
1651
+ if (max <= domain[1]) {
1652
+ domain[0] = +domain[0] - (domain[1] - max);
1653
+ domain[1] = max;
1567
1654
  }
1568
1655
  return domain;
1569
1656
  };
@@ -1623,7 +1710,7 @@
1623
1710
  var $$ = this, name;
1624
1711
  if (data) {
1625
1712
  name = $$.config.data_names[data.id];
1626
- data.name = name ? name : data.id;
1713
+ data.name = name !== undefined ? name : data.id;
1627
1714
  }
1628
1715
  return data;
1629
1716
  };
@@ -1717,7 +1804,7 @@
1717
1804
  };
1718
1805
  c3_chart_internal_fn.mapToTargetIds = function (ids) {
1719
1806
  var $$ = this;
1720
- return ids ? (isString(ids) ? [ids] : ids) : $$.mapToIds($$.data.targets);
1807
+ return ids ? [].concat(ids) : $$.mapToIds($$.data.targets);
1721
1808
  };
1722
1809
  c3_chart_internal_fn.hasTarget = function (targets, id) {
1723
1810
  var ids = this.mapToIds(targets), i;
@@ -1741,7 +1828,8 @@
1741
1828
  c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
1742
1829
  var $$ = this;
1743
1830
  var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
1744
- return $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
1831
+ xs = $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
1832
+ return xs.sort(function (a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; });
1745
1833
  };
1746
1834
  c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
1747
1835
  this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
@@ -1875,7 +1963,7 @@
1875
1963
  return $$.findClosest(candidates, pos);
1876
1964
  };
1877
1965
  c3_chart_internal_fn.findClosest = function (values, pos) {
1878
- var $$ = this, minDist = 100, closest;
1966
+ var $$ = this, minDist = $$.config.point_sensitivity, closest;
1879
1967
 
1880
1968
  // find mouseovering bar
1881
1969
  values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
@@ -1902,7 +1990,7 @@
1902
1990
  yIndex = config.axis_rotated ? 0 : 1,
1903
1991
  y = $$.circleY(data, data.index),
1904
1992
  x = $$.x(data.x);
1905
- return Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2);
1993
+ return Math.sqrt(Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2));
1906
1994
  };
1907
1995
  c3_chart_internal_fn.convertValuesToStep = function (values) {
1908
1996
  var converted = [].concat(values), i;
@@ -1938,9 +2026,15 @@
1938
2026
  return current;
1939
2027
  };
1940
2028
 
1941
- c3_chart_internal_fn.convertUrlToData = function (url, mimeType, keys, done) {
2029
+ c3_chart_internal_fn.convertUrlToData = function (url, mimeType, headers, keys, done) {
1942
2030
  var $$ = this, type = mimeType ? mimeType : 'csv';
1943
- $$.d3.xhr(url, function (error, data) {
2031
+ var req = $$.d3.xhr(url);
2032
+ if (headers) {
2033
+ Object.keys(headers).forEach(function (header) {
2034
+ req.header(header, headers[header]);
2035
+ });
2036
+ }
2037
+ req.get(function (error, data) {
1944
2038
  var d;
1945
2039
  if (!data) {
1946
2040
  throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')');
@@ -1988,7 +2082,10 @@
1988
2082
  var new_row = [];
1989
2083
  targetKeys.forEach(function (key) {
1990
2084
  // convert undefined to null because undefined data will be removed in convertDataToTargets()
1991
- var v = isUndefined(o[key]) ? null : o[key];
2085
+ var v = $$.findValueInJson(o, key);
2086
+ if (isUndefined(v)) {
2087
+ v = null;
2088
+ }
1992
2089
  new_row.push(v);
1993
2090
  });
1994
2091
  new_rows.push(new_row);
@@ -2002,6 +2099,20 @@
2002
2099
  }
2003
2100
  return data;
2004
2101
  };
2102
+ c3_chart_internal_fn.findValueInJson = function (object, path) {
2103
+ path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties (replace [] with .)
2104
+ path = path.replace(/^\./, ''); // strip a leading dot
2105
+ var pathArray = path.split('.');
2106
+ for (var i = 0; i < pathArray.length; ++i) {
2107
+ var k = pathArray[i];
2108
+ if (k in object) {
2109
+ object = object[k];
2110
+ } else {
2111
+ return;
2112
+ }
2113
+ }
2114
+ return object;
2115
+ };
2005
2116
  c3_chart_internal_fn.convertRowsToData = function (rows) {
2006
2117
  var keys = rows[0], new_row = {}, new_rows = [], i, j;
2007
2118
  for (i = 1; i < rows.length; i++) {
@@ -2080,17 +2191,26 @@
2080
2191
  id: convertedId,
2081
2192
  id_org: id,
2082
2193
  values: data.map(function (d, i) {
2083
- var xKey = $$.getXKey(id), rawX = d[xKey], x = $$.generateTargetX(rawX, id, i);
2194
+ var xKey = $$.getXKey(id), rawX = d[xKey],
2195
+ value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null, x;
2084
2196
  // use x as categories if custom x and categorized
2085
- if ($$.isCustomX() && $$.isCategorized() && index === 0 && rawX) {
2086
- if (i === 0) { config.axis_x_categories = []; }
2087
- config.axis_x_categories.push(rawX);
2197
+ if ($$.isCustomX() && $$.isCategorized() && index === 0 && !isUndefined(rawX)) {
2198
+ if (index === 0 && i === 0) {
2199
+ config.axis_x_categories = [];
2200
+ }
2201
+ x = config.axis_x_categories.indexOf(rawX);
2202
+ if (x === -1) {
2203
+ x = config.axis_x_categories.length;
2204
+ config.axis_x_categories.push(rawX);
2205
+ }
2206
+ } else {
2207
+ x = $$.generateTargetX(rawX, id, i);
2088
2208
  }
2089
2209
  // mark as x = undefined if value is undefined and filter to remove after mapped
2090
2210
  if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
2091
2211
  x = undefined;
2092
2212
  }
2093
- return {x: x, value: d[id] !== null && !isNaN(d[id]) ? +d[id] : null, id: convertedId};
2213
+ return {x: x, value: value, id: convertedId};
2094
2214
  }).filter(function (v) { return isDefined(v.x); })
2095
2215
  };
2096
2216
  });
@@ -2117,6 +2237,10 @@
2117
2237
  });
2118
2238
  });
2119
2239
 
2240
+ // cache information about values
2241
+ $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets);
2242
+ $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets);
2243
+
2120
2244
  // set target types
2121
2245
  if (config.data_type) {
2122
2246
  $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
@@ -2171,7 +2295,7 @@
2171
2295
  $$.load($$.convertDataToTargets(args.data), args);
2172
2296
  }
2173
2297
  else if (args.url) {
2174
- $$.convertUrlToData(args.url, args.mimeType, args.keys, function (data) {
2298
+ $$.convertUrlToData(args.url, args.mimeType, args.headers, args.keys, function (data) {
2175
2299
  $$.load($$.convertDataToTargets(data), args);
2176
2300
  });
2177
2301
  }
@@ -2514,7 +2638,7 @@
2514
2638
  $$.showXGridFocus(selectedData);
2515
2639
 
2516
2640
  // Show cursor as pointer if point is close to mouse position
2517
- if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
2641
+ if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
2518
2642
  $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
2519
2643
  if (!$$.mouseover) {
2520
2644
  config.data_onmouseover.call($$.api, closest);
@@ -2525,16 +2649,13 @@
2525
2649
  .on('click', function () {
2526
2650
  var targetsToShow = $$.filterTargetsToShow($$.data.targets);
2527
2651
  var mouse, closest;
2528
-
2529
2652
  if ($$.hasArcType(targetsToShow)) { return; }
2530
2653
 
2531
2654
  mouse = d3.mouse(this);
2532
2655
  closest = $$.findClosestFromTargets(targetsToShow, mouse);
2533
-
2534
2656
  if (! closest) { return; }
2535
-
2536
2657
  // select if selection enabled
2537
- if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < 100) {
2658
+ if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
2538
2659
  $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).selectAll('.' + CLASS.shape + '-' + closest.index).each(function () {
2539
2660
  if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
2540
2661
  $$.toggleShape(this, closest, closest.index);
@@ -2573,11 +2694,16 @@
2573
2694
  c3_chart_internal_fn.getCurrentHeight = function () {
2574
2695
  var $$ = this, config = $$.config,
2575
2696
  h = config.size_height ? config.size_height : $$.getParentHeight();
2576
- return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
2697
+ return h > 0 ? h : 320 / ($$.hasType('gauge') && !config.gauge_fullCircle ? 2 : 1);
2577
2698
  };
2578
2699
  c3_chart_internal_fn.getCurrentPaddingTop = function () {
2579
- var config = this.config;
2580
- return isValue(config.padding_top) ? config.padding_top : 0;
2700
+ var $$ = this,
2701
+ config = $$.config,
2702
+ padding = isValue(config.padding_top) ? config.padding_top : 0;
2703
+ if ($$.title && $$.title.node()) {
2704
+ padding += $$.getTitlePadding();
2705
+ }
2706
+ return padding;
2581
2707
  };
2582
2708
  c3_chart_internal_fn.getCurrentPaddingBottom = function () {
2583
2709
  var config = this.config;
@@ -2658,12 +2784,18 @@
2658
2784
  var $$ = this, config = $$.config, h = 30;
2659
2785
  if (axisId === 'x' && !config.axis_x_show) { return 8; }
2660
2786
  if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
2661
- if (axisId === 'y' && !config.axis_y_show) { return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1; }
2787
+ if (axisId === 'y' && !config.axis_y_show) {
2788
+ return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1;
2789
+ }
2662
2790
  if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
2663
2791
  // Calculate x axis height when tick rotated
2664
2792
  if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
2665
2793
  h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
2666
2794
  }
2795
+ // Calculate y axis height when tick rotated
2796
+ if (axisId === 'y' && config.axis_rotated && config.axis_y_tick_rotate) {
2797
+ h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_y_tick_rotate) / 180);
2798
+ }
2667
2799
  return h + ($$.axis.getLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
2668
2800
  };
2669
2801
 
@@ -2714,7 +2846,17 @@
2714
2846
  var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
2715
2847
  if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
2716
2848
  if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
2717
- if (values[i].value * d.value >= 0) {
2849
+ // check if the x values line up
2850
+ if (typeof values[i] === 'undefined' || +values[i].x !== +d.x) { // "+" for timeseries
2851
+ // if not, try to find the value that does line up
2852
+ i = -1;
2853
+ values.forEach(function (v, j) {
2854
+ if (v.x === d.x) {
2855
+ i = j;
2856
+ }
2857
+ });
2858
+ }
2859
+ if (i in values && values[i].value * d.value >= 0) {
2718
2860
  offset += scale(values[i].value) - y0;
2719
2861
  }
2720
2862
  }
@@ -2739,8 +2881,9 @@
2739
2881
 
2740
2882
 
2741
2883
  c3_chart_internal_fn.getInterpolate = function (d) {
2742
- var $$ = this;
2743
- return $$.isSplineType(d) ? "cardinal" : $$.isStepType(d) ? $$.config.line_step_type : "linear";
2884
+ var $$ = this,
2885
+ interpolation = $$.isInterpolationType($$.config.spline_interpolation_type) ? $$.config.spline_interpolation_type : 'cardinal';
2886
+ return $$.isSplineType(d) ? interpolation : $$.isStepType(d) ? $$.config.line_step_type : "linear";
2744
2887
  };
2745
2888
 
2746
2889
  c3_chart_internal_fn.initLine = function () {
@@ -2801,7 +2944,7 @@
2801
2944
  };
2802
2945
  c3_chart_internal_fn.redrawLine = function (drawLine, withTransition) {
2803
2946
  return [
2804
- (withTransition ? this.mainLine.transition() : this.mainLine)
2947
+ (withTransition ? this.mainLine.transition(Math.random().toString()) : this.mainLine)
2805
2948
  .attr("d", drawLine)
2806
2949
  .style("stroke", this.color)
2807
2950
  .style("opacity", 1)
@@ -2977,7 +3120,7 @@
2977
3120
  };
2978
3121
  c3_chart_internal_fn.redrawArea = function (drawArea, withTransition) {
2979
3122
  return [
2980
- (withTransition ? this.mainArea.transition() : this.mainArea)
3123
+ (withTransition ? this.mainArea.transition(Math.random().toString()) : this.mainArea)
2981
3124
  .attr("d", drawArea)
2982
3125
  .style("fill", this.color)
2983
3126
  .style("opacity", this.orgAreaOpacity)
@@ -2995,7 +3138,7 @@
2995
3138
  return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
2996
3139
  };
2997
3140
 
2998
- area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
3141
+ area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(config.area_above ? 0 : value0).y1(value1);
2999
3142
  if (!config.line_connectNull) {
3000
3143
  area = area.defined(function (d) { return d.value !== null; });
3001
3144
  }
@@ -3060,12 +3203,12 @@
3060
3203
  c3_chart_internal_fn.redrawCircle = function (cx, cy, withTransition) {
3061
3204
  var selectedCircles = this.main.selectAll('.' + CLASS.selectedCircle);
3062
3205
  return [
3063
- (withTransition ? this.mainCircle.transition() : this.mainCircle)
3206
+ (withTransition ? this.mainCircle.transition(Math.random().toString()) : this.mainCircle)
3064
3207
  .style('opacity', this.opacityForCircle.bind(this))
3065
3208
  .style("fill", this.color)
3066
3209
  .attr("cx", cx)
3067
3210
  .attr("cy", cy),
3068
- (withTransition ? selectedCircles.transition() : selectedCircles)
3211
+ (withTransition ? selectedCircles.transition(Math.random().toString()) : selectedCircles)
3069
3212
  .attr("cx", cx)
3070
3213
  .attr("cy", cy)
3071
3214
  ];
@@ -3117,7 +3260,7 @@
3117
3260
  };
3118
3261
  c3_chart_internal_fn.pointSelectR = function (d) {
3119
3262
  var $$ = this, config = $$.config;
3120
- return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
3263
+ return isFunction(config.point_select_r) ? config.point_select_r(d) : ((config.point_select_r) ? config.point_select_r : $$.pointR(d) * 4);
3121
3264
  };
3122
3265
  c3_chart_internal_fn.isWithinCircle = function (that, r) {
3123
3266
  var d3 = this.d3,
@@ -3173,7 +3316,7 @@
3173
3316
  };
3174
3317
  c3_chart_internal_fn.redrawBar = function (drawBar, withTransition) {
3175
3318
  return [
3176
- (withTransition ? this.mainBar.transition() : this.mainBar)
3319
+ (withTransition ? this.mainBar.transition(Math.random().toString()) : this.mainBar)
3177
3320
  .attr('d', drawBar)
3178
3321
  .style("fill", this.color)
3179
3322
  .style("opacity", 1)
@@ -3301,14 +3444,16 @@
3301
3444
  .style("fill-opacity", forFlow ? 0 : this.opacityForText.bind(this))
3302
3445
  ];
3303
3446
  };
3304
- c3_chart_internal_fn.getTextRect = function (text, cls) {
3447
+ c3_chart_internal_fn.getTextRect = function (text, cls, element) {
3305
3448
  var dummy = this.d3.select('body').append('div').classed('c3', true),
3306
3449
  svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
3450
+ font = this.d3.select(element).style('font'),
3307
3451
  rect;
3308
3452
  svg.selectAll('.dummy')
3309
3453
  .data([text])
3310
3454
  .enter().append('text')
3311
3455
  .classed(cls ? cls : "", true)
3456
+ .style('font', font)
3312
3457
  .text(text)
3313
3458
  .each(function () { rect = this.getBoundingClientRect(); });
3314
3459
  dummy.remove();
@@ -3352,7 +3497,7 @@
3352
3497
  yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
3353
3498
  } else {
3354
3499
  yPos = points[2][1];
3355
- if (d.value < 0) {
3500
+ if (d.value < 0 || (d.value === 0 && !$$.hasPositiveValue)) {
3356
3501
  yPos += box.height;
3357
3502
  if ($$.isBarType(d) && $$.isSafari()) {
3358
3503
  yPos -= 3;
@@ -3466,6 +3611,9 @@
3466
3611
  c3_chart_internal_fn.barOrLineData = function (d) {
3467
3612
  return this.isBarType(d) || this.isLineType(d) ? d.values : [];
3468
3613
  };
3614
+ c3_chart_internal_fn.isInterpolationType = function (type) {
3615
+ return ['linear', 'linear-closed', 'basis', 'basis-open', 'basis-closed', 'bundle', 'cardinal', 'cardinal-open', 'cardinal-closed', 'monotone'].indexOf(type) >= 0;
3616
+ };
3469
3617
 
3470
3618
  c3_chart_internal_fn.initGrid = function () {
3471
3619
  var $$ = this, config = $$.config, d3 = $$.d3;
@@ -3739,21 +3887,44 @@
3739
3887
  titleFormat = config.tooltip_format_title || defaultTitleFormat,
3740
3888
  nameFormat = config.tooltip_format_name || function (name) { return name; },
3741
3889
  valueFormat = config.tooltip_format_value || defaultValueFormat,
3742
- text, i, title, value, name, bgcolor;
3890
+ text, i, title, value, name, bgcolor,
3891
+ orderAsc = $$.isOrderAsc();
3892
+
3893
+ if (config.data_groups.length === 0) {
3894
+ d.sort(function(a, b){
3895
+ var v1 = a ? a.value : null, v2 = b ? b.value : null;
3896
+ return orderAsc ? v1 - v2 : v2 - v1;
3897
+ });
3898
+ } else {
3899
+ var ids = $$.orderTargets($$.data.targets).map(function (i) {
3900
+ return i.id;
3901
+ });
3902
+ d.sort(function(a, b) {
3903
+ var v1 = a ? a.value : null, v2 = b ? b.value : null;
3904
+ if (v1 > 0 && v2 > 0) {
3905
+ v1 = a ? ids.indexOf(a.id) : null;
3906
+ v2 = b ? ids.indexOf(b.id) : null;
3907
+ }
3908
+ return orderAsc ? v1 - v2 : v2 - v1;
3909
+ });
3910
+ }
3911
+
3743
3912
  for (i = 0; i < d.length; i++) {
3744
3913
  if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
3745
3914
 
3746
3915
  if (! text) {
3747
- title = titleFormat ? titleFormat(d[i].x) : d[i].x;
3748
- text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
3916
+ title = sanitise(titleFormat ? titleFormat(d[i].x) : d[i].x);
3917
+ text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
3749
3918
  }
3750
3919
 
3751
- value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
3920
+ value = sanitise(valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index, d));
3752
3921
  if (value !== undefined) {
3753
- name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
3922
+ // Skip elements when their name is set to null
3923
+ if (d[i].name === null) { continue; }
3924
+ name = sanitise(nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index));
3754
3925
  bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
3755
3926
 
3756
- text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
3927
+ text += "<tr class='" + $$.CLASS.tooltipName + "-" + $$.getTargetSelectorSuffix(d[i].id) + "'>";
3757
3928
  text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
3758
3929
  text += "<td class='value'>" + value + "</td>";
3759
3930
  text += "</tr>";
@@ -3785,7 +3956,7 @@
3785
3956
  }
3786
3957
 
3787
3958
  if (tooltipRight > chartRight) {
3788
- // 20 is needed for Firefox to keep tooletip width
3959
+ // 20 is needed for Firefox to keep tooltip width
3789
3960
  tooltipLeft -= tooltipRight - chartRight + 20;
3790
3961
  }
3791
3962
  if (tooltipTop + tHeight > $$.currentHeight) {
@@ -3937,19 +4108,24 @@
3937
4108
  };
3938
4109
  c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
3939
4110
  var $$ = this, config = $$.config;
3940
- var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect;
3941
- var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = 15;
4111
+ var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect, x1ForLegendTile, x2ForLegendTile, yForLegendTile;
4112
+ var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = config.legend_item_tile_width + 5;
3942
4113
  var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
3943
4114
  var withTransition, withTransitionForTransform;
3944
4115
  var texts, rects, tiles, background;
3945
4116
 
4117
+ // Skip elements when their name is set to null
4118
+ targetIds = targetIds.filter(function(id) {
4119
+ return !isDefined(config.data_names[id]) || config.data_names[id] !== null;
4120
+ });
4121
+
3946
4122
  options = options || {};
3947
4123
  withTransition = getOption(options, "withTransition", true);
3948
4124
  withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
3949
4125
 
3950
4126
  function getTextBox(textElement, id) {
3951
4127
  if (!$$.legendItemTextBox[id]) {
3952
- $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem);
4128
+ $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem, textElement);
3953
4129
  }
3954
4130
  return $$.legendItemTextBox[id];
3955
4131
  }
@@ -3957,7 +4133,7 @@
3957
4133
  function updatePositions(textElement, id, index) {
3958
4134
  var reset = index === 0, isLast = index === targetIds.length - 1,
3959
4135
  box = getTextBox(textElement, id),
3960
- itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight),
4136
+ itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight) + config.legend_padding,
3961
4137
  itemHeight = box.height + paddingTop,
3962
4138
  itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
3963
4139
  areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
@@ -4030,10 +4206,13 @@
4030
4206
  xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
4031
4207
  yForLegend = function (id) { return maxHeight * steps[id]; };
4032
4208
  }
4033
- xForLegendText = function (id, i) { return xForLegend(id, i) + 14; };
4209
+ xForLegendText = function (id, i) { return xForLegend(id, i) + 4 + config.legend_item_tile_width; };
4034
4210
  yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
4035
4211
  xForLegendRect = function (id, i) { return xForLegend(id, i); };
4036
4212
  yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
4213
+ x1ForLegendTile = function (id, i) { return xForLegend(id, i) - 2; };
4214
+ x2ForLegendTile = function (id, i) { return xForLegend(id, i) - 2 + config.legend_item_tile_width; };
4215
+ yForLegendTile = function (id, i) { return yForLegend(id, i) + 4; };
4037
4216
 
4038
4217
  // Define g for legend area
4039
4218
  l = $$.legend.selectAll('.' + CLASS.legendItem)
@@ -4056,20 +4235,24 @@
4056
4235
  }
4057
4236
  })
4058
4237
  .on('mouseover', function (id) {
4059
- $$.d3.select(this).classed(CLASS.legendItemFocused, true);
4060
- if (!$$.transiting && $$.isTargetToShow(id)) {
4061
- $$.api.focus(id);
4062
- }
4063
4238
  if (config.legend_item_onmouseover) {
4064
4239
  config.legend_item_onmouseover.call($$, id);
4065
4240
  }
4241
+ else {
4242
+ $$.d3.select(this).classed(CLASS.legendItemFocused, true);
4243
+ if (!$$.transiting && $$.isTargetToShow(id)) {
4244
+ $$.api.focus(id);
4245
+ }
4246
+ }
4066
4247
  })
4067
4248
  .on('mouseout', function (id) {
4068
- $$.d3.select(this).classed(CLASS.legendItemFocused, false);
4069
- $$.api.revert();
4070
4249
  if (config.legend_item_onmouseout) {
4071
4250
  config.legend_item_onmouseout.call($$, id);
4072
4251
  }
4252
+ else {
4253
+ $$.d3.select(this).classed(CLASS.legendItemFocused, false);
4254
+ $$.api.revert();
4255
+ }
4073
4256
  });
4074
4257
  l.append('text')
4075
4258
  .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
@@ -4082,14 +4265,15 @@
4082
4265
  .style('fill-opacity', 0)
4083
4266
  .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200)
4084
4267
  .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
4085
- l.append('rect')
4086
- .attr("class", CLASS.legendItemTile)
4268
+ l.append('line')
4269
+ .attr('class', CLASS.legendItemTile)
4270
+ .style('stroke', $$.color)
4087
4271
  .style("pointer-events", "none")
4088
- .style('fill', $$.color)
4089
- .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
4090
- .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegend)
4091
- .attr('width', 10)
4092
- .attr('height', 10);
4272
+ .attr('x1', $$.isLegendRight || $$.isLegendInset ? x1ForLegendTile : -200)
4273
+ .attr('y1', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile)
4274
+ .attr('x2', $$.isLegendRight || $$.isLegendInset ? x2ForLegendTile : -200)
4275
+ .attr('y2', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile)
4276
+ .attr('stroke-width', config.legend_item_tile_height);
4093
4277
 
4094
4278
  // Set background for inset legend
4095
4279
  background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
@@ -4115,12 +4299,14 @@
4115
4299
  .attr('x', xForLegendRect)
4116
4300
  .attr('y', yForLegendRect);
4117
4301
 
4118
- tiles = $$.legend.selectAll('rect.' + CLASS.legendItemTile)
4119
- .data(targetIds);
4120
- (withTransition ? tiles.transition() : tiles)
4121
- .style('fill', $$.color)
4122
- .attr('x', xForLegend)
4123
- .attr('y', yForLegend);
4302
+ tiles = $$.legend.selectAll('line.' + CLASS.legendItemTile)
4303
+ .data(targetIds);
4304
+ (withTransition ? tiles.transition() : tiles)
4305
+ .style('stroke', $$.color)
4306
+ .attr('x1', x1ForLegendTile)
4307
+ .attr('y1', yForLegendTile)
4308
+ .attr('x2', x2ForLegendTile)
4309
+ .attr('y2', yForLegendTile);
4124
4310
 
4125
4311
  if (background) {
4126
4312
  (withTransition ? background.transition() : background)
@@ -4145,6 +4331,38 @@
4145
4331
  $$.legendHasRendered = true;
4146
4332
  };
4147
4333
 
4334
+ c3_chart_internal_fn.initTitle = function () {
4335
+ var $$ = this;
4336
+ $$.title = $$.svg.append("text")
4337
+ .text($$.config.title_text)
4338
+ .attr("class", $$.CLASS.title);
4339
+ };
4340
+ c3_chart_internal_fn.redrawTitle = function () {
4341
+ var $$ = this;
4342
+ $$.title
4343
+ .attr("x", $$.xForTitle.bind($$))
4344
+ .attr("y", $$.yForTitle.bind($$));
4345
+ };
4346
+ c3_chart_internal_fn.xForTitle = function () {
4347
+ var $$ = this, config = $$.config, position = config.title_position || 'left', x;
4348
+ if (position.indexOf('right') >= 0) {
4349
+ x = $$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width - config.title_padding.right;
4350
+ } else if (position.indexOf('center') >= 0) {
4351
+ x = ($$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width) / 2;
4352
+ } else { // left
4353
+ x = config.title_padding.left;
4354
+ }
4355
+ return x;
4356
+ };
4357
+ c3_chart_internal_fn.yForTitle = function () {
4358
+ var $$ = this;
4359
+ return $$.config.title_padding.top + $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).height;
4360
+ };
4361
+ c3_chart_internal_fn.getTitlePadding = function() {
4362
+ var $$ = this;
4363
+ return $$.yForTitle() + $$.config.title_padding.bottom;
4364
+ };
4365
+
4148
4366
  function Axis(owner) {
4149
4367
  API.call(this, owner);
4150
4368
  }
@@ -4195,7 +4413,7 @@
4195
4413
  },
4196
4414
  axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
4197
4415
 
4198
- if ($$.isTimeSeries() && tickValues) {
4416
+ if ($$.isTimeSeries() && tickValues && typeof tickValues !== "function") {
4199
4417
  tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
4200
4418
  }
4201
4419
 
@@ -4223,17 +4441,16 @@
4223
4441
  }
4224
4442
  return tickValues;
4225
4443
  };
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);
4444
+ Axis.prototype.getYAxis = function getYAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
4445
+ var $$ = this.owner, config = $$.config,
4446
+ axisParams = {
4447
+ withOuterTick: withOuterTick,
4448
+ withoutTransition: withoutTransition,
4449
+ tickTextRotate: withoutRotateTickText ? 0 : config.axis_y_tick_rotate
4450
+ },
4451
+ axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
4235
4452
  if ($$.isTimeSeriesY()) {
4236
- axis.ticks(d3.time[config.axis_y_tick_time_value], config.axis_y_tick_time_interval);
4453
+ axis.ticks($$.d3.time[config.axis_y_tick_time_value], config.axis_y_tick_time_interval);
4237
4454
  } else {
4238
4455
  axis.tickValues(tickValues);
4239
4456
  }
@@ -4423,10 +4640,10 @@
4423
4640
  targetsToShow = $$.filterTargetsToShow($$.data.targets);
4424
4641
  if (id === 'y') {
4425
4642
  scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
4426
- axis = this.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, false, true);
4643
+ axis = this.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, false, true, true);
4427
4644
  } else if (id === 'y2') {
4428
4645
  scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
4429
- axis = this.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, false, true);
4646
+ axis = this.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, false, true, true);
4430
4647
  } else {
4431
4648
  scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
4432
4649
  axis = this.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, false, true, true);
@@ -4468,14 +4685,15 @@
4468
4685
  .text(this.textForY2AxisLabel.bind(this));
4469
4686
  };
4470
4687
  Axis.prototype.getPadding = function getPadding(padding, key, defaultValue, domainLength) {
4471
- if (!isValue(padding[key])) {
4688
+ var p = typeof padding === 'number' ? padding : padding[key];
4689
+ if (!isValue(p)) {
4472
4690
  return defaultValue;
4473
4691
  }
4474
4692
  if (padding.unit === 'ratio') {
4475
4693
  return padding[key] * domainLength;
4476
4694
  }
4477
4695
  // assume padding is pixels if unit is not specified
4478
- return this.convertPixelsToAxisPadding(padding[key], domainLength);
4696
+ return this.convertPixelsToAxisPadding(p, domainLength);
4479
4697
  };
4480
4698
  Axis.prototype.convertPixelsToAxisPadding = function convertPixelsToAxisPadding(pixels, domainLength) {
4481
4699
  var $$ = this.owner,
@@ -4617,7 +4835,12 @@
4617
4835
  c3_chart_internal_fn.updateAngle = function (d) {
4618
4836
  var $$ = this, config = $$.config,
4619
4837
  found = false, index = 0,
4620
- gMin = config.gauge_min, gMax = config.gauge_max, gTic, gValue;
4838
+ gMin, gMax, gTic, gValue;
4839
+
4840
+ if (!config) {
4841
+ return null;
4842
+ }
4843
+
4621
4844
  $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
4622
4845
  if (! found && t.data.id === d.data.id) {
4623
4846
  found = true;
@@ -4633,9 +4856,11 @@
4633
4856
  d.endAngle = d.startAngle;
4634
4857
  }
4635
4858
  if ($$.isGaugeType(d.data)) {
4636
- gTic = (Math.PI) / (gMax - gMin);
4859
+ gMin = config.gauge_min;
4860
+ gMax = config.gauge_max;
4861
+ gTic = (Math.PI * (config.gauge_fullCircle ? 2 : 1)) / (gMax - gMin);
4637
4862
  gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
4638
- d.startAngle = -1 * (Math.PI / 2);
4863
+ d.startAngle = config.gauge_startingAngle;
4639
4864
  d.endAngle = d.startAngle + gTic * gValue;
4640
4865
  }
4641
4866
  return found ? d : null;
@@ -4670,15 +4895,20 @@
4670
4895
 
4671
4896
 
4672
4897
  c3_chart_internal_fn.transformForArcLabel = function (d) {
4673
- var $$ = this,
4898
+ var $$ = this, config = $$.config,
4674
4899
  updated = $$.updateAngle(d), c, x, y, h, ratio, translate = "";
4675
4900
  if (updated && !$$.hasType('gauge')) {
4676
4901
  c = this.svgArc.centroid(updated);
4677
4902
  x = isNaN(c[0]) ? 0 : c[0];
4678
4903
  y = isNaN(c[1]) ? 0 : c[1];
4679
4904
  h = Math.sqrt(x * x + y * y);
4680
- // TODO: ratio should be an option?
4681
- ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
4905
+ if ($$.hasType('donut') && config.donut_label_ratio) {
4906
+ ratio = isFunction(config.donut_label_ratio) ? config.donut_label_ratio(d, $$.radius, h) : config.donut_label_ratio;
4907
+ } else if ($$.hasType('pie') && config.pie_label_ratio) {
4908
+ ratio = isFunction(config.pie_label_ratio) ? config.pie_label_ratio(d, $$.radius, h) : config.pie_label_ratio;
4909
+ } else {
4910
+ ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
4911
+ }
4682
4912
  translate = "translate(" + (x * ratio) + ',' + (y * ratio) + ")";
4683
4913
  }
4684
4914
  return translate;
@@ -4686,7 +4916,8 @@
4686
4916
 
4687
4917
  c3_chart_internal_fn.getArcRatio = function (d) {
4688
4918
  var $$ = this,
4689
- whole = $$.hasType('gauge') ? Math.PI : (Math.PI * 2);
4919
+ config = $$.config,
4920
+ whole = Math.PI * ($$.hasType('gauge') && !config.gauge_fullCircle ? 1 : 2);
4690
4921
  return d ? (d.endAngle - d.startAngle) / whole : null;
4691
4922
  };
4692
4923
 
@@ -4733,9 +4964,9 @@
4733
4964
  $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
4734
4965
  if (! $$.shouldExpand(d.data.id)) { return; }
4735
4966
  $$.d3.select(this).selectAll('path')
4736
- .transition().duration(50)
4967
+ .transition().duration($$.expandDuration(d.data.id))
4737
4968
  .attr("d", $$.svgArcExpanded)
4738
- .transition().duration(100)
4969
+ .transition().duration($$.expandDuration(d.data.id) * 2)
4739
4970
  .attr("d", $$.svgArcExpandedSub)
4740
4971
  .each(function (d) {
4741
4972
  if ($$.isDonutType(d.data)) {
@@ -4753,15 +4984,34 @@
4753
4984
  targetIds = $$.mapToTargetIds(targetIds);
4754
4985
 
4755
4986
  $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
4756
- .transition().duration(50)
4987
+ .transition().duration(function(d) {
4988
+ return $$.expandDuration(d.data.id);
4989
+ })
4757
4990
  .attr("d", $$.svgArc);
4758
4991
  $$.svg.selectAll('.' + CLASS.arc)
4759
4992
  .style("opacity", 1);
4760
4993
  };
4761
4994
 
4995
+ c3_chart_internal_fn.expandDuration = function (id) {
4996
+ var $$ = this, config = $$.config;
4997
+
4998
+ if ($$.isDonutType(id)) {
4999
+ return config.donut_expand_duration;
5000
+ } else if ($$.isGaugeType(id)) {
5001
+ return config.gauge_expand_duration;
5002
+ } else if ($$.isPieType(id)) {
5003
+ return config.pie_expand_duration;
5004
+ } else {
5005
+ return 50;
5006
+ }
5007
+
5008
+ };
5009
+
4762
5010
  c3_chart_internal_fn.shouldExpand = function (id) {
4763
5011
  var $$ = this, config = $$.config;
4764
- return ($$.isDonutType(id) && config.donut_expand) || ($$.isGaugeType(id) && config.gauge_expand) || ($$.isPieType(id) && config.pie_expand);
5012
+ return ($$.isDonutType(id) && config.donut_expand) ||
5013
+ ($$.isGaugeType(id) && config.gauge_expand) ||
5014
+ ($$.isPieType(id) && config.pie_expand);
4765
5015
  };
4766
5016
 
4767
5017
  c3_chart_internal_fn.shouldShowArcLabel = function () {
@@ -4842,7 +5092,7 @@
4842
5092
  .style("opacity", 0)
4843
5093
  .each(function (d) {
4844
5094
  if ($$.isGaugeType(d.data)) {
4845
- d.startAngle = d.endAngle = -1 * (Math.PI / 2);
5095
+ d.startAngle = d.endAngle = config.gauge_startingAngle;
4846
5096
  }
4847
5097
  this._current = d;
4848
5098
  });
@@ -4855,18 +5105,22 @@
4855
5105
  return;
4856
5106
  }
4857
5107
  updated = $$.updateAngle(d);
4858
- arcData = $$.convertToArcData(updated);
4859
- // transitions
4860
- $$.expandArc(updated.data.id);
4861
- $$.api.focus(updated.data.id);
4862
- $$.toggleFocusLegend(updated.data.id, true);
4863
- $$.config.data_onmouseover(arcData, this);
5108
+ if (updated) {
5109
+ arcData = $$.convertToArcData(updated);
5110
+ // transitions
5111
+ $$.expandArc(updated.data.id);
5112
+ $$.api.focus(updated.data.id);
5113
+ $$.toggleFocusLegend(updated.data.id, true);
5114
+ $$.config.data_onmouseover(arcData, this);
5115
+ }
4864
5116
  } : null)
4865
5117
  .on('mousemove', config.interaction_enabled ? function (d) {
4866
- var updated = $$.updateAngle(d),
5118
+ var updated = $$.updateAngle(d), arcData, selectedData;
5119
+ if (updated) {
4867
5120
  arcData = $$.convertToArcData(updated),
4868
5121
  selectedData = [arcData];
4869
- $$.showTooltip(selectedData, this);
5122
+ $$.showTooltip(selectedData, this);
5123
+ }
4870
5124
  } : null)
4871
5125
  .on('mouseout', config.interaction_enabled ? function (d) {
4872
5126
  var updated, arcData;
@@ -4874,19 +5128,25 @@
4874
5128
  return;
4875
5129
  }
4876
5130
  updated = $$.updateAngle(d);
4877
- arcData = $$.convertToArcData(updated);
4878
- // transitions
4879
- $$.unexpandArc(updated.data.id);
4880
- $$.api.revert();
4881
- $$.revertLegend();
4882
- $$.hideTooltip();
4883
- $$.config.data_onmouseout(arcData, this);
5131
+ if (updated) {
5132
+ arcData = $$.convertToArcData(updated);
5133
+ // transitions
5134
+ $$.unexpandArc(updated.data.id);
5135
+ $$.api.revert();
5136
+ $$.revertLegend();
5137
+ $$.hideTooltip();
5138
+ $$.config.data_onmouseout(arcData, this);
5139
+ }
4884
5140
  } : null)
4885
5141
  .on('click', config.interaction_enabled ? function (d, i) {
4886
- var updated = $$.updateAngle(d),
5142
+ var updated = $$.updateAngle(d), arcData;
5143
+ if (updated) {
4887
5144
  arcData = $$.convertToArcData(updated);
4888
- if ($$.toggleShape) { $$.toggleShape(this, arcData, i); }
4889
- $$.config.data_onclick.call($$.api, arcData, this);
5145
+ if ($$.toggleShape) {
5146
+ $$.toggleShape(this, arcData, i);
5147
+ }
5148
+ $$.config.data_onclick.call($$.api, arcData, this);
5149
+ }
4890
5150
  } : null)
4891
5151
  .each(function () { $$.transiting = true; })
4892
5152
  .transition().duration(duration)
@@ -4942,8 +5202,8 @@
4942
5202
  .attr("d", function () {
4943
5203
  var d = {
4944
5204
  data: [{value: config.gauge_max}],
4945
- startAngle: -1 * (Math.PI / 2),
4946
- endAngle: Math.PI / 2
5205
+ startAngle: config.gauge_startingAngle,
5206
+ endAngle: -1 * config.gauge_startingAngle
4947
5207
  };
4948
5208
  return $$.getArc(d, true, true);
4949
5209
  });
@@ -4951,11 +5211,11 @@
4951
5211
  .attr("dy", ".75em")
4952
5212
  .text(config.gauge_label_show ? config.gauge_units : '');
4953
5213
  $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
4954
- .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
5214
+ .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2))) + "px")
4955
5215
  .attr("dy", "1.2em")
4956
5216
  .text(config.gauge_label_show ? config.gauge_min : '');
4957
5217
  $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
4958
- .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
5218
+ .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2)) + "px")
4959
5219
  .attr("dy", "1.2em")
4960
5220
  .text(config.gauge_label_show ? config.gauge_max : '');
4961
5221
  }
@@ -4998,16 +5258,23 @@
4998
5258
  $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
4999
5259
  .data(config.regions);
5000
5260
  $$.mainRegion.enter().append('g')
5001
- .attr('class', $$.classRegion.bind($$))
5002
5261
  .append('rect')
5003
5262
  .style("fill-opacity", 0);
5263
+ $$.mainRegion
5264
+ .attr('class', $$.classRegion.bind($$));
5004
5265
  $$.mainRegion.exit().transition().duration(duration)
5005
5266
  .style("opacity", 0)
5006
5267
  .remove();
5007
5268
  };
5008
5269
  c3_chart_internal_fn.redrawRegion = function (withTransition) {
5009
5270
  var $$ = this,
5010
- regions = $$.mainRegion.selectAll('rect'),
5271
+ regions = $$.mainRegion.selectAll('rect').each(function () {
5272
+ // data is binded to g and it's not transferred to rect (child node) automatically,
5273
+ // then data of each rect has to be updated manually.
5274
+ // TODO: there should be more efficient way to solve this?
5275
+ var parentData = $$.d3.select(this.parentNode).datum();
5276
+ $$.d3.select(this).datum(parentData);
5277
+ }),
5011
5278
  x = $$.regionX.bind($$),
5012
5279
  y = $$.regionY.bind($$),
5013
5280
  w = $$.regionWidth.bind($$),
@@ -5167,7 +5434,7 @@
5167
5434
  };
5168
5435
  c3_chart_internal_fn.unselectPoint = function (target, d, i) {
5169
5436
  var $$ = this;
5170
- $$.config.data_onunselected(d, target.node());
5437
+ $$.config.data_onunselected.call($$.api, d, target.node());
5171
5438
  // remove selected-circle from low layer g
5172
5439
  $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
5173
5440
  .transition().duration(100).attr('r', 0)
@@ -5179,14 +5446,18 @@
5179
5446
  c3_chart_internal_fn.selectPath = function (target, d) {
5180
5447
  var $$ = this;
5181
5448
  $$.config.data_onselected.call($$, d, target.node());
5182
- target.transition().duration(100)
5183
- .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
5449
+ if ($$.config.interaction_brighten) {
5450
+ target.transition().duration(100)
5451
+ .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
5452
+ }
5184
5453
  };
5185
5454
  c3_chart_internal_fn.unselectPath = function (target, d) {
5186
5455
  var $$ = this;
5187
5456
  $$.config.data_onunselected.call($$, d, target.node());
5188
- target.transition().duration(100)
5189
- .style("fill", function () { return $$.color(d); });
5457
+ if ($$.config.interaction_brighten) {
5458
+ target.transition().duration(100)
5459
+ .style("fill", function () { return $$.color(d); });
5460
+ }
5190
5461
  };
5191
5462
  c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
5192
5463
  selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
@@ -5236,9 +5507,10 @@
5236
5507
  };
5237
5508
  c3_chart_internal_fn.initSubchart = function () {
5238
5509
  var $$ = this, config = $$.config,
5239
- context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context'));
5510
+ context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context')),
5511
+ visibility = config.subchart_show ? 'visible' : 'hidden';
5240
5512
 
5241
- context.style('visibility', config.subchart_show ? 'visible' : 'hidden');
5513
+ context.style('visibility', visibility);
5242
5514
 
5243
5515
  // Define g for chart area
5244
5516
  context.append('g')
@@ -5264,7 +5536,8 @@
5264
5536
  $$.axes.subx = context.append("g")
5265
5537
  .attr("class", CLASS.axisX)
5266
5538
  .attr("transform", $$.getTranslate('subx'))
5267
- .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis);
5539
+ .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis)
5540
+ .style("visibility", config.subchart_axis_x_show ? visibility : 'hidden');
5268
5541
  };
5269
5542
  c3_chart_internal_fn.updateTargetsForSubchart = function (targets) {
5270
5543
  var $$ = this, context = $$.context, config = $$.config,
@@ -5321,7 +5594,7 @@
5321
5594
  .remove();
5322
5595
  };
5323
5596
  c3_chart_internal_fn.redrawBarForSubchart = function (drawBarOnSub, withTransition, duration) {
5324
- (withTransition ? this.contextBar.transition().duration(duration) : this.contextBar)
5597
+ (withTransition ? this.contextBar.transition(Math.random().toString()).duration(duration) : this.contextBar)
5325
5598
  .attr('d', drawBarOnSub)
5326
5599
  .style('opacity', 1);
5327
5600
  };
@@ -5339,7 +5612,7 @@
5339
5612
  .remove();
5340
5613
  };
5341
5614
  c3_chart_internal_fn.redrawLineForSubchart = function (drawLineOnSub, withTransition, duration) {
5342
- (withTransition ? this.contextLine.transition().duration(duration) : this.contextLine)
5615
+ (withTransition ? this.contextLine.transition(Math.random().toString()).duration(duration) : this.contextLine)
5343
5616
  .attr("d", drawLineOnSub)
5344
5617
  .style('opacity', 1);
5345
5618
  };
@@ -5358,7 +5631,7 @@
5358
5631
  .remove();
5359
5632
  };
5360
5633
  c3_chart_internal_fn.redrawAreaForSubchart = function (drawAreaOnSub, withTransition, duration) {
5361
- (withTransition ? this.contextArea.transition().duration(duration) : this.contextArea)
5634
+ (withTransition ? this.contextArea.transition(Math.random().toString()).duration(duration) : this.contextArea)
5362
5635
  .attr("d", drawAreaOnSub)
5363
5636
  .style("fill", this.color)
5364
5637
  .style("opacity", this.orgAreaOpacity);
@@ -5458,12 +5731,18 @@
5458
5731
  return [extent[0], Math.max($$.getMaxDataCount() / extent[1], extent[1])];
5459
5732
  };
5460
5733
  $$.zoom.updateScaleExtent = function () {
5461
- var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.orgXDomain),
5734
+ var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.getZoomDomain()),
5462
5735
  extent = this.orgScaleExtent();
5463
5736
  this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
5464
5737
  return this;
5465
5738
  };
5466
5739
  };
5740
+ c3_chart_internal_fn.getZoomDomain = function () {
5741
+ var $$ = this, config = $$.config, d3 = $$.d3,
5742
+ min = d3.min([$$.orgXDomain[0], config.zoom_x_min]),
5743
+ max = d3.max([$$.orgXDomain[1], config.zoom_x_max]);
5744
+ return [min, max];
5745
+ };
5467
5746
  c3_chart_internal_fn.updateZoom = function () {
5468
5747
  var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
5469
5748
  $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
@@ -5633,6 +5912,7 @@
5633
5912
  defocused: 'c3-defocused',
5634
5913
  region: 'c3-region',
5635
5914
  regions: 'c3-regions',
5915
+ title: 'c3-title',
5636
5916
  tooltipContainer: 'c3-tooltip-container',
5637
5917
  tooltip: 'c3-tooltip',
5638
5918
  tooltipName: 'c3-tooltip-name',
@@ -5805,10 +6085,10 @@
5805
6085
  return d[1] - d[0];
5806
6086
  },
5807
6087
  isEmpty = c3_chart_internal_fn.isEmpty = function (o) {
5808
- return !o || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
6088
+ return typeof o === 'undefined' || o === null || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
5809
6089
  },
5810
6090
  notEmpty = c3_chart_internal_fn.notEmpty = function (o) {
5811
- return Object.keys(o).length > 0;
6091
+ return !c3_chart_internal_fn.isEmpty(o);
5812
6092
  },
5813
6093
  getOption = c3_chart_internal_fn.getOption = function (options, key, defaultValue) {
5814
6094
  return isDefined(options[key]) ? options[key] : defaultValue;
@@ -5820,6 +6100,9 @@
5820
6100
  });
5821
6101
  return found;
5822
6102
  },
6103
+ sanitise = c3_chart_internal_fn.sanitise = function (str) {
6104
+ return typeof str === 'string' ? str.replace(/</g, '&lt;').replace(/>/g, '&gt;') : str;
6105
+ },
5823
6106
  getPathBox = c3_chart_internal_fn.getPathBox = function (path) {
5824
6107
  var box = path.getBoundingClientRect(),
5825
6108
  items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
@@ -5962,12 +6245,48 @@
5962
6245
  $$.redraw({withUpdateXDomain: true});
5963
6246
  };
5964
6247
 
6248
+ c3_chart_fn.zoom.max = function (max) {
6249
+ var $$ = this.internal, config = $$.config, d3 = $$.d3;
6250
+ if (max === 0 || max) {
6251
+ config.zoom_x_max = d3.max([$$.orgXDomain[1], max]);
6252
+ }
6253
+ else {
6254
+ return config.zoom_x_max;
6255
+ }
6256
+ };
6257
+
6258
+ c3_chart_fn.zoom.min = function (min) {
6259
+ var $$ = this.internal, config = $$.config, d3 = $$.d3;
6260
+ if (min === 0 || min) {
6261
+ config.zoom_x_min = d3.min([$$.orgXDomain[0], min]);
6262
+ }
6263
+ else {
6264
+ return config.zoom_x_min;
6265
+ }
6266
+ };
6267
+
6268
+ c3_chart_fn.zoom.range = function (range) {
6269
+ if (arguments.length) {
6270
+ if (isDefined(range.max)) { this.domain.max(range.max); }
6271
+ if (isDefined(range.min)) { this.domain.min(range.min); }
6272
+ } else {
6273
+ return {
6274
+ max: this.domain.max(),
6275
+ min: this.domain.min()
6276
+ };
6277
+ }
6278
+ };
6279
+
5965
6280
  c3_chart_fn.load = function (args) {
5966
6281
  var $$ = this.internal, config = $$.config;
5967
6282
  // update xs if specified
5968
6283
  if (args.xs) {
5969
6284
  $$.addXs(args.xs);
5970
6285
  }
6286
+ // update names if exists
6287
+ if ('names' in args) {
6288
+ c3_chart_fn.data.names.bind(this)(args.names);
6289
+ }
5971
6290
  // update classes if exists
5972
6291
  if ('classes' in args) {
5973
6292
  Object.keys(args.classes).forEach(function (id) {
@@ -6224,7 +6543,7 @@
6224
6543
  translateX = diffDomain(domain) / 2;
6225
6544
  }
6226
6545
  }
6227
- } else if (flow.orgDataCount === 1 || flowStart.x === flowEnd.x) {
6546
+ } else if (flow.orgDataCount === 1 || (flowStart && flowStart.x) === (flowEnd && flowEnd.x)) {
6228
6547
  translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
6229
6548
  } else {
6230
6549
  if ($$.isTimeSeries()) {
@@ -6236,9 +6555,7 @@
6236
6555
  scaleX = (diffDomain(orgDomain) / diffDomain(domain));
6237
6556
  transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
6238
6557
 
6239
- // hide tooltip
6240
6558
  $$.hideXGridFocus();
6241
- $$.hideTooltip();
6242
6559
 
6243
6560
  d3.transition().ease('linear').duration(durationForFlow).each(function () {
6244
6561
  wait.add($$.axes.x.transition().call($$.xAxis));
@@ -6624,7 +6941,22 @@
6624
6941
  var $$ = this.internal;
6625
6942
 
6626
6943
  window.clearInterval($$.intervalForObserveInserted);
6627
- window.onresize = null;
6944
+
6945
+ if ($$.resizeTimeout !== undefined) {
6946
+ window.clearTimeout($$.resizeTimeout);
6947
+ }
6948
+
6949
+ if (window.detachEvent) {
6950
+ window.detachEvent('onresize', $$.resizeFunction);
6951
+ } else if (window.removeEventListener) {
6952
+ window.removeEventListener('resize', $$.resizeFunction);
6953
+ } else {
6954
+ var wrapper = window.onresize;
6955
+ // check if no one else removed our wrapper and remove our resizeFunction from it
6956
+ if (wrapper && wrapper.add && wrapper.remove) {
6957
+ wrapper.remove($$.resizeFunction);
6958
+ }
6959
+ }
6628
6960
 
6629
6961
  $$.selectChart.classed('c3', false).html("");
6630
6962
 
@@ -6666,10 +6998,14 @@
6666
6998
  // emulate mouse events to show
6667
6999
  $$.dispatchEvent('mouseover', index, mouse);
6668
7000
  $$.dispatchEvent('mousemove', index, mouse);
7001
+
7002
+ $$.config.tooltip_onshow.call($$, args.data);
6669
7003
  };
6670
7004
  c3_chart_fn.tooltip.hide = function () {
6671
7005
  // TODO: get target data by checking the state of focus
6672
7006
  this.internal.dispatchEvent('mouseout', 0);
7007
+
7008
+ this.internal.config.tooltip_onhide.call(this);
6673
7009
  };
6674
7010
 
6675
7011
  // Features:
@@ -7012,6 +7348,8 @@
7012
7348
  return ua.indexOf('Chrome') >= 0;
7013
7349
  };
7014
7350
 
7351
+ /* jshint ignore:start */
7352
+
7015
7353
  // PhantomJS doesn't have support for Function.prototype.bind, which has caused confusion. Use
7016
7354
  // this polyfill to avoid the confusion.
7017
7355
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill
@@ -7038,8 +7376,823 @@
7038
7376
  };
7039
7377
  }
7040
7378
 
7379
+ //SVGPathSeg API polyfill
7380
+ //https://github.com/progers/pathseg
7381
+ //
7382
+ //This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from
7383
+ //SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec
7384
+ //changes which were implemented in Firefox 43 and Chrome 46.
7385
+ //Chrome 48 removes these APIs, so this polyfill is required.
7386
+
7387
+ (function() { "use strict";
7388
+ if (!("SVGPathSeg" in window)) {
7389
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
7390
+ window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) {
7391
+ this.pathSegType = type;
7392
+ this.pathSegTypeAsLetter = typeAsLetter;
7393
+ this._owningPathSegList = owningPathSegList;
7394
+ }
7395
+
7396
+ SVGPathSeg.PATHSEG_UNKNOWN = 0;
7397
+ SVGPathSeg.PATHSEG_CLOSEPATH = 1;
7398
+ SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
7399
+ SVGPathSeg.PATHSEG_MOVETO_REL = 3;
7400
+ SVGPathSeg.PATHSEG_LINETO_ABS = 4;
7401
+ SVGPathSeg.PATHSEG_LINETO_REL = 5;
7402
+ SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
7403
+ SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
7404
+ SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
7405
+ SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
7406
+ SVGPathSeg.PATHSEG_ARC_ABS = 10;
7407
+ SVGPathSeg.PATHSEG_ARC_REL = 11;
7408
+ SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
7409
+ SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
7410
+ SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
7411
+ SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
7412
+ SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
7413
+ SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
7414
+ SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
7415
+ SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
7416
+
7417
+ // Notify owning PathSegList on any changes so they can be synchronized back to the path element.
7418
+ SVGPathSeg.prototype._segmentChanged = function() {
7419
+ if (this._owningPathSegList)
7420
+ this._owningPathSegList.segmentChanged(this);
7421
+ }
7422
+
7423
+ window.SVGPathSegClosePath = function(owningPathSegList) {
7424
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList);
7425
+ }
7426
+ SVGPathSegClosePath.prototype = Object.create(SVGPathSeg.prototype);
7427
+ SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; }
7428
+ SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; }
7429
+ SVGPathSegClosePath.prototype.clone = function() { return new SVGPathSegClosePath(undefined); }
7430
+
7431
+ window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) {
7432
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList);
7433
+ this._x = x;
7434
+ this._y = y;
7435
+ }
7436
+ SVGPathSegMovetoAbs.prototype = Object.create(SVGPathSeg.prototype);
7437
+ SVGPathSegMovetoAbs.prototype.toString = function() { return "[object SVGPathSegMovetoAbs]"; }
7438
+ SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7439
+ SVGPathSegMovetoAbs.prototype.clone = function() { return new SVGPathSegMovetoAbs(undefined, this._x, this._y); }
7440
+ Object.defineProperty(SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7441
+ Object.defineProperty(SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7442
+
7443
+ window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) {
7444
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList);
7445
+ this._x = x;
7446
+ this._y = y;
7447
+ }
7448
+ SVGPathSegMovetoRel.prototype = Object.create(SVGPathSeg.prototype);
7449
+ SVGPathSegMovetoRel.prototype.toString = function() { return "[object SVGPathSegMovetoRel]"; }
7450
+ SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7451
+ SVGPathSegMovetoRel.prototype.clone = function() { return new SVGPathSegMovetoRel(undefined, this._x, this._y); }
7452
+ Object.defineProperty(SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7453
+ Object.defineProperty(SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7454
+
7455
+ window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) {
7456
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList);
7457
+ this._x = x;
7458
+ this._y = y;
7459
+ }
7460
+ SVGPathSegLinetoAbs.prototype = Object.create(SVGPathSeg.prototype);
7461
+ SVGPathSegLinetoAbs.prototype.toString = function() { return "[object SVGPathSegLinetoAbs]"; }
7462
+ SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7463
+ SVGPathSegLinetoAbs.prototype.clone = function() { return new SVGPathSegLinetoAbs(undefined, this._x, this._y); }
7464
+ Object.defineProperty(SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7465
+ Object.defineProperty(SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7466
+
7467
+ window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) {
7468
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList);
7469
+ this._x = x;
7470
+ this._y = y;
7471
+ }
7472
+ SVGPathSegLinetoRel.prototype = Object.create(SVGPathSeg.prototype);
7473
+ SVGPathSegLinetoRel.prototype.toString = function() { return "[object SVGPathSegLinetoRel]"; }
7474
+ SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7475
+ SVGPathSegLinetoRel.prototype.clone = function() { return new SVGPathSegLinetoRel(undefined, this._x, this._y); }
7476
+ Object.defineProperty(SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7477
+ Object.defineProperty(SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7478
+
7479
+ window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) {
7480
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList);
7481
+ this._x = x;
7482
+ this._y = y;
7483
+ this._x1 = x1;
7484
+ this._y1 = y1;
7485
+ this._x2 = x2;
7486
+ this._y2 = y2;
7487
+ }
7488
+ SVGPathSegCurvetoCubicAbs.prototype = Object.create(SVGPathSeg.prototype);
7489
+ SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicAbs]"; }
7490
+ SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
7491
+ SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
7492
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7493
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7494
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
7495
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
7496
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
7497
+ Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
7498
+
7499
+ window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) {
7500
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList);
7501
+ this._x = x;
7502
+ this._y = y;
7503
+ this._x1 = x1;
7504
+ this._y1 = y1;
7505
+ this._x2 = x2;
7506
+ this._y2 = y2;
7507
+ }
7508
+ SVGPathSegCurvetoCubicRel.prototype = Object.create(SVGPathSeg.prototype);
7509
+ SVGPathSegCurvetoCubicRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicRel]"; }
7510
+ SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
7511
+ SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
7512
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7513
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7514
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
7515
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
7516
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
7517
+ Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
7518
+
7519
+ window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) {
7520
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList);
7521
+ this._x = x;
7522
+ this._y = y;
7523
+ this._x1 = x1;
7524
+ this._y1 = y1;
7525
+ }
7526
+ SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(SVGPathSeg.prototype);
7527
+ SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticAbs]"; }
7528
+ SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
7529
+ SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); }
7530
+ Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7531
+ Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7532
+ Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
7533
+ Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
7534
+
7535
+ window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) {
7536
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList);
7537
+ this._x = x;
7538
+ this._y = y;
7539
+ this._x1 = x1;
7540
+ this._y1 = y1;
7541
+ }
7542
+ SVGPathSegCurvetoQuadraticRel.prototype = Object.create(SVGPathSeg.prototype);
7543
+ SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticRel]"; }
7544
+ SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
7545
+ SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); }
7546
+ Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7547
+ Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7548
+ Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
7549
+ Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
7550
+
7551
+ window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
7552
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList);
7553
+ this._x = x;
7554
+ this._y = y;
7555
+ this._r1 = r1;
7556
+ this._r2 = r2;
7557
+ this._angle = angle;
7558
+ this._largeArcFlag = largeArcFlag;
7559
+ this._sweepFlag = sweepFlag;
7560
+ }
7561
+ SVGPathSegArcAbs.prototype = Object.create(SVGPathSeg.prototype);
7562
+ SVGPathSegArcAbs.prototype.toString = function() { return "[object SVGPathSegArcAbs]"; }
7563
+ SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
7564
+ SVGPathSegArcAbs.prototype.clone = function() { return new SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
7565
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7566
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7567
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
7568
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
7569
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
7570
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
7571
+ Object.defineProperty(SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
7572
+
7573
+ window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
7574
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList);
7575
+ this._x = x;
7576
+ this._y = y;
7577
+ this._r1 = r1;
7578
+ this._r2 = r2;
7579
+ this._angle = angle;
7580
+ this._largeArcFlag = largeArcFlag;
7581
+ this._sweepFlag = sweepFlag;
7582
+ }
7583
+ SVGPathSegArcRel.prototype = Object.create(SVGPathSeg.prototype);
7584
+ SVGPathSegArcRel.prototype.toString = function() { return "[object SVGPathSegArcRel]"; }
7585
+ SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
7586
+ SVGPathSegArcRel.prototype.clone = function() { return new SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
7587
+ Object.defineProperty(SVGPathSegArcRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7588
+ Object.defineProperty(SVGPathSegArcRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7589
+ Object.defineProperty(SVGPathSegArcRel.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
7590
+ Object.defineProperty(SVGPathSegArcRel.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
7591
+ Object.defineProperty(SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
7592
+ Object.defineProperty(SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
7593
+ Object.defineProperty(SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
7594
+
7595
+ window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) {
7596
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList);
7597
+ this._x = x;
7598
+ }
7599
+ SVGPathSegLinetoHorizontalAbs.prototype = Object.create(SVGPathSeg.prototype);
7600
+ SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalAbs]"; }
7601
+ SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
7602
+ SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new SVGPathSegLinetoHorizontalAbs(undefined, this._x); }
7603
+ Object.defineProperty(SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7604
+
7605
+ window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) {
7606
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList);
7607
+ this._x = x;
7608
+ }
7609
+ SVGPathSegLinetoHorizontalRel.prototype = Object.create(SVGPathSeg.prototype);
7610
+ SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalRel]"; }
7611
+ SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
7612
+ SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new SVGPathSegLinetoHorizontalRel(undefined, this._x); }
7613
+ Object.defineProperty(SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7614
+
7615
+ window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) {
7616
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList);
7617
+ this._y = y;
7618
+ }
7619
+ SVGPathSegLinetoVerticalAbs.prototype = Object.create(SVGPathSeg.prototype);
7620
+ SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalAbs]"; }
7621
+ SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
7622
+ SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new SVGPathSegLinetoVerticalAbs(undefined, this._y); }
7623
+ Object.defineProperty(SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7624
+
7625
+ window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) {
7626
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList);
7627
+ this._y = y;
7628
+ }
7629
+ SVGPathSegLinetoVerticalRel.prototype = Object.create(SVGPathSeg.prototype);
7630
+ SVGPathSegLinetoVerticalRel.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalRel]"; }
7631
+ SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
7632
+ SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new SVGPathSegLinetoVerticalRel(undefined, this._y); }
7633
+ Object.defineProperty(SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7634
+
7635
+ window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) {
7636
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList);
7637
+ this._x = x;
7638
+ this._y = y;
7639
+ this._x2 = x2;
7640
+ this._y2 = y2;
7641
+ }
7642
+ SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(SVGPathSeg.prototype);
7643
+ SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothAbs]"; }
7644
+ SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
7645
+ SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); }
7646
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7647
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7648
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
7649
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
7650
+
7651
+ window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) {
7652
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList);
7653
+ this._x = x;
7654
+ this._y = y;
7655
+ this._x2 = x2;
7656
+ this._y2 = y2;
7657
+ }
7658
+ SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(SVGPathSeg.prototype);
7659
+ SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothRel]"; }
7660
+ SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
7661
+ SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); }
7662
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7663
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7664
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
7665
+ Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
7666
+
7667
+ window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) {
7668
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList);
7669
+ this._x = x;
7670
+ this._y = y;
7671
+ }
7672
+ SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(SVGPathSeg.prototype);
7673
+ SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothAbs]"; }
7674
+ SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7675
+ SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); }
7676
+ Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7677
+ Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7678
+
7679
+ window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) {
7680
+ SVGPathSeg.call(this, SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList);
7681
+ this._x = x;
7682
+ this._y = y;
7683
+ }
7684
+ SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(SVGPathSeg.prototype);
7685
+ SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothRel]"; }
7686
+ SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
7687
+ SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); }
7688
+ Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
7689
+ Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
7690
+
7691
+ // Add createSVGPathSeg* functions to SVGPathElement.
7692
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathElement.
7693
+ SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new SVGPathSegClosePath(undefined); }
7694
+ SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new SVGPathSegMovetoAbs(undefined, x, y); }
7695
+ SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new SVGPathSegMovetoRel(undefined, x, y); }
7696
+ SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new SVGPathSegLinetoAbs(undefined, x, y); }
7697
+ SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new SVGPathSegLinetoRel(undefined, x, y); }
7698
+ SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); }
7699
+ SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); }
7700
+ SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); }
7701
+ SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); }
7702
+ SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
7703
+ SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
7704
+ SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new SVGPathSegLinetoHorizontalAbs(undefined, x); }
7705
+ SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new SVGPathSegLinetoHorizontalRel(undefined, x); }
7706
+ SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new SVGPathSegLinetoVerticalAbs(undefined, y); }
7707
+ SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new SVGPathSegLinetoVerticalRel(undefined, y); }
7708
+ SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); }
7709
+ SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); }
7710
+ SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); }
7711
+ SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); }
7712
+ }
7713
+
7714
+ if (!("SVGPathSegList" in window)) {
7715
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
7716
+ window.SVGPathSegList = function(pathElement) {
7717
+ this._pathElement = pathElement;
7718
+ this._list = this._parsePath(this._pathElement.getAttribute("d"));
7719
+
7720
+ // Use a MutationObserver to catch changes to the path's "d" attribute.
7721
+ this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] };
7722
+ this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this));
7723
+ this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
7724
+ }
7725
+
7726
+ Object.defineProperty(SVGPathSegList.prototype, "numberOfItems", {
7727
+ get: function() {
7728
+ this._checkPathSynchronizedToList();
7729
+ return this._list.length;
7730
+ },
7731
+ enumerable: true
7732
+ });
7733
+
7734
+ // Add the pathSegList accessors to SVGPathElement.
7735
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
7736
+ Object.defineProperty(SVGPathElement.prototype, "pathSegList", {
7737
+ get: function() {
7738
+ if (!this._pathSegList)
7739
+ this._pathSegList = new SVGPathSegList(this);
7740
+ return this._pathSegList;
7741
+ },
7742
+ enumerable: true
7743
+ });
7744
+ // FIXME: The following are not implemented and simply return SVGPathElement.pathSegList.
7745
+ Object.defineProperty(SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
7746
+ Object.defineProperty(SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
7747
+ Object.defineProperty(SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
7748
+
7749
+ // Process any pending mutations to the path element and update the list as needed.
7750
+ // This should be the first call of all public functions and is needed because
7751
+ // MutationObservers are not synchronous so we can have pending asynchronous mutations.
7752
+ SVGPathSegList.prototype._checkPathSynchronizedToList = function() {
7753
+ this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
7754
+ }
7755
+
7756
+ SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) {
7757
+ if (!this._pathElement)
7758
+ return;
7759
+ var hasPathMutations = false;
7760
+ mutationRecords.forEach(function(record) {
7761
+ if (record.attributeName == "d")
7762
+ hasPathMutations = true;
7763
+ });
7764
+ if (hasPathMutations)
7765
+ this._list = this._parsePath(this._pathElement.getAttribute("d"));
7766
+ }
7767
+
7768
+ // Serialize the list and update the path's 'd' attribute.
7769
+ SVGPathSegList.prototype._writeListToPath = function() {
7770
+ this._pathElementMutationObserver.disconnect();
7771
+ this._pathElement.setAttribute("d", SVGPathSegList._pathSegArrayAsString(this._list));
7772
+ this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
7773
+ }
7774
+
7775
+ // When a path segment changes the list needs to be synchronized back to the path element.
7776
+ SVGPathSegList.prototype.segmentChanged = function(pathSeg) {
7777
+ this._writeListToPath();
7778
+ }
7779
+
7780
+ SVGPathSegList.prototype.clear = function() {
7781
+ this._checkPathSynchronizedToList();
7782
+
7783
+ this._list.forEach(function(pathSeg) {
7784
+ pathSeg._owningPathSegList = null;
7785
+ });
7786
+ this._list = [];
7787
+ this._writeListToPath();
7788
+ }
7789
+
7790
+ SVGPathSegList.prototype.initialize = function(newItem) {
7791
+ this._checkPathSynchronizedToList();
7792
+
7793
+ this._list = [newItem];
7794
+ newItem._owningPathSegList = this;
7795
+ this._writeListToPath();
7796
+ return newItem;
7797
+ }
7798
+
7799
+ SVGPathSegList.prototype._checkValidIndex = function(index) {
7800
+ if (isNaN(index) || index < 0 || index >= this.numberOfItems)
7801
+ throw "INDEX_SIZE_ERR";
7802
+ }
7803
+
7804
+ SVGPathSegList.prototype.getItem = function(index) {
7805
+ this._checkPathSynchronizedToList();
7806
+
7807
+ this._checkValidIndex(index);
7808
+ return this._list[index];
7809
+ }
7810
+
7811
+ SVGPathSegList.prototype.insertItemBefore = function(newItem, index) {
7812
+ this._checkPathSynchronizedToList();
7813
+
7814
+ // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
7815
+ if (index > this.numberOfItems)
7816
+ index = this.numberOfItems;
7817
+ if (newItem._owningPathSegList) {
7818
+ // SVG2 spec says to make a copy.
7819
+ newItem = newItem.clone();
7820
+ }
7821
+ this._list.splice(index, 0, newItem);
7822
+ newItem._owningPathSegList = this;
7823
+ this._writeListToPath();
7824
+ return newItem;
7825
+ }
7826
+
7827
+ SVGPathSegList.prototype.replaceItem = function(newItem, index) {
7828
+ this._checkPathSynchronizedToList();
7829
+
7830
+ if (newItem._owningPathSegList) {
7831
+ // SVG2 spec says to make a copy.
7832
+ newItem = newItem.clone();
7833
+ }
7834
+ this._checkValidIndex(index);
7835
+ this._list[index] = newItem;
7836
+ newItem._owningPathSegList = this;
7837
+ this._writeListToPath();
7838
+ return newItem;
7839
+ }
7840
+
7841
+ SVGPathSegList.prototype.removeItem = function(index) {
7842
+ this._checkPathSynchronizedToList();
7843
+
7844
+ this._checkValidIndex(index);
7845
+ var item = this._list[index];
7846
+ this._list.splice(index, 1);
7847
+ this._writeListToPath();
7848
+ return item;
7849
+ }
7850
+
7851
+ SVGPathSegList.prototype.appendItem = function(newItem) {
7852
+ this._checkPathSynchronizedToList();
7853
+
7854
+ if (newItem._owningPathSegList) {
7855
+ // SVG2 spec says to make a copy.
7856
+ newItem = newItem.clone();
7857
+ }
7858
+ this._list.push(newItem);
7859
+ newItem._owningPathSegList = this;
7860
+ // TODO: Optimize this to just append to the existing attribute.
7861
+ this._writeListToPath();
7862
+ return newItem;
7863
+ }
7864
+
7865
+ SVGPathSegList._pathSegArrayAsString = function(pathSegArray) {
7866
+ var string = "";
7867
+ var first = true;
7868
+ pathSegArray.forEach(function(pathSeg) {
7869
+ if (first) {
7870
+ first = false;
7871
+ string += pathSeg._asPathString();
7872
+ } else {
7873
+ string += " " + pathSeg._asPathString();
7874
+ }
7875
+ });
7876
+ return string;
7877
+ }
7878
+
7879
+ // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
7880
+ SVGPathSegList.prototype._parsePath = function(string) {
7881
+ if (!string || string.length == 0)
7882
+ return [];
7883
+
7884
+ var owningPathSegList = this;
7885
+
7886
+ var Builder = function() {
7887
+ this.pathSegList = [];
7888
+ }
7889
+
7890
+ Builder.prototype.appendSegment = function(pathSeg) {
7891
+ this.pathSegList.push(pathSeg);
7892
+ }
7893
+
7894
+ var Source = function(string) {
7895
+ this._string = string;
7896
+ this._currentIndex = 0;
7897
+ this._endIndex = this._string.length;
7898
+ this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN;
7899
+
7900
+ this._skipOptionalSpaces();
7901
+ }
7902
+
7903
+ Source.prototype._isCurrentSpace = function() {
7904
+ var character = this._string[this._currentIndex];
7905
+ return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f");
7906
+ }
7907
+
7908
+ Source.prototype._skipOptionalSpaces = function() {
7909
+ while (this._currentIndex < this._endIndex && this._isCurrentSpace())
7910
+ this._currentIndex++;
7911
+ return this._currentIndex < this._endIndex;
7912
+ }
7913
+
7914
+ Source.prototype._skipOptionalSpacesOrDelimiter = function() {
7915
+ if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",")
7916
+ return false;
7917
+ if (this._skipOptionalSpaces()) {
7918
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") {
7919
+ this._currentIndex++;
7920
+ this._skipOptionalSpaces();
7921
+ }
7922
+ }
7923
+ return this._currentIndex < this._endIndex;
7924
+ }
7925
+
7926
+ Source.prototype.hasMoreData = function() {
7927
+ return this._currentIndex < this._endIndex;
7928
+ }
7929
+
7930
+ Source.prototype.peekSegmentType = function() {
7931
+ var lookahead = this._string[this._currentIndex];
7932
+ return this._pathSegTypeFromChar(lookahead);
7933
+ }
7934
+
7935
+ Source.prototype._pathSegTypeFromChar = function(lookahead) {
7936
+ switch (lookahead) {
7937
+ case "Z":
7938
+ case "z":
7939
+ return SVGPathSeg.PATHSEG_CLOSEPATH;
7940
+ case "M":
7941
+ return SVGPathSeg.PATHSEG_MOVETO_ABS;
7942
+ case "m":
7943
+ return SVGPathSeg.PATHSEG_MOVETO_REL;
7944
+ case "L":
7945
+ return SVGPathSeg.PATHSEG_LINETO_ABS;
7946
+ case "l":
7947
+ return SVGPathSeg.PATHSEG_LINETO_REL;
7948
+ case "C":
7949
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
7950
+ case "c":
7951
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
7952
+ case "Q":
7953
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
7954
+ case "q":
7955
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
7956
+ case "A":
7957
+ return SVGPathSeg.PATHSEG_ARC_ABS;
7958
+ case "a":
7959
+ return SVGPathSeg.PATHSEG_ARC_REL;
7960
+ case "H":
7961
+ return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
7962
+ case "h":
7963
+ return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
7964
+ case "V":
7965
+ return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
7966
+ case "v":
7967
+ return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
7968
+ case "S":
7969
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
7970
+ case "s":
7971
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
7972
+ case "T":
7973
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
7974
+ case "t":
7975
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
7976
+ default:
7977
+ return SVGPathSeg.PATHSEG_UNKNOWN;
7978
+ }
7979
+ }
7980
+
7981
+ Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
7982
+ // Check for remaining coordinates in the current command.
7983
+ if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != SVGPathSeg.PATHSEG_CLOSEPATH) {
7984
+ if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_ABS)
7985
+ return SVGPathSeg.PATHSEG_LINETO_ABS;
7986
+ if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_REL)
7987
+ return SVGPathSeg.PATHSEG_LINETO_REL;
7988
+ return previousCommand;
7989
+ }
7990
+ return SVGPathSeg.PATHSEG_UNKNOWN;
7991
+ }
7992
+
7993
+ Source.prototype.initialCommandIsMoveTo = function() {
7994
+ // If the path is empty it is still valid, so return true.
7995
+ if (!this.hasMoreData())
7996
+ return true;
7997
+ var command = this.peekSegmentType();
7998
+ // Path must start with moveTo.
7999
+ return command == SVGPathSeg.PATHSEG_MOVETO_ABS || command == SVGPathSeg.PATHSEG_MOVETO_REL;
8000
+ }
8001
+
8002
+ // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
8003
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
8004
+ Source.prototype._parseNumber = function() {
8005
+ var exponent = 0;
8006
+ var integer = 0;
8007
+ var frac = 1;
8008
+ var decimal = 0;
8009
+ var sign = 1;
8010
+ var expsign = 1;
8011
+
8012
+ var startIndex = this._currentIndex;
8013
+
8014
+ this._skipOptionalSpaces();
8015
+
8016
+ // Read the sign.
8017
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+")
8018
+ this._currentIndex++;
8019
+ else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") {
8020
+ this._currentIndex++;
8021
+ sign = -1;
8022
+ }
8023
+
8024
+ if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != "."))
8025
+ // The first character of a number must be one of [0-9+-.].
8026
+ return undefined;
8027
+
8028
+ // Read the integer part, build right-to-left.
8029
+ var startIntPartIndex = this._currentIndex;
8030
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9")
8031
+ this._currentIndex++; // Advance to first non-digit.
8032
+
8033
+ if (this._currentIndex != startIntPartIndex) {
8034
+ var scanIntPartIndex = this._currentIndex - 1;
8035
+ var multiplier = 1;
8036
+ while (scanIntPartIndex >= startIntPartIndex) {
8037
+ integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0");
8038
+ multiplier *= 10;
8039
+ }
8040
+ }
8041
+
8042
+ // Read the decimals.
8043
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") {
8044
+ this._currentIndex++;
8045
+
8046
+ // There must be a least one digit following the .
8047
+ if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
8048
+ return undefined;
8049
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9")
8050
+ decimal += (this._string.charAt(this._currentIndex++) - "0") * (frac *= 0.1);
8051
+ }
8052
+
8053
+ // Read the exponent part.
8054
+ if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) {
8055
+ this._currentIndex++;
8056
+
8057
+ // Read the sign of the exponent.
8058
+ if (this._string.charAt(this._currentIndex) == "+") {
8059
+ this._currentIndex++;
8060
+ } else if (this._string.charAt(this._currentIndex) == "-") {
8061
+ this._currentIndex++;
8062
+ expsign = -1;
8063
+ }
8064
+
8065
+ // There must be an exponent.
8066
+ if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
8067
+ return undefined;
8068
+
8069
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
8070
+ exponent *= 10;
8071
+ exponent += (this._string.charAt(this._currentIndex) - "0");
8072
+ this._currentIndex++;
8073
+ }
8074
+ }
8075
+
8076
+ var number = integer + decimal;
8077
+ number *= sign;
8078
+
8079
+ if (exponent)
8080
+ number *= Math.pow(10, expsign * exponent);
8081
+
8082
+ if (startIndex == this._currentIndex)
8083
+ return undefined;
8084
+
8085
+ this._skipOptionalSpacesOrDelimiter();
8086
+
8087
+ return number;
8088
+ }
8089
+
8090
+ Source.prototype._parseArcFlag = function() {
8091
+ if (this._currentIndex >= this._endIndex)
8092
+ return undefined;
8093
+ var flag = false;
8094
+ var flagChar = this._string.charAt(this._currentIndex++);
8095
+ if (flagChar == "0")
8096
+ flag = false;
8097
+ else if (flagChar == "1")
8098
+ flag = true;
8099
+ else
8100
+ return undefined;
8101
+
8102
+ this._skipOptionalSpacesOrDelimiter();
8103
+ return flag;
8104
+ }
8105
+
8106
+ Source.prototype.parseSegment = function() {
8107
+ var lookahead = this._string[this._currentIndex];
8108
+ var command = this._pathSegTypeFromChar(lookahead);
8109
+ if (command == SVGPathSeg.PATHSEG_UNKNOWN) {
8110
+ // Possibly an implicit command. Not allowed if this is the first command.
8111
+ if (this._previousCommand == SVGPathSeg.PATHSEG_UNKNOWN)
8112
+ return null;
8113
+ command = this._nextCommandHelper(lookahead, this._previousCommand);
8114
+ if (command == SVGPathSeg.PATHSEG_UNKNOWN)
8115
+ return null;
8116
+ } else {
8117
+ this._currentIndex++;
8118
+ }
8119
+
8120
+ this._previousCommand = command;
8121
+
8122
+ switch (command) {
8123
+ case SVGPathSeg.PATHSEG_MOVETO_REL:
8124
+ return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
8125
+ case SVGPathSeg.PATHSEG_MOVETO_ABS:
8126
+ return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
8127
+ case SVGPathSeg.PATHSEG_LINETO_REL:
8128
+ return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
8129
+ case SVGPathSeg.PATHSEG_LINETO_ABS:
8130
+ return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
8131
+ case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
8132
+ return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
8133
+ case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
8134
+ return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
8135
+ case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
8136
+ return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
8137
+ case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
8138
+ return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
8139
+ case SVGPathSeg.PATHSEG_CLOSEPATH:
8140
+ this._skipOptionalSpaces();
8141
+ return new SVGPathSegClosePath(owningPathSegList);
8142
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
8143
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8144
+ return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
8145
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
8146
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8147
+ return new SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
8148
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
8149
+ var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8150
+ return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
8151
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
8152
+ var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8153
+ return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
8154
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
8155
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8156
+ return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
8157
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
8158
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
8159
+ return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
8160
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
8161
+ return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
8162
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
8163
+ return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
8164
+ case SVGPathSeg.PATHSEG_ARC_REL:
8165
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
8166
+ return new SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
8167
+ case SVGPathSeg.PATHSEG_ARC_ABS:
8168
+ var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
8169
+ return new SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
8170
+ default:
8171
+ throw "Unknown path seg type."
8172
+ }
8173
+ }
8174
+
8175
+ var builder = new Builder();
8176
+ var source = new Source(string);
8177
+
8178
+ if (!source.initialCommandIsMoveTo())
8179
+ return [];
8180
+ while (source.hasMoreData()) {
8181
+ var pathSeg = source.parseSegment();
8182
+ if (!pathSeg)
8183
+ return [];
8184
+ builder.appendSegment(pathSeg);
8185
+ }
8186
+
8187
+ return builder.pathSegList;
8188
+ }
8189
+ }
8190
+ }());
8191
+
8192
+ /* jshint ignore:end */
8193
+
7041
8194
  if (typeof define === 'function' && define.amd) {
7042
- define("c3", ["d3"], c3);
8195
+ define("c3", ["d3"], function () { return c3; });
7043
8196
  } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
7044
8197
  module.exports = c3;
7045
8198
  } else {