During a drag and drop action in d3.js, the mouse over event does not trigger

I am currently facing an issue while trying to drag one circle over another circle in order to connect two paths. The problem arises when I attempt to drag a circle (c2) over another circle (c1). If circle c1 is created before circle c2, the mouse over event for c1 does not get triggered.

Visit this JSFiddle link

    var closedRoad = true;

    var width = 960,
        height = 500;

    // remaining code...

I could use some assistance with this challenge. Any help would be greatly appreciated!

Thank you! aGO!

Answer №1

The issue lies in the fact that the 'mouseover' event is triggered only on the topmost element when two elements overlap each other. This behavior persists regardless of whether the mouse event is handled for the top element or not, and changing this will require significant workarounds, none of which are perfect.

Here are some potential solutions:

  • Within your drag function, continuously check if another circle is present at that point.

    You can utilize the

    SVGSVGElement.getIntersectionList()
    method to identify all elements within a specified rectangle. It's essential to note that this method is invoked on an SVG node, not on a d3 selection.

  • While dragging a node, render it "transparent" to mouse events by applying the style pointer-events:none; to it.

    This action will also make it transparent to the drag event, requiring you to attach the drag event to the container instead of the nodes. Subsequently, determine the dragged circle during the 'dragstart' event, modify its pointer-events style, store the circle selection in an accessible variable for your drag and dragend functions. Furthermore, include a background rectangle to the <svg> or <g> element with drag functionality to respond to mouse events even when solely over a "transparent" circle.

  • When dragging a node, reposition it at the bottom of the painting order to ensure other nodes are placed above it.

    Given that SVG lacks a 'z-index' property akin to HTML, rearranging the DOM via selection.order() or plain JavaScript insertBefore() is the sole approach to accomplish this.

  • Alternatively, acknowledge this as merely a minor visual flaw that doesn't impact your code's operation significantly, rendering the effort and performance implications of the prior methods unnecessary.

    If you're unhappy about some circles changing color when dragged over, consider adding a 'dragging' class to the svg during dragging and base your CSS for the 'highlight' class so that it only executes visible changes if it isn't a child of 'svg.dragging'.

Answer №2

Introducing a snippet of code that detects if the user is moving circles and prompts the creation of a new circle if they are not moving. Hopefully, this solution proves useful to you.

    var roadClosed = true;
    var canvasWidth = 960,
        canvasHeight = 500;

    var points = d3.range(1, 5).map(function(i) {
        return [i * canvasWidth / 5, 50 + Math.random() * (canvasHeight - 100)];
    });

    var points1 = d3.range(1, 5).map(function(i) {
        return [i * canvasWidth / 5, 50 + Math.random() * (canvasHeight - 100)];
    });

    var points2 = d3.range(1, 5).map(function(i) {
        return [i * canvasWidth / 5, 50 + Math.random() * (canvasHeight - 100)];
    });

    var count = 0;
    var ways = [];

    var currentWay = null;

    var selected = null;

    var line = d3.svg.line();

    var svg = d3.select("body").append("svg")
    .attr("width", canvasWidth)
    .attr("height", canvasHeight);

    var rect = svg.append("rect")
    .attr("width", canvasWidth)
    .attr("height", canvasHeight);

    ways.forEach(function(way, i) {
        svg.append("path")
        .datum(way)
        .attr("id", "p" + way.id)
        .attr("class", "line")
        .call(redraw);
    });

    d3.select(window)
    .on("keydown", keydown)
    //.on("mousemove", mousemove)
    .on("mouseup", mouseup)
    .on("mousedown", mousedown)
    .on("dblclick", dblclick);

    function redraw(way) {
        way.attr("d", function(d) { return line(d.pts); });

        var circle = svg.selectAll(".way" + way.data()[0].id)
        .data(way.data()[0].pts, function(d) { return d; });
        circle.enter().append("circle")
        .attr("class", "way" + way.data()[0].id)
        .attr("r", 1e-6)
        .on("mousedown", function(d) { 
            if (roadClosed) {
                currentWay = way.data()[0];
                selected = d; 

                if (d3.event) {
                    d3.event.preventDefault();
                    d3.event.stopPropagation();
                }
            }
        })
        .on("mouseover", function() { d3.select(d3.event.target).classed("highlight", true); })
        .on("mouseout", function() { d3.select(d3.event.target).classed("highlight", false); })
        .transition()
        .duration(750)
        .ease("elastic")
        .attr("r", 6.5);

        circle
        .attr("cx", function(d) { return d[0]; })
        .attr("cy", function(d) { return d[1]; });

        ////
        var drag = d3.behavior.drag();
        drag.on("dragstart", function(d) {
            console.log('START');
        })
        .on("drag", function(d) {
            console.log('MOVE');

            var m = d3.mouse(svg.node());
            d[0] = Math.max(0, Math.min(canvasWidth, m[0]));
            d[1] = Math.max(0, Math.min(canvasHeight, m[1]));

            //redraw(way);
            redrawAll();
        })
        .on("dragend", function(d) {
            console.log('END');
        });

        circle.call(drag);
        ////

        circle.exit().remove();

        /*   if (d3.event) {
            d3.event.preventDefault();
            d3.event.stopPropagation();
        }*/
    }

    function dblclick() {
        currentWay.pts.pop();
        //redraw(svg.select("#p" + currentWay.id));
        redrawAll();

        roadClosed = true;
    }

    function mousedown() {
        start = event.pageX + event.pageY;
        console.log(start);

    }
    function mouseup(){
        if(start >= (event.pageX + event.pageY) - 10 && start <= (event.pageX + event.pageY) + 10){
        if (roadClosed) {
            currentWay = { id: ++count, pts: [] };
            ways.push(currentWay); 

            svg.append("path")
            .datum(currentWay)
            .attr("id", "p" + currentWay.id)
            .attr("class", "line")
            .on("mouseover", function() { 
                d3.select(d3.event.target).classed("highlight", true); 
            })
            .on("mouseout", function() { d3.select(d3.event.target).classed("highlight", false); })
            .call(redraw);

            roadClosed = false;
        }

        currentWay.pts.push(selected = d3.mouse(svg.node()));
        //redraw(svg.select("#p" + currentWay.id));
        redrawAll();
        }else{

        roadClosed = true;
        }
    }
    function redrawAll() {
        ways.forEach(function(way, i) {
            redraw(svg.select("#p" + way.id));
        });
    }

    function mousemove() {

    }


    function keydown() {
        if (!selected) return;
        switch (d3.event.keyCode) {
            case 8: // backspace
            case 46: { // delete
                var i = currentWay.pts.indexOf(selected);
                currentWay.pts.splice(i, 1);
                selected = currentWay.pts.length ? currentWay.pts[i > 0 ? i - 1 : 0] : null;
                redraw(svg.select("#p" + currentWay.id));
                break;
            }
        }
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

the `req.body` method fetches an object with a property named `json

Having an issue with accessing data from req.body in my form created with JS { 'object Object': '' } //when using JSON.stringify: { '{"A":"a","B":"b","C":"c"}': &apo ...

Storing numerous JSON records into an array by parsing them from a file

As a beginner in JS programming, I have a question that may seem trivial. Despite hours of searching online, I haven't been able to find a solution that works for me. I am dealing with multiple JSON feeds where each URL provides a multilayer JSON rec ...

When attempting to make a GET request, Express/Mongoose is returning a null array

I am having trouble retrieving the list of books from my database. Even though I have successfully inserted the data into Mongoose Compass, when I try to fetch it, all I get is an empty array. //Model File import mongoose from "mongoose"; cons ...

Ensuring the Safety of CloudKit.js

After reviewing the example provided by Apple in the CloudKit catalog, I noticed that every time you want to write or read data, you must include your API token in the script. Since Javascript is client-based, does this mean that any user can access and m ...

Is there a way to delegate the operation of Object3d.toJSON() to a web worker for optimization?

Is there a way to efficiently convert the active scene in threejs to a JSON object? The process seems to slow down as the models get larger, making it difficult to show a progress bar. I attempted sending the threejs scene to a web worker for conversion, ...

What exactly is the purpose of FormControl and why is it employed? In what ways should FormControl be properly utilized?

I'm a bit confused about how to properly use FormControl in Material-UI when creating forms in React. Can someone simplify for me what exactly FormControl does and why I should consider using it in my project? Currently, I have a Form.js Component wh ...

Ensure that all JavaScript functions operate correctly on Ajax-loaded content

Currently, I am customizing a standard bootstrap theme that features various elements such as a JavaScript slider, popup, text-rotation, and masonry boxes. This particular theme comes equipped with all the necessary JavaScript libraries and a main.js file ...

A guide on utilizing AngularJS to extract data from a webpage

I'm attempting to transfer the information from a specific page on my website and paste it into a file. I know how to post a sample text stored in a variable from Angular and save it in a file in the backend using Node Express, so writing a file isn&a ...

Utilizing AngularJS Factory to Retrieve Data from PHP Service via $http Request

I am new to JavaScript and this marks my first inquiry on StackOverflow. Therefore, any feedback or criticism is appreciated. Here you can find the AngularJS Flowchart project on GitHub. There is also another discussion on StackOverflow that explains how ...

Setting the date in a datetimepicker using the model

I've encountered an issue while trying to utilize the angular date time picker. It seems that when I load data from the model, the picker does not bind the value correctly. If I manually set the value to a date, it works fine. However, when the data ...

Ways to automatically scroll text inside a div based on the div's width

I currently have a div with a fixed width. My goal is to automatically scroll the text (left and right in a horizontal direction) within the div if the content exceeds the width of the div. How can I achieve this using CSS or jQuery? The class for the div ...

Is the Flowplayer JS API malfunctioning due to Flowplayer not being properly 'loaded'?

On a webpage, I have implemented multiple videos to autoplay using Flowplayer and jQuery with the following code: $('.video').each(function (k, obj) { $(obj).flowplayer(...) }) These videos are streaming and start playing automatically. At a ...

Navigating advanced search through nuanced filters dynamically with AngularJS

Here you will find the advanced search form: https://i.stack.imgur.com/g7Hiz.png I have successfully created a URL and parameters for document sections, but I am struggling to come up with a solution for managing the "Add Property Restrictions" section w ...

What is the best way to ensure all requests have been completed before proceeding?

Is there a way to ensure that the sortOrder function only runs once the getOrders function has fully completed its execution? I have considered using a callback, but I am unsure of how to implement it. Do you have any suggestions on how I can achieve this ...

Encountering an Unexpected Token Error While Parsing JSON with jQuery

Utilizing the Envato API with jQuery to collect user stats is my current project. An example JSON response that I will display is as follows: { "new-files-from-user":[ { "thumbnail":"http://3.s3.envato.com/files/60560.jpg", "tags":"", "use ...

The Google API Node.js client version 5.2.0 is facing difficulties in installing its dependencies

After updating to version 5.2.0, I encountered issues with npm failing to install dependencies. Launching my project resulted in a "dependency swig is missing" error message. Attempting to manually install it using the command (npm install swig), I then ...

What could be causing the 500 error when receiving images from the API, while all other data is successfully retrieved?

I've encountered a puzzling issue while running my Next.js project. When requesting a photo from the API, I receive a 500 error, whereas other data like price is fetched without any problem. Below is the fetchApi snippet: import axios from "axio ...

Using an arbitrary object as an argument in a CoffeeScript anonymous function

When I execute the below Coffeescript code: @total = (a, b) -> a + b The resulting compiled Javascript is: (function() { this.total = function(a, b) { return a + b; }; }).call(this); Is there a method in Coffeescript to substitute ...

What could be causing my text to not adapt to a mobile device screen?

Using my MacBook with a display size of 15.4-inch (2880 x 1800), I have captured screenshots of different sections of my homepage to show how they appear. #app (section1) https://i.sstatic.net/QjrXe.png #section2 (section2) https://i.sstatic.net/5HWp0. ...

Mastering the art of simultaneously running multiple animations

Utilizing two functions to apply a Fade In/Fade Out effect on an element. Confident in the functionality of both functions, as testing them sequentially in the Console proves their effectiveness. However, executing: fadeIn() fadeOut() seems to result in ...