Home > Software engineering >  drag circle area rather than border
drag circle area rather than border

Time:07-19

Below code try to link two circles from border to border. Drag event only take effect when click on circle border, I would like it work in circle area as well ( more easy to be dragged).

demo()

function demo() {
        function dragstarted(event,d) {    
                if (!event.active) simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
        }

        function dragged(event,d) {
                d.fx = event.x;
                d.fy = event.y;
        }

        function dragended(event,d) {
                // if (!event.active) simulation.alphaTarget(0);
                // d.fx = null;
                // d.fy = null;
        }
        var data = {
                "nodes":[{
                        "id":1,
                        "influence": 1
                },{
                        "id": 2,
                        "influence": 2
                }],
                "links":[{
                        "source": 1,
                        "target": 2,
                        "weight": 3
                }]
        }

        var width = 200
        var height = 200
        const simulation = d3.forceSimulation(data.nodes)
                    .force('charge', d3.forceManyBody().strength(-100))
                    .force('link', d3.forceLink(data.links).id(d => d.id)
                                 .distance(150))
                    .force('center', d3.forceCenter(width/2, height/2))

        const svg = d3.select('body')
                    .append("svg")
                    .attr("viewBox", [0,0,width,height]);

        var path = ['M',2,6,'L',2,2,10,6,2,10,'z'].join(' ')
        svg
                .append('defs')
                .append('marker')
                .attr('id', 'arr1')
                .attr('viewBox', [0, 0, 12, 12])
                .attr('refX', 10)
                .attr('refY', 6)
                .attr('markerWidth', 12)
                .attr('markerHeight', 12)
                .attr('orient', 'auto-start-reverse')
                .append('path')
                .attr('d',path)
                .attr('stroke', 'black')
                .attr('fill','black')

        var r = 35
        const node = svg.selectAll('circle')
                    .data(data.nodes)
                    .enter()
                    .append('circle')
                    .attr('r', r)
                    .attr('stroke','black')
                    .attr('stroke-width',4)
                    .attr('fill', 'none')
                    .call(d3.drag()
                                .on("start", dragstarted)
                                .on("drag", dragged)
                                .on("end", dragended));

        const link = svg
                    .selectAll('path.link')
                    .data(data.links)
                    .enter()
                    .append('line')
                    .attr('stroke', 'black')
                    .attr('fill', 'none');


        simulation.on('tick', () => {
                node.attr('cx', d => d.x);
                node.attr('cy', d => d.y);
                
                link.attr('x1', d => {
                        var sx = d.source.x
                        var sy = d.source.y
                        var tx = d.target.x
                        var ty = d.target.y

                        var dx = tx - sx
                        var dy = ty - sy
                        var length = Math.sqrt((dx * dx)   (dy * dy))
                        var x = r*dx/length
                        var y = r*dy/length

                        d.source.bx = sx   x
                        d.source.by = sy   y
                        d.target.bx = tx - x
                        d.target.by = ty - y
                        return d.source.bx
                })
                        .attr('y1',d => d.source.by)
                        .attr('x2',d => d.target.bx)
                        .attr('y2',d => d.target.by)
                
                link.attr('marker-end', 'url(#arr1)')
        });     
}
<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>

CodePudding user response:

Your fill is set to none, therefore you have to set the adequate value to pointer-events, like all. The problem is that the default pointer-events value is visiblePainted, in which, as the MDN explains:

The element can only be the target of a pointer event when [...] the fill property is set to a value other than none.

For a more detailed list have a look at MDN here: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

Here's your code setting pointer-events to all:

demo()

function demo() {
        function dragstarted(event,d) {    
                if (!event.active) simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
        }

        function dragged(event,d) {
                d.fx = event.x;
                d.fy = event.y;
        }

        function dragended(event,d) {
                // if (!event.active) simulation.alphaTarget(0);
                // d.fx = null;
                // d.fy = null;
        }
        var data = {
                "nodes":[{
                        "id":1,
                        "influence": 1
                },{
                        "id": 2,
                        "influence": 2
                }],
                "links":[{
                        "source": 1,
                        "target": 2,
                        "weight": 3
                }]
        }

        var width = 200
        var height = 200
        const simulation = d3.forceSimulation(data.nodes)
                    .force('charge', d3.forceManyBody().strength(-100))
                    .force('link', d3.forceLink(data.links).id(d => d.id)
                                 .distance(150))
                    .force('center', d3.forceCenter(width/2, height/2))

        const svg = d3.select('body')
                    .append("svg")
                    .attr("viewBox", [0,0,width,height]);

        var path = ['M',2,6,'L',2,2,10,6,2,10,'z'].join(' ')
        svg
                .append('defs')
                .append('marker')
                .attr('id', 'arr1')
                .attr('viewBox', [0, 0, 12, 12])
                .attr('refX', 10)
                .attr('refY', 6)
                .attr('markerWidth', 12)
                .attr('markerHeight', 12)
                .attr('orient', 'auto-start-reverse')
                .append('path')
                .attr('d',path)
                .attr('stroke', 'black')
                .attr('fill','black')

        var r = 35
        const node = svg.selectAll('circle')
                    .data(data.nodes)
                    .enter()
                    .append('circle')
                    .attr('r', r)
                    .attr('stroke','black')
                    .attr('stroke-width',4)
                    .attr('fill', 'none')
                    .attr("pointer-events", "all")
                    .call(d3.drag()
                                .on("start", dragstarted)
                                .on("drag", dragged)
                                .on("end", dragended));

        const link = svg
                    .selectAll('path.link')
                    .data(data.links)
                    .enter()
                    .append('line')
                    .attr('stroke', 'black')
                    .attr('fill', 'none');


        simulation.on('tick', () => {
                node.attr('cx', d => d.x);
                node.attr('cy', d => d.y);
                
                link.attr('x1', d => {
                        var sx = d.source.x
                        var sy = d.source.y
                        var tx = d.target.x
                        var ty = d.target.y

                        var dx = tx - sx
                        var dy = ty - sy
                        var length = Math.sqrt((dx * dx)   (dy * dy))
                        var x = r*dx/length
                        var y = r*dy/length

                        d.source.bx = sx   x
                        d.source.by = sy   y
                        d.target.bx = tx - x
                        d.target.by = ty - y
                        return d.source.bx
                })
                        .attr('y1',d => d.source.by)
                        .attr('x2',d => d.target.bx)
                        .attr('y2',d => d.target.by)
                
                link.attr('marker-end', 'url(#arr1)')
        });     
}
<script src="https://unpkg.com/[email protected]/dist/d3.min.js"></script>

  • Related