@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.
702 lines • 21.5 kB
JavaScript
import { AxisDependency } from '../components/YAxis';
export class ChartData {
/**
* Default constructor.
*/
// public ChartData() {
// this.mDataSets = [];
// }
/**
* Constructor taking single or multiple DataSet objects.
*
* @param dataSets
*/
constructor(dataSets) {
/**
* maximum y-value in the value array across all axes
*/
this.mYMax = -Infinity;
/**
* the minimum y-value in the value array across all axes
*/
this.mYMin = Infinity;
/**
* maximum x-value in the value array
*/
this.mXMax = -Infinity;
/**
* minimum x-value in the value array
*/
this.mXMin = Infinity;
this.mLeftAxisMax = -Infinity;
this.mLeftAxisMin = Infinity;
this.mRightAxisMax = -Infinity;
this.mRightAxisMin = Infinity;
this.mDataSets = dataSets || [];
this.notifyDataChanged();
}
// /**
// * Created because Arrays.asList(...) does not support modification.
// *
// * @param array
// * @return
// */
// private List<T> arrayToList(T[] array) {
// List<T> list = new ArrayList<>();
// for (T set : array) {
// list.add(set);
// }
// return list;
// }
// /**
// * constructor for chart data
// *
// * @param sets the dataset array
// */
// public ChartData(List<T> sets) {
// this.mDataSets = sets;
// notifyDataChanged();
// }
/**
* Call this method to let the ChartData know that the underlying data has
* changed. Calling this performs all necessary recalculations needed when
* the contained data has changed.
*/
notifyDataChanged() {
this.calcMinMax();
}
/**
* Calc minimum and maximum y-values over all DataSets.
* Tell DataSets to recalculate their min and max y-values, this is only needed for autoScaleMinMax.
*
* @param fromX the x-value to start the calculation from
* @param toX the x-value to which the calculation should be performed
*/
calcMinMaxYRange(fromX, toX) {
for (const set of this.mDataSets) {
set.calcMinMaxYRange(fromX, toX);
}
// apply the new data
this.calcMinMax();
}
/**
* Calc minimum and maximum values (both x and y) over all DataSets.
*/
calcMinMax() {
this.mYMax = -Infinity;
this.mYMin = Infinity;
this.mXMax = -Infinity;
this.mXMin = Infinity;
this.mLeftAxisMax = -Infinity;
this.mLeftAxisMin = Infinity;
this.mRightAxisMax = -Infinity;
this.mRightAxisMin = Infinity;
if (!this.mDataSets || this.mDataSets.length === 0)
return;
const visibleDatasets = this.visibleDataSets;
for (const set of visibleDatasets) {
this.calcMinMaxForDataSet(set);
}
// this.mLeftAxisMax = -Infinity;
// this.mLeftAxisMin = Infinity;
// this.mRightAxisMax = -Infinity;
// this.mRightAxisMin = Infinity;
// for (let i = 0; i < visibleDatasets.length; i++) {
// const set = visibleDatasets[i];
// if (set.axisDependency === AxisDependency.RIGHT) {
// this.mRightAxisMin = Math.min(this.mRightAxisMin, set.yMin);
// this.mRightAxisMax = Math.min(this.mRightAxisMax, set.yMax);
// } else {
// this.mLeftAxisMin = Math.min(this.mLeftAxisMin, set.yMin);
// this.mLeftAxisMax = Math.min(this.mLeftAxisMax, set.yMax);
// }
// }
}
/** ONLY GETTERS AND SETTERS BELOW THIS */
/**
* returns the number of LineDataSets this object contains
*/
get dataSetCount() {
if (!this.mDataSets)
return 0;
return this.mDataSets.length;
}
/**
* Returns the minimum y-value for the specified axis.
*
* @param axis
* @return
*/
getYMin(axis) {
if (axis === undefined) {
return this.mYMin;
}
if (axis === AxisDependency.LEFT) {
if (!Number.isFinite(this.mLeftAxisMin)) {
if (!Number.isFinite(this.mRightAxisMin)) {
return 0;
}
return this.mRightAxisMin;
}
else
return this.mLeftAxisMin;
}
else {
if (!Number.isFinite(this.mRightAxisMin)) {
if (!Number.isFinite(this.mLeftAxisMin)) {
return 0;
}
return this.mLeftAxisMin;
}
else
return this.mRightAxisMin;
}
}
get yMin() {
return this.mYMin;
}
get yMax() {
return this.mYMax;
}
/**
* Returns the maximum y-value for the specified axis.
*
* @param axis
* @return
*/
getYMax(axis) {
if (axis === undefined) {
return this.mYMax;
}
if (axis === AxisDependency.LEFT) {
if (!Number.isFinite(this.mLeftAxisMax)) {
if (!Number.isFinite(this.mRightAxisMax)) {
return 0;
}
return this.mRightAxisMax;
}
else
return this.mLeftAxisMax;
}
else {
if (!Number.isFinite(this.mRightAxisMax)) {
if (!Number.isFinite(this.mLeftAxisMax)) {
return 0;
}
return this.mLeftAxisMax;
}
else
return this.mRightAxisMax;
}
}
/**
* Returns the minimum x-value this data object contains.
*/
get xMin() {
return this.mXMin;
}
/**
* Returns the maximum x-value this data object contains.
*/
get xMax() {
return this.mXMax;
}
/**
* Returns all DataSet objects this ChartData object holds.
*/
get dataSets() {
return this.mDataSets;
}
get visibleDataSets() {
return this.mDataSets.filter((s) => s.visible);
}
/**
* Retrieve the index of a DataSet with a specific label from the ChartData.
* Search can be case sensitive or not. IMPORTANT: This method does
* calculations at runtime, do not over-use in performance critical
* situations.
*
* @param dataSets the DataSet array to search
* @param label
* @param ignorecase if true, the search is not case-sensitive
* @return
*/
getDataSetIndexByLabel(dataSets, label, ignorecase = false) {
if (ignorecase) {
const toTest = label.toLowerCase();
for (let i = 0; i < dataSets.length; i++)
if (toTest === dataSets[i].label?.toLowerCase())
return i;
}
else {
for (let i = 0; i < dataSets.length; i++)
if (label === dataSets[i].label)
return i;
}
return -1;
}
/**
* Returns the labels of all DataSets as a string array.
*/
getDataSetLabels() {
const types = [];
for (let i = 0; i < this.mDataSets.length; i++) {
types[i] = this.mDataSets[i].label;
}
return types;
}
/**
* Get the Entry for a corresponding highlight object
*
* @param highlight
* @return the entry that is highlighted
*/
getEntryForHighlight(highlight) {
if (highlight.entry) {
return highlight.entry;
}
if (highlight.dataSetIndex >= this.mDataSets.length)
return null;
else {
return this.mDataSets[highlight.dataSetIndex].getEntryForXValue(highlight.x, highlight.y);
}
}
/**
* Get the Entry for a corresponding highlight object
*
* @param highlight
* @return the entry that is highlighted
*/
getEntryAndIndexForHighlight(highlight) {
if (highlight.entry) {
return { entry: highlight.entry, index: highlight.entryIndex };
}
if (highlight.dataSetIndex >= this.mDataSets.length)
return null;
else {
return this.mDataSets[highlight.dataSetIndex].getEntryAndIndexForXValue(highlight.x, highlight.y);
}
}
/**
* Returns the DataSet object with the given label. Search can be case
* sensitive or not. IMPORTANT: This method does calculations at runtime.
* Use with care in performance critical situations.
*
* @param label
* @param ignorecase
* @return
*/
getDataSetByLabel(label, ignorecase = false) {
const index = this.getDataSetIndexByLabel(this.mDataSets, label, ignorecase);
if (index < 0 || index >= this.mDataSets.length)
return null;
else
return this.mDataSets[index];
}
getDataSetByIndex(index) {
if (!this.mDataSets || index < 0 || index >= this.mDataSets.length)
return null;
return this.mDataSets[index];
}
/**
* Adds a DataSet dynamically.
*
* @param d
*/
addDataSet(d) {
if (!d)
return;
if (d.visible) {
this.calcMinMaxForDataSet(d);
}
this.mDataSets.push(d);
}
/**
* Removes the given DataSet from this data object. Also recalculates all
* minimum and maximum values. Returns true if a DataSet was removed, false
* if no DataSet could be removed.
*
* @param d
*/
removeDataSet(d) {
if (!d)
return false;
const index = this.mDataSets.indexOf(d);
// if a DataSet was removed
if (index >= 0) {
this.mDataSets.splice(index, 1);
this.calcMinMax();
}
return index >= 0;
}
/**
* Removes the DataSet at the given index in the DataSet array from the data
* object. Also recalculates all minimum and maximum values. Returns true if
* a DataSet was removed, false if no DataSet could be removed.
*
* @param index
*/
removeDataSetAtIndex(index) {
if (index >= this.mDataSets.length || index < 0)
return false;
this.mDataSets.splice(index, 1);
this.calcMinMax();
return true;
}
/**
* Adds an Entry to the DataSet at the specified index.
* Entries are added to the end of the list.
*
* @param e
* @param dataSetIndex
*/
addEntry(e, dataSetIndex) {
if (this.mDataSets.length > dataSetIndex && dataSetIndex >= 0) {
const set = this.mDataSets[dataSetIndex];
// add the entry to the dataset
const length = set.entryCount;
if (!set.addEntry(e))
return;
if (set.visible) {
this.calcMinMaxForEntry(set, e, length, set.axisDependency);
}
}
else {
console.error('addEntry', 'Cannot add Entry because dataSetIndex too high or too low.');
}
}
/**
* Adjusts the current minimum and maximum values based on the provided Entry object.
*
* @param e
* @param axis
*/
calcMinMaxForEntry(set, e, entryIndex, axis) {
const xValue = set.getEntryXValue(e, entryIndex);
const yValue = e[set.yProperty];
this.mYMin = Math.min(this.mYMin, yValue);
this.mYMax = Math.max(this.mYMax, yValue);
this.mXMin = Math.min(this.mXMin, xValue);
this.mXMax = Math.max(this.mXMax, xValue);
if (axis === AxisDependency.LEFT) {
this.mLeftAxisMin = Math.min(this.mLeftAxisMin, yValue);
this.mLeftAxisMax = Math.max(this.mLeftAxisMax, yValue);
}
else {
this.mRightAxisMin = Math.min(this.mRightAxisMin, yValue);
this.mRightAxisMax = Math.max(this.mRightAxisMax, yValue);
}
}
/**
* Adjusts the minimum and maximum values based on the given DataSet.
*
* @param d
*/
calcMinMaxForDataSet(d) {
this.mXMin = Math.min(this.mXMin, d.xMin);
this.mXMax = Math.max(this.mXMax, d.xMax);
this.mYMin = Math.min(this.mYMin, d.yMin);
this.mYMax = Math.max(this.mYMax, d.yMax);
if (d.axisDependency === AxisDependency.LEFT) {
this.mLeftAxisMin = Math.min(this.mLeftAxisMin, d.yMin);
this.mLeftAxisMax = Math.max(this.mLeftAxisMax, d.yMax);
}
else {
this.mRightAxisMin = Math.min(this.mRightAxisMin, d.yMin);
this.mRightAxisMax = Math.max(this.mRightAxisMax, d.yMax);
}
}
/**
* Removes the given Entry object from the DataSet at the specified index.
*
* @param e
* @param dataSetIndex
*/
removeEntry(e, dataSetIndex) {
// entry null, outofbounds
if (!e || dataSetIndex >= this.mDataSets.length)
return false;
const set = this.mDataSets[dataSetIndex];
if (set) {
// remove the entry from the dataset
const removed = set.removeEntry(e);
if (removed) {
this.calcMinMax();
}
return removed;
}
else
return false;
}
/**
* Removes the Entry object closest to the given DataSet at the
* specified index. Returns true if an Entry was removed, false if no Entry
* was found that meets the specified requirements.
*
* @param xValue
* @param dataSetIndex
* @return
*/
removeEntryForXValue(xValue, dataSetIndex) {
if (dataSetIndex >= this.mDataSets.length)
return false;
const dataSet = this.mDataSets[dataSetIndex];
const e = dataSet.getEntryForXValue(xValue, NaN);
if (!e)
return false;
return this.removeEntry(e, dataSetIndex);
}
/**
* Removes the Entry object closest to the given DataSet at the
* specified index. Returns true if an Entry was removed, false if no Entry
* was found that meets the specified requirements.
*
* @param xValue
* @param dataSetIndex
* @return
*/
removeEntryAtIndex(index, dataSetIndex) {
// entry null, outofbounds
if (dataSetIndex >= this.mDataSets.length)
return false;
const set = this.mDataSets[dataSetIndex];
if (set) {
// remove the entry from the dataset
const removed = set.removeEntryAtIndex(index);
if (removed) {
this.calcMinMax();
}
return removed;
}
else
return false;
}
/**
* Returns the DataSet that contains the provided Entry, or null, if no
* DataSet contains this Entry.
*
* @param e
* @return
*/
getDataSetForEntry(e) {
// WARNING: wont work if index is used as xKey(xKey not set)
if (!e)
return null;
for (let i = 0; i < this.mDataSets.length; i++) {
const set = this.mDataSets[i];
const xKey = set.xProperty;
const yKey = set.yProperty;
// for (let j = 0; j < set.entryCount; j++) {
if (e === set.getEntryForXValue(e[xKey], e[yKey]))
return set;
// }
}
return null;
}
/**
* Returns the DataSet that contains the provided Entry and the entry index, or null, if no
* DataSet contains this Entry.
*
* @param e
* @return
*/
getDataSetAndIndexForEntry(e) {
// WARNING: wont work if index is used as xKey(xKey not set)
if (!e)
return null;
for (let i = 0; i < this.mDataSets.length; i++) {
const set = this.mDataSets[i];
const xKey = set.xProperty;
const yKey = set.yProperty;
const r = set.getEntryAndIndexForXValue(e[xKey], e[yKey]);
// for (let j = 0; j < set.entryCount; j++) {
if (e === r.entry)
return { set, index: r.index };
// }
}
return null;
}
/**
* Returns all colors used across all DataSet objects this object
* represents.
*/
get colors() {
if (!this.mDataSets)
return null;
let clrcnt = 0;
for (let i = 0; i < this.mDataSets.length; i++) {
clrcnt += this.mDataSets[i].colors.length;
}
const colors = [];
let cnt = 0;
for (let i = 0; i < this.mDataSets.length; i++) {
const clrs = this.mDataSets[i].colors;
for (const clr of clrs) {
colors[cnt] = clr;
cnt++;
}
}
return colors;
}
/**
* Returns the index of the provided DataSet in the DataSet array of this data object, or -1 if it does not exist.
*
* @param dataSet
* @return
*/
getIndexOfDataSet(dataSet) {
return this.mDataSets.indexOf(dataSet);
}
/**
* Returns the first DataSet from the datasets-array that has it's dependency on the left axis.
* Returns null if no DataSet with left dependency could be found.
*/
getFirstLeft(sets) {
for (const dataSet of sets) {
if (dataSet.axisDependency === AxisDependency.LEFT)
return dataSet;
}
return null;
}
/**
* Returns the first DataSet from the datasets-array that has it's dependency on the right axis.
* Returns null if no DataSet with right dependency could be found.
*/
getFirstRight(sets) {
for (const dataSet of sets) {
if (dataSet.axisDependency === AxisDependency.RIGHT)
return dataSet;
}
return null;
}
/**
* Sets a custom IValueFormatter for all DataSets this data object contains.
*
* @param f
*/
set valueFormatter(f) {
for (const set of this.mDataSets) {
set.valueFormatter = f;
}
}
/**
* Sets the color of the value-text (color in which the value-labels are
* drawn) for all DataSets this data object contains.
*
* @param color
*/
set valueTextColor(color) {
for (const set of this.mDataSets) {
set.valueTextColor = color;
}
}
/**
* Sets the same list of value-colors for all DataSets this
* data object contains.
*
* @param colors
*/
set valueTextColors(colors) {
for (const set of this.mDataSets) {
set.valueTextColors = colors;
}
}
/**
* Sets the Typeface for all value-labels for all DataSets this data object
* contains.
*
* @param tf
*/
set valueTypeface(tf) {
for (const set of this.mDataSets) {
set.valueTypeface = tf;
}
}
/**
* Sets the size (in dp) of the value-text for all DataSets this data object
* contains.
*
* @param size
*/
set valueTextSize(size) {
for (const set of this.mDataSets) {
set.valueTextSize = size;
}
}
/**
* Enables / disables drawing values (value-text) for all DataSets this data
* object contains.
*
* @param enabled
*/
set drawValuesEnabled(enabled) {
for (const set of this.mDataSets) {
set.drawValuesEnabled = enabled;
}
}
/**
* Enables / disables highlighting values for all DataSets this data object
* contains. If set to true, this means that values can
* be highlighted programmatically or by touch gesture.
*/
setHighlightEnabled(enabled) {
for (const set of this.mDataSets) {
set.highlightEnabled = enabled;
}
}
/**
* Returns true if highlighting of all underlying values is enabled, false
* if not.
*/
get highlightEnabled() {
for (const set of this.mDataSets) {
if (!set.highlightEnabled)
return false;
}
return true;
}
/**
* Clears this data object from all DataSets and removes all Entries. Don't
* forget to invalidate the chart after this.
*/
clearValues() {
if (this.mDataSets) {
this.mDataSets = [];
}
this.notifyDataChanged();
}
/**
* Checks if this data object contains the specified DataSet. Returns true
* if so, false if not.
*
* @param dataSet
* @return
*/
contains(dataSet) {
return this.mDataSets.indexOf(dataSet) >= 0;
}
/**
* Returns the total entry count across all DataSet objects this data object contains.
*/
get entryCount() {
let count = 0;
for (const set of this.mDataSets) {
count += set.entryCount;
}
return count;
}
/**
* Returns the DataSet object with the maximum number of entries or null if there are no DataSets.
*/
get maxEntryCountSet() {
if (!this.mDataSets || this.mDataSets.length === 0)
return null;
let max = this.mDataSets[0];
for (const set of this.mDataSets) {
if (set.entryCount > max.entryCount)
max = set;
}
return max;
}
}
//# sourceMappingURL=ChartData.js.map