victory-core 31.1.0 → 31.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,9 +53,19 @@ function _assertThisInitialized(self) { if (self === void 0) { throw new Referen
53
53
 
54
54
  var datumHasXandY = function (datum) {
55
55
  return !(0, _isNil2.default)(datum._x) && !(0, _isNil2.default)(datum._y);
56
- };
56
+ }; // used for checking state changes. Expected components can be passed in via options
57
+
57
58
 
58
- var _default = function _default(WrappedComponent) {
59
+ var defaultComponents = [{
60
+ name: "parent",
61
+ index: "parent"
62
+ }, {
63
+ name: "data"
64
+ }, {
65
+ name: "labels"
66
+ }];
67
+
68
+ var _default = function _default(WrappedComponent, options) {
59
69
  return (
60
70
  /*#__PURE__*/
61
71
  function (_WrappedComponent) {
@@ -85,23 +95,72 @@ var _default = function _default(WrappedComponent) {
85
95
  _this.cacheValues(calculatedValues);
86
96
 
87
97
  _this.externalMutations = _this.getExternalMutations(props);
98
+ _this.calculatedState = _this.getStateChanges(props, calculatedValues);
88
99
  return _this;
89
100
  }
90
101
 
91
102
  _createClass(addEvents, [{
92
- key: "componentDidUpdate",
93
- value: function componentDidUpdate() {
94
- var externalMutations = this.getExternalMutations(this.props);
95
-
96
- if (!(0, _reactFastCompare.default)(this.externalMutations, externalMutations)) {
103
+ key: "shouldComponentUpdate",
104
+ value: function shouldComponentUpdate(nextProps) {
105
+ var calculatedValues = this.getCalculatedValues(nextProps);
106
+ var externalMutations = this.getExternalMutations(nextProps);
107
+ var animating = this.props.animating || this.props.animate;
108
+ var newMutation = !(0, _reactFastCompare.default)(externalMutations, this.externalMutations);
109
+
110
+ if (animating || newMutation) {
111
+ this.cacheValues(calculatedValues);
97
112
  this.externalMutations = externalMutations;
98
- this.applyExternalMutations(this.props, externalMutations);
113
+ this.applyExternalMutations(nextProps, externalMutations);
114
+ return true;
99
115
  }
100
- }
116
+
117
+ var calculatedState = this.getStateChanges(nextProps, calculatedValues);
118
+
119
+ if (!(0, _reactFastCompare.default)(this.calculatedState, calculatedState)) {
120
+ this.calculatedState = calculatedState;
121
+ this.cacheValues(calculatedValues);
122
+ return true;
123
+ }
124
+
125
+ if (!(0, _reactFastCompare.default)(this.props, nextProps)) {
126
+ this.cacheValues(calculatedValues);
127
+ return true;
128
+ }
129
+
130
+ return false;
131
+ } // compile all state changes from own and parent state. Order doesn't matter, as any state
132
+ // state change should trigger a re-render
133
+
101
134
  }, {
102
- key: "componentWillReceiveProps",
103
- value: function componentWillReceiveProps(nextProps) {
104
- this.cacheValues(this.getCalculatedValues(nextProps));
135
+ key: "getStateChanges",
136
+ value: function getStateChanges(props, calculatedValues) {
137
+ var _this2 = this;
138
+
139
+ var hasEvents = calculatedValues.hasEvents,
140
+ getSharedEventState = calculatedValues.getSharedEventState;
141
+
142
+ if (!hasEvents) {
143
+ return {};
144
+ }
145
+
146
+ var getState = function (key, type) {
147
+ var result = (0, _defaults2.default)({}, _this2.getEventState(key, type), getSharedEventState(key, type));
148
+ return (0, _isEmpty2.default)(result) ? undefined : result;
149
+ };
150
+
151
+ options = options || {};
152
+ var components = options.components || defaultComponents;
153
+ var stateChanges = components.map(function (component) {
154
+ if (!props.standalone && component.name === "parent") {
155
+ // don't check for changes on parent props for non-standalone components
156
+ return undefined;
157
+ } else {
158
+ return component.index !== undefined ? getState(component.index, component.name) : calculatedValues.dataKeys.map(function (key) {
159
+ return getState(key, component.name);
160
+ }).filter(Boolean);
161
+ }
162
+ }).filter(Boolean);
163
+ return stateChanges;
105
164
  }
106
165
  }, {
107
166
  key: "applyExternalMutations",
@@ -155,10 +214,10 @@ var _default = function _default(WrappedComponent) {
155
214
  }, {
156
215
  key: "cacheValues",
157
216
  value: function cacheValues(obj) {
158
- var _this2 = this;
217
+ var _this3 = this;
159
218
 
160
219
  (0, _keys2.default)(obj).forEach(function (key) {
161
- _this2[key] = obj[key];
220
+ _this3[key] = obj[key];
162
221
  });
163
222
  }
164
223
  }, {
@@ -237,14 +296,14 @@ var _default = function _default(WrappedComponent) {
237
296
  }, {
238
297
  key: "renderContinuousData",
239
298
  value: function renderContinuousData(props) {
240
- var _this3 = this;
299
+ var _this4 = this;
241
300
 
242
301
  var dataComponent = props.dataComponent,
243
302
  labelComponent = props.labelComponent,
244
303
  groupComponent = props.groupComponent;
245
304
  var dataKeys = (0, _without2.default)(this.dataKeys, "all");
246
305
  var labelComponents = dataKeys.reduce(function (memo, key) {
247
- var labelProps = _this3.getComponentProps(labelComponent, "labels", key);
306
+ var labelProps = _this4.getComponentProps(labelComponent, "labels", key);
248
307
 
249
308
  if (labelProps && labelProps.text !== undefined && labelProps.text !== null) {
250
309
  memo = memo.concat(_react.default.cloneElement(labelComponent, labelProps));
@@ -259,14 +318,14 @@ var _default = function _default(WrappedComponent) {
259
318
  }, {
260
319
  key: "renderData",
261
320
  value: function renderData(props) {
262
- var _this4 = this;
321
+ var _this5 = this;
263
322
 
264
323
  var shouldRenderDatum = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : datumHasXandY;
265
324
  var dataComponent = props.dataComponent,
266
325
  labelComponent = props.labelComponent,
267
326
  groupComponent = props.groupComponent;
268
327
  var dataComponents = this.dataKeys.reduce(function (validDataComponents, _dataKey, index) {
269
- var dataProps = _this4.getComponentProps(dataComponent, "data", index);
328
+ var dataProps = _this5.getComponentProps(dataComponent, "data", index);
270
329
 
271
330
  if (shouldRenderDatum(dataProps.datum)) {
272
331
  validDataComponents.push(_react.default.cloneElement(dataComponent, dataProps));
@@ -275,7 +334,7 @@ var _default = function _default(WrappedComponent) {
275
334
  return validDataComponents;
276
335
  }, []);
277
336
  var labelComponents = this.dataKeys.map(function (_dataKey, index) {
278
- var labelProps = _this4.getComponentProps(labelComponent, "labels", index);
337
+ var labelProps = _this5.getComponentProps(labelComponent, "labels", index);
279
338
 
280
339
  if (labelProps.text !== undefined && labelProps.text !== null) {
281
340
  return _react.default.cloneElement(labelComponent, labelProps);
@@ -19,6 +19,8 @@ var _uniq2 = _interopRequireDefault(require("lodash/uniq"));
19
19
 
20
20
  var _invert2 = _interopRequireDefault(require("lodash/invert"));
21
21
 
22
+ var _isObject2 = _interopRequireDefault(require("lodash/isObject"));
23
+
22
24
  var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
23
25
 
24
26
  var _identity2 = _interopRequireDefault(require("lodash/identity"));
@@ -229,8 +231,10 @@ function stringTicks(props) {
229
231
  }
230
232
 
231
233
  function getDefaultTickFormat(props) {
232
- var tickValues = props.tickValues,
233
- stringMap = props.stringMap;
234
+ var tickValues = props.tickValues;
235
+ var axis = getAxis(props);
236
+ var currentAxis = getCurrentAxis(axis, props.horizontal);
237
+ var stringMap = props.stringMap && props.stringMap[currentAxis];
234
238
  var fallbackFormat = tickValues && !_collection.default.containsDates(tickValues) ? function (x) {
235
239
  return x;
236
240
  } : undefined;
@@ -256,8 +260,10 @@ function getDefaultTickFormat(props) {
256
260
  }
257
261
 
258
262
  function getTickFormat(props, scale) {
259
- var tickFormat = props.tickFormat,
260
- stringMap = props.stringMap;
263
+ var tickFormat = props.tickFormat;
264
+ var axis = getAxis(props);
265
+ var currentAxis = getCurrentAxis(axis, props.horizontal);
266
+ var stringMap = props.stringMap && props.stringMap[currentAxis];
261
267
 
262
268
  if (!tickFormat) {
263
269
  var defaultTickFormat = getDefaultTickFormat(props);
@@ -287,8 +293,9 @@ function getTickFormat(props, scale) {
287
293
  }
288
294
 
289
295
  function getStringTicks(props) {
290
- var stringMap = props.stringMap;
291
296
  var axis = getAxis(props);
297
+ var currentAxis = getCurrentAxis(axis, props.horizontal);
298
+ var stringMap = props.stringMap && props.stringMap[currentAxis];
292
299
  var categories = Array.isArray(props.categories) ? props.categories : props.categories && props.categories[axis];
293
300
  var ticksFromCategories = categories && _collection.default.containsOnlyStrings(categories) ? categories.map(function (tick) {
294
301
  return stringMap[tick];
@@ -299,8 +306,10 @@ function getStringTicks(props) {
299
306
 
300
307
  function getTickArray(props) {
301
308
  var tickValues = props.tickValues,
302
- tickFormat = props.tickFormat,
303
- stringMap = props.stringMap;
309
+ tickFormat = props.tickFormat;
310
+ var axis = getAxis(props);
311
+ var currentAxis = getCurrentAxis(axis, props.horizontal);
312
+ var stringMap = props.stringMap && props.stringMap[currentAxis];
304
313
 
305
314
  var getTicksFromFormat = function () {
306
315
  if (!tickFormat || !Array.isArray(tickFormat)) {
@@ -327,7 +336,6 @@ function getTickArray(props) {
327
336
  var tickArray = ticks ? (0, _uniq2.default)(ticks) : getTicksFromFormat(props);
328
337
 
329
338
  var filterArray = function (arr) {
330
- var axis = getAxis(props);
331
339
  var domain = props.domain && props.domain[axis] || props.domain;
332
340
  return Array.isArray(domain) ? arr.filter(function (t) {
333
341
  return t >= Math.min.apply(Math, _toConsumableArray(domain)) && t <= Math.max.apply(Math, _toConsumableArray(domain));
@@ -427,6 +435,24 @@ function getDomain(props, axis) {
427
435
  return _domain.default.createDomainFunction(getDomainFromData)(props, inherentAxis);
428
436
  }
429
437
 
438
+ function getAxisValue(props, axis) {
439
+ if (!props.axisValue) {
440
+ return undefined;
441
+ }
442
+
443
+ var scaleAxis = axis === "x" ? "y" : "x";
444
+ var scale = (0, _isObject2.default)(props.scale) && (0, _isFunction2.default)(props.scale[scaleAxis]) ? props.scale[scaleAxis] : undefined;
445
+
446
+ if (!scale) {
447
+ return undefined;
448
+ }
449
+
450
+ var stringMapAxis = getCurrentAxis(axis, props.horizontal) === "x" ? "y" : "x";
451
+ var stringMap = (0, _isObject2.default)(props.stringMap) && props.stringMap[stringMapAxis];
452
+ var axisValue = stringMap && typeof props.axisValue === "string" ? stringMap[props.axisValue] : props.axisValue;
453
+ return scale(axisValue);
454
+ }
455
+
430
456
  var _default = {
431
457
  getTicks: getTicks,
432
458
  getTickFormat: getTickFormat,
@@ -440,6 +466,7 @@ var _default = {
440
466
  getOriginSign: getOriginSign,
441
467
  getDomain: getDomain,
442
468
  isVertical: isVertical,
443
- stringTicks: stringTicks
469
+ stringTicks: stringTicks,
470
+ getAxisValue: getAxisValue
444
471
  };
445
472
  exports.default = _default;
@@ -359,9 +359,14 @@ function getStringsFromData(props, axis) {
359
359
 
360
360
  var key = props[axis] === undefined ? axis : props[axis];
361
361
 
362
- var accessor = _helpers.default.createAccessor(key);
362
+ var accessor = _helpers.default.createAccessor(key); // support immutable data
363
363
 
364
- var sortedData = sortData(props.data, props.sortKey, props.sortOrder);
364
+
365
+ var data = props.data.reduce(function (memo, d) {
366
+ memo.push(parseDatum(d));
367
+ return memo;
368
+ }, []);
369
+ var sortedData = sortData(data, props.sortKey, props.sortOrder);
365
370
  var dataStrings = sortedData.reduce(function (dataArr, datum) {
366
371
  datum = parseDatum(datum);
367
372
  dataArr.push(accessor(datum));
@@ -300,9 +300,7 @@ function reduceChildren(children, iteratee) {
300
300
  } else {
301
301
  var result = iteratee(child, childName, parent);
302
302
 
303
- if (Array.isArray(result)) {
304
- memo = result.reduce(combine, memo);
305
- } else if (result) {
303
+ if (result) {
306
304
  memo = combine(memo, result);
307
305
  }
308
306
  }
@@ -163,14 +163,15 @@ var _default = {
163
163
  getAllEvents: function (props) {
164
164
  var components = ["groupComponent", "containerComponent", "labelComponent"];
165
165
  this.componentEvents = _events.default.getComponentEvents(props, components);
166
+ var events = props.events;
166
167
 
167
168
  if (Array.isArray(this.componentEvents)) {
168
169
  var _componentEvents;
169
170
 
170
- return Array.isArray(props.events) ? (_componentEvents = this.componentEvents).concat.apply(_componentEvents, _toConsumableArray(props.events)) : this.componentEvents;
171
+ events = Array.isArray(props.events) ? (_componentEvents = this.componentEvents).concat.apply(_componentEvents, _toConsumableArray(props.events)) : this.componentEvents;
171
172
  }
172
173
 
173
- return props.events;
174
+ return events || [];
174
175
  },
175
176
  getAnimationProps: function (props, child, index) {
176
177
  var _this = this;
@@ -409,9 +410,15 @@ var _default = {
409
410
  };
410
411
 
411
412
  var combine = function (memo, datum) {
413
+ var x = Array.isArray(datum) ? datum.map(function (d) {
414
+ return d.x;
415
+ }).filter(Boolean) : datum.x;
416
+ var y = Array.isArray(datum) ? datum.map(function (d) {
417
+ return d.y;
418
+ }).filter(Boolean) : datum.y;
412
419
  return {
413
- x: datum.x !== undefined ? memo.x.concat(datum.x) : memo.x,
414
- y: datum.y !== undefined ? memo.y.concat(datum.y) : memo.y
420
+ x: x !== undefined ? memo.x.concat(x) : memo.x,
421
+ y: y !== undefined ? memo.y.concat(y) : memo.y
415
422
  };
416
423
  };
417
424
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "victory-core",
3
- "version": "31.1.0",
3
+ "version": "31.2.0",
4
4
  "description": "Victory Core",
5
5
  "keywords": [
6
6
  "data visualization",
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
4
4
  import * as d3Ease from "d3-ease";
5
5
  import { victoryInterpolator } from "./util";
6
6
  import Timer from "../victory-util/timer";
7
+ import isEqual from "react-fast-compare";
7
8
 
8
9
  export default class VictoryAnimation extends React.Component {
9
10
  static displayName = "VictoryAnimation";
@@ -98,24 +99,27 @@ export default class VictoryAnimation extends React.Component {
98
99
  }
99
100
  }
100
101
 
101
- /* lifecycle */
102
- componentWillReceiveProps(nextProps) {
103
- /* cancel existing loop if it exists */
104
- this.getTimer().unsubscribe(this.loopID);
102
+ shouldComponentUpdate(nextProps, nextState) {
103
+ const equalProps = isEqual(this.props, nextProps);
104
+ if (!equalProps) {
105
+ /* cancel existing loop if it exists */
106
+ this.getTimer().unsubscribe(this.loopID);
105
107
 
106
- /* If an object was supplied */
107
- if (!Array.isArray(nextProps.data)) {
108
- // Replace the tween queue. Could set `this.queue = [nextProps.data]`,
109
- // but let's reuse the same array.
110
- this.queue.length = 0;
111
- this.queue.push(nextProps.data);
112
- /* If an array was supplied */
113
- } else {
114
- /* Extend the tween queue */
115
- this.queue.push(...nextProps.data);
108
+ /* If an object was supplied */
109
+ if (!Array.isArray(nextProps.data)) {
110
+ // Replace the tween queue. Could set `this.queue = [nextProps.data]`,
111
+ // but let's reuse the same array.
112
+ this.queue.length = 0;
113
+ this.queue.push(nextProps.data);
114
+ /* If an array was supplied */
115
+ } else {
116
+ /* Extend the tween queue */
117
+ this.queue.push(...nextProps.data);
118
+ }
119
+ /* Start traversing the tween queue */
120
+ this.traverseQueue();
116
121
  }
117
- /* Start traversing the tween queue */
118
- this.traverseQueue();
122
+ return nextState.animationInfo.animating || !equalProps;
119
123
  }
120
124
 
121
125
  componentWillUnmount() {
@@ -6,6 +6,7 @@ import Helpers from "../victory-util/helpers";
6
6
  import Timer from "../victory-util/timer";
7
7
  import Transitions from "../victory-util/transitions";
8
8
  import { defaults, isFunction, pick, isObject } from "lodash";
9
+ import isEqual from "react-fast-compare";
9
10
 
10
11
  export default class VictoryTransition extends React.Component {
11
12
  static displayName = "VictoryTransition";
@@ -33,11 +34,14 @@ export default class VictoryTransition extends React.Component {
33
34
  this.setState({ nodesShouldLoad: true }); //eslint-disable-line react/no-did-mount-set-state
34
35
  }
35
36
 
36
- componentWillReceiveProps(nextProps) {
37
- this.getTimer().bypassAnimation();
38
- this.setState(this.getTransitionState(this.props, nextProps), () =>
39
- this.getTimer().resumeAnimation()
40
- );
37
+ shouldComponentUpdate(nextProps) {
38
+ if (!isEqual(this.props, nextProps)) {
39
+ this.getTimer().bypassAnimation();
40
+ this.setState(this.getTransitionState(this.props, nextProps), () =>
41
+ this.getTimer().resumeAnimation()
42
+ );
43
+ }
44
+ return true;
41
45
  }
42
46
 
43
47
  componentWillUnmount() {
@@ -8,7 +8,14 @@ const datumHasXandY = (datum) => {
8
8
  return !isNil(datum._x) && !isNil(datum._y);
9
9
  };
10
10
 
11
- export default (WrappedComponent) => {
11
+ // used for checking state changes. Expected components can be passed in via options
12
+ const defaultComponents = [
13
+ { name: "parent", index: "parent" },
14
+ { name: "data" },
15
+ { name: "labels" }
16
+ ];
17
+
18
+ export default (WrappedComponent, options) => {
12
19
  return class addEvents extends WrappedComponent {
13
20
  constructor(props) {
14
21
  super(props);
@@ -22,18 +29,63 @@ export default (WrappedComponent) => {
22
29
  const calculatedValues = this.getCalculatedValues(props);
23
30
  this.cacheValues(calculatedValues);
24
31
  this.externalMutations = this.getExternalMutations(props);
32
+ this.calculatedState = this.getStateChanges(props, calculatedValues);
25
33
  }
26
34
 
27
- componentDidUpdate() {
28
- const externalMutations = this.getExternalMutations(this.props);
29
- if (!isEqual(this.externalMutations, externalMutations)) {
35
+ shouldComponentUpdate(nextProps) {
36
+ const calculatedValues = this.getCalculatedValues(nextProps);
37
+ const externalMutations = this.getExternalMutations(nextProps);
38
+ const animating = this.props.animating || this.props.animate;
39
+ const newMutation = !isEqual(externalMutations, this.externalMutations);
40
+ if (animating || newMutation) {
41
+ this.cacheValues(calculatedValues);
30
42
  this.externalMutations = externalMutations;
31
- this.applyExternalMutations(this.props, externalMutations);
43
+ this.applyExternalMutations(nextProps, externalMutations);
44
+ return true;
32
45
  }
46
+ const calculatedState = this.getStateChanges(nextProps, calculatedValues);
47
+ if (!isEqual(this.calculatedState, calculatedState)) {
48
+ this.calculatedState = calculatedState;
49
+ this.cacheValues(calculatedValues);
50
+ return true;
51
+ }
52
+ if (!isEqual(this.props, nextProps)) {
53
+ this.cacheValues(calculatedValues);
54
+ return true;
55
+ }
56
+ return false;
33
57
  }
34
58
 
35
- componentWillReceiveProps(nextProps) {
36
- this.cacheValues(this.getCalculatedValues(nextProps));
59
+ // compile all state changes from own and parent state. Order doesn't matter, as any state
60
+ // state change should trigger a re-render
61
+ getStateChanges(props, calculatedValues) {
62
+ const { hasEvents, getSharedEventState } = calculatedValues;
63
+ if (!hasEvents) {
64
+ return {};
65
+ }
66
+
67
+ const getState = (key, type) => {
68
+ const result = defaults({}, this.getEventState(key, type), getSharedEventState(key, type));
69
+ return isEmpty(result) ? undefined : result;
70
+ };
71
+
72
+ options = options || {};
73
+ const components = options.components || defaultComponents;
74
+ const stateChanges = components
75
+ .map((component) => {
76
+ if (!props.standalone && component.name === "parent") {
77
+ // don't check for changes on parent props for non-standalone components
78
+ return undefined;
79
+ } else {
80
+ return component.index !== undefined
81
+ ? getState(component.index, component.name)
82
+ : calculatedValues.dataKeys
83
+ .map((key) => getState(key, component.name))
84
+ .filter(Boolean);
85
+ }
86
+ })
87
+ .filter(Boolean);
88
+ return stateChanges;
37
89
  }
38
90
 
39
91
  applyExternalMutations(props, externalMutations) {
@@ -3,6 +3,7 @@ import React from "react";
3
3
  import {
4
4
  identity,
5
5
  isFunction,
6
+ isObject,
6
7
  invert,
7
8
  uniq,
8
9
  range,
@@ -171,7 +172,10 @@ function stringTicks(props) {
171
172
  }
172
173
 
173
174
  function getDefaultTickFormat(props) {
174
- const { tickValues, stringMap } = props;
175
+ const { tickValues } = props;
176
+ const axis = getAxis(props);
177
+ const currentAxis = getCurrentAxis(axis, props.horizontal);
178
+ const stringMap = props.stringMap && props.stringMap[currentAxis];
175
179
  const fallbackFormat = tickValues && !Collection.containsDates(tickValues) ? (x) => x : undefined;
176
180
  if (!stringMap) {
177
181
  return stringTicks(props) ? (x, index) => tickValues[index] : fallbackFormat;
@@ -186,7 +190,10 @@ function getDefaultTickFormat(props) {
186
190
  }
187
191
 
188
192
  function getTickFormat(props, scale) {
189
- const { tickFormat, stringMap } = props;
193
+ const { tickFormat } = props;
194
+ const axis = getAxis(props);
195
+ const currentAxis = getCurrentAxis(axis, props.horizontal);
196
+ const stringMap = props.stringMap && props.stringMap[currentAxis];
190
197
  if (!tickFormat) {
191
198
  const defaultTickFormat = getDefaultTickFormat(props);
192
199
  const scaleTickFormat =
@@ -207,8 +214,9 @@ function getTickFormat(props, scale) {
207
214
  }
208
215
 
209
216
  function getStringTicks(props) {
210
- const { stringMap } = props;
211
217
  const axis = getAxis(props);
218
+ const currentAxis = getCurrentAxis(axis, props.horizontal);
219
+ const stringMap = props.stringMap && props.stringMap[currentAxis];
212
220
  const categories = Array.isArray(props.categories)
213
221
  ? props.categories
214
222
  : props.categories && props.categories[axis];
@@ -223,7 +231,10 @@ function getStringTicks(props) {
223
231
  }
224
232
 
225
233
  function getTickArray(props) {
226
- const { tickValues, tickFormat, stringMap } = props;
234
+ const { tickValues, tickFormat } = props;
235
+ const axis = getAxis(props);
236
+ const currentAxis = getCurrentAxis(axis, props.horizontal);
237
+ const stringMap = props.stringMap && props.stringMap[currentAxis];
227
238
  const getTicksFromFormat = () => {
228
239
  if (!tickFormat || !Array.isArray(tickFormat)) {
229
240
  return undefined;
@@ -240,7 +251,6 @@ function getTickArray(props) {
240
251
  }
241
252
  const tickArray = ticks ? uniq(ticks) : getTicksFromFormat(props);
242
253
  const filterArray = (arr) => {
243
- const axis = getAxis(props);
244
254
  const domain = (props.domain && props.domain[axis]) || props.domain;
245
255
  return Array.isArray(domain)
246
256
  ? arr.filter((t) => t >= Math.min(...domain) && t <= Math.max(...domain))
@@ -318,6 +328,25 @@ function getDomain(props, axis) {
318
328
  return Domain.createDomainFunction(getDomainFromData)(props, inherentAxis);
319
329
  }
320
330
 
331
+ function getAxisValue(props, axis) {
332
+ if (!props.axisValue) {
333
+ return undefined;
334
+ }
335
+ const scaleAxis = axis === "x" ? "y" : "x";
336
+ const scale =
337
+ isObject(props.scale) && isFunction(props.scale[scaleAxis])
338
+ ? props.scale[scaleAxis]
339
+ : undefined;
340
+ if (!scale) {
341
+ return undefined;
342
+ }
343
+ const stringMapAxis = getCurrentAxis(axis, props.horizontal) === "x" ? "y" : "x";
344
+ const stringMap = isObject(props.stringMap) && props.stringMap[stringMapAxis];
345
+ const axisValue =
346
+ stringMap && typeof props.axisValue === "string" ? stringMap[props.axisValue] : props.axisValue;
347
+ return scale(axisValue);
348
+ }
349
+
321
350
  export default {
322
351
  getTicks,
323
352
  getTickFormat,
@@ -331,5 +360,6 @@ export default {
331
360
  getOriginSign,
332
361
  getDomain,
333
362
  isVertical,
334
- stringTicks
363
+ stringTicks,
364
+ getAxisValue
335
365
  };
@@ -307,7 +307,13 @@ function getStringsFromData(props, axis) {
307
307
  const key = props[axis] === undefined ? axis : props[axis];
308
308
  const accessor = Helpers.createAccessor(key);
309
309
 
310
- const sortedData = sortData(props.data, props.sortKey, props.sortOrder);
310
+ // support immutable data
311
+ const data = props.data.reduce((memo, d) => {
312
+ memo.push(parseDatum(d));
313
+ return memo;
314
+ }, []);
315
+
316
+ const sortedData = sortData(data, props.sortKey, props.sortOrder);
311
317
  const dataStrings = sortedData
312
318
  .reduce((dataArr, datum) => {
313
319
  datum = parseDatum(datum);
@@ -231,9 +231,7 @@ function reduceChildren(
231
231
  memo = combine(memo, nestedResults);
232
232
  } else {
233
233
  const result = iteratee(child, childName, parent);
234
- if (Array.isArray(result)) {
235
- memo = result.reduce(combine, memo);
236
- } else if (result) {
234
+ if (result) {
237
235
  memo = combine(memo, result);
238
236
  }
239
237
  }
@@ -116,12 +116,13 @@ export default {
116
116
  getAllEvents(props) {
117
117
  const components = ["groupComponent", "containerComponent", "labelComponent"];
118
118
  this.componentEvents = Events.getComponentEvents(props, components);
119
+ let events = props.events;
119
120
  if (Array.isArray(this.componentEvents)) {
120
- return Array.isArray(props.events)
121
+ events = Array.isArray(props.events)
121
122
  ? this.componentEvents.concat(...props.events)
122
123
  : this.componentEvents;
123
124
  }
124
- return props.events;
125
+ return events || [];
125
126
  },
126
127
 
127
128
  getAnimationProps(props, child, index) {
@@ -298,11 +299,14 @@ export default {
298
299
  };
299
300
 
300
301
  const initialMemo = { x: [], y: [] };
301
- const combine = (memo, datum) => ({
302
- x: datum.x !== undefined ? memo.x.concat(datum.x) : memo.x,
303
- y: datum.y !== undefined ? memo.y.concat(datum.y) : memo.y
304
- });
305
-
302
+ const combine = (memo, datum) => {
303
+ const x = Array.isArray(datum) ? datum.map((d) => d.x).filter(Boolean) : datum.x;
304
+ const y = Array.isArray(datum) ? datum.map((d) => d.y).filter(Boolean) : datum.y;
305
+ return {
306
+ x: x !== undefined ? memo.x.concat(x) : memo.x,
307
+ y: y !== undefined ? memo.y.concat(y) : memo.y
308
+ };
309
+ };
306
310
  return Helpers.reduceChildren(childComponents.slice(0), iteratee, {}, initialMemo, combine);
307
311
  },
308
312