devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
303 lines (298 loc) • 12.8 kB
JavaScript
/**
* DevExtreme (esm/viz/axes/tick.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import {
isDefined
} from "../../core/utils/type";
import {
extend
} from "../../core/utils/extend";
import {
Deferred,
when
} from "../../core/utils/deferred";
function getPathStyle(options) {
return {
stroke: options.color,
"stroke-width": options.width,
"stroke-opacity": options.opacity,
opacity: 1
}
}
function createTick(axis, renderer, tickOptions, gridOptions, skippedCategory, skipLabels, offset) {
const tickOffset = offset || axis._tickOffset;
const lineGroup = axis._axisLineGroup;
const elementsGroup = axis._axisElementsGroup;
const tickStyle = getPathStyle(tickOptions);
const gridStyle = getPathStyle(gridOptions);
const emptyStrRegExp = /^\s+$/;
const axisOptions = axis.getOptions();
const labelOptions = axisOptions.label;
const labelStyle = axis._textOptions;
function getLabelFontStyle(tick) {
let fontStyle = axis._textFontStyles;
const customizeColor = labelOptions.customizeColor;
if (customizeColor && customizeColor.call) {
fontStyle = extend({}, axis._textFontStyles, {
fill: customizeColor.call(tick, tick)
})
}
return fontStyle
}
function createLabelHint(tick, range) {
const labelHint = axis.formatHint(tick.value, labelOptions, range);
if (isDefined(labelHint) && "" !== labelHint) {
tick.getContentContainer().setTitle(labelHint)
}
}
return function(value) {
const tick = {
value: value,
updateValue(newValue) {
this.value = value = newValue
},
initCoords: function() {
this.coords = axis._getTranslatedValue(value, tickOffset);
this.labelCoords = axis._getTranslatedValue(value)
},
saveCoords() {
when(this._templateDef).done((() => {
this._lastStoredCoordinates = {
coords: this._storedCoords,
labelCoords: this._storedLabelsCoords
};
this._storedCoords = this.coords;
this._storedLabelsCoords = this.templateContainer ? this._getTemplateCoords() : this.labelCoords
}))
},
resetCoordinates() {
if (this._lastStoredCoordinates) {
this._storedCoords = this._lastStoredCoordinates.coords;
this._storedLabelsCoords = this._lastStoredCoordinates.labelCoords
}
},
drawMark(options) {
if (!tickOptions.visible || skippedCategory === value) {
return
}
if (axis.areCoordsOutsideAxis(this.coords)) {
return
}
if (this.mark) {
this.mark.append(lineGroup);
axis.sharp(this.mark, axis.getSharpDirectionByCoords(this.coords));
this.updateTickPosition(options)
} else {
this.mark = axis._createPathElement([], tickStyle, axis.getSharpDirectionByCoords(this.coords)).append(lineGroup);
this.updateTickPosition(options)
}
},
setSkippedCategory(category) {
skippedCategory = category
},
_updateLine(lineElement, settings, storedSettings, animate, isGridLine) {
if (!lineElement) {
return
}
if (null === settings.points || null === settings.r) {
lineElement.remove();
return
}
if (animate && storedSettings && null !== storedSettings.points) {
settings.opacity = 1;
lineElement.attr(storedSettings);
lineElement.animate(settings)
} else {
settings.opacity = animate ? 0 : 1;
lineElement.attr(settings);
animate && lineElement.animate({
opacity: 1
}, {
delay: .5,
partitionDuration: .5
})
}
this.coords.angle && axis._rotateTick(lineElement, this.coords, isGridLine)
},
updateTickPosition: function(options, animate) {
this._updateLine(this.mark, {
points: axis._getTickMarkPoints(tick.coords, tickOptions.length, options)
}, this._storedCoords && {
points: axis._getTickMarkPoints(tick._storedCoords, tickOptions.length, options)
}, animate, false)
},
drawLabel: function(range, template) {
if (this.templateContainer && axis.isRendered()) {
this.updateLabelPosition();
return
}
const labelIsVisible = labelOptions.visible && !skipLabels && !axis.getTranslator().getBusinessRange().isEmpty() && !axis.areCoordsOutsideAxis(this.labelCoords);
if (!labelIsVisible) {
if (this.label) {
this.removeLabel()
}
return
}
const templateOption = labelOptions.template;
const text = axis.formatLabel(value, labelOptions, range);
if (this.label) {
this.label.attr({
text: text,
rotate: 0
}).append(elementsGroup);
createLabelHint(this, range);
this.updateLabelPosition();
return
}
if (templateOption) {
this.templateContainer = renderer.g().append(elementsGroup);
this._templateDef && this._templateDef.reject();
this._templateDef = new Deferred;
template.render({
model: {
valueText: text,
value: this.value,
labelFontStyle: getLabelFontStyle(this),
labelStyle: labelStyle
},
container: this.templateContainer.element,
onRendered: () => {
this.updateLabelPosition();
this._templateDef && this._templateDef.resolve()
}
})
} else if (isDefined(text) && "" !== text && !emptyStrRegExp.test(text)) {
this.label = renderer.text(text).css(getLabelFontStyle(this)).attr(labelStyle).append(elementsGroup);
this.updateLabelPosition();
createLabelHint(this, range)
}
const containerForData = this.getContentContainer();
containerForData && containerForData.data("chart-data-argument", this.value);
this.templateContainer && createLabelHint(this, range)
},
getTemplateDeferred() {
return this._templateDef
},
getContentContainer() {
return this.templateContainer || this.label
},
fadeOutElements() {
const startSettings = {
opacity: 1
};
const endSettings = {
opacity: 0
};
const animationSettings = {
partitionDuration: .5
};
if (this.getContentContainer()) {
this._fadeOutLabel()
}
if (this.grid) {
this.grid.append(axis._axisGridGroup).attr(startSettings).animate(endSettings, animationSettings)
}
if (this.mark) {
this.mark.append(axis._axisLineGroup).attr(startSettings).animate(endSettings, animationSettings)
}
},
_fadeInLabel() {
const group = axis._renderer.g().attr({
opacity: 0
}).append(axis._axisElementsGroup).animate({
opacity: 1
}, {
delay: .5,
partitionDuration: .5
});
this.getContentContainer().append(group)
},
_fadeOutLabel() {
const group = axis._renderer.g().attr({
opacity: 1
}).animate({
opacity: 0
}, {
partitionDuration: .5
}).append(axis._axisElementsGroup).toBackground();
this.getContentContainer().append(group)
},
_getTemplateCoords() {
return axis._getLabelAdjustedCoord(this, (axis._constantLabelOffset || 0) + (tick.labelOffset || 0))
},
updateLabelPosition: function(animate) {
const templateContainer = this.templateContainer;
if (!this.getContentContainer()) {
return
}
if (animate && this._storedLabelsCoords) {
if (templateContainer) {
templateContainer.attr(this._storedLabelsCoords);
const lCoords = this._getTemplateCoords();
templateContainer.animate(lCoords)
} else {
this.label.attr({
x: this._storedLabelsCoords.x,
y: this._storedLabelsCoords.y
});
this.label.animate({
x: this.labelCoords.x,
y: this.labelCoords.y
})
}
} else {
if (templateContainer) {
const lCoords = this._getTemplateCoords();
templateContainer.attr(lCoords)
} else {
this.label.attr({
x: this.labelCoords.x,
y: this.labelCoords.y
})
}
if (animate) {
this._fadeInLabel()
}
}
},
updateMultilineTextAlignment() {
if (labelOptions.template || !this.label) {
return
}
this.label.attr({
textsAlignment: this.labelAlignment || axis.getOptions().label.alignment
})
},
drawGrid: function(drawLine) {
if (gridOptions.visible && skippedCategory !== this.value) {
if (this.grid) {
this.grid.append(axis._axisGridGroup);
axis.sharp(this.grid, axis.getSharpDirectionByCoords(this.coords));
this.updateGridPosition()
} else {
this.grid = drawLine(this, gridStyle);
this.grid && this.grid.append(axis._axisGridGroup)
}
}
},
updateGridPosition: function(animate) {
this._updateLine(this.grid, axis._getGridPoints(tick.coords), this._storedCoords && axis._getGridPoints(this._storedCoords), animate, true)
},
removeLabel() {
const contentContainer = this.getContentContainer();
contentContainer && contentContainer.remove();
this._templateDef && this._templateDef.reject();
this._templateDef = this.templateContainer = this.label = null
}
};
return tick
}
}
export {
createTick as tick
};