| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- /**
- * DevExtreme (viz/translators/translator2d.js)
- * Version: 19.1.16
- * Build date: Tue Oct 18 2022
- *
- * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
- * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
- */
- "use strict";
- var extend = require("../../core/utils/extend").extend;
- var each = require("../../core/utils/iterator").each;
- var Range = require("./range").Range;
- var categoryTranslator = require("./category_translator");
- var intervalTranslator = require("./interval_translator");
- var datetimeTranslator = require("./datetime_translator");
- var logarithmicTranslator = require("./logarithmic_translator");
- var vizUtils = require("../core/utils");
- var typeUtils = require("../../core/utils/type");
- var getLog = vizUtils.getLog;
- var getPower = vizUtils.getPower;
- var isDefined = typeUtils.isDefined;
- var adjust = require("../../core/utils/math").adjust;
- var _abs = Math.abs;
- var CANVAS_PROP = ["width", "height", "left", "top", "bottom", "right"];
- var _Translator2d;
- var addInterval = require("../../core/utils/date").addInterval;
- var dummyTranslator = {
- to: function(value) {
- var coord = this._canvasOptions.startPoint + (this._options.conversionValue ? value : Math.round(value));
- return coord > this._canvasOptions.endPoint ? this._canvasOptions.endPoint : coord
- },
- from: function(value) {
- return value - this._canvasOptions.startPoint
- }
- };
- var validateCanvas = function(canvas) {
- each(CANVAS_PROP, function(_, prop) {
- canvas[prop] = parseInt(canvas[prop]) || 0
- });
- return canvas
- };
- var makeCategoriesToPoints = function(categories) {
- var categoriesToPoints = {};
- categories.forEach(function(item, i) {
- categoriesToPoints[item.valueOf()] = i
- });
- return categoriesToPoints
- };
- var validateBusinessRange = function(businessRange) {
- if (!(businessRange instanceof Range)) {
- businessRange = new Range(businessRange)
- }
- function validate(valueSelector, baseValueSelector) {
- if (!isDefined(businessRange[valueSelector]) && isDefined(businessRange[baseValueSelector])) {
- businessRange[valueSelector] = businessRange[baseValueSelector]
- }
- }
- validate("minVisible", "min");
- validate("maxVisible", "max");
- return businessRange
- };
- function prepareBreaks(breaks, range) {
- var transform = "logarithmic" === range.axisType ? function(value) {
- return getLog(value, range.base)
- } : function(value) {
- return value
- };
- var array = [];
- var br;
- var transformFrom;
- var transformTo;
- var i;
- var length = breaks.length;
- var sum = 0;
- for (i = 0; i < length; i++) {
- br = breaks[i];
- transformFrom = transform(br.from);
- transformTo = transform(br.to);
- sum += transformTo - transformFrom;
- array.push({
- trFrom: transformFrom,
- trTo: transformTo,
- from: br.from,
- to: br.to,
- length: sum,
- cumulativeWidth: br.cumulativeWidth
- })
- }
- return array
- }
- function getCanvasBounds(range) {
- var min = range.min;
- var max = range.max;
- var minVisible = range.minVisible;
- var maxVisible = range.maxVisible;
- var isLogarithmic = "logarithmic" === range.axisType;
- if (isLogarithmic) {
- maxVisible = getLog(maxVisible, range.base);
- minVisible = getLog(minVisible, range.base);
- min = getLog(min, range.base);
- max = getLog(max, range.base)
- }
- return {
- base: range.base,
- rangeMin: min,
- rangeMax: max,
- rangeMinVisible: minVisible,
- rangeMaxVisible: maxVisible
- }
- }
- function getCheckingMethodsAboutBreaks(inverted) {
- return {
- isStartSide: !inverted ? function(pos, breaks, start, end) {
- return pos < breaks[0][start]
- } : function(pos, breaks, start, end) {
- return pos <= breaks[breaks.length - 1][end]
- },
- isEndSide: !inverted ? function(pos, breaks, start, end) {
- return pos >= breaks[breaks.length - 1][end]
- } : function(pos, breaks, start, end) {
- return pos > breaks[0][start]
- },
- isInBreak: !inverted ? function(pos, br, start, end) {
- return pos >= br[start] && pos < br[end]
- } : function(pos, br, start, end) {
- return pos > br[end] && pos <= br[start]
- },
- isBetweenBreaks: !inverted ? function(pos, br, prevBreak, start, end) {
- return pos < br[start] && pos >= prevBreak[end]
- } : function(pos, br, prevBreak, start, end) {
- return pos >= br[end] && pos < prevBreak[start]
- },
- getLength: !inverted ? function(br) {
- return br.length
- } : function(br, lastBreak) {
- return lastBreak.length - br.length
- },
- getBreaksSize: !inverted ? function(br) {
- return br.cumulativeWidth
- } : function(br, lastBreak) {
- return lastBreak.cumulativeWidth - br.cumulativeWidth
- }
- }
- }
- exports.Translator2D = _Translator2d = function(businessRange, canvas, options) {
- this.update(businessRange, canvas, options)
- };
- _Translator2d.prototype = {
- constructor: _Translator2d,
- reinit: function() {
- var that = this;
- var options = that._options;
- var range = that._businessRange;
- var categories = range.categories || [];
- var script = {};
- var canvasOptions = that._prepareCanvasOptions();
- var visibleCategories = vizUtils.getCategoriesInfo(categories, range.minVisible, range.maxVisible).categories;
- var categoriesLength = visibleCategories.length;
- if (range.isEmpty()) {
- script = dummyTranslator
- } else {
- switch (range.axisType) {
- case "logarithmic":
- script = logarithmicTranslator;
- break;
- case "semidiscrete":
- script = intervalTranslator;
- canvasOptions.ratioOfCanvasRange = canvasOptions.canvasLength / (addInterval(canvasOptions.rangeMaxVisible, options.interval) - canvasOptions.rangeMinVisible);
- break;
- case "discrete":
- script = categoryTranslator;
- that._categories = categories;
- canvasOptions.interval = that._getDiscreteInterval(options.addSpiderCategory ? categoriesLength + 1 : categoriesLength, canvasOptions);
- that._categoriesToPoints = makeCategoriesToPoints(categories, canvasOptions.invert);
- if (categoriesLength) {
- canvasOptions.startPointIndex = that._categoriesToPoints[visibleCategories[0].valueOf()];
- that.visibleCategories = visibleCategories
- }
- break;
- default:
- if ("datetime" === range.dataType) {
- script = datetimeTranslator
- }
- }
- }(that._oldMethods || []).forEach(function(methodName) {
- delete that[methodName]
- });
- that._oldMethods = Object.keys(script);
- extend(that, script);
- that._conversionValue = options.conversionValue ? function(value) {
- return value
- } : function(value) {
- return Math.round(value)
- };
- that.sc = {};
- that._checkingMethodsAboutBreaks = [getCheckingMethodsAboutBreaks(false), getCheckingMethodsAboutBreaks(that.isInverted())];
- that._translateBreaks();
- that._calculateSpecialValues()
- },
- _translateBreaks: function() {
- var breaks = this._breaks;
- var size = this._options.breaksSize;
- var i;
- var b;
- var end;
- var length;
- if (void 0 === breaks) {
- return
- }
- for (i = 0, length = breaks.length; i < length; i++) {
- b = breaks[i];
- end = this.translate(b.to);
- b.end = end;
- b.start = !b.gapSize ? !this.isInverted() ? end - size : end + size : end
- }
- },
- _checkValueAboutBreaks: function(breaks, pos, start, end, methods) {
- var i;
- var length;
- var prop = {
- length: 0,
- breaksSize: void 0,
- inBreak: false
- };
- var br;
- var prevBreak;
- var lastBreak = breaks[breaks.length - 1];
- if (methods.isStartSide(pos, breaks, start, end)) {
- return prop
- } else {
- if (methods.isEndSide(pos, breaks, start, end)) {
- return {
- length: lastBreak.length,
- breaksSize: lastBreak.cumulativeWidth,
- inBreak: false
- }
- }
- }
- for (i = 0, length = breaks.length; i < length; i++) {
- br = breaks[i];
- prevBreak = breaks[i - 1];
- if (methods.isInBreak(pos, br, start, end)) {
- prop.inBreak = true;
- prop.break = br;
- break
- }
- if (prevBreak && methods.isBetweenBreaks(pos, br, prevBreak, start, end)) {
- prop = {
- length: methods.getLength(prevBreak, lastBreak),
- breaksSize: methods.getBreaksSize(prevBreak, lastBreak),
- inBreak: false
- };
- break
- }
- }
- return prop
- },
- isInverted: function() {
- return !(this._options.isHorizontal ^ this._businessRange.invert)
- },
- _getDiscreteInterval: function(categoriesLength, canvasOptions) {
- var correctedCategoriesCount = categoriesLength - (this._options.stick ? 1 : 0);
- return correctedCategoriesCount > 0 ? canvasOptions.canvasLength / correctedCategoriesCount : canvasOptions.canvasLength
- },
- _prepareCanvasOptions: function() {
- var that = this;
- var businessRange = that._businessRange;
- var canvasOptions = that._canvasOptions = getCanvasBounds(businessRange);
- var canvas = that._canvas;
- var breaks = that._breaks;
- var length;
- canvasOptions.startPadding = canvas.startPadding || 0;
- canvasOptions.endPadding = canvas.endPadding || 0;
- if (that._options.isHorizontal) {
- canvasOptions.startPoint = canvas.left + canvasOptions.startPadding;
- length = canvas.width;
- canvasOptions.endPoint = canvas.width - canvas.right - canvasOptions.endPadding;
- canvasOptions.invert = businessRange.invert
- } else {
- canvasOptions.startPoint = canvas.top + canvasOptions.startPadding;
- length = canvas.height;
- canvasOptions.endPoint = canvas.height - canvas.bottom - canvasOptions.endPadding;
- canvasOptions.invert = !businessRange.invert
- }
- that.canvasLength = canvasOptions.canvasLength = canvasOptions.endPoint - canvasOptions.startPoint;
- canvasOptions.rangeDoubleError = Math.pow(10, getPower(canvasOptions.rangeMax - canvasOptions.rangeMin) - getPower(length) - 2);
- canvasOptions.ratioOfCanvasRange = canvasOptions.canvasLength / (canvasOptions.rangeMaxVisible - canvasOptions.rangeMinVisible);
- if (void 0 !== breaks) {
- canvasOptions.ratioOfCanvasRange = (canvasOptions.canvasLength - breaks[breaks.length - 1].cumulativeWidth) / (canvasOptions.rangeMaxVisible - canvasOptions.rangeMinVisible - breaks[breaks.length - 1].length)
- }
- return canvasOptions
- },
- updateCanvas: function(canvas) {
- this._canvas = validateCanvas(canvas);
- this.reinit()
- },
- updateBusinessRange: function(businessRange) {
- var that = this;
- var breaks = businessRange.breaks || [];
- that._businessRange = validateBusinessRange(businessRange);
- that._breaks = breaks.length ? prepareBreaks(breaks, that._businessRange) : void 0;
- that.reinit()
- },
- update: function(businessRange, canvas, options) {
- var that = this;
- that._options = extend(that._options || {}, options);
- that._canvas = validateCanvas(canvas);
- that.updateBusinessRange(businessRange)
- },
- getBusinessRange: function() {
- return this._businessRange
- },
- getEventScale: function(zoomEvent) {
- return zoomEvent.deltaScale || 1
- },
- getCanvasVisibleArea: function() {
- return {
- min: this._canvasOptions.startPoint,
- max: this._canvasOptions.endPoint
- }
- },
- _calculateSpecialValues: function() {
- var that = this;
- var canvasOptions = that._canvasOptions;
- var startPoint = canvasOptions.startPoint - canvasOptions.startPadding;
- var endPoint = canvasOptions.endPoint + canvasOptions.endPadding;
- var range = that._businessRange;
- var minVisible = range.minVisible;
- var maxVisible = range.maxVisible;
- var canvas_position_center_middle = startPoint + canvasOptions.canvasLength / 2;
- var canvas_position_default;
- if (minVisible < 0 && maxVisible > 0 && minVisible !== maxVisible) {
- canvas_position_default = that.translate(0, 1)
- }
- if (!isDefined(canvas_position_default)) {
- var invert = range.invert ^ (minVisible < 0 && maxVisible <= 0);
- if (that._options.isHorizontal) {
- canvas_position_default = invert ? endPoint : startPoint
- } else {
- canvas_position_default = invert ? startPoint : endPoint
- }
- }
- that.sc = {
- canvas_position_default: canvas_position_default,
- canvas_position_left: startPoint,
- canvas_position_top: startPoint,
- canvas_position_center: canvas_position_center_middle,
- canvas_position_middle: canvas_position_center_middle,
- canvas_position_right: endPoint,
- canvas_position_bottom: endPoint,
- canvas_position_start: canvasOptions.invert ? endPoint : startPoint,
- canvas_position_end: canvasOptions.invert ? startPoint : endPoint
- }
- },
- translateSpecialCase: function(value) {
- return this.sc[value]
- },
- _calculateProjection: function(distance) {
- var canvasOptions = this._canvasOptions;
- return canvasOptions.invert ? canvasOptions.endPoint - distance : canvasOptions.startPoint + distance
- },
- _calculateUnProjection: function(distance) {
- var canvasOptions = this._canvasOptions;
- return canvasOptions.invert ? canvasOptions.rangeMaxVisible.valueOf() - distance : canvasOptions.rangeMinVisible.valueOf() + distance
- },
- getMinBarSize: function(minBarSize) {
- var visibleArea = this.getCanvasVisibleArea();
- var minValue = this.from(visibleArea.min + minBarSize);
- return _abs(this.from(visibleArea.min) - (!isDefined(minValue) ? this.from(visibleArea.max) : minValue))
- },
- checkMinBarSize: function(value, minShownValue, stackValue) {
- return _abs(value) < minShownValue ? value >= 0 ? minShownValue : -minShownValue : value
- },
- translate: function(bp, direction) {
- var specialValue = this.translateSpecialCase(bp);
- if (isDefined(specialValue)) {
- return Math.round(specialValue)
- }
- if (isNaN(bp)) {
- return null
- }
- return this.to(bp, direction)
- },
- getInterval: function(interval) {
- var canvasOptions = this._canvasOptions;
- interval = isDefined(interval) ? interval : this._businessRange.interval;
- if (interval) {
- return Math.round(canvasOptions.ratioOfCanvasRange * interval)
- }
- return Math.round(canvasOptions.endPoint - canvasOptions.startPoint)
- },
- zoom: function(translate, scale, wholeRange) {
- var canvasOptions = this._canvasOptions;
- if (canvasOptions.rangeMinVisible.valueOf() === canvasOptions.rangeMaxVisible.valueOf() && 0 !== translate) {
- return this.zoomZeroLengthRange(translate, scale)
- }
- var startPoint = canvasOptions.startPoint;
- var endPoint = canvasOptions.endPoint;
- var isInverted = this.isInverted();
- var newStart = (startPoint + translate) / scale;
- var newEnd = (endPoint + translate) / scale;
- wholeRange = wholeRange || {};
- var minPoint = this.to(isInverted ? wholeRange.endValue : wholeRange.startValue);
- var maxPoint = this.to(isInverted ? wholeRange.startValue : wholeRange.endValue);
- var min;
- var max;
- if (minPoint > newStart) {
- newEnd -= newStart - minPoint;
- newStart = minPoint;
- min = isInverted ? wholeRange.endValue : wholeRange.startValue
- }
- if (maxPoint < newEnd) {
- newStart -= newEnd - maxPoint;
- newEnd = maxPoint;
- max = isInverted ? wholeRange.startValue : wholeRange.endValue
- }
- if (maxPoint - minPoint < newEnd - newStart) {
- newStart = minPoint;
- newEnd = maxPoint
- }
- translate = (endPoint - startPoint) * newStart / (newEnd - newStart) - startPoint;
- scale = (startPoint + translate) / newStart || 1;
- min = isDefined(min) ? min : adjust(this.from(newStart, 1));
- max = isDefined(max) ? max : adjust(this.from(newEnd, -1));
- if (min > max) {
- min = min > wholeRange.endValue ? wholeRange.endValue : min;
- max = max < wholeRange.startValue ? wholeRange.startValue : max
- } else {
- min = min < wholeRange.startValue ? wholeRange.startValue : min;
- max = max > wholeRange.endValue ? wholeRange.endValue : max
- }
- return {
- min: min,
- max: max,
- translate: adjust(translate),
- scale: adjust(scale)
- }
- },
- zoomZeroLengthRange: function(translate, scale) {
- var canvasOptions = this._canvasOptions;
- var min = canvasOptions.rangeMin;
- var max = canvasOptions.rangeMax;
- var correction = (max.valueOf() !== min.valueOf() ? max.valueOf() - min.valueOf() : _abs(canvasOptions.rangeMinVisible.valueOf() - min.valueOf())) / canvasOptions.canvasLength;
- var isDateTime = typeUtils.isDate(max) || typeUtils.isDate(min);
- var isLogarithmic = "logarithmic" === this._businessRange.axisType;
- var newMin = canvasOptions.rangeMinVisible.valueOf() - correction;
- var newMax = canvasOptions.rangeMaxVisible.valueOf() + correction;
- newMin = isLogarithmic ? adjust(Math.pow(canvasOptions.base, newMin)) : isDateTime ? new Date(newMin) : newMin;
- newMax = isLogarithmic ? adjust(Math.pow(canvasOptions.base, newMax)) : isDateTime ? new Date(newMax) : newMax;
- return {
- min: newMin,
- max: newMax,
- translate: translate,
- scale: scale
- }
- },
- getMinScale: function(zoom) {
- return zoom ? 1.1 : .9
- },
- getScale: function(val1, val2) {
- var canvasOptions = this._canvasOptions;
- if (canvasOptions.rangeMax === canvasOptions.rangeMin) {
- return 1
- }
- val1 = isDefined(val1) ? this._fromValue(val1) : canvasOptions.rangeMin;
- val2 = isDefined(val2) ? this._fromValue(val2) : canvasOptions.rangeMax;
- return (canvasOptions.rangeMax - canvasOptions.rangeMin) / Math.abs(val1 - val2)
- },
- isValid: function(value) {
- var co = this._canvasOptions;
- value = this._fromValue(value);
- return null !== value && !isNaN(value) && value.valueOf() + co.rangeDoubleError >= co.rangeMin && value.valueOf() - co.rangeDoubleError <= co.rangeMax
- },
- getCorrectValue: function(value, direction) {
- var that = this;
- var breaks = that._breaks;
- var prop;
- value = that._fromValue(value);
- if (that._breaks) {
- prop = that._checkValueAboutBreaks(breaks, value, "trFrom", "trTo", that._checkingMethodsAboutBreaks[0]);
- if (true === prop.inBreak) {
- return that._toValue(direction > 0 ? prop.break.trTo : prop.break.trFrom)
- }
- }
- return that._toValue(value)
- },
- to: function(bp, direction) {
- var range = this.getBusinessRange();
- if (isDefined(range.maxVisible) && isDefined(range.minVisible) && range.maxVisible.valueOf() === range.minVisible.valueOf()) {
- if (!isDefined(bp) || range.maxVisible.valueOf() !== bp.valueOf()) {
- return null
- }
- return this.translateSpecialCase(0 === bp && this._options.shiftZeroValue ? "canvas_position_default" : "canvas_position_middle")
- }
- bp = this._fromValue(bp);
- var that = this;
- var canvasOptions = that._canvasOptions;
- var breaks = that._breaks;
- var prop = {
- length: 0
- };
- var commonBreakSize = 0;
- if (void 0 !== breaks) {
- prop = that._checkValueAboutBreaks(breaks, bp, "trFrom", "trTo", that._checkingMethodsAboutBreaks[0]);
- commonBreakSize = isDefined(prop.breaksSize) ? prop.breaksSize : 0
- }
- if (true === prop.inBreak) {
- if (direction > 0) {
- return prop.break.start
- } else {
- if (direction < 0) {
- return prop.break.end
- } else {
- return null
- }
- }
- }
- return that._conversionValue(that._calculateProjection((bp - canvasOptions.rangeMinVisible - prop.length) * canvasOptions.ratioOfCanvasRange + commonBreakSize))
- },
- from: function(pos, direction) {
- var that = this;
- var breaks = that._breaks;
- var prop = {
- length: 0
- };
- var canvasOptions = that._canvasOptions;
- var startPoint = canvasOptions.startPoint;
- var commonBreakSize = 0;
- if (void 0 !== breaks) {
- prop = that._checkValueAboutBreaks(breaks, pos, "start", "end", that._checkingMethodsAboutBreaks[1]);
- commonBreakSize = isDefined(prop.breaksSize) ? prop.breaksSize : 0
- }
- if (true === prop.inBreak) {
- if (direction > 0) {
- return that._toValue(prop.break.trTo)
- } else {
- if (direction < 0) {
- return that._toValue(prop.break.trFrom)
- } else {
- return null
- }
- }
- }
- return that._toValue(that._calculateUnProjection((pos - startPoint - commonBreakSize) / canvasOptions.ratioOfCanvasRange + prop.length))
- },
- isValueProlonged: false,
- getRange: function() {
- return [this._toValue(this._canvasOptions.rangeMin), this._toValue(this._canvasOptions.rangeMax)]
- },
- getScreenRange: function() {
- return [this._canvasOptions.startPoint, this._canvasOptions.endPoint]
- },
- add: function(value, diff, dir) {
- return this._add(value, diff, (this._businessRange.invert ? -1 : 1) * dir)
- },
- _add: function(value, diff, coeff) {
- return this._toValue(this._fromValue(value) + diff * coeff)
- },
- _fromValue: function(value) {
- return null !== value ? Number(value) : null
- },
- _toValue: function(value) {
- return null !== value ? Number(value) : null
- },
- ratioOfCanvasRange: function() {
- return this._canvasOptions.ratioOfCanvasRange
- }
- };
|