UNPKG

@nativescript-community/ui-chart

Version:

A powerful chart / graph plugin, supporting line, bar, pie, radar, bubble, and candlestick charts as well as scaling, panning and animations.

220 lines 7.8 kB
import { AxisDependency } from '../components/YAxis'; import { Rounding } from '../data/DataSet'; import { LineDataSet } from '../data/LineDataSet'; export class ChartHighlighter { constructor(chart) { /** * buffer for storing previously highlighted values */ this.mHighlightBuffer = []; this.mChart = chart; } getHighlight(x, y) { const pos = this.getValsForTouch(x, y); const xVal = pos.x; return this.getHighlightForX(xVal, x, y); } /** * Returns a recyclable MPPointD instance. * Returns the corresponding xPos for a given touch-position in pixels. * * @param x * @param y * @return */ getValsForTouch(x, y) { // take any transformer to determine the x-axis value const pos = this.mChart.transformer.getValuesByTouchPoint(x, y); return pos; } /** * Returns the corresponding Highlight for a given xVal and x- and y-touch position in pixels. * * @param xVal * @param x * @param y * @return */ getHighlightForX(xVal, x, y) { const closestValues = this.getHighlightsAtXValue(xVal, x, y); if (closestValues.length <= 1) { return closestValues; } const chart = this.mChart; let axis; if (chart.highlightsFilterByAxis) { const leftAxisMinDist = this.getMinimumDistance(closestValues, y, AxisDependency.LEFT); const rightAxisMinDist = this.getMinimumDistance(closestValues, y, AxisDependency.RIGHT); axis = leftAxisMinDist < rightAxisMinDist ? AxisDependency.LEFT : AxisDependency.RIGHT; } // const detail = this.getClosestHighlightByPixel(closestValues, x, y, chart.maxHighlightDistance, axis); // return [detail]; return this.sortedHighlights(closestValues, x, y, chart.maxHighlightDistance, axis); } /** * Returns the minimum distance from a touch value (in pixels) to the * closest value (in pixels) that is displayed in the chart. * * @param closestValues * @param pos * @param axis * @return */ getMinimumDistance(closestValues, pos, axis) { let distance = Infinity; for (let i = 0; i < closestValues.length; i++) { const high = closestValues[i]; if (high.axis === axis) { const tempDistance = Math.abs(this.getHighlightPos(high) - pos); if (tempDistance < distance) { distance = tempDistance; } } } return distance; } getHighlightPos(h) { return h.yPx; } getChartData() { return this.mChart.data; } /** * Returns a list of Highlight objects representing the entries closest to the given xVal. * The returned list contains two objects per DataSet (closest rounding up, closest rounding down). * * @param xVal the transformed x-value of the x-touch position * @return */ getHighlightsAtXValue(xVal, x, y) { this.mHighlightBuffer = []; const data = this.getChartData(); if (!data) return this.mHighlightBuffer; for (let i = 0, dataSetCount = data.dataSetCount; i < dataSetCount; i++) { const dataSet = data.getDataSetByIndex(i); // don't include DataSets that cannot be highlighted if (!dataSet.highlightEnabled) continue; this.mHighlightBuffer.push(...this.buildHighlights(dataSet, i, x, y, xVal, Rounding.CLOSEST)); } return this.mHighlightBuffer; } /** * An array of `Highlight` objects corresponding to the selected xValue and dataSetIndex. * * @param set * @param dataSetIndex * @param xVal * @param rounding * @return */ buildHighlights(set, dataSetIndex, touchX, touchY, xVal, rounding) { const yKey = set.yProperty; const highlights = []; if (set instanceof LineDataSet) { set.ignoreFiltered = true; } //noinspection unchecked let entries = set.getEntriesAndIndexesForXValue(xVal); if (entries.length === 0) { // Try to find closest x-value and take all entries for that x-value const closest = set.getEntryAndIndexForXValue(xVal, NaN, rounding); if (closest) { //noinspection unchecked entries = set.getEntriesAndIndexesForXValue(set.getEntryXValue(closest.entry, closest.index)); } } if (entries.length === 0) return highlights; for (const r of entries) { const e = r.entry; const index = r.index; const xVal = set.getEntryXValue(e, index); // const pixels = this.mChart.getTransformer(set.axisDependency).getPixelForValues(xVal, e[yKey]); const pixels = this.mChart.getPixelForEntry(set, e, index); highlights.push({ entry: e, entryIndex: index, x: xVal, y: e[yKey], xTouchPx: touchX, yTouchPx: touchY, xPx: pixels.x, yPx: pixels.y, dataSetIndex, axis: set.axisDependency }); } if (set instanceof LineDataSet) { set.ignoreFiltered = false; } return highlights; } /** * Returns the Highlight of the DataSet that contains the closest value on the * y-axis. * * @param closestValues contains two Highlight objects per DataSet closest to the selected x-position (determined by * rounding up an down) * @param x * @param y * @param minSelectionDistance * @param axis the closest axis * @return */ getClosestHighlightByPixel(closestValues, x, y, minSelectionDistance, axis) { let closest = null; let distance = minSelectionDistance; for (let i = 0; i < closestValues.length; i++) { const high = closestValues[i]; if (axis !== undefined || high.axis === axis) { const cDistance = this.getDistance(x, y, high.xPx, high.yPx); if (cDistance < distance) { closest = high; distance = cDistance; } } } return closest; } /** * Returns sorted highlights based on distance to touch x,y * * @param closestValues contains two Highlight objects per DataSet closest to the selected x-position (determined by * rounding up an down) * @param x * @param y * @param minSelectionDistance * @param axis the closest axis * @return */ sortedHighlights(closestValues, x, y, minSelectionDistance, axis) { if (axis !== undefined) { closestValues = closestValues.filter((h) => h.axis === axis); } return closestValues .map((h) => ({ h, d: this.getDistance(x, y, h.xPx, h.yPx) })) .sort((h1, h2) => h1.d - h2.d) .filter((v) => v.d < minSelectionDistance) .map((v) => v.h); } /** * Calculates the distance between the two given points. * * @param x1 * @param y1 * @param x2 * @param y2 * @return */ getDistance(x1, y1, x2, y2) { //return Math.abs(y1 - y2); //return Math.abs(x1 - x2); return Math.hypot(x1 - x2, y1 - y2); } getData() { return this.mChart.data; } } //# sourceMappingURL=ChartHighlighter.js.map