1

Hello I am tring to make a svg editor where I can create and drag the rectangles I create. Each time the mouseDown event gets fired I add 2 eventListeners to the svg element (mouseMove and mouseUp) and each time mouseUp gets called I try to remove these events, but because the remove doesn't work the element has multiple mouseMove and mouseUp listeners attached to it. I can't figure out what's wrong. MouseDown does 2 things, first it can draw the rectangles and then if createMode is false it let me drag them

   this.domElement.addEventListener("mousedown", (event) => {
    if (event.button === 0 && this.createMode === true) {
        document.body.style.cursor = 'crosshair'
        const rect = document.createElementNS(this.svgns, 'rect');
        //rect.setAttribute('tabindex', "1");
        let first_mouseX = event.clientX;
        let first_mouseY = event.clientY;

        const drawRect = (event) => {

            let mouseX = event.clientX;
            let mouseY = event.clientY;
            const width = Math.abs(mouseX - first_mouseX);
            const height = Math.abs(mouseY - first_mouseY);

            if (mouseX > first_mouseX) {
                mouseX = first_mouseX;
            }

            if (mouseY > first_mouseY) {
                mouseY = first_mouseY;
            }

            rect.setAttribute('x', mouseX - this.domElement.getBoundingClientRect().left)
            rect.setAttribute('y', mouseY - this.domElement.getBoundingClientRect().top);
            rect.setAttribute('width', width);
            rect.setAttribute('height', height);
            rect.setAttribute('stroke', "black");
            rect.setAttribute('fill', 'white');
            rect.setAttribute('stroke-width', 2);
            this.rect = rect;


            this.domElement.appendChild(rect);
        }

        const endDraw = () => {
            this.domElement.removeEventListener("mousemove", drawRect);
            this.domElement.removeEventListener("mouseup", endDraw);

            if (this.rect !== null) {
                this.rect.addEventListener('click', () => {
                    this.createMode = false;
                    document.body.style.cursor = "auto"
                    event.target.focus()
                })

                this.rect.addEventListener('blur', () => {
                    this.stergeClick();

                })

                this.rect.addEventListener("focus", (event) => {
                    this.stergeClick();
                    this.adaugaClick(event.target)
                })
                this.rect.focus();
                this.rect = null;
            }

        }

        this.domElement.addEventListener("mouseup", endDraw)
        this.domElement.addEventListener("mousemove", drawRect)
    } else if (this.createMode === false) {

        const startDrag = (event) => {
            this.selectedItem = {}
            this.selectedItem.item = event.target
            this.selectedItem.offsetX = event.clientX - this.selectedItem.item.getAttribute('x');
            this.selectedItem.offsetY = event.clientY - this.selectedItem.item.getAttribute('y');
        }

        startDrag(event)

        const drag = (event) => {

            if (Object.keys(this.selectedItem).length > 0 && this.createMode === false && this.selectedItem.item.nodeName !== "svg") {
                this.stergeClick();
                this.adaugaClick(this.selectedItem.item);
                this.selectedItem.item.setAttribute('x', event.clientX - this.selectedItem.offsetX);
                this.selectedItem.item.setAttribute('y', event.clientY - this.selectedItem.offsetY);
            } else {
                return false
            }
        }

        const endDrag = (ev) => {
            if (Object.keys(this.selectedItem).length > 0 && this.selectedItem.item.nodeName !== "svg") {
                this.stergeClick();
                this.adaugaClick(this.selectedItem.item);
                ev.target.removeEventListener('mouseup', drag);
                ev.target.removeEventListener('mousemove', endDrag);
                this.domElement.removeEventListener('mouseup', drag);
                this.domElement.removeEventListener('mousemove', endDrag);
                this.selectedItem = {};
            }
        }

        this.domElement.addEventListener("mousemove", drag);
        this.domElement.addEventListener("mouseup", endDrag);

    }

})

}

AbsoluteBeginner
  • 2,160
  • 3
  • 11
  • 21
Siam
  • 17
  • 7
  • Why doesn't the remove work? What's the exact error you're getting? – timotgl Dec 26 '20 at 12:21
  • There is no error, if I place a console.log("mouseUp") in the endDrag function, it will first log the message one time, then on the next click it will log it 2 times (total of 3), then 3(total of 6), etc. So I think it just adds more and more eventListeners without removing them – Siam Dec 26 '20 at 12:24
  • 1
    Hm it seems like your trying to remove the event listeners quite aggressively as early as possible. Can't you keep them attached until a rectangle gets deleted? You'd have to re-attach them every time a rectangle is dragged anyway. Maybe that would make the code a bit more straight forward. Also, check out this: https://stackoverflow.com/questions/4936324/javascript-remove-an-event-listener-from-within-that-listener?rq=1 there's a way to have the listener run only once automatically, so you'd not have to remove it yourself. Could simplify your code. – timotgl Dec 26 '20 at 12:34
  • Thanks for the suggestion, setting once=true for mouseUp works great because it only needs to fire once, but mouseMove has to be able to fire multiple times. What I am trying to do is after mouseUp fires, the dragging should stop but the selectedItem should remain selected. So the dragging should only be able to occur when the mouse is down. I can also achieve this with a boolean var, that is set to true if mouseDown fired and to false is mouseUp fired. But I still don't know why the removing doesn't work – Siam Dec 26 '20 at 12:53
  • I don't have much experience with building a GUI like that, but my gut feeling says to rely on global state (like the boolean var you mentioned) and rely on generic event listeners, rather than adding and removing them individually on every drawn shape. The drag and drop behavior is the probably the same in principle, it just affects a different shape on the screen.. if that makes sense. – timotgl Dec 26 '20 at 13:07

0 Answers0