Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce calls to getStringSize when calculating visible ticks (#2589) #3953

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/cartesian/getEquidistantTicks.ts
Expand Up @@ -31,11 +31,19 @@ export function getEquidistantTicks(
}

// Check if the element collides with the next element
const size = getTickSize(entry, index);
const i = index;
let size: number | undefined;
const getSize = () => {
if (size === undefined) {
size = getTickSize(entry, i);
}

return size;
};

const tickCoord = entry.coordinate;
// We will always show the first tick.
const isShow = index === 0 || isVisible(sign, tickCoord, size, start, end);
const isShow = index === 0 || isVisible(sign, tickCoord, getSize, start, end);
Comment on lines +35 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are now redefining this in three places. I wonder: Could we instead extract this combination of getSize with isVisible into a new helper function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we could because there might be other places where getSize is used.
For example, in getTicksEnd we use it in lines 37, 46 and 49. It isn't just used for isVisible, so it's hard to abstract that


if (!isShow) {
// Start all over with a larger stepsize
Expand All @@ -46,7 +54,7 @@ export function getEquidistantTicks(

if (isShow) {
// If it can be shown, update the start
start = tickCoord + sign * (size / 2 + minTickGap);
start = tickCoord + sign * (getSize() / 2 + minTickGap);
index += stepsize;
}
}
Expand Down
33 changes: 24 additions & 9 deletions src/cartesian/getTicks.ts
Expand Up @@ -24,9 +24,17 @@ function getTicksEnd(

for (let i = len - 1; i >= 0; i--) {
let entry = result[i];
const size = getTickSize(entry, i);
let size: number | undefined;
const getSize = () => {
if (size === undefined) {
size = getTickSize(entry, i);
}

return size;
};
nikolasrieble marked this conversation as resolved.
Show resolved Hide resolved

if (i === len - 1) {
const gap = sign * (entry.coordinate + (sign * size) / 2 - end);
const gap = sign * (entry.coordinate + (sign * getSize()) / 2 - end);
result[i] = entry = {
...entry,
tickCoord: gap > 0 ? entry.coordinate - gap * sign : entry.coordinate,
Expand All @@ -35,10 +43,10 @@ function getTicksEnd(
result[i] = entry = { ...entry, tickCoord: entry.coordinate };
}

const isShow = isVisible(sign, entry.tickCoord, size, start, end);
const isShow = isVisible(sign, entry.tickCoord, getSize, start, end);

if (isShow) {
end = entry.tickCoord - sign * (size / 2 + minTickGap);
end = entry.tickCoord - sign * (getSize() / 2 + minTickGap);
result[i] = { ...entry, isShow: true };
}
}
Expand Down Expand Up @@ -69,7 +77,7 @@ function getTicksStart(
tickCoord: tailGap > 0 ? tail.coordinate - tailGap * sign : tail.coordinate,
};

const isTailShow = isVisible(sign, tail.tickCoord, tailSize, start, end);
const isTailShow = isVisible(sign, tail.tickCoord, () => tailSize, start, end);
nikolasrieble marked this conversation as resolved.
Show resolved Hide resolved

if (isTailShow) {
end = tail.tickCoord - sign * (tailSize / 2 + minTickGap);
Expand All @@ -80,10 +88,17 @@ function getTicksStart(
const count = preserveEnd ? len - 1 : len;
for (let i = 0; i < count; i++) {
let entry = result[i];
const size = getTickSize(entry, i);
let size: number | undefined;
const getSize = () => {
if (size === undefined) {
size = getTickSize(entry, i);
}

return size;
};

if (i === 0) {
const gap = sign * (entry.coordinate - (sign * size) / 2 - start);
const gap = sign * (entry.coordinate - (sign * getSize()) / 2 - start);
result[i] = entry = {
...entry,
tickCoord: gap < 0 ? entry.coordinate - gap * sign : entry.coordinate,
Expand All @@ -92,10 +107,10 @@ function getTicksStart(
result[i] = entry = { ...entry, tickCoord: entry.coordinate };
}

const isShow = isVisible(sign, entry.tickCoord, size, start, end);
const isShow = isVisible(sign, entry.tickCoord, getSize, start, end);

if (isShow) {
start = entry.tickCoord + sign * (size / 2 + minTickGap);
start = entry.tickCoord + sign * (getSize() / 2 + minTickGap);
result[i] = { ...entry, isShow: true };
}
}
Expand Down
16 changes: 15 additions & 1 deletion src/util/TickUtils.ts
Expand Up @@ -23,7 +23,21 @@ export function getTickBoundaries(viewBox: CartesianViewBox, sign: number, sizeK
};
}

export function isVisible(sign: number, tickPosition: number, size: number, start: number, end: number): boolean {
export function isVisible(
sign: number,
tickPosition: number,
getSize: () => number,
start: number,
end: number,
): boolean {
/* Since getSize() is expensive (it reads the ticks' size from the DOM), we do this check first to avoid calculating
* the tick's size. */
if (sign * tickPosition < sign * start || sign * tickPosition > sign * end) {
return false;
}
nikolasrieble marked this conversation as resolved.
Show resolved Hide resolved

const size = getSize();

return sign * (tickPosition - (sign * size) / 2 - start) >= 0 && sign * (tickPosition + (sign * size) / 2 - end) <= 0;
}

Expand Down
28 changes: 28 additions & 0 deletions test/util/TickUtils.spec.ts
@@ -0,0 +1,28 @@
import { isVisible } from '../../src/util/TickUtils';

describe('isVisible', () => {
test.each([
{ sign: 1, position: 50, size: 10, start: 0, end: 100 },
{ sign: 1, position: 50, size: 50, start: 0, end: 100 },
{ sign: 1, position: 50, size: 100, start: 0, end: 100 },
{ sign: 0, position: 50, size: 10, start: 0, end: 100 },
{ sign: 0, position: 50, size: 50, start: 0, end: 100 },
{ sign: 0, position: 50, size: 100, start: 0, end: 100 },
])('is returns true if tick is inside limits: (%o)', ({ sign, position, size, start, end }) => {
expect(isVisible(sign, position, () => size, start, end)).toBeTruthy();
});

test.each([
{ sign: -1, position: 50, size: 10, start: 0, end: 100 },
{ sign: -1, position: 50, size: 50, start: 0, end: 100 },
{ sign: -1, position: 50, size: 100, start: 0, end: 100 },
{ sign: 1, position: 50, size: 101, start: 0, end: 100 },
{ sign: 1, position: 10, size: 10_000, start: 50, end: 100 },
{ sign: 1, position: 110, size: 10_000, start: 50, end: 100 },
{ sign: -1, position: 50, size: 101, start: 0, end: 100 },
{ sign: -1, position: 10, size: 10_000, start: 50, end: 100 },
{ sign: -1, position: 110, size: 10_000, start: 50, end: 100 },
])('is returns false if tick is outside limits: (%o)', ({ sign, position, size, start, end }) => {
expect(isVisible(sign, position, () => size, start, end)).toBeFalsy();
});
});