Skip to content

Commit

Permalink
🐛 Fix chart ID not being unique + tooltip anchor issues
Browse files Browse the repository at this point in the history
* Tooltip anchor was being reused if multiple charts
  exist in the same page/instance
* chartID wasn't unique everywhere in one chart - it
  was being recalculated everytime it was called
  • Loading branch information
joao-m-santos authored and joao committed Feb 28, 2023
1 parent e5f3259 commit 8391edf
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/components/core/lume-axis/lume-axis.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ enum TYPES {
<script setup lang="ts">
import {
computed,
inject,
onMounted,
PropType,
reactive,
Expand All @@ -113,7 +114,6 @@ import {
PortalTarget as VuePortalTarget,
} from 'portal-vue';
import { useBase } from '@/composables/base';
import { useFormat } from '@/composables/format';
import { AxisOptions, useOptions, withOptions } from '@/composables/options';
import { ComputedScaleBand, Scale } from '@/composables/scales';
Expand Down Expand Up @@ -170,7 +170,7 @@ const tickRefs = ref<Array<SVGTextElement>>(null);
const root = ref<SVGGElement>(null);
const ticksWithAttributes = ref(null);
const { chartID } = useBase();
const chartID = inject('chartID');
const computedPosition = computed(() =>
props.type ? TYPES[props.type] : props.position
Expand Down
39 changes: 22 additions & 17 deletions src/components/core/lume-chart/lume-chart.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<lume-chart-container
:id="`lume-chart_${chartID}`"
ref="chartContainer"
:margins="allOptions.margins"
:container-size="containerSize"
Expand Down Expand Up @@ -127,10 +128,10 @@
<!-- Tooltip anchors -->
<g v-if="shouldGenerateTooltipAnchors">
<circle
v-for="attrs in tooltipAnchorAttributes"
v-for="(attrs, index) in tooltipAnchorAttributes"
v-bind="attrs"
ref="tooltipAnchor"
:key="`anchor-${attrs.cx}${attrs.cy}`"
:key="`anchor_${index}`"
:r="tooltipAnchorRadius"
class="lume-fill--transparent"
/>
Expand Down Expand Up @@ -191,7 +192,15 @@
</template>

<script setup lang="ts">
import { computed, onMounted, PropType, ref, toRefs, useSlots } from 'vue';
import {
computed,
onMounted,
PropType,
provide,
ref,
toRefs,
useSlots,
} from 'vue';
import {
LumeAxis,
Expand All @@ -211,6 +220,7 @@ import {
useNegativeValues,
} from '@/composables/negative-values';
import {
AnchorAttributes,
useTooltip,
useTooltipAnchors,
useTooltipItems,
Expand Down Expand Up @@ -240,16 +250,12 @@ const { data, labels, color, options, orientation, chartType } = toRefs(props);
const hoveredIndex = ref<number>(-1);
const tooltipAnchor = ref<SVGCircleElement>(null);
const chartContainer = ref<InstanceType<typeof LumeChartContainer>>(null);
const tooltipAnchorAttributes = ref<Array<AnchorAttributes> | null>(null);
const { allOptions } = useOptions<ChartOptions>(options);
const { internalData, computedLabels, containerSize, updateSize } = useBase(
data,
labels,
color,
allOptions,
orientation
);
const { internalData, computedLabels, containerSize, updateSize, chartID } =
useBase(data, labels, color, allOptions, orientation);
const { xScale, yScale } = useBaseScales(
internalData,
Expand Down Expand Up @@ -299,12 +305,6 @@ const showYAxisTitle = computed(() => {
return allOptions.value.yAxisOptions?.withTitle !== false && yAxisTitle.value;
});
const shouldGenerateTooltipAnchors = computed(
() =>
allOptions.value.withTooltip !== false &&
!allOptions.value.tooltipOptions?.targetElement
);
const isReady = computed(() => {
const conditions = [];
Expand All @@ -325,7 +325,9 @@ const { negativeBarAttributes } = useNegativeValues(
orientation
);
const { tooltipAnchorAttributes } = useTooltipAnchors(
const { shouldGenerateTooltipAnchors } = useTooltipAnchors(
tooltipAnchorAttributes,
allOptions,
computedXScale,
computedYScale,
orientation,
Expand Down Expand Up @@ -362,6 +364,9 @@ function handleMouseleave() {
hoveredIndex.value = -1;
}
provide('chartID', chartID);
provide('tooltipAnchorAttributes', tooltipAnchorAttributes); // provide anchors to re-compute in some cases
onMounted(() => {
if (!slots.groups?.()) {
console.error('"groups" `<slot>` must have content.');
Expand Down
15 changes: 12 additions & 3 deletions src/components/groups/lume-line-group/lume-line-group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const LUME_TRANSITION_TIME_FULL = 1; // 1s
</script>

<script setup lang="ts">
import { computed, defineProps, toRefs } from 'vue';
import { computed, defineProps, inject, Ref, toRefs } from 'vue';
import { ScaleLinear } from 'd3';
import LumeLine from '@/components/core/lume-line';
Expand All @@ -63,7 +63,7 @@ import { useLineNullValues } from '@/composables/line-null-values';
import { getLinePathDefinition } from '@/composables/line-values';
import { withGroupProps } from '@/composables/group-props';
import { LineChartOptions } from '@/composables/options';
import { useTooltipAnchors } from '@/composables/tooltip';
import { AnchorAttributes, useTooltipAnchors } from '@/composables/tooltip';
import {
getDomainLength,
Expand All @@ -86,6 +86,16 @@ const props = defineProps({
const { data, options, xScale, yScale } = toRefs(props);
const tooltipAnchorAttributes: Ref<AnchorAttributes[]> = inject(
'tooltipAnchorAttributes'
);
const { updateTooltipAnchorAttributes } = useTooltipAnchors(
tooltipAnchorAttributes,
options,
xScale,
yScale
);
const computedGroupData = computed(() => {
// Check if all datasets have `isDashed` function (which means data has been computed for line null values)
if (data.value.every((dataset) => dataset.isDashed)) {
Expand All @@ -96,7 +106,6 @@ const computedGroupData = computed(() => {
const { computedLineData } = useLineNullValues(data);
if (options.value.withTooltip !== false) {
const { updateTooltipAnchorAttributes } = useTooltipAnchors(xScale, yScale);
updateTooltipAnchorAttributes(computedLineData.value); // Updates tooltip anchors for null values
}
Expand Down
38 changes: 23 additions & 15 deletions src/composables/tooltip.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { computed, reactive, ref, Ref, watch } from 'vue';
import { computed, reactive, Ref, watch } from 'vue';

import { getXByIndex, Scale } from './scales';

import { NO_DATA, Orientation, ORIENTATIONS } from '@/utils/constants';
import { InternalData } from '@/types/dataset';
import { ChartOptions } from './options';

interface AnchorAttributes {
export interface AnchorAttributes {
cx: number;
cy: number;
}
Expand Down Expand Up @@ -41,22 +42,28 @@ const ANCHOR_CALCULATION_METHOD_MAP: {
'stacked-bar': getStackedHighestValue,
};

const tooltipAnchorAttributes = ref<Array<AnchorAttributes> | null>(null);

export function useTooltipAnchors(
anchorAttributeArray: Ref<Array<AnchorAttributes> | null>,
options: Ref<ChartOptions>,
xScale: Ref<Scale>,
yScale: Ref<Scale>,
orientation?: Ref<Orientation>,
data?: Ref<InternalData>,
chartType?: Ref<string>
) {
const shouldGenerateTooltipAnchors = computed(
() =>
options.value.withTooltip !== false &&
!options.value.tooltipOptions?.targetElement
);

function updateTooltipAnchorAttributes(renderedData: InternalData) {
const highestValues =
chartType?.value && ANCHOR_CALCULATION_METHOD_MAP[chartType.value]
? ANCHOR_CALCULATION_METHOD_MAP[chartType.value](renderedData)
: getHighestValues(renderedData);

tooltipAnchorAttributes.value = highestValues.map((value, index) => ({
anchorAttributeArray.value = highestValues.map((value, index) => ({
cx:
orientation?.value === ORIENTATIONS.HORIZONTAL
? xScale.value(value)
Expand All @@ -68,17 +75,18 @@ export function useTooltipAnchors(
}));
}

watch(
[xScale, yScale],
() => {
if (xScale.value && yScale.value && data?.value) {
updateTooltipAnchorAttributes(data.value);
}
},
{ immediate: true }
);
watch([xScale, yScale], () => {
if (
xScale.value &&
yScale.value &&
data?.value &&
shouldGenerateTooltipAnchors.value
) {
updateTooltipAnchorAttributes(data.value);
}
});

return { tooltipAnchorAttributes, updateTooltipAnchorAttributes };
return { shouldGenerateTooltipAnchors, updateTooltipAnchorAttributes };
}

export function useTooltip() {
Expand Down

0 comments on commit 8391edf

Please sign in to comment.