Search

Annotations Positioning

Annotations

Compare annotations positioned by subjects and world coordinates.

Annotations Positioning
View live example →

Use the buttons above the chart to switch between different positioning methods for annotations.

Annotations with subjects can be positioned relative to their subjects, and move to keep in their relative position even when the subjects move.

Alternatively, they can be positioned using world coordinates, and stay fixed in place even when the subjects move or the chart or view changes.

See also

import React, { useMemo, useRef, useState } from "react";
import { createRoot } from "react-dom/client";

import { Chart } from "regraph";

import { data } from "./data";

import "@fortawesome/fontawesome-free/css/fontawesome.css";
import "@fortawesome/fontawesome-free/css/solid.css";
import "@ci/theme/rg/css/properties.css";

const backgroundColor = "rgb(231, 234, 224)";
const layout = { name: "sequential" };

function toTwoDecimals(num) {
  return Number(num.toFixed(2));
}

export const Demo = () => <RelativeVsWorldPositioning items={data} />;

function RelativeVsWorldPositioning({ items }) {
  const [isUsingRelativePositioning, setIsUsingRelativePositioning] = useState(true);
  const [relativeAnnotationPosition, setRelativeAnnotationPosition] = useState({
    angle: 0,
    distance: 20,
  });
  const [worldAnnotationPosition, setWorldAnnotationPosition] = useState({ x: 0, y: -135.12 });
  const chartRef = useRef(null);

  const formattedAnnotationPositions = useMemo(
    () => ({
      relative: {
        angle: toTwoDecimals(relativeAnnotationPosition.angle),
        distance: toTwoDecimals(relativeAnnotationPosition.distance),
      },
      world: {
        x: toTwoDecimals(worldAnnotationPosition.x),
        y: toTwoDecimals(worldAnnotationPosition.y),
      },
    }),
    [relativeAnnotationPosition, worldAnnotationPosition]
  );

  // keep the annotation position states up to date with chart interactions
  const onChange = () => {
    // annotation position helper instance methods can be used to convert between position types
    setRelativeAnnotationPosition(chartRef.current.getRelativeAnnotationPosition("annotation"));
    setWorldAnnotationPosition(chartRef.current.getWorldAnnotationPosition("annotation"));
  };

  return (
    <div className="story">
      <div className="options" style={{ backgroundColor }}>
        <button
          type="button"
          className={isUsingRelativePositioning ? "active" : ""}
          onClick={() => setIsUsingRelativePositioning(!isUsingRelativePositioning)}
        >
          Relative to subject position
        </button>
        <button
          type="button"
          className={isUsingRelativePositioning ? "" : "active"}
          onClick={() => setIsUsingRelativePositioning(!isUsingRelativePositioning)}
        >
          World coordinates position
        </button>
      </div>
      <div className="chart-wrapper">
        <Chart
          items={items}
          annotationPositions={{
            annotation: isUsingRelativePositioning
              ? relativeAnnotationPosition
              : worldAnnotationPosition,
          }}
          layout={layout}
          options={{
            navigation: false,
            overview: false,
            backgroundColor,
            fit: "none",
          }}
          ref={chartRef}
          onChange={onChange}
          animation={{ animate: false }}
        />
        <pre className="properties">
          {"Relative to subject position\n"}
          {JSON.stringify(formattedAnnotationPositions.relative, null, 2)}
          {"\nWorld position\n"}
          {JSON.stringify(formattedAnnotationPositions.world, null, 2)}
        </pre>
      </div>
    </div>
  );
}

const root = createRoot(document.getElementById("regraph"));
root.render(<Demo />);
const nodeColor = "rgb(50, 152, 138)";

export const data = {
  node1: {
    color: nodeColor,
  },
  node2: {
    color: nodeColor,
  },
  annotation: {
    subject: ["node1", "node2"],
    label: {
      text: "Drag the nodes to compare the annotation position types",
    },
  },
};
<!doctype html>
<html>
  <body>
    <div id="regraph" style="height: 100vh"></div>
    <script type="module" src="./code.jsx"></script>
  </body>
</html>

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.