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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draggable Annotations don't work in React #910

Open
PaulSender opened this issue Oct 10, 2023 · 3 comments
Open

Draggable Annotations don't work in React #910

PaulSender opened this issue Oct 10, 2023 · 3 comments

Comments

@PaulSender
Copy link

I've set up my chart to mimic the configuration on this page.

element never gets updated even if I put it in a state variable

Here's the code for reference.

const dragger = {
    id: 'dragger',
    beforeEvent(chart, args, options) {
      console.log(element, _ele); // logs undefined always
      if (handleDrag(args.event)) {
        args.changed = true;
        return;
      }
    },
  };

  const [element, setElement] = useState<any>();
  const [lastEvent, setLastEvent] = useState<any>();
  let _ele;

  const drag = function (moveX, moveY) {
    element.x += moveX;
    element.y += moveY;
    element.x2 += moveX;
    element.y2 += moveY;
    element.centerX += moveX;
    element.centerY += moveY;
    if (element.elements && element.elements.length) {
      for (const subEl of element.elements) {
        subEl.x += moveX;
        subEl.y += moveY;
        subEl.x2 += moveX;
        subEl.y2 += moveY;
        subEl.centerX += moveX;
        subEl.centerY += moveY;
        subEl.bX += moveX;
        subEl.bY += moveY;
      }
    }
  };

  const handleElementDragging = function (event) {
    console.log('dragging'); // never logs
    if (!lastEvent || !element) {
      return;
    }
    const moveX = event.x - lastEvent.x;
    const moveY = event.y - lastEvent.y;
    drag(moveX, moveY);
    setLastEvent(event);
    return true;
  };

  const handleDrag = function (event) {
    console.log(element, _ele); // logs undefined always
    if (element) {
      switch (event.type) {
        case 'mousemove':
          return handleElementDragging(event);
        case 'mouseout':
        case 'mouseup':
          setLastEvent(undefined);
          break;
        case 'mousedown':
          setLastEvent(event);
          break;
        default:
      }
    }
  };

     <_Chart
            type="bar"
            data={chartData}
            plugins={[dragger]}
            options={{
              events: ['mousedown', 'mouseup', 'mousemove', 'mouseout'],
              scales: {
                y: {
                  beginAtZero: true,
                  min: 0,
                  max: 100,
                },
              },
              plugins: {
                annotation: {
                  enter(ctx) {
                    setElement(ctx.element);
                    _ele = ctx.element;
                    console.log(_ele); // logs correctly here
                  },
                  leave() {
                    setElement(undefined);
                    setLastEvent(undefined);
                  },
                  annotations: {
                    annotation1: {
                      type: 'label',
                      backgroundColor: 'rgba(255, 99, 132, 0.25)',
                      borderWidth: 3,
                      borderColor: 'black',
                      content: ['Label annotation', 'to drag'],
                      callout: {
                        display: true,
                        borderColor: 'black',
                      },
                      xValue: 1,
                      yValue: 40,
                    },
                  },
                },
              },
            }}
          />
@stockiNail
Copy link
Collaborator

@PaulSender thank you for the issue. I'm not so expert on React. Can you prepare a codesandbox with the sample in order to reproduce the issue?

@TristanDuck
Copy link

Did you ever fix this?

@Gregorha
Copy link

Gregorha commented Apr 7, 2024

You can use Ref to fix this problems with external mutations
To setup the variable you can do with use ref const elementRef = useRef();
Updates to values can be done with elementRef.current =.
The entire code will look like this:

const elementRef = useRef<AnnotationElement | undefined>();
  const lastEventRef = useRef<AnnotationEvents | undefined>();

  const drag = function (moveX: number, moveY: number) {
    elementRef.current.x += moveX;
    elementRef.current.y += moveY;
    elementRef.current.x2 += moveX;
    elementRef.current.y2 += moveY;
    elementRef.current.centerX += moveX;
    elementRef.current.centerY += moveY;
    if (elementRef.current.elements && elementRef.current.elements.length) {
      for (const subEl of elementRef.current.elements) {
        subEl.x += moveX;
        subEl.y += moveY;
        subEl.x2 += moveX;
        subEl.y2 += moveY;
        subEl.centerX += moveX;
        subEl.centerY += moveY;
        subEl.bX += moveX;
        subEl.bY += moveY;
      }
    }
  };

  const handleElementDragging = function (event) {

    if (!lastEventRef.current || !elementRef.current) {
      return;
    }
    const moveX = event.x - lastEventRef.current.x;
    const moveY = event.y - lastEventRef.current.y;
    drag(moveX, moveY);
    lastEventRef.current = event;
    return true;
  };

  const handleDrag = function (event) {
    if (elementRef.current && elementRef.current.options.id === "draggablebox") {
      switch (event.type) {
        case "mousemove":
          return handleElementDragging(event);
        case "mouseout":
        case "mouseup":
          lastEventRef.current = undefined;
          break;
        case "mousedown":
          lastEventRef.current = event;
          break;
        default:
      }
    }
  };

  const handleEnter = (ctx) => {
    elementRef.current = ctx.element;
    console.log(elementRef.current)
  };

  const handleLeave = () => {
    elementRef.current = undefined;
    lastEventRef.current = undefined;
  };

  const dragger = {
    id: "dragger",
    beforeEvent(chart, args, options) {
      if (handleDrag(args.event)) {
        args.changed = true;
        return;
      }
    },
  };
  const options: ChartOptions<"line"> = {
    responsive: true,
    interaction: {
      mode: "index" as const,
      intersect: false,
    },
    plugins: {
      annotation: {
        enter(ctx) {
          handleEnter(ctx)
        },
        leave() {
          handleLeave()
        },
        annotations: {
          draggablebox: {
            type: "box",
            backgroundColor: "rgba(165, 214, 167, 0.2)",
            borderColor: "rgb(165, 214, 167)",
            borderWidth: 2,
            label: {
              display: true,
              content: ["Box annotation", "to drag"],
              textAlign: "center",
            },
            xMax: labels[2],
            xMin: labels[7],
            xScaleID: "x",
            yMax: 5,
            yMin: 0,
            yScaleID: "y",
          },
        },
      },
    },
    events: ["mousedown", "mouseup", "mousemove", "mouseout"],
  };
  // const labels =  dates && getUniqueDays(dates)
  const datasets = dataGraph.registros && [
    {
      label: "data",
      data: dataGraph.registros.map((registro) => registro.aceleracaoXEmMs2),
      borderColor: "#ffc210",
      backgroundColor: colorLib("#ffc210").alpha(0.5).rgbString(),
    },
  ];

  const data: ChartData<"line"> = {
    datasets,
    labels,
  };


  return (
    <>
      <div id="chart-area">
        {datasets && labels && <Line options={options} data={data} plugins={[dragger]} />}
      </div>
    </>
  );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants