简体   繁体   中英

How to select multiple svg elements using d3js

How do I select multiple SVG elements using the right mouse button and the CRTL key?

What I would like is similar to this example I found (the part on the right). It is possible to select only one element or, by holding down the CTRL key, several elements.

I looked at the code and I can't reproduce it in my case.

My case: JSFIDDLE

I have more circles I wish I could select. I would like that when the user selects a circle, the id of the chosen circle is printed. When the user has finished selecting what he wants, and he presses the Finish button, then I would like the list of selected items to be printed.

Can this be done? Any assistance is greatly appreciated.


UPDATE

I changed the code of @Shashank, now it works. I hope it can be useful to someone :)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <script src="https://code.jquery.com/jquery-3.2.1.js"></script>
    <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    <link rel="stylesheet" type="text/css" href="style.css" media="screen"/>
</head>

<body>

    <div id="circles">
        <svg>
            <circle id="first" cx="10" cy="10" r="10" fill="purple" />
            <circle id="second" cx="60" cy="60" r="5" fill="red" />
            <circle id="third" cx="110" cy="110" r="15" fill="orange" />
            <circle id="fourth" cx="90" cy="50" r="7" fill="yellow" />
        </svg>
    </div>

  <button type="button" id="finalSelection">Finish</button>

  <span style="display:block;margin-top: 10px;">Selected IDs: <span class="values"></span></span>
  <script src="script.js"></script>
</body>

</html>

script.js

var selectedIds = [];

d3.selectAll('#circles svg circle').on('click', function() {
    // fetch ID
    var id = d3.select(this).attr('id');

    // toggle "clicked" class and push/splice id within the selectedIds array accordingly based on event.metaKey (CTRL)
    if(d3.select(this).classed('clicked')) { // classed add/remove a CSS class from the selection
        d3.select(this).classed('clicked', false).style('stroke', null);
        selectedIds.splice(selectedIds.indexOf(id), 1); // the splice() method adds/removes items to/from an array, and returns the removed item(s)
    } 
    else { // if an item has never been selected
        if(selectedIds.length) { // if the array selectedIds is not empty
            if(d3.event.ctrlKey) { // if CTRL is pressed
                d3.select(this).classed('clicked', true).style('stroke', 'blue');
                selectedIds.push(id); 
            }
            else { // *** OK *** if the item I'm selecting has never been selected and before I had already selected other elements
                // I "remove" all those already selected
                d3.selectAll(".clicked").classed('clicked', false).style('stroke', null);
                selectedIds = [];
                // I consider selected the one actually selected
                d3.select(this).classed('clicked', true).style('stroke', 'blue');
                selectedIds.push(id); 
            }
        } 
        else { // if the array selectedIds is empty
            d3.select(this).classed('clicked', true).style('stroke', 'blue');
            selectedIds.push(id);
        }
    }

    $('span.values').html(selectedIds.join(', '));
});

$('button#finalSelection').click(function() {
    $('span.values').html(selectedIds.join(', '));
    console.log("compare!")
});

style.css

span.values {
  color: #428bca;
}

JSFIDDLE with the updated code.

Yes sure it can done. Are you sure it should be a right mouse button click and CTRL?

Here's a snippet doing that:

 var selectedIds = []; d3.selectAll('#circles svg circle').on('contextmenu', function() { // prevent default right click functionality d3.event.preventDefault(); // fetch ID var id = d3.select(this).attr('id'); // toggle "clicked" class and push/splice id within the selectedIds array accordingly based on event.ctrlKey (CTRL) if(d3.select(this).classed('clicked')) { if(selectedIds.length > 1) { if(d3.event.ctrlKey) { d3.select(this).classed('clicked', false).style('stroke', null); selectedIds.splice(selectedIds.indexOf(id), 1); } } else { d3.select(this).classed('clicked', false).style('stroke', null); selectedIds.splice(selectedIds.indexOf(id), 1); } } else { if(selectedIds.length) { if(d3.event.ctrlKey) { d3.select(this).classed('clicked', true).style('stroke', '#000'); selectedIds.push(id); } } else { d3.select(this).classed('clicked', true).style('stroke', '#000'); selectedIds.push(id); } } $('span.values').html(selectedIds.join(', ')); }); $('button#finalSelection').click(function() { $('span.values').html(selectedIds.join(', ')); }); 
 span.values { color: #428bca; } 
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <script src="https://code.jquery.com/jquery-3.2.1.js"></script> <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script> </head> <body> <div id="circles"> <svg> <circle id="first" cx="10" cy="10" r="10" fill="purple" /> <circle id="second" cx="60" cy="60" r="5" fill="red" /> <circle id="third" cx="110" cy="110" r="15" fill="orange" /> <circle id="fourth" cx="90" cy="50" r="7" fill="yellow" /> </svg> </div> <button type="button" id="finalSelection">Finish</button> <span style="display:block;margin-top: 10px;">Selected IDs: <span class="values"></span></span> </body> </html> 

I've added comments within the snippet but let me tell you how it works:

  1. Use d3.select().on('contextmenu', function()) for mouse right click event listeners.
  2. preventDefault() has to be called to prevent the default functionality of a mouse right button click ie hide the default contextmenu.
  3. selectedIds is an array that keeps a track of clicked IDs.
  4. d3.event.ctrlKey is the key here -- which checks for CTRL press.
  5. Added simple HTML to print the IDs. I think you can take it from here.

Also, just in case you change your mind to make it a left mouse click + CTRL , change the contextmenu to click and take out the call to preventDefault() .

Let me know if you have any questions. Hope this helps :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM