diff --git a/packages/core/src/components/axes/axis.ts b/packages/core/src/components/axes/axis.ts index a0068d7cb1..2fe6e2336c 100644 --- a/packages/core/src/components/axes/axis.ts +++ b/packages/core/src/components/axes/axis.ts @@ -10,6 +10,7 @@ import { import { Tools } from "../../tools"; import { ChartModel } from "../../model"; import { DOMUtils } from "../../services"; +import { TickRotations } from "../../interfaces/enums"; import * as Configuration from "../../configuration"; import { computeTimeIntervalName, @@ -29,9 +30,6 @@ export class Axis extends Component { scale: any; scaleType: ScaleTypes; - // Track whether zoom domain needs to update in a render - zoomDomainChanging = false; - constructor(model: ChartModel, services: any, configs?: any) { super(model, services, configs); @@ -40,31 +38,8 @@ export class Axis extends Component { } this.margins = this.configs.margins; - this.init(); - } - - init() { - this.services.events.addEventListener( - Events.ZoomBar.SELECTION_START, - this.handleZoomBarSelectionStart - ); - this.services.events.addEventListener( - Events.ZoomBar.SELECTION_END, - this.handleZoomBarSelectionEnd - ); } - handleZoomBarSelectionStart = () => { - this.zoomDomainChanging = true; - }; - - handleZoomBarSelectionEnd = () => { - this.zoomDomainChanging = false; - // need another update after zoom bar selection is completed - // to make sure the tick rotation is calculated correctly - this.services.events.dispatchEvent(Events.Model.UPDATE); - }; - render(animate = true) { const { position: axisPosition } = this.configs; const options = this.model.getOptions(); @@ -439,41 +414,56 @@ export class Axis extends Component { axisPosition === AxisPositions.BOTTOM || axisPosition === AxisPositions.TOP ) { - let rotateTicks = false; - - // If we're dealing with a discrete scale type - // We're able to grab the spacing between the ticks - if (scale.step) { - const textNodes = invisibleAxisRef - .selectAll("g.tick text") - .nodes(); - - // If any ticks are any larger than the scale step size - rotateTicks = textNodes.some( - (textNode) => - DOMUtils.getSVGElementSize(textNode, { useBBox: true }) - .width >= scale.step() - ); - } else { - // When dealing with a continuous scale - // We need to calculate an estimated size of the ticks - const minTickSize = - Tools.getProperty( - axisOptions, - "ticks", - "rotateIfSmallerThan" - ) || Configuration.axis.ticks.rotateIfSmallerThan; - const ticksNumber = isTimeScaleType - ? axis.tickValues().length - : scale.ticks().length; - const estimatedTickSize = width / ticksNumber / 2; - rotateTicks = isTimeScaleType - ? estimatedTickSize < minTickSize * 2 // datetime tick could be very long - : estimatedTickSize < minTickSize; + let shouldRotateTicks = false; + // user could decide if tick rotation is required during zoom domain changing + const tickRotation = Tools.getProperty( + axisOptions, + "ticks", + "rotation" + ); + + if (tickRotation === TickRotations.ALWAYS) { + shouldRotateTicks = true; + } else if (tickRotation === TickRotations.NEVER) { + shouldRotateTicks = false; + } else if (!tickRotation || tickRotation === TickRotations.AUTO) { + // if the option is not set or set to AUTO + + // depending on if tick rotation is necessary by calculating space + // If we're dealing with a discrete scale type + // We're able to grab the spacing between the ticks + if (scale.step) { + const textNodes = invisibleAxisRef + .selectAll("g.tick text") + .nodes(); + + // If any ticks are any larger than the scale step size + shouldRotateTicks = textNodes.some( + (textNode) => + DOMUtils.getSVGElementSize(textNode, { + useBBox: true + }).width >= scale.step() + ); + } else { + // When dealing with a continuous scale + // We need to calculate an estimated size of the ticks + const minTickSize = + Tools.getProperty( + axisOptions, + "ticks", + "rotateIfSmallerThan" + ) || Configuration.axis.ticks.rotateIfSmallerThan; + const ticksNumber = isTimeScaleType + ? axis.tickValues().length + : scale.ticks().length; + const estimatedTickSize = width / ticksNumber / 2; + shouldRotateTicks = isTimeScaleType + ? estimatedTickSize < minTickSize * 2 // datetime tick could be very long + : estimatedTickSize < minTickSize; + } } - // always rotate ticks if zoomDomain is changing to avoid rotation flips during zoomDomain changing - if (rotateTicks || this.zoomDomainChanging) { + if (shouldRotateTicks) { if (!isNumberOfTicksProvided) { axis.ticks( this.getNumberOfFittingTicks( @@ -690,15 +680,5 @@ export class Axis extends Component { .on("mouseover", null) .on("mousemove", null) .on("mouseout", null); - - // Remove zoom bar event listeners - this.services.events.removeEventListener( - Events.ZoomBar.SELECTION_START, - this.handleZoomBarSelectionStart - ); - this.services.events.removeEventListener( - Events.ZoomBar.SELECTION_END, - this.handleZoomBarSelectionEnd - ); } } diff --git a/packages/core/src/interfaces/axis-scales.ts b/packages/core/src/interfaces/axis-scales.ts index 63e05e2f3d..0939c92c42 100644 --- a/packages/core/src/interfaces/axis-scales.ts +++ b/packages/core/src/interfaces/axis-scales.ts @@ -1,4 +1,4 @@ -import { ScaleTypes } from "./enums"; +import { ScaleTypes, TickRotations } from "./enums"; import { AxisDomain } from "d3"; import { Locale } from "date-fns"; import { ThresholdOptions } from "./components"; @@ -74,6 +74,10 @@ export interface AxisOptions { * before getting rotated (in pixels) */ rotateIfSmallerThan?: number; + /** + * when to rotate ticks + */ + rotation?: TickRotations; /** * function to format the ticks */ diff --git a/packages/core/src/interfaces/enums.ts b/packages/core/src/interfaces/enums.ts index d30d5dd2ba..d4e930910e 100644 --- a/packages/core/src/interfaces/enums.ts +++ b/packages/core/src/interfaces/enums.ts @@ -163,3 +163,12 @@ export enum Statuses { WARNING = "warning", DANGER = "danger" } + +/** + * enum of axis ticks rotation + */ +export enum TickRotations { + ALWAYS = "always", + AUTO = "auto", + NEVER = "never" +}