Skip to content

Implement a Tooltip (SkiaText) Inside a Card-Like Container #496

@unbroken360

Description

@unbroken360

I'm working with Victory Native XL and trying to implement a custom tooltip (ActiveValueIndicator) using SkiaText from @shopify/react-native-skia. The goal is to display the value inside a card-like container (similar to a Paper.Card look) when interacting with the chart.

I currently have this working with SkiaText, but I'm struggling to style it like a card with background color, rounded corners, and padding. I understand that using Skia components is necessary, but I'm unsure how to replicate the card effect effectively.

My current implemeantion:

const ActiveValueIndicator = ({
  xPosition,
  yPosition,
  top,
  bottom,
  activeValue,
  textColor,
  lineColor,
  indicatorColor,
  topOffset = 0,
  prefix = "",
  suffix = "",
  decimalPlaces = 2,
  index = 0,
}) => {
  const FONT_SIZE = 16;
  const LINE_SPACING = FONT_SIZE + 4;
  const themeColors = useTheme();
  const font = useFont(inter, FONT_SIZE);
  const start = useDerivedValue(() => vec(xPosition.value, bottom));
  const end = useDerivedValue(() =>
    vec(xPosition.value, top + 1.5 * FONT_SIZE + topOffset)
  );

  const activeValueDisplay = useDerivedValue(
    () => `${prefix} ${activeValue.value.toFixed(decimalPlaces)} ${suffix}`
  );
  const activeValueWidth = useDerivedValue(
    () => font?.measureText(activeValueDisplay.value).width || 0
  );
  const activeValueX = useDerivedValue(
    () => xPosition.value - activeValueWidth.value / 2
  );

  return (
    <>
      <SkiaLine p1={start} p2={end} color={lineColor} strokeWidth={2} />
      <Circle cx={xPosition} cy={yPosition} r={4} color={indicatorColor} />
      <Circle
        cx={xPosition}
        cy={yPosition}
        r={3}
        color={themeColors.colors.onBackground}
      />
      <SkiaText
        color={textColor}
        font={font}
        text={activeValueDisplay}
        x={activeValueX}
        //y={top + FONT_SIZE + topOffset + index * LINE_SPACING} // Dynamic offset
        y={top - FONT_SIZE - topOffset - index * LINE_SPACING}
      />
    </>
  );
};

<CartesianChart
            data={chartData}
            xKey="x"
            yKeys={yKeys}
            padding={{ top: 50, bottom: 15, left: 15, right: 15 }}
            chartPressState={[firstTouch]}
            xAxis={{
              font: robotoLightFont,
              labelColor: labelColor,
              labelOffset: 0,
              tickCount: 5,
              axisSide: "bottom",
              lineColor: "transparent",
              labelPosition: "inset",
              formatXLabel: (value) => formatXLabel(value),
            }}
            yAxis={[
              {
                font: robotoLightFont,
                labelColor: labelColor,
                labelOffset: 5,
                //tickCount: 5,
                axisSide: "left",
                lineColor: themeColors.colors.text,
                labelPosition: "outset",
                formatYLabel: (value) => `${Math.round(value)}`,
                domain: [0, maxYValue],
                tickValues: tickValues,
              },
            ]}
            domainPadding={10}
            renderOutside={({ chartBounds, points }) => (
              <>
                {isFirstPressActive &&
                  yKeys.map((key, index) => {
                    const config = yAxisConfig[key] || {};
                    return (
                      <ActiveValueIndicator
                        key={`indicator-${key}`}
                        xPosition={firstTouch.x.position}
                        yPosition={firstTouch.y[key]?.position ?? 0}
                        activeValue={firstTouch.y[key]?.value ?? 0}
                        bottom={chartBounds.bottom}
                        top={chartBounds.top}
                        textColor={labelColor}
                        lineColor={lineColor}
                        indicatorColor={config.color || "#000"} // Dynamic color
                        prefix={config.prefix || ""}
                        suffix={config.suffix || ""}
                        decimalPlaces={config.decimalPlaces ?? 2} // Dynamic decimals
                        index={index}
                      />
                    );
                  })}
              </>
            )}
          />

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions