UNPKG

@carbon/charts

Version:
556 lines 26 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; // Internal Imports import * as Configuration from '../configuration'; import { Service } from './service'; import { AxisPositions, CartesianOrientations, ScaleTypes, } from '../interfaces'; import { Tools } from '../tools'; // D3 Imports import { scaleBand, scaleLinear, scaleTime, scaleLog } from 'd3-scale'; import { extent, sum } from 'd3-array'; import { map, values } from 'd3-collection'; // Misc import { differenceInYears, addYears, subYears, differenceInMonths, addMonths, subMonths, differenceInDays, addDays, subDays, differenceInHours, addHours, subHours, differenceInMinutes, addMinutes, subMinutes, differenceInSeconds, subSeconds, addSeconds, } from 'date-fns'; var CartesianScales = /** @class */ (function (_super) { __extends(CartesianScales, _super); function CartesianScales() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.scaleTypes = { top: null, right: null, bottom: null, left: null, }; _this.scales = { top: null, right: null, bottom: null, left: null, }; return _this; } CartesianScales.prototype.getDomainAxisPosition = function (_a) { var _b = (_a === void 0 ? {} : _a).datum, datum = _b === void 0 ? null : _b; var _c; if (this.dualAxes && datum) { var options = this.model.getOptions(); var groupMapsTo = options.data.groupMapsTo; var axesOptions = Tools.getProperty(options, 'axes', this.secondaryDomainAxisPosition); var dataset = datum[groupMapsTo]; if (((_c = axesOptions) === null || _c === void 0 ? void 0 : _c.correspondingDatasets) && axesOptions.correspondingDatasets.includes(dataset)) { return this.secondaryDomainAxisPosition; } } return this.domainAxisPosition; }; CartesianScales.prototype.getRangeAxisPosition = function (_a) { var _b = _a === void 0 ? {} : _a, _c = _b.datum, datum = _c === void 0 ? null : _c, _d = _b.groups, groups = _d === void 0 ? null : _d; var _e; if (this.dualAxes) { var options = this.model.getOptions(); var groupMapsTo = options.data.groupMapsTo; var axisOptions = Tools.getProperty(options, 'axes', this.secondaryRangeAxisPosition); var dataset = void 0; if (datum !== null) { dataset = datum[groupMapsTo]; } else if (groups && groups.length > 0) { dataset = groups[0]; } if (((_e = axisOptions) === null || _e === void 0 ? void 0 : _e.correspondingDatasets) && axisOptions.correspondingDatasets.includes(dataset)) { return this.secondaryRangeAxisPosition; } } return this.rangeAxisPosition; }; CartesianScales.prototype.getAxisOptions = function (position) { return Tools.getProperty(this.model.getOptions(), 'axes', position); }; CartesianScales.prototype.getDomainAxisOptions = function () { var domainAxisPosition = this.getDomainAxisPosition(); return this.getAxisOptions(domainAxisPosition); }; CartesianScales.prototype.getRangeAxisOptions = function () { var rangeAxisPosition = this.getRangeAxisPosition(); return this.getAxisOptions(rangeAxisPosition); }; CartesianScales.prototype.update = function (animate) { var _this = this; if (animate === void 0) { animate = true; } this.determineAxisDuality(); this.findDomainAndRangeAxes(); this.determineOrientation(); var axisPositions = Object.keys(AxisPositions).map(function (axisPositionKey) { return AxisPositions[axisPositionKey]; }); axisPositions.forEach(function (axisPosition) { _this.scales[axisPosition] = _this.createScale(axisPosition); }); }; CartesianScales.prototype.findDomainAndRangeAxes = function () { // find main axes between (left & right) && (bottom & top) var verticalAxesPositions = this.findVerticalAxesPositions(); var horizontalAxesPositions = this.findHorizontalAxesPositions(); // Now we have horizontal & vertical main axes to choose domain & range axes from var domainAndRangeAxesPositions = this.findDomainAndRangeAxesPositions(verticalAxesPositions, horizontalAxesPositions); this.domainAxisPosition = domainAndRangeAxesPositions.primaryDomainAxisPosition; this.rangeAxisPosition = domainAndRangeAxesPositions.primaryRangeAxisPosition; if (this.isDualAxes()) { this.secondaryDomainAxisPosition = domainAndRangeAxesPositions.secondaryDomainAxisPosition; this.secondaryRangeAxisPosition = domainAndRangeAxesPositions.secondaryRangeAxisPosition; } }; CartesianScales.prototype.determineOrientation = function () { if ((this.rangeAxisPosition === AxisPositions.LEFT || this.rangeAxisPosition === AxisPositions.RIGHT) && (this.domainAxisPosition === AxisPositions.BOTTOM || this.domainAxisPosition === AxisPositions.TOP)) { this.orientation = CartesianOrientations.VERTICAL; } else { this.orientation = CartesianOrientations.HORIZONTAL; } }; CartesianScales.prototype.isDualAxes = function () { return this.dualAxes; }; // if any of the axes objects have correspondingDatasets [] asserted we flag the chart as dual axes // it does not count as dual axes if it just has another axis turned on but is not actually using it to map a dataset CartesianScales.prototype.determineAxisDuality = function () { var _a, _b, _c, _d; var options = this.model.getOptions(); var axesOptions = Tools.getProperty(options, 'axes'); if ((((_a = axesOptions[AxisPositions.LEFT]) === null || _a === void 0 ? void 0 : _a.correspondingDatasets) && axesOptions[AxisPositions.RIGHT]) || (((_b = axesOptions[AxisPositions.RIGHT]) === null || _b === void 0 ? void 0 : _b.correspondingDatasets) && axesOptions[AxisPositions.LEFT]) || (((_c = axesOptions[AxisPositions.TOP]) === null || _c === void 0 ? void 0 : _c.correspondingDatasets) && axesOptions[AxisPositions.BOTTOM]) || (((_d = axesOptions[AxisPositions.BOTTOM]) === null || _d === void 0 ? void 0 : _d.correspondingDatasets) && axesOptions[AxisPositions.TOP])) { this.dualAxes = true; } }; CartesianScales.prototype.getOrientation = function () { return this.orientation; }; CartesianScales.prototype.getScaleByPosition = function (axisPosition) { return this.scales[axisPosition]; }; CartesianScales.prototype.getScaleTypeByPosition = function (axisPosition) { return this.scaleTypes[axisPosition]; }; CartesianScales.prototype.getDomainAxisScaleType = function () { var domainAxisPosition = this.getDomainAxisPosition(); return this.getScaleTypeByPosition(domainAxisPosition); }; CartesianScales.prototype.getRangeAxisScaleType = function () { var rangeAxisPosition = this.getRangeAxisPosition(); return this.getScaleTypeByPosition(rangeAxisPosition); }; CartesianScales.prototype.getDomainScale = function () { return this.scales[this.domainAxisPosition]; }; CartesianScales.prototype.getRangeScale = function () { return this.scales[this.rangeAxisPosition]; }; // Find the main x-axis out of the 2 x-axis on the chart (when 2D axis is used) CartesianScales.prototype.getMainXAxisPosition = function () { var possibleXAxisPositions = [ AxisPositions.BOTTOM, AxisPositions.TOP, ]; return [this.domainAxisPosition, this.rangeAxisPosition].find(function (position) { return possibleXAxisPositions.indexOf(position) > -1; }); }; // Find the main y-axis out of the 2 y-axis on the chart (when 2D axis is used) CartesianScales.prototype.getMainYAxisPosition = function () { var possibleYAxisPositions = [ AxisPositions.LEFT, AxisPositions.RIGHT, ]; return [this.domainAxisPosition, this.rangeAxisPosition].find(function (position) { return possibleYAxisPositions.indexOf(position) > -1; }); }; CartesianScales.prototype.getMainXScale = function () { return this.scales[this.getMainXAxisPosition()]; }; CartesianScales.prototype.getMainYScale = function () { return this.scales[this.getMainYAxisPosition()]; }; CartesianScales.prototype.getValueFromScale = function (scale, scaleType, axisPosition, datum, index) { var options = this.model.getOptions(); var axesOptions = Tools.getProperty(options, 'axes'); var axisOptions = axesOptions[axisPosition]; var mapsTo = axisOptions.mapsTo; var value = datum[mapsTo] !== undefined ? datum[mapsTo] : datum; var scaledValue; switch (scaleType) { case ScaleTypes.LABELS: scaledValue = scale(value) + scale.step() / 2; break; case ScaleTypes.TIME: scaledValue = scale(new Date(value)); break; default: scaledValue = scale(value); } return scaledValue; }; CartesianScales.prototype.getBoundedScaledValues = function (datum, index) { var bounds = this.model.getOptions().bounds; var scale = this.scales[this.rangeAxisPosition]; var options = this.model.getOptions(); var axesOptions = Tools.getProperty(options, 'axes'); var axisOptions = axesOptions[this.rangeAxisPosition]; var mapsTo = axisOptions.mapsTo; var value = datum[mapsTo] !== undefined ? datum[mapsTo] : datum; var boundedValues = [ scale(datum[bounds.upperBoundMapsTo] ? datum[bounds.upperBoundMapsTo] : value), scale(datum[bounds.lowerBoundMapsTo] ? datum[bounds.lowerBoundMapsTo] : value), ]; return boundedValues; }; CartesianScales.prototype.getValueThroughAxisPosition = function (axisPosition, datum, index) { var scaleType = this.scaleTypes[axisPosition]; var scale = this.scales[axisPosition]; return this.getValueFromScale(scale, scaleType, axisPosition, datum, index); }; CartesianScales.prototype.getDomainValue = function (d, i) { var axisPosition = this.getDomainAxisPosition({ datum: d }); return this.getValueThroughAxisPosition(axisPosition, d, i); }; CartesianScales.prototype.getRangeValue = function (d, i) { var axisPosition = this.getRangeAxisPosition({ datum: d }); return this.getValueThroughAxisPosition(axisPosition, d, i); }; CartesianScales.prototype.getMainXScaleType = function () { return this.getScaleTypeByPosition(this.getMainXAxisPosition()); }; CartesianScales.prototype.getMainYScaleType = function () { return this.getScaleTypeByPosition(this.getMainYAxisPosition()); }; CartesianScales.prototype.getDomainIdentifier = function (datum) { var options = this.model.getOptions(); return Tools.getProperty(options, 'axes', this.getDomainAxisPosition({ datum: datum }), 'mapsTo'); }; CartesianScales.prototype.getRangeIdentifier = function (datum) { var options = this.model.getOptions(); return Tools.getProperty(options, 'axes', this.getRangeAxisPosition({ datum: datum }), 'mapsTo'); }; CartesianScales.prototype.extendsDomain = function (axisPosition, domain) { var options = this.model.getOptions(); var axisOptions = Tools.getProperty(options, 'axes', axisPosition); if (axisOptions.scaleType === ScaleTypes.TIME) { var spaceToAddToEdges = Tools.getProperty(options, 'timeScale', 'addSpaceOnEdges'); return addSpacingToTimeDomain(domain, spaceToAddToEdges); } else { return addSpacingToContinuousDomain(domain, Configuration.axis.paddingRatio); } }; CartesianScales.prototype.findVerticalAxesPositions = function () { var options = this.model.getOptions(); var axesOptions = Tools.getProperty(options, 'axes'); var dualAxes = this.isDualAxes(); // If right axis has been specified as `main` if ((Tools.getProperty(axesOptions, AxisPositions.LEFT) === null && Tools.getProperty(axesOptions, AxisPositions.RIGHT) !== null) || Tools.getProperty(axesOptions, AxisPositions.RIGHT, 'main') === true || (dualAxes && Tools.getProperty(axesOptions, AxisPositions.LEFT, 'correspondingDatasets'))) { return { primary: AxisPositions.RIGHT, secondary: AxisPositions.LEFT, }; } return { primary: AxisPositions.LEFT, secondary: AxisPositions.RIGHT }; }; CartesianScales.prototype.findHorizontalAxesPositions = function () { var options = this.model.getOptions(); var axesOptions = Tools.getProperty(options, 'axes'); var dualAxes = this.isDualAxes(); // If top axis has been specified as `main` if ((Tools.getProperty(axesOptions, AxisPositions.BOTTOM) === null && Tools.getProperty(axesOptions, AxisPositions.TOP) !== null) || Tools.getProperty(axesOptions, AxisPositions.TOP, 'main') === true || (dualAxes && Tools.getProperty(axesOptions, AxisPositions.BOTTOM, 'correspondingDatasets'))) { return { primary: AxisPositions.TOP, secondary: AxisPositions.BOTTOM, }; } return { primary: AxisPositions.BOTTOM, secondary: AxisPositions.TOP }; }; CartesianScales.prototype.findDomainAndRangeAxesPositions = function (verticalAxesPositions, horizontalAxesPositions) { var options = this.model.getOptions(); var mainVerticalAxisOptions = Tools.getProperty(options, 'axes', verticalAxesPositions.primary); var mainHorizontalAxisOptions = Tools.getProperty(options, 'axes', horizontalAxesPositions.primary); var mainVerticalScaleType = mainVerticalAxisOptions.scaleType || ScaleTypes.LINEAR; var mainHorizontalScaleType = mainHorizontalAxisOptions.scaleType || ScaleTypes.LINEAR; var result = { primaryDomainAxisPosition: null, secondaryDomainAxisPosition: null, primaryRangeAxisPosition: null, secondaryRangeAxisPosition: null, }; // assign to to be a vertical chart by default result.primaryDomainAxisPosition = horizontalAxesPositions.primary; result.primaryRangeAxisPosition = verticalAxesPositions.primary; // secondary axes result.secondaryDomainAxisPosition = horizontalAxesPositions.secondary; result.secondaryRangeAxisPosition = verticalAxesPositions.secondary; // if neither the horizontal axes are label or time // and atleast one of the main vertical ones are labels or time then it should be horizontal if ((!(mainHorizontalScaleType === ScaleTypes.LABELS || mainHorizontalScaleType === ScaleTypes.TIME) && mainVerticalScaleType === ScaleTypes.LABELS) || mainVerticalScaleType === ScaleTypes.TIME) { result.primaryDomainAxisPosition = verticalAxesPositions.primary; result.primaryRangeAxisPosition = horizontalAxesPositions.primary; // secondary axes result.secondaryDomainAxisPosition = verticalAxesPositions.secondary; result.secondaryRangeAxisPosition = horizontalAxesPositions.secondary; } return result; }; CartesianScales.prototype.getScaleDomain = function (axisPosition) { var options = this.model.getOptions(); var axisOptions = Tools.getProperty(options, 'axes', axisPosition); var bounds = Tools.getProperty(options, 'bounds'); var includeZero = axisOptions.includeZero; var scaleType = Tools.getProperty(axisOptions, 'scaleType') || ScaleTypes.LINEAR; if (this.model.isDataEmpty()) { return []; } var displayData = this.model.getDisplayData(); var mapsTo = axisOptions.mapsTo, percentage = axisOptions.percentage; // If domain is specified return that domain if (axisOptions.domain) { if (scaleType === ScaleTypes.LABELS) { return axisOptions.domain; } else if (scaleType === ScaleTypes.TIME) { axisOptions.domain = axisOptions.domain.map(function (d) { return d.getTime === undefined ? new Date(d) : d; }); } return this.extendsDomain(axisPosition, axisOptions.domain); } // Return [0, 100] for percentage axis scale if (percentage) { return [0, 100]; } // If scale is a LABELS scale, return some labels as the domain if (axisOptions && scaleType === ScaleTypes.LABELS) { // Get unique values return map(displayData, function (d) { return d[mapsTo]; }).keys(); } // Get the extent of the domain var domain; var allDataValues; var dataGroupNames = this.model.getDataGroupNames(); if (scaleType === ScaleTypes.TIME) { allDataValues = displayData.map(function (datum) { return +new Date(datum[mapsTo]); }); } else if (bounds && options.axes) { allDataValues = []; displayData.forEach(function (datum) { allDataValues.push(datum[mapsTo]); if (datum[bounds.upperBoundMapsTo]) { allDataValues.push(datum[bounds.upperBoundMapsTo]); } if (datum[bounds.lowerBoundMapsTo]) { allDataValues.push(datum[bounds.lowerBoundMapsTo]); } }); } else if (axisOptions.stacked === true && dataGroupNames && axisPosition === this.getRangeAxisPosition()) { var groupMapsTo_1 = options.data.groupMapsTo; var dataValuesGroupedByKeys = this.model.getDataValuesGroupedByKeys(dataGroupNames); var nonStackedGroupsData = displayData.filter(function (datum) { return !dataGroupNames.includes(datum[groupMapsTo_1]); }); var stackedValues = dataValuesGroupedByKeys.map(function (dataValues) { var sharedStackKey = dataValues.sharedStackKey, numericalValues = __rest(dataValues, ["sharedStackKey"]); return sum(values(numericalValues)); }); allDataValues = __spreadArrays(stackedValues, nonStackedGroupsData.map(function (datum) { return datum[mapsTo]; })); } else { allDataValues = displayData.map(function (datum) { return datum[mapsTo]; }); } if (scaleType !== ScaleTypes.TIME && includeZero) { allDataValues.push(0); } domain = extent(allDataValues); domain = this.extendsDomain(axisPosition, domain); return domain; }; CartesianScales.prototype.createScale = function (axisPosition) { var options = this.model.getOptions(); var axisOptions = Tools.getProperty(options, 'axes', axisPosition); if (!axisOptions) { return null; } var scaleType = Tools.getProperty(axisOptions, 'scaleType') || ScaleTypes.LINEAR; this.scaleTypes[axisPosition] = scaleType; var scale; if (scaleType === ScaleTypes.TIME) { scale = scaleTime(); } else if (scaleType === ScaleTypes.LOG) { scale = scaleLog().base(axisOptions.base || 10); } else if (scaleType === ScaleTypes.LABELS) { scale = scaleBand(); } else { scale = scaleLinear(); } scale.domain(this.getScaleDomain(axisPosition)); return scale; }; CartesianScales.prototype.getHighestDomainThreshold = function () { var axesOptions = Tools.getProperty(this.model.getOptions(), 'axes'); var domainAxisPosition = this.getDomainAxisPosition(); var thresholds = axesOptions[domainAxisPosition].thresholds; if (!thresholds) { return null; } var domainScale = this.getDomainScale(); // Find the highest threshold for the domain var highestThreshold = thresholds.sort(function (a, b) { return b.value - a.value; })[0]; var scaleType = this.getScaleTypeByPosition(domainAxisPosition); if (scaleType === ScaleTypes.TIME && (typeof highestThreshold.value === 'string' || highestThreshold.value.getTime === undefined)) { highestThreshold.value = new Date(highestThreshold.value); } return { threshold: highestThreshold, scaleValue: domainScale(highestThreshold.value), }; }; CartesianScales.prototype.getHighestRangeThreshold = function () { var axesOptions = Tools.getProperty(this.model.getOptions(), 'axes'); var rangeAxisPosition = this.getRangeAxisPosition(); var thresholds = axesOptions[rangeAxisPosition].thresholds; if (!thresholds) { return null; } var rangeScale = this.getRangeScale(); // Find the highest threshold for the range var highestThreshold = thresholds.sort(function (a, b) { return b.value - a.value; })[0]; return { threshold: highestThreshold, scaleValue: rangeScale(highestThreshold.value), }; }; return CartesianScales; }(Service)); export { CartesianScales }; function addSpacingToTimeDomain(domain, spaceToAddToEdges) { var startDate = new Date(domain[0]); var endDate = new Date(domain[1]); if (differenceInYears(endDate, startDate) > 1) { return [ subYears(startDate, spaceToAddToEdges), addYears(endDate, spaceToAddToEdges), ]; } if (differenceInMonths(endDate, startDate) > 1) { return [ subMonths(startDate, spaceToAddToEdges), addMonths(endDate, spaceToAddToEdges), ]; } if (differenceInDays(endDate, startDate) > 1) { return [ subDays(startDate, spaceToAddToEdges), addDays(endDate, spaceToAddToEdges), ]; } if (differenceInHours(endDate, startDate) > 1) { return [ subHours(startDate, spaceToAddToEdges), addHours(endDate, spaceToAddToEdges), ]; } if (differenceInMinutes(endDate, startDate) > 30) { return [ subMinutes(startDate, spaceToAddToEdges * 30), addMinutes(endDate, spaceToAddToEdges * 30), ]; } if (differenceInMinutes(endDate, startDate) > 1) { return [ subMinutes(startDate, spaceToAddToEdges), addMinutes(endDate, spaceToAddToEdges), ]; } if (differenceInSeconds(endDate, startDate) > 15) { return [ subSeconds(startDate, spaceToAddToEdges * 15), addSeconds(endDate, spaceToAddToEdges * 15), ]; } if (differenceInSeconds(endDate, startDate) > 1) { return [ subSeconds(startDate, spaceToAddToEdges), addSeconds(endDate, spaceToAddToEdges), ]; } return [startDate, endDate]; } function addSpacingToContinuousDomain(_a, paddingRatio) { var lower = _a[0], upper = _a[1]; var domainLength = upper - lower; var padding = domainLength * paddingRatio; // If padding crosses 0, keep 0 as new upper bound var newUpper = upper <= 0 && upper + padding > 0 ? 0 : upper + padding; // If padding crosses 0, keep 0 as new lower bound var newLower = lower >= 0 && lower - padding < 0 ? 0 : lower - padding; return [newLower, newUpper]; } //# sourceMappingURL=../../src/services/scales-cartesian.js.map