UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

644 lines (625 loc) • 24.2 kB
/** * DevExtreme (viz/core/utils.js) * Version: 20.1.7 * Build date: Tue Aug 25 2020 * * Copyright (c) 2012 - 2020 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var _common = require("../../core/utils/common"); var _type = require("../../core/utils/type"); var _extend = require("../../core/utils/extend"); var _iterator = require("../../core/utils/iterator"); var _math = require("../../core/utils/math"); var _date = require("../../core/utils/date"); var _dom_adapter = require("../../core/dom_adapter"); var _dom_adapter2 = _interopRequireDefault(_dom_adapter); var _color = require("../../color"); var _color2 = _interopRequireDefault(_color); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } var PI = Math.PI, LN10 = Math.LN10, abs = Math.abs, log = Math.log, floor = Math.floor, ceil = Math.ceil, pow = Math.pow, sqrt = Math.sqrt, atan2 = Math.atan2; var _min = Math.min; var _max = Math.max; var _cos = Math.cos; var _sin = Math.sin; var _round = Math.round; var MAX_PIXEL_COUNT = 1e10; var PI_DIV_180 = PI / 180; var _isNaN = isNaN; var _Number = Number; var _NaN = NaN; var PANE_PADDING = 10; var getLog = function(value, base) { if (!value) { return _NaN } return log(value) / log(base) }; var getAdjustedLog10 = function(value) { return (0, _math.adjust)(getLog(value, 10)) }; var raiseTo = function(power, base) { return pow(base, power) }; var normalizeAngle = function(angle) { return (angle % 360 + 360) % 360 }; var convertAngleToRendererSpace = function(angle) { return 90 - angle }; var degreesToRadians = function(value) { return PI * value / 180 }; var getCosAndSin = function(angle) { var angleInRadians = degreesToRadians(angle); return { cos: _cos(angleInRadians), sin: _sin(angleInRadians) } }; var DECIMAL_ORDER_THRESHOLD = 1e-14; var getDistance = function(x1, y1, x2, y2) { var diffX = x2 - x1; var diffY = y2 - y1; return sqrt(diffY * diffY + diffX * diffX) }; var getDecimalOrder = function(number) { var n = abs(number); var cn; if (!_isNaN(n)) { if (n > 0) { n = log(n) / LN10; cn = ceil(n); return cn - n < DECIMAL_ORDER_THRESHOLD ? cn : floor(n) } return 0 } return _NaN }; var getAppropriateFormat = function(start, end, count) { var order = _max(getDecimalOrder(start), getDecimalOrder(end)); var precision = -getDecimalOrder(abs(end - start) / count); var format; if (!_isNaN(order) && !_isNaN(precision)) { if (abs(order) <= 4) { format = "fixedPoint"; precision < 0 && (precision = 0); precision > 4 && (precision = 4) } else { format = "exponential"; precision += order - 1; precision > 3 && (precision = 3) } return { type: format, precision: precision } } return null }; var roundValue = function(value, precision) { if (precision > 20) { precision = 20 } if ((0, _type.isNumeric)(value)) { if ((0, _type.isExponential)(value)) { return _Number(value.toExponential(precision)) } else { return _Number(value.toFixed(precision)) } } }; var getPower = function(value) { return value.toExponential().split("e")[1] }; function map(array, callback) { var i = 0; var len = array.length; var result = []; var value; while (i < len) { value = callback(array[i], i); if (null !== value) { result.push(value) } i++ } return result } function selectByKeys(object, keys) { return map(keys, function(key) { return object[key] ? object[key] : null }) } function decreaseFields(object, keys, eachDecrease, decrease) { var dec = decrease; (0, _iterator.each)(keys, function(_, key) { if (object[key]) { object[key] -= eachDecrease; dec -= eachDecrease } }); return dec } function normalizeEnum(value) { return String(value).toLowerCase() } function setCanvasValues(canvas) { if (canvas) { canvas.originalTop = canvas.top; canvas.originalBottom = canvas.bottom; canvas.originalLeft = canvas.left; canvas.originalRight = canvas.right } return canvas } function normalizeBBoxField(value) { return -MAX_PIXEL_COUNT < value && value < +MAX_PIXEL_COUNT ? value : 0 } function normalizeBBox(bBox) { var xl = normalizeBBoxField(floor(bBox.x)); var yt = normalizeBBoxField(floor(bBox.y)); var xr = normalizeBBoxField(ceil(bBox.width + bBox.x)); var yb = normalizeBBoxField(ceil(bBox.height + bBox.y)); var result = { x: xl, y: yt, width: xr - xl, height: yb - yt }; result.isEmpty = !result.x && !result.y && !result.width && !result.height; return result } function rotateBBox(bBox, center, angle) { var cos = _Number(_cos(angle * PI_DIV_180).toFixed(3)); var sin = _Number(_sin(angle * PI_DIV_180).toFixed(3)); var w2 = bBox.width / 2; var h2 = bBox.height / 2; var centerX = bBox.x + w2; var centerY = bBox.y + h2; var w2_ = abs(w2 * cos) + abs(h2 * sin); var h2_ = abs(w2 * sin) + abs(h2 * cos); var centerX_ = center[0] + (centerX - center[0]) * cos + (centerY - center[1]) * sin; var centerY_ = center[1] - (centerX - center[0]) * sin + (centerY - center[1]) * cos; return normalizeBBox({ x: centerX_ - w2_, y: centerY_ - h2_, width: 2 * w2_, height: 2 * h2_ }) }(0, _extend.extend)(exports, { decreaseGaps: function(object, keys, decrease) { var arrayGaps; do { arrayGaps = selectByKeys(object, keys); arrayGaps.push(ceil(decrease / arrayGaps.length)); decrease = decreaseFields(object, keys, _min.apply(null, arrayGaps), decrease) } while (decrease > 0 && arrayGaps.length > 1); return decrease }, normalizeEnum: normalizeEnum, parseScalar: function(value, defaultValue) { return void 0 !== value ? value : defaultValue }, enumParser: function(values) { var stored = {}; var i; var ii; for (i = 0, ii = values.length; i < ii; ++i) { stored[normalizeEnum(values[i])] = 1 } return function(value, defaultValue) { var _value = normalizeEnum(value); return stored[_value] ? _value : defaultValue } }, patchFontOptions: function(options) { var fontOptions = {}; (0, _iterator.each)(options || {}, function(key, value) { if (/^(cursor)$/i.test(key)) {} else { if ("opacity" === key) { value = null } else { if ("color" === key) { key = "fill"; if ("opacity" in options) { var color = new _color2.default(value); value = "rgba(".concat(color.r, ",").concat(color.g, ",").concat(color.b, ",").concat(options.opacity, ")") } } else { key = "font-" + key } } } fontOptions[key] = value }); return fontOptions }, checkElementHasPropertyFromStyleSheet: function(element, property) { var slice = Array.prototype.slice; var cssRules = slice.call(_dom_adapter2.default.getDocument().styleSheets).reduce(function(rules, styleSheet) { return rules.concat(slice.call(styleSheet.cssRules || styleSheet.rules)) }, []); var elementRules = cssRules.filter(function(rule) { try { return _dom_adapter2.default.elementMatches(element, rule.selectorText) } catch (e) { return false } }); return elementRules.some(function(rule) { return !!rule.style[property] }) }, convertPolarToXY: function(centerCoords, startAngle, angle, radius) { var shiftAngle = 90; var normalizedRadius = radius > 0 ? radius : 0; angle = (0, _type.isDefined)(angle) ? angle + startAngle - shiftAngle : 0; var cosSin = getCosAndSin(angle); return { x: _round(centerCoords.x + normalizedRadius * cosSin.cos), y: _round(centerCoords.y + normalizedRadius * cosSin.sin) } }, convertXYToPolar: function(centerCoords, x, y) { var radius = getDistance(centerCoords.x, centerCoords.y, x, y); var angle = atan2(y - centerCoords.y, x - centerCoords.x); return { phi: _round(normalizeAngle(180 * angle / PI)), r: _round(radius) } }, processSeriesTemplate: function(seriesTemplate, items) { var customizeSeries = (0, _type.isFunction)(seriesTemplate.customizeSeries) ? seriesTemplate.customizeSeries : _common.noop; var nameField = seriesTemplate.nameField; var generatedSeries = {}; var seriesOrder = []; var series; var i = 0; var length; var data; items = items || []; for (length = items.length; i < length; i++) { data = items[i]; if (nameField in data) { series = generatedSeries[data[nameField]]; if (!series) { series = generatedSeries[data[nameField]] = { name: data[nameField], nameFieldValue: data[nameField] }; seriesOrder.push(series.name) } } } return map(seriesOrder, function(orderedName) { var group = generatedSeries[orderedName]; return (0, _extend.extend)(group, customizeSeries.call(null, group.name)) }) }, getCategoriesInfo: function(categories, startValue, endValue) { if (0 === categories.length) { return { categories: [] } } startValue = (0, _type.isDefined)(startValue) ? startValue : categories[0]; endValue = (0, _type.isDefined)(endValue) ? endValue : categories[categories.length - 1]; var categoriesValue = map(categories, function(category) { return null === category || void 0 === category ? void 0 : category.valueOf() }); var indexStartValue = categoriesValue.indexOf(startValue.valueOf()); var indexEndValue = categoriesValue.indexOf(endValue.valueOf()); var swapBuf; var inverted = false; indexStartValue < 0 && (indexStartValue = 0); indexEndValue < 0 && (indexEndValue = categories.length - 1); if (indexEndValue < indexStartValue) { swapBuf = indexEndValue; indexEndValue = indexStartValue; indexStartValue = swapBuf; inverted = true } var visibleCategories = categories.slice(indexStartValue, indexEndValue + 1); var lastIdx = visibleCategories.length - 1; return { categories: visibleCategories, start: visibleCategories[inverted ? lastIdx : 0], end: visibleCategories[inverted ? 0 : lastIdx], inverted: inverted } }, setCanvasValues: setCanvasValues, normalizePanesHeight: function(panes) { panes.forEach(function(pane) { var height = pane.height; var unit = 0; var parsedHeight = parseFloat(height) || void 0; if ((0, _type.isString)(height) && height.indexOf("px") > -1 || (0, _type.isNumeric)(height) && height > 1) { parsedHeight = _round(parsedHeight); unit = 1 } if (!unit && parsedHeight) { if ((0, _type.isString)(height) && height.indexOf("%") > -1) { parsedHeight /= 100 } else { if (parsedHeight < 0) { parsedHeight = parsedHeight < -1 ? 1 : abs(parsedHeight) } } } pane.height = parsedHeight; pane.unit = unit }); var weightSum = panes.filter(function(pane) { return !pane.unit }).reduce(function(prev, next) { return prev + (next.height || 0) }, 0); var weightHeightCount = panes.filter(function(pane) { return !pane.unit }).length; var emptyHeightCount = panes.filter(function(pane) { return !pane.unit && !pane.height }).length; if (weightSum < 1 && emptyHeightCount) { panes.filter(function(pane) { return !pane.unit && !pane.height }).forEach(function(pane) { return pane.height = (1 - weightSum) / emptyHeightCount }) } else { if (weightSum > 1 || weightSum < 1 && !emptyHeightCount || 1 === weightSum && emptyHeightCount) { if (emptyHeightCount) { var weightForEmpty = weightSum / weightHeightCount; var emptyWeightSum = emptyHeightCount * weightForEmpty; panes.filter(function(pane) { return !pane.unit && pane.height }).forEach(function(pane) { return pane.height *= (weightSum - emptyWeightSum) / weightSum }); panes.filter(function(pane) { return !pane.unit && !pane.height }).forEach(function(pane) { return pane.height = weightForEmpty }) } panes.forEach(function(pane) { return !pane.unit && (pane.height *= 1 / weightSum) }) } } }, updatePanesCanvases: function(panes, canvas, rotated) { var distributedSpace = 0; var padding = PANE_PADDING; var paneSpace = rotated ? canvas.width - canvas.left - canvas.right : canvas.height - canvas.top - canvas.bottom; var usefulSpace = paneSpace - padding * (panes.length - 1); var startName = rotated ? "left" : "top"; var endName = rotated ? "right" : "bottom"; var totalCustomSpace = panes.reduce(function(prev, cur) { return prev + (cur.unit ? cur.height : 0) }, 0); usefulSpace -= totalCustomSpace; panes.forEach(function(pane) { var calcLength = pane.unit ? pane.height : _round(pane.height * usefulSpace); pane.canvas = pane.canvas || {}; (0, _extend.extend)(pane.canvas, canvas); pane.canvas[startName] = canvas[startName] + distributedSpace; pane.canvas[endName] = canvas[endName] + (paneSpace - calcLength - distributedSpace); distributedSpace = distributedSpace + calcLength + padding; setCanvasValues(pane.canvas) }) }, unique: function(array) { var values = {}; return map(array, function(item) { var result = !values[item] ? item : null; values[item] = true; return result }) }, map: map, getVerticallyShiftedAngularCoords: function(bBox, dy, center) { var isPositive = bBox.x + bBox.width / 2 >= center.x; var horizontalOffset1 = (isPositive ? bBox.x : bBox.x + bBox.width) - center.x; var verticalOffset1 = bBox.y - center.y; var verticalOffset2 = verticalOffset1 + dy; var horizontalOffset2 = _round(sqrt(horizontalOffset1 * horizontalOffset1 + verticalOffset1 * verticalOffset1 - verticalOffset2 * verticalOffset2)); var dx = (isPositive ? +horizontalOffset2 : -horizontalOffset2) || horizontalOffset1; return { x: center.x + (isPositive ? dx : dx - bBox.width), y: bBox.y + dy } }, mergeMarginOptions: function(opt1, opt2) { return { checkInterval: opt1.checkInterval || opt2.checkInterval, size: _max(opt1.size || 0, opt2.size || 0), percentStick: opt1.percentStick || opt2.percentStick, sizePointNormalState: _max(opt1.sizePointNormalState || 0, opt2.sizePointNormalState || 0) } } }); function getVizRangeObject(value) { if (Array.isArray(value)) { return { startValue: value[0], endValue: value[1] } } else { return value || {} } } function convertVisualRangeObject(visualRange, convertToVisualRange) { if (convertToVisualRange) { return visualRange } return [visualRange.startValue, visualRange.endValue] } function getAddFunction(range, correctZeroLevel) { if ("datetime" === range.dataType) { return function(rangeValue, marginValue) { var sign = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1; return new Date(rangeValue.getTime() + sign * marginValue) } } if ("logarithmic" === range.axisType) { return function(rangeValue, marginValue) { var sign = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1; var log = getLogExt(rangeValue, range.base) + sign * marginValue; return raiseToExt(log, range.base) } } return function(rangeValue, marginValue) { var sign = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1; var newValue = rangeValue + sign * marginValue; return correctZeroLevel && newValue * rangeValue <= 0 ? 0 : newValue } } function adjustVisualRange(options, visualRange, wholeRange, dataRange) { var minDefined = (0, _type.isDefined)(visualRange.startValue); var maxDefined = (0, _type.isDefined)(visualRange.endValue); var nonDiscrete = "discrete" !== options.axisType; dataRange = dataRange || wholeRange; var add = getAddFunction(options, false); var min = minDefined ? visualRange.startValue : dataRange.min; var max = maxDefined ? visualRange.endValue : dataRange.max; var rangeLength = visualRange.length; var categories = dataRange.categories; if (nonDiscrete && !(0, _type.isDefined)(min) && !(0, _type.isDefined)(max)) { return { startValue: min, endValue: max } } if ((0, _type.isDefined)(rangeLength)) { if (nonDiscrete) { if ("datetime" === options.dataType && !(0, _type.isNumeric)(rangeLength)) { rangeLength = (0, _date.dateToMilliseconds)(rangeLength) } if (maxDefined && !minDefined || !maxDefined && !minDefined) { (0, _type.isDefined)(wholeRange.max) && (max = max > wholeRange.max ? wholeRange.max : max); min = add(max, rangeLength, -1) } else { if (minDefined && !maxDefined) { (0, _type.isDefined)(wholeRange.min) && (min = min < wholeRange.min ? wholeRange.min : min); max = add(min, rangeLength) } } } else { rangeLength = parseInt(rangeLength); if (!isNaN(rangeLength) && isFinite(rangeLength)) { rangeLength--; if (!maxDefined && !minDefined) { max = categories[categories.length - 1]; min = categories[categories.length - 1 - rangeLength] } else { if (minDefined && !maxDefined) { var categoriesInfo = exports.getCategoriesInfo(categories, min, void 0); max = categoriesInfo.categories[rangeLength] } else { if (!minDefined && maxDefined) { var _categoriesInfo = exports.getCategoriesInfo(categories, void 0, max); min = _categoriesInfo.categories[_categoriesInfo.categories.length - 1 - rangeLength] } } } } } } if (nonDiscrete) { if ((0, _type.isDefined)(wholeRange.max) && max > wholeRange.max) { max = wholeRange.max } if ((0, _type.isDefined)(wholeRange.min) && min < wholeRange.min) { min = wholeRange.min } } return { startValue: min, endValue: max } } function getLogExt(value, base) { var allowNegatives = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : false; var linearThreshold = arguments.length > 3 ? arguments[3] : void 0; if (!allowNegatives) { return getLog(value, base) } if (0 === value) { return 0 } var transformValue = getLog(abs(value), base) - (linearThreshold - 1); if (transformValue < 0) { return 0 } return (0, _math.adjust)((0, _math.sign)(value) * transformValue, Number(pow(base, linearThreshold - 1).toFixed(abs(linearThreshold)))) } function raiseToExt(value, base) { var allowNegatives = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : false; var linearThreshold = arguments.length > 3 ? arguments[3] : void 0; if (!allowNegatives) { return raiseTo(value, base) } if (0 === value) { return 0 } var transformValue = raiseTo(abs(value) + (linearThreshold - 1), base); if (transformValue < 0) { return 0 } return (0, _math.adjust)((0, _math.sign)(value) * transformValue, Number(pow(base, linearThreshold).toFixed(abs(linearThreshold)))) } function rangesAreEqual(range, rangeFromOptions) { if (Array.isArray(rangeFromOptions)) { return range.length === rangeFromOptions.length && range.every(function(item, i) { return valueOf(item) === valueOf(rangeFromOptions[i]) }) } else { return valueOf(range.startValue) === valueOf(rangeFromOptions.startValue) && valueOf(range.endValue) === valueOf(rangeFromOptions.endValue) } } function valueOf(value) { return value && value.valueOf() } function pointInCanvas(canvas, x, y) { return x >= canvas.left && x <= canvas.right && y >= canvas.top && y <= canvas.bottom } exports.getVizRangeObject = getVizRangeObject; exports.convertVisualRangeObject = convertVisualRangeObject; exports.adjustVisualRange = adjustVisualRange; exports.getAddFunction = getAddFunction; exports.getLog = getLog; exports.getLogExt = getLogExt; exports.getAdjustedLog10 = getAdjustedLog10; exports.raiseTo = raiseTo; exports.raiseToExt = raiseToExt; exports.normalizeAngle = normalizeAngle; exports.convertAngleToRendererSpace = convertAngleToRendererSpace; exports.degreesToRadians = degreesToRadians; exports.getCosAndSin = getCosAndSin; exports.getDecimalOrder = getDecimalOrder; exports.getAppropriateFormat = getAppropriateFormat; exports.getDistance = getDistance; exports.roundValue = roundValue; exports.getPower = getPower; exports.valueOf = valueOf; exports.rotateBBox = rotateBBox; exports.normalizeBBox = normalizeBBox; exports.PANE_PADDING = PANE_PADDING; exports.rangesAreEqual = rangesAreEqual; exports.pointInCanvas = pointInCanvas;