@devexpress/dx-chart-core
Advanced tools
Comparing version
/** | ||
* 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
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
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
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
0
-100%237802
-1.77%2295
-0.82%+ Added
+ Added
Updated