@devexpress/dx-chart-core
Advanced tools
Comparing version 1.9.1 to 1.10.0
/** | ||
* Bundle of @devexpress/dx-chart-core | ||
* Generated: 2018-12-07 | ||
* Version: 1.9.1 | ||
* Generated: 2018-12-25 | ||
* Version: 1.10.0 | ||
* License: https://js.devexpress.com/Licensing | ||
@@ -10,3 +10,3 @@ */ | ||
import { scaleLinear, scaleBand, scaleOrdinal } from 'd3-scale'; | ||
import { symbol, symbolCircle, line, curveMonotoneX, area, arc, pie, stack } from 'd3-shape'; | ||
import { area, line, curveMonotoneX, pie, arc, symbol, symbolCircle, stack } from 'd3-shape'; | ||
@@ -121,7 +121,4 @@ function _defineProperty(obj, key, value) { | ||
var createScale = function createScale(_ref, width, height, constructor) { | ||
var domain = _ref.domain, | ||
orientation = _ref.orientation; | ||
var scale = constructor(); | ||
return scale.domain(domain).range(orientation === HORIZONTAL ? [0, width] : [height, 0]); | ||
var isHorizontal = function isHorizontal(name) { | ||
return name === ARGUMENT_DOMAIN; | ||
}; | ||
@@ -141,6 +138,17 @@ var getWidth = function getWidth(scale) { | ||
var isDefined = function isDefined(item) { | ||
return item !== undefined; | ||
}; // TODO: Property name should not contain "axis" part as it actually means domain. | ||
var _defaultDomains; | ||
var defaultDomains = (_defaultDomains = {}, _defineProperty(_defaultDomains, ARGUMENT_DOMAIN, {}), _defineProperty(_defaultDomains, VALUE_DOMAIN, {}), _defaultDomains); | ||
var addDomain = function addDomain(domains, name, props) { | ||
return _objectSpread({}, domains, _defineProperty({}, name, props)); | ||
}; | ||
var copy = function copy(domains) { | ||
var result = {}; | ||
Object.keys(domains).forEach(function (name) { | ||
result[name] = _objectSpread({}, domains[name], { | ||
domain: [] | ||
}); | ||
}); | ||
return result; | ||
}; | ||
@@ -151,6 +159,10 @@ var getSeriesValueDomainName = function getSeriesValueDomainName(series) { | ||
var calculateDomainField = function calculateDomainField(items, domain, type) { | ||
return type === BAND ? _toConsumableArray(domain).concat(_toConsumableArray(items)) : extent(_toConsumableArray(domain).concat(_toConsumableArray(extent(items)))); | ||
var mergeContinuousDomains = function mergeContinuousDomains(domain, items) { | ||
return extent([].concat(_toConsumableArray(domain), _toConsumableArray(items))); | ||
}; | ||
var mergeDiscreteDomains = function mergeDiscreteDomains(domain, items) { | ||
return Array.from(new Set([].concat(_toConsumableArray(domain), _toConsumableArray(items)))); | ||
}; | ||
var getArgument = function getArgument(point) { | ||
@@ -164,4 +176,7 @@ return point.argument; | ||
var getCorrectAxisType = function getCorrectAxisType(type, points, getItem) { | ||
return type || points.length && typeof getItem(points[0]) === 'string' && BAND || LINEAR; | ||
var extendDomain = function extendDomain(target, items) { | ||
var merge = target.isDiscrete ? mergeDiscreteDomains : mergeContinuousDomains; | ||
Object.assign(target, { | ||
domain: merge(target.domain, items) | ||
}); | ||
}; | ||
@@ -172,7 +187,3 @@ | ||
var valueDomainName = getSeriesValueDomainName(seriesItem); | ||
var points = seriesItem.points; | ||
var argumentDomain = domains[ARGUMENT_DOMAIN]; | ||
var valueDomain = domains[valueDomainName]; | ||
var valueType = getCorrectAxisType(valueDomain.type, points, getValue); | ||
var argumentType = getCorrectAxisType(argumentDomain.type, points, getArgument); // TODO: This is a temporary workaround for Stack plugin. | ||
var points = seriesItem.points; // TODO: This is a temporary workaround for Stack plugin. | ||
// Once scales (or domains) are exposed for modification Stack will modify scale and | ||
@@ -182,96 +193,72 @@ // this code will be removed. | ||
var valueDomainItems = seriesItem.getValueDomain ? seriesItem.getValueDomain(points) : points.map(getValue); | ||
valueDomain.domain = calculateDomainField(valueDomainItems, valueDomain.domain, valueType); | ||
valueDomain.type = valueType; | ||
argumentDomain.domain = calculateDomainField(points.map(getArgument), argumentDomain.domain, argumentType); | ||
argumentDomain.type = argumentType; | ||
extendDomain(domains[valueDomainName], valueDomainItems); | ||
extendDomain(domains[ARGUMENT_DOMAIN], points.map(getArgument)); | ||
}); | ||
}; | ||
var computeExtension = function computeExtension(extension) { | ||
var defaultExtension = [{ | ||
type: LINEAR, | ||
constructor: scaleLinear | ||
}, { | ||
type: BAND, | ||
constructor: function constructor() { | ||
return scaleBand().paddingInner(0.3).paddingOuter(0.15); | ||
} | ||
}]; | ||
return extension.concat(defaultExtension); | ||
var scaleLinear$1 = scaleLinear; | ||
var scaleBand$1 = function scaleBand$$1() { | ||
return scaleBand().paddingInner(0.3).paddingOuter(0.15); | ||
}; | ||
var collectDomains = function collectDomains(seriesList) { | ||
var domains = _defineProperty({}, ARGUMENT_DOMAIN, { | ||
domain: [], | ||
orientation: HORIZONTAL | ||
}); | ||
var guessFactory = function guessFactory(points, getItem) { | ||
return points.length && typeof getItem(points[0]) === 'string' && scaleBand$1 || scaleLinear$1; | ||
}; | ||
var collectDomainsFromSeries = function collectDomainsFromSeries(domains, seriesList) { | ||
seriesList.forEach(function (seriesItem) { | ||
var name = getSeriesValueDomainName(seriesItem); | ||
var domain = domains[name] || { | ||
domain: [], | ||
orientation: VERTICAL | ||
}; | ||
domains[name] = domain; | ||
if (!domains[ARGUMENT_DOMAIN].factory) { | ||
Object.assign(domains[ARGUMENT_DOMAIN], { | ||
factory: guessFactory(seriesItem.points, getArgument) | ||
}); | ||
} | ||
if (seriesItem.getPointTransformer.isStartedFromZero && domain.domain.length === 0) { | ||
domain.domain = [0]; | ||
var valueDomainName = getSeriesValueDomainName(seriesItem); | ||
var obj = domains[valueDomainName]; | ||
if (!obj.factory) { | ||
obj.factory = guessFactory(seriesItem.points, getValue); | ||
} // TODO: It is to be removed together with *TODO* from above. | ||
if (seriesItem.getPointTransformer.isStartedFromZero && obj.domain.length === 0) { | ||
obj.domain = [0]; | ||
} | ||
}); | ||
return domains; | ||
}; | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
var takeTypeFromAxesOptions = function takeTypeFromAxesOptions(domains, axes) { | ||
axes.forEach(function (_ref) { | ||
var scaleName = _ref.scaleName, | ||
type = _ref.type; | ||
var domain = domains[scaleName]; | ||
if (!obj.factory) { | ||
obj.factory = scaleLinear$1; | ||
} | ||
if (domain) { | ||
domain.type = type; | ||
} | ||
obj.isDiscrete = !!obj.factory().bandwidth; | ||
}); | ||
return domains; | ||
}; | ||
var takeRestAxesOptions = function takeRestAxesOptions(domains, axes) { | ||
axes.forEach(function (_ref2) { | ||
var scaleName = _ref2.scaleName, | ||
min = _ref2.min, | ||
max = _ref2.max; | ||
var domain = domains[scaleName]; | ||
var customizeDomains = function customizeDomains(domains) { | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
if (!domain) { | ||
return; | ||
if (obj.modifyDomain) { | ||
obj.domain = obj.modifyDomain(obj.domain); | ||
} | ||
if (domain.type !== BAND) { | ||
domain.domain = [isDefined(min) ? min : domain.domain[0], isDefined(max) ? max : domain.domain[1]]; | ||
} | ||
}); | ||
}; | ||
var computeDomains = function computeDomains(axes, series) { | ||
var result = collectDomains(series); // Axes options are taken in two steps because *type* is required for domains calculation | ||
// and other options must be applied after domains are calculated. | ||
takeTypeFromAxesOptions(result, axes); | ||
calculateDomains(result, series); | ||
takeRestAxesOptions(result, axes); | ||
var computeDomains = function computeDomains(domains, seriesList) { | ||
var result = copy(domains); | ||
collectDomainsFromSeries(result, seriesList); | ||
calculateDomains(result, seriesList); | ||
customizeDomains(result); | ||
return result; | ||
}; | ||
var buildScales = function buildScales(domains, scaleExtension, _ref3) { | ||
var width = _ref3.width, | ||
height = _ref3.height; | ||
var buildScales = function buildScales(domains, _ref) { | ||
var width = _ref.width, | ||
height = _ref.height; | ||
var scales = {}; | ||
Object.entries(domains).forEach(function (_ref4) { | ||
var _ref5 = _slicedToArray(_ref4, 2), | ||
name = _ref5[0], | ||
domain = _ref5[1]; | ||
var _scaleExtension$find = scaleExtension.find(function (item) { | ||
return item.type === domain.type; | ||
}), | ||
constructor = _scaleExtension$find.constructor; | ||
scales[name] = createScale(domain, width, height, constructor); | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
scales[name] = obj.factory().domain(obj.domain).range(isHorizontal(name) ? [0, width] : [height, 0]); | ||
}); | ||
@@ -296,6 +283,2 @@ return scales; | ||
var isHorizontal = function isHorizontal(name) { | ||
return name === ARGUMENT_DOMAIN; | ||
}; | ||
var getTicks = function getTicks(scale) { | ||
@@ -396,5 +379,2 @@ return scale.ticks ? scale.ticks() : scale.domain(); | ||
}; | ||
var axesData = function axesData(axes, axisProps) { | ||
return _toConsumableArray(axes).concat([axisProps]); | ||
}; | ||
@@ -899,44 +879,22 @@ var getX = function getX(_ref) { | ||
// Comparing by reference is not an option as Tracker always sends new objects. | ||
// On the other side Tracker cannot persist references as it actually operates with simple scalars | ||
// Tracker cannot persist references as it actually operates with simple scalars | ||
// and constructs objects to provide info in a slightly more suitable way. | ||
var compareTargets = function compareTargets(target1, target2) { | ||
return target1.series === target2.series && target1.point === target2.point; | ||
}; // Current value is chosen roughly and expected to be adjusted. | ||
}; // If *currentTarget* is among *targets* then it has priority but only while its distance | ||
// is not significantly greater (DISTANCE_PRIORITY_RATIO) than that of the best candidate. | ||
var DISTANCE_PRIORITY_RATIO = 4; // If *currentTarget* is among *targets* then it has priority but only while its distance | ||
// is not significantly greater (DISTANCE_PRIORITY_RATIO) than that of the best candidate. | ||
var selectTarget = function selectTarget(targets, currentTarget) { | ||
var candidate = targets[0]; | ||
var selectTarget = function selectTarget(targets, currentTarget) { | ||
if (!currentTarget) { | ||
return targets.length ? targets[0] : undefined; | ||
return candidate; | ||
} | ||
if (!targets.length) { | ||
if (!candidate) { | ||
return null; | ||
} | ||
var candidate = targets[0]; // Skip complex checks if *currentTarget* has minimal distance. | ||
if (compareTargets(candidate, currentTarget)) { | ||
return undefined; | ||
} // Skip complex check if there is single candidate. | ||
if (targets.length === 1) { | ||
return candidate; | ||
} | ||
var current = targets.find(function (target) { | ||
return compareTargets(target, currentTarget); | ||
}); | ||
if (current) { | ||
// Here *current.distance* is exactly greater than *candidate.distance*. | ||
// The question is - how much greater? | ||
var ratio = current.distance / candidate.distance; | ||
return ratio > DISTANCE_PRIORITY_RATIO ? candidate : undefined; | ||
} | ||
return candidate; | ||
return compareTargets(candidate, currentTarget) ? undefined : candidate; | ||
}; | ||
@@ -956,13 +914,2 @@ | ||
return nextTarget; | ||
}; // It handles the case when point is hovered and series does not contain visual points. | ||
// Series then knows that it is also hovered and can represent the changed state. | ||
var getHoverTargets = function getHoverTargets(hover) { | ||
if (!hover) { | ||
return []; | ||
} | ||
return hover.point >= 0 ? [{ | ||
series: hover.series | ||
}, hover] : [hover]; | ||
}; | ||
@@ -990,24 +937,59 @@ | ||
var getUniformDistance = function getUniformDistance(dx, dy, rx, ry) { | ||
return Math.max(Math.abs(dx) / rx, Math.abs(dy) / ry); | ||
}; // Based on https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm | ||
var getSegmentLength = function getSegmentLength(dx, dy) { | ||
return Math.sqrt(dx * dx + dy * dy); | ||
}; // *distance* is a normalized distance to point. | ||
// It belongs to [0, Infinity): | ||
// = 0 - at point center | ||
// = 1 - at point border | ||
// > 1 - outside point | ||
// This function is called from event handlers (when DOM is available) - | ||
// *window.document* can be accessed safely. | ||
var getEuclideanDistance = function getEuclideanDistance(dx, dy, rx, ry) { | ||
return Math.sqrt(dx * dx / (rx * rx) + dy * dy / (ry * ry)); | ||
var createContext = function createContext() { | ||
return document.createElement('canvas').getContext('2d'); | ||
}; // eslint-disable-line no-undef | ||
// For a start using browser canvas will suffice. | ||
// However a better and more clean solution should be found. | ||
// Can't d3 perform hit testing? | ||
var createCanvasAbusingHitTester = function createCanvasAbusingHitTester(makePath, points) { | ||
var ctx = createContext(); | ||
var path = makePath(); | ||
path.context(ctx); | ||
path(points); | ||
return function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2), | ||
x = _ref2[0], | ||
y = _ref2[1]; | ||
return ctx.isPointInPath(x, y); | ||
}; | ||
}; | ||
var createPointsEnumeratingHitTesterCreator = function createPointsEnumeratingHitTesterCreator(hitTestPoint) { | ||
var LINE_POINT_SIZE = 20; | ||
var LINE_TOLERANCE = 10; | ||
var getContinuousPointDistance = function getContinuousPointDistance(_ref3, _ref4) { | ||
var _ref5 = _slicedToArray(_ref3, 2), | ||
px = _ref5[0], | ||
py = _ref5[1]; | ||
var x = _ref4.x, | ||
y = _ref4.y; | ||
return getSegmentLength(px - x, py - y); | ||
}; | ||
var createContinuousSeriesHitTesterCreator = function createContinuousSeriesHitTesterCreator(makePath) { | ||
return function (points) { | ||
var fallbackHitTest = createCanvasAbusingHitTester(makePath, points); | ||
return function (target) { | ||
var minDistance = Number.MAX_VALUE; | ||
var minIndex; | ||
var list = []; | ||
points.forEach(function (point) { | ||
// *distance* is a normalized distance to point. | ||
// It belongs to [0, Infinity): | ||
// = 0 - at point center | ||
// = 1 - at point border | ||
// > 1 - outside point | ||
var distance = hitTestPoint(target, point); | ||
points.forEach(function (point, i) { | ||
var distance = getContinuousPointDistance(target, point); | ||
if (distance <= 1) { | ||
if (distance <= LINE_POINT_SIZE) { | ||
list.push({ | ||
@@ -1018,3 +1000,17 @@ index: point.index, | ||
} | ||
}); | ||
if (distance < minDistance) { | ||
minDistance = distance; | ||
minIndex = i; | ||
} | ||
}); // This is special case for continuous series - if no point is actually hit | ||
// then the closest point to the pointer position is picked. | ||
if (!list.length && fallbackHitTest(target)) { | ||
list.push({ | ||
index: points[minIndex].index, | ||
distance: minDistance | ||
}); | ||
} | ||
return list.length ? { | ||
@@ -1027,31 +1023,19 @@ points: list | ||
var LINE_TOLERANCE = 10; | ||
var createContinuousSeriesPointsHitTester = createPointsEnumeratingHitTesterCreator(function (_ref, _ref2) { | ||
var _ref3 = _slicedToArray(_ref, 2), | ||
px = _ref3[0], | ||
py = _ref3[1]; | ||
var createPointsEnumeratingHitTesterCreator = function createPointsEnumeratingHitTesterCreator(hitTestPoint) { | ||
return function (points) { | ||
return function (target) { | ||
var list = []; | ||
points.forEach(function (point) { | ||
var status = hitTestPoint(target, point); | ||
var x = _ref2.x, | ||
y = _ref2.y; | ||
return getEuclideanDistance(px - x, py - y, LINE_TOLERANCE, LINE_TOLERANCE); | ||
}); // This function is called from event handlers (when DOM is available) - | ||
// *window.document* can be accessed safely. | ||
var createContext = function createContext() { | ||
return document.createElement('canvas').getContext('2d'); | ||
}; // eslint-disable-line no-undef | ||
// For a start using browser canvas will suffice. | ||
// However a better and more clean solution should be found. | ||
// Can't d3 perform hit testing? | ||
var createCanvasAbusingHitTesterCreator = function createCanvasAbusingHitTesterCreator(makePath) { | ||
return function (points) { | ||
var ctx = createContext(); | ||
var path = makePath(); | ||
path.context(ctx); | ||
path(points); | ||
var hitTestPoints = createContinuousSeriesPointsHitTester(points); | ||
return function (point) { | ||
return ctx.isPointInPath(point[0], point[1]) ? hitTestPoints(point) || {} : null; | ||
if (status) { | ||
list.push({ | ||
index: point.index, | ||
distance: status.distance | ||
}); | ||
} | ||
}); | ||
return list.length ? { | ||
points: list | ||
} : null; | ||
}; | ||
@@ -1061,3 +1045,3 @@ }; | ||
var createAreaHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createAreaHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = area(); | ||
@@ -1069,3 +1053,3 @@ path.x(dArea.x()); | ||
}); | ||
var createLineHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createLineHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = area(); | ||
@@ -1082,3 +1066,3 @@ var getY = dLine.y(); | ||
}); | ||
var createSplineHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createSplineHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = area(); | ||
@@ -1095,9 +1079,16 @@ var getY = dSpline.y(); | ||
return path; | ||
}); // Some kind of binary search can be used here as bars can be ordered along argument axis. | ||
}); | ||
var createBarHitTester = createPointsEnumeratingHitTesterCreator(function (_ref4, point) { | ||
var _ref5 = _slicedToArray(_ref4, 2), | ||
px = _ref5[0], | ||
py = _ref5[1]; | ||
var hitTestRect = function hitTestRect(dx, dy, halfX, halfY) { | ||
return Math.abs(dx) <= halfX && Math.abs(dy) <= halfY ? { | ||
distance: getSegmentLength(dx, dy) | ||
} : null; | ||
}; // Some kind of binary search can be used here as bars can be ordered along argument axis. | ||
var createBarHitTester = createPointsEnumeratingHitTesterCreator(function (_ref6, point) { | ||
var _ref7 = _slicedToArray(_ref6, 2), | ||
px = _ref7[0], | ||
py = _ref7[1]; | ||
var xCenter = point.x + point.width / 2; | ||
@@ -1107,13 +1098,16 @@ var yCenter = (point.y + point.y1) / 2; | ||
var halfHeight = Math.abs(point.y - point.y1) / 2; | ||
return getUniformDistance(px - xCenter, py - yCenter, halfWidth, halfHeight); | ||
return hitTestRect(px - xCenter, py - yCenter, halfWidth, halfHeight); | ||
}); // TODO: Use actual point size here! | ||
var createScatterHitTester = createPointsEnumeratingHitTesterCreator(function (_ref6, _ref7) { | ||
var _ref8 = _slicedToArray(_ref6, 2), | ||
px = _ref8[0], | ||
py = _ref8[1]; | ||
var createScatterHitTester = createPointsEnumeratingHitTesterCreator(function (_ref8, _ref9) { | ||
var _ref10 = _slicedToArray(_ref8, 2), | ||
px = _ref10[0], | ||
py = _ref10[1]; | ||
var x = _ref7.x, | ||
y = _ref7.y; | ||
return getEuclideanDistance(px - x, py - y, 10, 10); | ||
var x = _ref9.x, | ||
y = _ref9.y; | ||
var distance = getSegmentLength(px - x, py - y); | ||
return distance <= 10 ? { | ||
distance: distance | ||
} : null; | ||
}); | ||
@@ -1127,13 +1121,13 @@ | ||
var createPieHitTester = createPointsEnumeratingHitTesterCreator(function (_ref9, _ref10) { | ||
var _ref11 = _slicedToArray(_ref9, 2), | ||
px = _ref11[0], | ||
py = _ref11[1]; | ||
var createPieHitTester = createPointsEnumeratingHitTesterCreator(function (_ref11, _ref12) { | ||
var _ref13 = _slicedToArray(_ref11, 2), | ||
px = _ref13[0], | ||
py = _ref13[1]; | ||
var x = _ref10.x, | ||
y = _ref10.y, | ||
innerRadius = _ref10.innerRadius, | ||
outerRadius = _ref10.outerRadius, | ||
startAngle = _ref10.startAngle, | ||
endAngle = _ref10.endAngle; | ||
var x = _ref12.x, | ||
y = _ref12.y, | ||
innerRadius = _ref12.innerRadius, | ||
outerRadius = _ref12.outerRadius, | ||
startAngle = _ref12.startAngle, | ||
endAngle = _ref12.endAngle; | ||
var rCenter = (innerRadius + outerRadius) / 2; | ||
@@ -1145,5 +1139,7 @@ var angleCenter = (startAngle + endAngle) / 2; | ||
var dy = py - y; | ||
var r = Math.sqrt(dx * dx + dy * dy); | ||
var angle = mapAngleTod3(Math.atan2(dy, dx)); | ||
return getUniformDistance(r - rCenter, angle - angleCenter, halfRadius, halfAngle); | ||
var r = getSegmentLength(dx, dy); | ||
var angle = mapAngleTod3(Math.atan2(dy, dx)); // This is not a correct distance calculation but for now it will suffice. | ||
// For Pie series it would not be actually used. | ||
return hitTestRect(r - rCenter, angle - angleCenter, halfRadius, halfAngle); | ||
}); | ||
@@ -1153,14 +1149,6 @@ | ||
var result = {}; | ||
targets.forEach(function (_ref12) { | ||
var series = _ref12.series, | ||
point = _ref12.point; | ||
result[series] = result[series] || { | ||
points: {} | ||
}; | ||
if (point >= 0) { | ||
result[series].points[point] = true; | ||
} else { | ||
result[series].self = true; | ||
} | ||
targets.forEach(function (_ref14) { | ||
var series = _ref14.series, | ||
point = _ref14.point; | ||
(result[series] = result[series] || new Set()).add(point); | ||
}); | ||
@@ -1178,5 +1166,5 @@ return result; | ||
var result = seriesList.map(function (seriesItem) { | ||
var obj = filter[seriesItem.name]; | ||
var set = filter[seriesItem.name]; | ||
if (!obj) { | ||
if (!set) { | ||
return seriesItem; | ||
@@ -1186,11 +1174,9 @@ } | ||
matches += 1; | ||
var props = {}; | ||
var props = { | ||
state: state | ||
}; | ||
if (obj.self) { | ||
props.state = state; | ||
} | ||
if (Object.keys(obj.points).length) { | ||
if (set.size) { | ||
props.points = seriesItem.points.map(function (point) { | ||
return obj.points[point.index] ? _objectSpread({}, point, { | ||
return set.has(point.index) ? _objectSpread({}, point, { | ||
state: state | ||
@@ -1220,3 +1206,3 @@ }) : point; | ||
return series[0].points.map(function (_ref2) { | ||
var text = _ref2.id, | ||
var text = _ref2.argument, | ||
color = _ref2.color; | ||
@@ -1229,8 +1215,8 @@ return { | ||
}; // The function supports special case when there is single Pie series. | ||
// There is no commom way to tell if series is of Pie type - | ||
// checking `seriesComponent` function name will suffice for now. | ||
// There is no common way to tell if series is PieSeries - | ||
// checking `radius` props will suffice for now. | ||
var isSinglePieSeriesCase = function isSinglePieSeriesCase(series) { | ||
return series.length === 1 && series[0].seriesComponent.name === 'SliceCollection'; | ||
return series.length === 1 && 'innerRadius' in series[0] && 'outerRadius' in series[0]; | ||
}; | ||
@@ -1256,4 +1242,13 @@ | ||
var compare = function compare(t1, t2) { | ||
return t1.distance - t2.distance; | ||
var DISTANCE_THRESHOLD = 20; | ||
var compareHitTargets = function compareHitTargets(t1, t2) { | ||
var distanceDelta = t1.distance - t2.distance; | ||
if (Math.abs(distanceDelta) <= DISTANCE_THRESHOLD) { | ||
var orderDelta = t2.order - t1.order; | ||
return orderDelta !== 0 ? orderDelta : distanceDelta; | ||
} | ||
return distanceDelta; | ||
}; | ||
@@ -1278,2 +1273,3 @@ | ||
var series = _ref.name, | ||
order = _ref.index, | ||
symbolName = _ref.symbolName; | ||
@@ -1283,22 +1279,17 @@ var status = hitTesters[symbolName](location); | ||
if (status) { | ||
if (status.points) { | ||
targets.push.apply(targets, _toConsumableArray(status.points.map(function (point) { | ||
return { | ||
series: series, | ||
point: point.index, | ||
distance: point.distance | ||
}; | ||
}))); | ||
} else { | ||
targets.push({ | ||
targets.push.apply(targets, _toConsumableArray(status.points.map(function (point) { | ||
return { | ||
series: series, | ||
distance: 1 | ||
}); | ||
} | ||
point: point.index, | ||
distance: point.distance, | ||
order: order | ||
}; | ||
}))); | ||
} | ||
}); | ||
targets.sort(compare); | ||
targets.sort(compareHitTargets); | ||
var arg = { | ||
location: location, | ||
targets: targets | ||
targets: targets, | ||
event: e.nativeEvent | ||
}; | ||
@@ -1341,3 +1332,3 @@ handlers.forEach(function (handler) { | ||
export { computeExtension, computeDomains, buildScales, bBoxes, axisCoordinates, getGridCoordinates, axesData, dArea, dLine, dSpline, getPiePointTransformer, getLinePointTransformer, getAreaPointTransformer, getBarPointTransformer, findSeriesByName, dBar, pointAttributes, addSeries, scaleSeriesPoints, getStackedSeries, getAreaAnimationStyle, getPieAnimationStyle, getScatterAnimationStyle, buildAnimatedStyleGetter, getParameters, processHandleTooltip, createAreaHitTester, createLineHitTester, createSplineHitTester, createBarHitTester, createScatterHitTester, createPieHitTester, changeSeriesState, createScale, getWidth, getValueDomainName, fixOffset, getLegendItems, buildEventHandlers, processPointerMove, getHoverTargets, HORIZONTAL, VERTICAL, TOP, BOTTOM, LEFT, RIGHT, MIDDLE, END, START, LINEAR, BAND, ARGUMENT_DOMAIN, VALUE_DOMAIN, HOVERED, SELECTED }; | ||
export { defaultDomains, addDomain, scaleLinear$1 as scaleLinear, scaleBand$1 as scaleBand, computeDomains, buildScales, bBoxes, axisCoordinates, getGridCoordinates, dArea, dLine, dSpline, getPiePointTransformer, getLinePointTransformer, getAreaPointTransformer, getBarPointTransformer, findSeriesByName, dBar, pointAttributes, addSeries, scaleSeriesPoints, getStackedSeries, getAreaAnimationStyle, getPieAnimationStyle, getScatterAnimationStyle, buildAnimatedStyleGetter, getParameters, processHandleTooltip, createAreaHitTester, createLineHitTester, createSplineHitTester, createBarHitTester, createScatterHitTester, createPieHitTester, changeSeriesState, isHorizontal, getWidth, getValueDomainName, fixOffset, getLegendItems, buildEventHandlers, processPointerMove, HORIZONTAL, VERTICAL, TOP, BOTTOM, LEFT, RIGHT, MIDDLE, END, START, LINEAR, BAND, ARGUMENT_DOMAIN, VALUE_DOMAIN, HOVERED, SELECTED }; | ||
//# sourceMappingURL=dx-chart-core.es.js.map |
/** | ||
* Bundle of @devexpress/dx-chart-core | ||
* Generated: 2018-12-07 | ||
* Version: 1.9.1 | ||
* Generated: 2018-12-25 | ||
* Version: 1.10.0 | ||
* License: https://js.devexpress.com/Licensing | ||
@@ -11,4 +11,4 @@ */ | ||
typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-scale', 'd3-shape'], factory) : | ||
(factory((global.DevExpress = global.DevExpress || {}, global.DevExpress.DXChartCore = {}),global.d3Array,global.d3Scale,global.d3Shape)); | ||
}(this, (function (exports,d3Array,d3Scale,d3Shape) { 'use strict'; | ||
(global = global || self, factory((global.DevExpress = global.DevExpress || {}, global.DevExpress.DXChartCore = {}), global.d3Array, global.d3Scale, global.d3Shape)); | ||
}(this, function (exports, d3Array, d3Scale, d3Shape) { 'use strict'; | ||
@@ -123,7 +123,4 @@ function _defineProperty(obj, key, value) { | ||
var createScale = function createScale(_ref, width, height, constructor) { | ||
var domain = _ref.domain, | ||
orientation = _ref.orientation; | ||
var scale = constructor(); | ||
return scale.domain(domain).range(orientation === HORIZONTAL ? [0, width] : [height, 0]); | ||
var isHorizontal = function isHorizontal(name) { | ||
return name === ARGUMENT_DOMAIN; | ||
}; | ||
@@ -143,6 +140,17 @@ var getWidth = function getWidth(scale) { | ||
var isDefined = function isDefined(item) { | ||
return item !== undefined; | ||
}; // TODO: Property name should not contain "axis" part as it actually means domain. | ||
var _defaultDomains; | ||
var defaultDomains = (_defaultDomains = {}, _defineProperty(_defaultDomains, ARGUMENT_DOMAIN, {}), _defineProperty(_defaultDomains, VALUE_DOMAIN, {}), _defaultDomains); | ||
var addDomain = function addDomain(domains, name, props) { | ||
return _objectSpread({}, domains, _defineProperty({}, name, props)); | ||
}; | ||
var copy = function copy(domains) { | ||
var result = {}; | ||
Object.keys(domains).forEach(function (name) { | ||
result[name] = _objectSpread({}, domains[name], { | ||
domain: [] | ||
}); | ||
}); | ||
return result; | ||
}; | ||
@@ -153,6 +161,10 @@ var getSeriesValueDomainName = function getSeriesValueDomainName(series) { | ||
var calculateDomainField = function calculateDomainField(items, domain, type) { | ||
return type === BAND ? _toConsumableArray(domain).concat(_toConsumableArray(items)) : d3Array.extent(_toConsumableArray(domain).concat(_toConsumableArray(d3Array.extent(items)))); | ||
var mergeContinuousDomains = function mergeContinuousDomains(domain, items) { | ||
return d3Array.extent([].concat(_toConsumableArray(domain), _toConsumableArray(items))); | ||
}; | ||
var mergeDiscreteDomains = function mergeDiscreteDomains(domain, items) { | ||
return Array.from(new Set([].concat(_toConsumableArray(domain), _toConsumableArray(items)))); | ||
}; | ||
var getArgument = function getArgument(point) { | ||
@@ -166,4 +178,7 @@ return point.argument; | ||
var getCorrectAxisType = function getCorrectAxisType(type, points, getItem) { | ||
return type || points.length && typeof getItem(points[0]) === 'string' && BAND || LINEAR; | ||
var extendDomain = function extendDomain(target, items) { | ||
var merge = target.isDiscrete ? mergeDiscreteDomains : mergeContinuousDomains; | ||
Object.assign(target, { | ||
domain: merge(target.domain, items) | ||
}); | ||
}; | ||
@@ -174,7 +189,3 @@ | ||
var valueDomainName = getSeriesValueDomainName(seriesItem); | ||
var points = seriesItem.points; | ||
var argumentDomain = domains[ARGUMENT_DOMAIN]; | ||
var valueDomain = domains[valueDomainName]; | ||
var valueType = getCorrectAxisType(valueDomain.type, points, getValue); | ||
var argumentType = getCorrectAxisType(argumentDomain.type, points, getArgument); // TODO: This is a temporary workaround for Stack plugin. | ||
var points = seriesItem.points; // TODO: This is a temporary workaround for Stack plugin. | ||
// Once scales (or domains) are exposed for modification Stack will modify scale and | ||
@@ -184,96 +195,72 @@ // this code will be removed. | ||
var valueDomainItems = seriesItem.getValueDomain ? seriesItem.getValueDomain(points) : points.map(getValue); | ||
valueDomain.domain = calculateDomainField(valueDomainItems, valueDomain.domain, valueType); | ||
valueDomain.type = valueType; | ||
argumentDomain.domain = calculateDomainField(points.map(getArgument), argumentDomain.domain, argumentType); | ||
argumentDomain.type = argumentType; | ||
extendDomain(domains[valueDomainName], valueDomainItems); | ||
extendDomain(domains[ARGUMENT_DOMAIN], points.map(getArgument)); | ||
}); | ||
}; | ||
var computeExtension = function computeExtension(extension) { | ||
var defaultExtension = [{ | ||
type: LINEAR, | ||
constructor: d3Scale.scaleLinear | ||
}, { | ||
type: BAND, | ||
constructor: function constructor() { | ||
return d3Scale.scaleBand().paddingInner(0.3).paddingOuter(0.15); | ||
} | ||
}]; | ||
return extension.concat(defaultExtension); | ||
var scaleLinear = d3Scale.scaleLinear; | ||
var scaleBand = function scaleBand() { | ||
return d3Scale.scaleBand().paddingInner(0.3).paddingOuter(0.15); | ||
}; | ||
var collectDomains = function collectDomains(seriesList) { | ||
var domains = _defineProperty({}, ARGUMENT_DOMAIN, { | ||
domain: [], | ||
orientation: HORIZONTAL | ||
}); | ||
var guessFactory = function guessFactory(points, getItem) { | ||
return points.length && typeof getItem(points[0]) === 'string' && scaleBand || scaleLinear; | ||
}; | ||
var collectDomainsFromSeries = function collectDomainsFromSeries(domains, seriesList) { | ||
seriesList.forEach(function (seriesItem) { | ||
var name = getSeriesValueDomainName(seriesItem); | ||
var domain = domains[name] || { | ||
domain: [], | ||
orientation: VERTICAL | ||
}; | ||
domains[name] = domain; | ||
if (!domains[ARGUMENT_DOMAIN].factory) { | ||
Object.assign(domains[ARGUMENT_DOMAIN], { | ||
factory: guessFactory(seriesItem.points, getArgument) | ||
}); | ||
} | ||
if (seriesItem.getPointTransformer.isStartedFromZero && domain.domain.length === 0) { | ||
domain.domain = [0]; | ||
var valueDomainName = getSeriesValueDomainName(seriesItem); | ||
var obj = domains[valueDomainName]; | ||
if (!obj.factory) { | ||
obj.factory = guessFactory(seriesItem.points, getValue); | ||
} // TODO: It is to be removed together with *TODO* from above. | ||
if (seriesItem.getPointTransformer.isStartedFromZero && obj.domain.length === 0) { | ||
obj.domain = [0]; | ||
} | ||
}); | ||
return domains; | ||
}; | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
var takeTypeFromAxesOptions = function takeTypeFromAxesOptions(domains, axes) { | ||
axes.forEach(function (_ref) { | ||
var scaleName = _ref.scaleName, | ||
type = _ref.type; | ||
var domain = domains[scaleName]; | ||
if (!obj.factory) { | ||
obj.factory = scaleLinear; | ||
} | ||
if (domain) { | ||
domain.type = type; | ||
} | ||
obj.isDiscrete = !!obj.factory().bandwidth; | ||
}); | ||
return domains; | ||
}; | ||
var takeRestAxesOptions = function takeRestAxesOptions(domains, axes) { | ||
axes.forEach(function (_ref2) { | ||
var scaleName = _ref2.scaleName, | ||
min = _ref2.min, | ||
max = _ref2.max; | ||
var domain = domains[scaleName]; | ||
var customizeDomains = function customizeDomains(domains) { | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
if (!domain) { | ||
return; | ||
if (obj.modifyDomain) { | ||
obj.domain = obj.modifyDomain(obj.domain); | ||
} | ||
if (domain.type !== BAND) { | ||
domain.domain = [isDefined(min) ? min : domain.domain[0], isDefined(max) ? max : domain.domain[1]]; | ||
} | ||
}); | ||
}; | ||
var computeDomains = function computeDomains(axes, series) { | ||
var result = collectDomains(series); // Axes options are taken in two steps because *type* is required for domains calculation | ||
// and other options must be applied after domains are calculated. | ||
takeTypeFromAxesOptions(result, axes); | ||
calculateDomains(result, series); | ||
takeRestAxesOptions(result, axes); | ||
var computeDomains = function computeDomains(domains, seriesList) { | ||
var result = copy(domains); | ||
collectDomainsFromSeries(result, seriesList); | ||
calculateDomains(result, seriesList); | ||
customizeDomains(result); | ||
return result; | ||
}; | ||
var buildScales = function buildScales(domains, scaleExtension, _ref3) { | ||
var width = _ref3.width, | ||
height = _ref3.height; | ||
var buildScales = function buildScales(domains, _ref) { | ||
var width = _ref.width, | ||
height = _ref.height; | ||
var scales = {}; | ||
Object.entries(domains).forEach(function (_ref4) { | ||
var _ref5 = _slicedToArray(_ref4, 2), | ||
name = _ref5[0], | ||
domain = _ref5[1]; | ||
var _scaleExtension$find = scaleExtension.find(function (item) { | ||
return item.type === domain.type; | ||
}), | ||
constructor = _scaleExtension$find.constructor; | ||
scales[name] = createScale(domain, width, height, constructor); | ||
Object.keys(domains).forEach(function (name) { | ||
var obj = domains[name]; | ||
scales[name] = obj.factory().domain(obj.domain).range(isHorizontal(name) ? [0, width] : [height, 0]); | ||
}); | ||
@@ -298,6 +285,2 @@ return scales; | ||
var isHorizontal = function isHorizontal(name) { | ||
return name === ARGUMENT_DOMAIN; | ||
}; | ||
var getTicks = function getTicks(scale) { | ||
@@ -398,5 +381,2 @@ return scale.ticks ? scale.ticks() : scale.domain(); | ||
}; | ||
var axesData = function axesData(axes, axisProps) { | ||
return _toConsumableArray(axes).concat([axisProps]); | ||
}; | ||
@@ -901,44 +881,22 @@ var getX = function getX(_ref) { | ||
// Comparing by reference is not an option as Tracker always sends new objects. | ||
// On the other side Tracker cannot persist references as it actually operates with simple scalars | ||
// Tracker cannot persist references as it actually operates with simple scalars | ||
// and constructs objects to provide info in a slightly more suitable way. | ||
var compareTargets = function compareTargets(target1, target2) { | ||
return target1.series === target2.series && target1.point === target2.point; | ||
}; // Current value is chosen roughly and expected to be adjusted. | ||
}; // If *currentTarget* is among *targets* then it has priority but only while its distance | ||
// is not significantly greater (DISTANCE_PRIORITY_RATIO) than that of the best candidate. | ||
var DISTANCE_PRIORITY_RATIO = 4; // If *currentTarget* is among *targets* then it has priority but only while its distance | ||
// is not significantly greater (DISTANCE_PRIORITY_RATIO) than that of the best candidate. | ||
var selectTarget = function selectTarget(targets, currentTarget) { | ||
var candidate = targets[0]; | ||
var selectTarget = function selectTarget(targets, currentTarget) { | ||
if (!currentTarget) { | ||
return targets.length ? targets[0] : undefined; | ||
return candidate; | ||
} | ||
if (!targets.length) { | ||
if (!candidate) { | ||
return null; | ||
} | ||
var candidate = targets[0]; // Skip complex checks if *currentTarget* has minimal distance. | ||
if (compareTargets(candidate, currentTarget)) { | ||
return undefined; | ||
} // Skip complex check if there is single candidate. | ||
if (targets.length === 1) { | ||
return candidate; | ||
} | ||
var current = targets.find(function (target) { | ||
return compareTargets(target, currentTarget); | ||
}); | ||
if (current) { | ||
// Here *current.distance* is exactly greater than *candidate.distance*. | ||
// The question is - how much greater? | ||
var ratio = current.distance / candidate.distance; | ||
return ratio > DISTANCE_PRIORITY_RATIO ? candidate : undefined; | ||
} | ||
return candidate; | ||
return compareTargets(candidate, currentTarget) ? undefined : candidate; | ||
}; | ||
@@ -958,13 +916,2 @@ | ||
return nextTarget; | ||
}; // It handles the case when point is hovered and series does not contain visual points. | ||
// Series then knows that it is also hovered and can represent the changed state. | ||
var getHoverTargets = function getHoverTargets(hover) { | ||
if (!hover) { | ||
return []; | ||
} | ||
return hover.point >= 0 ? [{ | ||
series: hover.series | ||
}, hover] : [hover]; | ||
}; | ||
@@ -992,24 +939,59 @@ | ||
var getUniformDistance = function getUniformDistance(dx, dy, rx, ry) { | ||
return Math.max(Math.abs(dx) / rx, Math.abs(dy) / ry); | ||
}; // Based on https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm | ||
var getSegmentLength = function getSegmentLength(dx, dy) { | ||
return Math.sqrt(dx * dx + dy * dy); | ||
}; // *distance* is a normalized distance to point. | ||
// It belongs to [0, Infinity): | ||
// = 0 - at point center | ||
// = 1 - at point border | ||
// > 1 - outside point | ||
// This function is called from event handlers (when DOM is available) - | ||
// *window.document* can be accessed safely. | ||
var getEuclideanDistance = function getEuclideanDistance(dx, dy, rx, ry) { | ||
return Math.sqrt(dx * dx / (rx * rx) + dy * dy / (ry * ry)); | ||
var createContext = function createContext() { | ||
return document.createElement('canvas').getContext('2d'); | ||
}; // eslint-disable-line no-undef | ||
// For a start using browser canvas will suffice. | ||
// However a better and more clean solution should be found. | ||
// Can't d3 perform hit testing? | ||
var createCanvasAbusingHitTester = function createCanvasAbusingHitTester(makePath, points) { | ||
var ctx = createContext(); | ||
var path = makePath(); | ||
path.context(ctx); | ||
path(points); | ||
return function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2), | ||
x = _ref2[0], | ||
y = _ref2[1]; | ||
return ctx.isPointInPath(x, y); | ||
}; | ||
}; | ||
var createPointsEnumeratingHitTesterCreator = function createPointsEnumeratingHitTesterCreator(hitTestPoint) { | ||
var LINE_POINT_SIZE = 20; | ||
var LINE_TOLERANCE = 10; | ||
var getContinuousPointDistance = function getContinuousPointDistance(_ref3, _ref4) { | ||
var _ref5 = _slicedToArray(_ref3, 2), | ||
px = _ref5[0], | ||
py = _ref5[1]; | ||
var x = _ref4.x, | ||
y = _ref4.y; | ||
return getSegmentLength(px - x, py - y); | ||
}; | ||
var createContinuousSeriesHitTesterCreator = function createContinuousSeriesHitTesterCreator(makePath) { | ||
return function (points) { | ||
var fallbackHitTest = createCanvasAbusingHitTester(makePath, points); | ||
return function (target) { | ||
var minDistance = Number.MAX_VALUE; | ||
var minIndex; | ||
var list = []; | ||
points.forEach(function (point) { | ||
// *distance* is a normalized distance to point. | ||
// It belongs to [0, Infinity): | ||
// = 0 - at point center | ||
// = 1 - at point border | ||
// > 1 - outside point | ||
var distance = hitTestPoint(target, point); | ||
points.forEach(function (point, i) { | ||
var distance = getContinuousPointDistance(target, point); | ||
if (distance <= 1) { | ||
if (distance <= LINE_POINT_SIZE) { | ||
list.push({ | ||
@@ -1020,3 +1002,17 @@ index: point.index, | ||
} | ||
}); | ||
if (distance < minDistance) { | ||
minDistance = distance; | ||
minIndex = i; | ||
} | ||
}); // This is special case for continuous series - if no point is actually hit | ||
// then the closest point to the pointer position is picked. | ||
if (!list.length && fallbackHitTest(target)) { | ||
list.push({ | ||
index: points[minIndex].index, | ||
distance: minDistance | ||
}); | ||
} | ||
return list.length ? { | ||
@@ -1029,31 +1025,19 @@ points: list | ||
var LINE_TOLERANCE = 10; | ||
var createContinuousSeriesPointsHitTester = createPointsEnumeratingHitTesterCreator(function (_ref, _ref2) { | ||
var _ref3 = _slicedToArray(_ref, 2), | ||
px = _ref3[0], | ||
py = _ref3[1]; | ||
var createPointsEnumeratingHitTesterCreator = function createPointsEnumeratingHitTesterCreator(hitTestPoint) { | ||
return function (points) { | ||
return function (target) { | ||
var list = []; | ||
points.forEach(function (point) { | ||
var status = hitTestPoint(target, point); | ||
var x = _ref2.x, | ||
y = _ref2.y; | ||
return getEuclideanDistance(px - x, py - y, LINE_TOLERANCE, LINE_TOLERANCE); | ||
}); // This function is called from event handlers (when DOM is available) - | ||
// *window.document* can be accessed safely. | ||
var createContext = function createContext() { | ||
return document.createElement('canvas').getContext('2d'); | ||
}; // eslint-disable-line no-undef | ||
// For a start using browser canvas will suffice. | ||
// However a better and more clean solution should be found. | ||
// Can't d3 perform hit testing? | ||
var createCanvasAbusingHitTesterCreator = function createCanvasAbusingHitTesterCreator(makePath) { | ||
return function (points) { | ||
var ctx = createContext(); | ||
var path = makePath(); | ||
path.context(ctx); | ||
path(points); | ||
var hitTestPoints = createContinuousSeriesPointsHitTester(points); | ||
return function (point) { | ||
return ctx.isPointInPath(point[0], point[1]) ? hitTestPoints(point) || {} : null; | ||
if (status) { | ||
list.push({ | ||
index: point.index, | ||
distance: status.distance | ||
}); | ||
} | ||
}); | ||
return list.length ? { | ||
points: list | ||
} : null; | ||
}; | ||
@@ -1063,3 +1047,3 @@ }; | ||
var createAreaHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createAreaHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = d3Shape.area(); | ||
@@ -1071,3 +1055,3 @@ path.x(dArea.x()); | ||
}); | ||
var createLineHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createLineHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = d3Shape.area(); | ||
@@ -1084,3 +1068,3 @@ var getY = dLine.y(); | ||
}); | ||
var createSplineHitTester = createCanvasAbusingHitTesterCreator(function () { | ||
var createSplineHitTester = createContinuousSeriesHitTesterCreator(function () { | ||
var path = d3Shape.area(); | ||
@@ -1097,9 +1081,16 @@ var getY = dSpline.y(); | ||
return path; | ||
}); // Some kind of binary search can be used here as bars can be ordered along argument axis. | ||
}); | ||
var createBarHitTester = createPointsEnumeratingHitTesterCreator(function (_ref4, point) { | ||
var _ref5 = _slicedToArray(_ref4, 2), | ||
px = _ref5[0], | ||
py = _ref5[1]; | ||
var hitTestRect = function hitTestRect(dx, dy, halfX, halfY) { | ||
return Math.abs(dx) <= halfX && Math.abs(dy) <= halfY ? { | ||
distance: getSegmentLength(dx, dy) | ||
} : null; | ||
}; // Some kind of binary search can be used here as bars can be ordered along argument axis. | ||
var createBarHitTester = createPointsEnumeratingHitTesterCreator(function (_ref6, point) { | ||
var _ref7 = _slicedToArray(_ref6, 2), | ||
px = _ref7[0], | ||
py = _ref7[1]; | ||
var xCenter = point.x + point.width / 2; | ||
@@ -1109,13 +1100,16 @@ var yCenter = (point.y + point.y1) / 2; | ||
var halfHeight = Math.abs(point.y - point.y1) / 2; | ||
return getUniformDistance(px - xCenter, py - yCenter, halfWidth, halfHeight); | ||
return hitTestRect(px - xCenter, py - yCenter, halfWidth, halfHeight); | ||
}); // TODO: Use actual point size here! | ||
var createScatterHitTester = createPointsEnumeratingHitTesterCreator(function (_ref6, _ref7) { | ||
var _ref8 = _slicedToArray(_ref6, 2), | ||
px = _ref8[0], | ||
py = _ref8[1]; | ||
var createScatterHitTester = createPointsEnumeratingHitTesterCreator(function (_ref8, _ref9) { | ||
var _ref10 = _slicedToArray(_ref8, 2), | ||
px = _ref10[0], | ||
py = _ref10[1]; | ||
var x = _ref7.x, | ||
y = _ref7.y; | ||
return getEuclideanDistance(px - x, py - y, 10, 10); | ||
var x = _ref9.x, | ||
y = _ref9.y; | ||
var distance = getSegmentLength(px - x, py - y); | ||
return distance <= 10 ? { | ||
distance: distance | ||
} : null; | ||
}); | ||
@@ -1129,13 +1123,13 @@ | ||
var createPieHitTester = createPointsEnumeratingHitTesterCreator(function (_ref9, _ref10) { | ||
var _ref11 = _slicedToArray(_ref9, 2), | ||
px = _ref11[0], | ||
py = _ref11[1]; | ||
var createPieHitTester = createPointsEnumeratingHitTesterCreator(function (_ref11, _ref12) { | ||
var _ref13 = _slicedToArray(_ref11, 2), | ||
px = _ref13[0], | ||
py = _ref13[1]; | ||
var x = _ref10.x, | ||
y = _ref10.y, | ||
innerRadius = _ref10.innerRadius, | ||
outerRadius = _ref10.outerRadius, | ||
startAngle = _ref10.startAngle, | ||
endAngle = _ref10.endAngle; | ||
var x = _ref12.x, | ||
y = _ref12.y, | ||
innerRadius = _ref12.innerRadius, | ||
outerRadius = _ref12.outerRadius, | ||
startAngle = _ref12.startAngle, | ||
endAngle = _ref12.endAngle; | ||
var rCenter = (innerRadius + outerRadius) / 2; | ||
@@ -1147,5 +1141,7 @@ var angleCenter = (startAngle + endAngle) / 2; | ||
var dy = py - y; | ||
var r = Math.sqrt(dx * dx + dy * dy); | ||
var angle = mapAngleTod3(Math.atan2(dy, dx)); | ||
return getUniformDistance(r - rCenter, angle - angleCenter, halfRadius, halfAngle); | ||
var r = getSegmentLength(dx, dy); | ||
var angle = mapAngleTod3(Math.atan2(dy, dx)); // This is not a correct distance calculation but for now it will suffice. | ||
// For Pie series it would not be actually used. | ||
return hitTestRect(r - rCenter, angle - angleCenter, halfRadius, halfAngle); | ||
}); | ||
@@ -1155,14 +1151,6 @@ | ||
var result = {}; | ||
targets.forEach(function (_ref12) { | ||
var series = _ref12.series, | ||
point = _ref12.point; | ||
result[series] = result[series] || { | ||
points: {} | ||
}; | ||
if (point >= 0) { | ||
result[series].points[point] = true; | ||
} else { | ||
result[series].self = true; | ||
} | ||
targets.forEach(function (_ref14) { | ||
var series = _ref14.series, | ||
point = _ref14.point; | ||
(result[series] = result[series] || new Set()).add(point); | ||
}); | ||
@@ -1180,5 +1168,5 @@ return result; | ||
var result = seriesList.map(function (seriesItem) { | ||
var obj = filter[seriesItem.name]; | ||
var set = filter[seriesItem.name]; | ||
if (!obj) { | ||
if (!set) { | ||
return seriesItem; | ||
@@ -1188,11 +1176,9 @@ } | ||
matches += 1; | ||
var props = {}; | ||
var props = { | ||
state: state | ||
}; | ||
if (obj.self) { | ||
props.state = state; | ||
} | ||
if (Object.keys(obj.points).length) { | ||
if (set.size) { | ||
props.points = seriesItem.points.map(function (point) { | ||
return obj.points[point.index] ? _objectSpread({}, point, { | ||
return set.has(point.index) ? _objectSpread({}, point, { | ||
state: state | ||
@@ -1222,3 +1208,3 @@ }) : point; | ||
return series[0].points.map(function (_ref2) { | ||
var text = _ref2.id, | ||
var text = _ref2.argument, | ||
color = _ref2.color; | ||
@@ -1231,8 +1217,8 @@ return { | ||
}; // The function supports special case when there is single Pie series. | ||
// There is no commom way to tell if series is of Pie type - | ||
// checking `seriesComponent` function name will suffice for now. | ||
// There is no common way to tell if series is PieSeries - | ||
// checking `radius` props will suffice for now. | ||
var isSinglePieSeriesCase = function isSinglePieSeriesCase(series) { | ||
return series.length === 1 && series[0].seriesComponent.name === 'SliceCollection'; | ||
return series.length === 1 && 'innerRadius' in series[0] && 'outerRadius' in series[0]; | ||
}; | ||
@@ -1258,4 +1244,13 @@ | ||
var compare = function compare(t1, t2) { | ||
return t1.distance - t2.distance; | ||
var DISTANCE_THRESHOLD = 20; | ||
var compareHitTargets = function compareHitTargets(t1, t2) { | ||
var distanceDelta = t1.distance - t2.distance; | ||
if (Math.abs(distanceDelta) <= DISTANCE_THRESHOLD) { | ||
var orderDelta = t2.order - t1.order; | ||
return orderDelta !== 0 ? orderDelta : distanceDelta; | ||
} | ||
return distanceDelta; | ||
}; | ||
@@ -1280,2 +1275,3 @@ | ||
var series = _ref.name, | ||
order = _ref.index, | ||
symbolName = _ref.symbolName; | ||
@@ -1285,22 +1281,17 @@ var status = hitTesters[symbolName](location); | ||
if (status) { | ||
if (status.points) { | ||
targets.push.apply(targets, _toConsumableArray(status.points.map(function (point) { | ||
return { | ||
series: series, | ||
point: point.index, | ||
distance: point.distance | ||
}; | ||
}))); | ||
} else { | ||
targets.push({ | ||
targets.push.apply(targets, _toConsumableArray(status.points.map(function (point) { | ||
return { | ||
series: series, | ||
distance: 1 | ||
}); | ||
} | ||
point: point.index, | ||
distance: point.distance, | ||
order: order | ||
}; | ||
}))); | ||
} | ||
}); | ||
targets.sort(compare); | ||
targets.sort(compareHitTargets); | ||
var arg = { | ||
location: location, | ||
targets: targets | ||
targets: targets, | ||
event: e.nativeEvent | ||
}; | ||
@@ -1343,3 +1334,6 @@ handlers.forEach(function (handler) { | ||
exports.computeExtension = computeExtension; | ||
exports.defaultDomains = defaultDomains; | ||
exports.addDomain = addDomain; | ||
exports.scaleLinear = scaleLinear; | ||
exports.scaleBand = scaleBand; | ||
exports.computeDomains = computeDomains; | ||
@@ -1350,3 +1344,2 @@ exports.buildScales = buildScales; | ||
exports.getGridCoordinates = getGridCoordinates; | ||
exports.axesData = axesData; | ||
exports.dArea = dArea; | ||
@@ -1378,3 +1371,3 @@ exports.dLine = dLine; | ||
exports.changeSeriesState = changeSeriesState; | ||
exports.createScale = createScale; | ||
exports.isHorizontal = isHorizontal; | ||
exports.getWidth = getWidth; | ||
@@ -1386,3 +1379,2 @@ exports.getValueDomainName = getValueDomainName; | ||
exports.processPointerMove = processPointerMove; | ||
exports.getHoverTargets = getHoverTargets; | ||
exports.HORIZONTAL = HORIZONTAL; | ||
@@ -1406,3 +1398,3 @@ exports.VERTICAL = VERTICAL; | ||
}))); | ||
})); | ||
//# sourceMappingURL=dx-chart-core.umd.js.map |
{ | ||
"name": "@devexpress/dx-chart-core", | ||
"version": "1.9.1", | ||
"version": "1.10.0", | ||
"description": "Core library for the DevExtreme Reactive Chart component", | ||
@@ -42,24 +42,24 @@ "author": { | ||
"devDependencies": { | ||
"@babel/core": "^7.1.6", | ||
"@babel/plugin-transform-runtime": "^7.1.0", | ||
"@babel/preset-env": "^7.1.6", | ||
"@babel/core": "^7.2.2", | ||
"@babel/plugin-transform-runtime": "^7.2.0", | ||
"@babel/preset-env": "^7.2.3", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-jest": "^23.6.0", | ||
"core-js": "^2.5.7", | ||
"eslint": "^5.9.0", | ||
"core-js": "^2.6.1", | ||
"eslint": "^5.11.0", | ||
"eslint-config-airbnb-base": "^13.1.0", | ||
"eslint-plugin-filenames": "^1.3.2", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jest": "^22.0.0", | ||
"eslint-plugin-jest": "^22.1.2", | ||
"jest": "^23.6.0", | ||
"rollup": "^0.67.3", | ||
"rollup-plugin-babel": "^4.0.3", | ||
"rollup": "^0.68.2", | ||
"rollup-plugin-babel": "^4.1.0", | ||
"rollup-plugin-license": "^0.7.0" | ||
}, | ||
"dependencies": { | ||
"d3-array": "^1.2.4", | ||
"d3-array": "^2.0.2", | ||
"d3-scale": "^2.1.2", | ||
"d3-shape": "^1.2.2" | ||
}, | ||
"gitHead": "29cb22ed32aac31a3fa3d985b9160300af79b12f" | ||
"gitHead": "0890839a23a7afd042ad3984dca69232767d60cd" | ||
} |
# DevExtreme Chart Core | ||
Project status: **CTP** | ||
Project status: **Beta** | ||
@@ -5,0 +5,0 @@ Core library for the DevExtreme Reactive Chart component. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
0
237802
2295
+ Addedd3-array@2.12.1(transitive)
+ Addedinternmap@1.0.1(transitive)
Updatedd3-array@^2.0.2