jQuery [object Object] is not a valid selector - javascript

I am trying to select tree-node element with children and first child but it is not a valid selector.
<g class="nodes">
<g class="tree-node enter" id="tree-node-cdl3c5he">
<g class="node-group">
<circle class="node-shape" r="80"></circle>
<g class="node-label-group" transform="translate(-80,-80)">
<foreignObject class="node-content-container" width="160" height="160">
<div class="node-content">
<div class="inner">
<div class="node-label" data-test-id="node-label-new-part">New Part</div>
</div></div></foreignObject></g><g class="root-group" transform="translate(0,-80)"><circle class="root-shape" r="15"></circle></g>
</g>
</g>
</g>
Using first child:
$('.nodes > .tree-node:first-child')
Ember test:
await click($('.nodes > .tree-node:first-child'));
Error:
Failed to execute 'querySelector' on 'Document': '#ember-testing [object Object]' is not a valid selector.

$('.nodes > .tree-node:first-child') works fine and is not an invalid selector as seen below. It will return the first child of .nodes with the class .tree-node , if you however want to fget the first child within .tree-node then you need to add a space $('.nodes > .tree-node :first-child')
$('.nodes > .tree-node:first-child')
Expected ► <g class="tree-node enter" id="tree-node-cdl3c5he">
var x = $('.nodes > .tree-node:first-child');
console.log(x)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<g class="nodes">
<g class="tree-node enter" id="tree-node-cdl3c5he">
<g class="node-group">
<circle class="node-shape" r="80"></circle>
<g class="node-label-group" transform="translate(-80,-80)">
<foreignObject class="node-content-container" width="160" height="160">
<div class="node-content">
<div class="inner">
<div class="node-label" data-test-id="node-label-new-part">New Part</div>
</div>
</div>
</foreignObject>
</g>
<g class="root-group" transform="translate(0,-80)">
<circle class="root-shape" r="15"></circle>
</g>
</g>
</g>
</g>
$('.nodes > .tree-node :first-child')
Expected ► <g class="node-group">
var x = $('.nodes > .tree-node :first-child');
console.log(x)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<g class="nodes">
<g class="tree-node enter" id="tree-node-cdl3c5he">
<g class="node-group">
<circle class="node-shape" r="80"></circle>
<g class="node-label-group" transform="translate(-80,-80)">
<foreignObject class="node-content-container" width="160" height="160">
<div class="node-content">
<div class="inner">
<div class="node-label" data-test-id="node-label-new-part">New Part</div>
</div>
</div>
</foreignObject>
</g>
<g class="root-group" transform="translate(0,-80)">
<circle class="root-shape" r="15"></circle>
</g>
</g>
</g>
</g>

By accessing the object like $('.nodes > .tree-node:first')[0] worked.

Related

SVG: redundant circle when using animateMotion

I am using animateMotion to have an animation on my path. Here is the simple code:
<!DOCTYPE html>
<html>
<head>
<title>Example Of Many Things!</title>
</head>
<body>
<svg width="465pt" height="188pt" viewBox="0.00 0.00 465.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<g id="3" class="cluster loop-node">
</g>
<g id="4" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M92.6667,-53C92.6667,-53 119.3333,-53 119.3333,-53 121.6667,-53 124,-55.3333 124,-57.6667 124,-57.6667 124,-62.3333 124,-62.3333 124,-64.6667 121.6667,-67 119.3333,-67 119.3333,-67 92.6667,-67 92.6667,-67 90.3333,-67 88,-64.6667 88,-62.3333 88,-62.3333 88,-57.6667 88,-57.6667 88,-55.3333 90.3333,-53 92.6667,-53"></path>
<text text-anchor="start" x="100.6663" y="-57.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:12</text>
</g>
<g id="5" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M167.3333,-25C167.3333,-25 195.6667,-25 195.6667,-25 199.3333,-25 203,-28.6667 203,-32.3333 203,-32.3333 203,-39.6667 203,-39.6667 203,-43.3333 199.3333,-47 195.6667,-47 195.6667,-47 167.3333,-47 167.3333,-47 163.6667,-47 160,-43.3333 160,-39.6667 160,-39.6667 160,-32.3333 160,-32.3333 160,-28.6667 163.6667,-25 167.3333,-25"></path>
<text text-anchor="start" x="176.1663" y="-33.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:13</text>
</g>
<g id="4t5" class="edge">
<path fill="none" stroke="#717070" d="M124.2764,-54.1903C133.5025,-51.2575 144.8656,-47.6454 155.028,-44.4149" id="path4t5"></path>
<polygon fill="#717070" stroke="#717070" points="155.6709,-46.0469 159.9058,-42.8644 154.6106,-42.7114 155.6709,-46.0469"></polygon>
<g id="6" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M246.3333,-25C246.3333,-25 274.6667,-25 274.6667,-25 278.3333,-25 282,-28.6667 282,-32.3333 282,-32.3333 282,-39.6667 282,-39.6667 282,-43.3333 278.3333,-47 274.6667,-47 274.6667,-47 246.3333,-47 246.3333,-47 242.6667,-47 239,-43.3333 239,-39.6667 239,-39.6667 239,-32.3333 239,-32.3333 239,-28.6667 242.6667,-25 246.3333,-25"></path>
<text text-anchor="start" x="255.1663" y="-33.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:14</text>
</g>
<g id="5t6" class="edge">
<path fill="none" stroke="#717070" d="M203.0871,-36C212.5795,-36 223.8229,-36 233.8327,-36" id="path5t6"></path>
<polygon fill="#717070" stroke="#717070" points="233.939,-37.7501 238.939,-36 233.939,-34.2501 233.939,-37.7501"></polygon>
</g>
</g>
</svg>
</body>
<script type="text/javascript">
var g8t3 = document.getElementById('4t5');
var path = document.getElementById('4t5').getElementsByTagName('path')[0]
path.setAttribute("id", "path4t5");
var circleAnim = ' <circle r="1" fill="green"><animateMotion id="myMoveAnimation4t5" dur="3s" begin="0s;myMoveAnimation5t6.end"><mpath xlink:href="#path4t5"></mpath></animateMotion></circle>'
g8t3.insertAdjacentHTML( 'beforeend', circleAnim );
// // now move circle on the path
var g8t4 = document.getElementById('5t6');
var path = document.getElementById('5t6').getElementsByTagName('path')[0]
path.setAttribute("id", "path5t6");
var circleAnim = ' <circle r="1" fill="green"><animateMotion id="myMoveAnimation5t6" dur="3s" begin="myMoveAnimation4t5.end"><mpath xlink:href="#path5t6"></mpath></animateMotion></circle>'
g8t4.insertAdjacentHTML( 'beforeend', circleAnim );
</script></html>
As you can see, there is a green circle on the path which is moving, which is correct.
But there is something weird: There is also another green circle on the left bottom of the graph, which is redundant. I don't how it appears and how I can get rid of it.
Any help?
Instead of appending two circles in your svg, append the two <animateMotion>s inside a single circle. Also, you'll probably want to set your <animationMotion>'s fill attribute to "fill".
As you wrote it, when your circles are in idle state, they will come back to their initial position (unset).
var g8t3 = document.getElementById('4t5');
var path = document.getElementById('4t5').getElementsByTagName('path')[0]
path.setAttribute("id", "path4t5");
var circleAnim = '<circle r="1" fill="green">' +
// first part of the anim
'<animateMotion id="myMoveAnimation4t5" dur="3s" begin="0s;myMoveAnimation5t6.end"><mpath xlink:href="#path4t5" fill="freeze"></mpath></animateMotion>' +
// second part of the anim
'<animateMotion id="myMoveAnimation5t6" dur="3s" begin="myMoveAnimation4t5.end" fill="freeze"><mpath xlink:href="#path5t6"></mpath></animateMotion>' +
'</circle>'
g8t3.insertAdjacentHTML('beforeend', circleAnim);
<svg width="465pt" height="188pt" viewBox="0.00 0.00 465.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<g id="3" class="cluster loop-node">
</g>
<g id="4" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M92.6667,-53C92.6667,-53 119.3333,-53 119.3333,-53 121.6667,-53 124,-55.3333 124,-57.6667 124,-57.6667 124,-62.3333 124,-62.3333 124,-64.6667 121.6667,-67 119.3333,-67 119.3333,-67 92.6667,-67 92.6667,-67 90.3333,-67 88,-64.6667 88,-62.3333 88,-62.3333 88,-57.6667 88,-57.6667 88,-55.3333 90.3333,-53 92.6667,-53"></path>
<text text-anchor="start" x="100.6663" y="-57.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:12</text>
</g>
<g id="5" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M167.3333,-25C167.3333,-25 195.6667,-25 195.6667,-25 199.3333,-25 203,-28.6667 203,-32.3333 203,-32.3333 203,-39.6667 203,-39.6667 203,-43.3333 199.3333,-47 195.6667,-47 195.6667,-47 167.3333,-47 167.3333,-47 163.6667,-47 160,-43.3333 160,-39.6667 160,-39.6667 160,-32.3333 160,-32.3333 160,-28.6667 163.6667,-25 167.3333,-25"></path>
<text text-anchor="start" x="176.1663" y="-33.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:13</text>
</g>
<g id="4t5" class="edge">
<path fill="none" stroke="#717070" d="M124.2764,-54.1903C133.5025,-51.2575 144.8656,-47.6454 155.028,-44.4149" id="path4t5"></path>
<polygon fill="#717070" stroke="#717070" points="155.6709,-46.0469 159.9058,-42.8644 154.6106,-42.7114 155.6709,-46.0469"></polygon>
<g id="6" class="node cu-node">
<path fill="#ffffff" stroke="#a4a4a4" d="M246.3333,-25C246.3333,-25 274.6667,-25 274.6667,-25 278.3333,-25 282,-28.6667 282,-32.3333 282,-32.3333 282,-39.6667 282,-39.6667 282,-43.3333 278.3333,-47 274.6667,-47 274.6667,-47 246.3333,-47 246.3333,-47 242.6667,-47 239,-43.3333 239,-39.6667 239,-39.6667 239,-32.3333 239,-32.3333 239,-28.6667 242.6667,-25 246.3333,-25"></path>
<text text-anchor="start" x="255.1663" y="-33.6" font-family="font-awesome" font-size="6.00" fill="#000000">1:14</text>
</g>
<g id="5t6" class="edge">
<path fill="none" stroke="#717070" d="M203.0871,-36C212.5795,-36 223.8229,-36 233.8327,-36" id="path5t6"></path>
<polygon fill="#717070" stroke="#717070" points="233.939,-37.7501 238.939,-36 233.939,-34.2501 233.939,-37.7501"></polygon>
</g>
</g>
</g>
</svg>

Add a prefix to mutliple elements from the parent attribute

I'm trying to figure out how to add a unique prefix to ID's and other reference links.
I have multiple identical SVGs on a page. These SVGs serve as a wrapper (they're devices - laptop, phone, etc.) which have image link that is inserted into the SVG after load. The problem is, the ID's for these svgs are identical so they all conflict with each other. What I'm trying to do (but am open to better solutions) is to insert a unique ID to each id,xlink:href, url(#, etc. but pass over the <image> href attribute and fill and stroke attributes.
EDIT: I added/tweaked the code provided by #Temani, which got me closer to my desired result, however, I'm now getting all the ID's added to each SVG element. Formatted the code to be executable.
Desired output:
<div class="device" data-screen="[[IMAGE TO USE]]" data-name"[[UNIQUE ID]]">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="635" height="420" viewBox="0 0 635 420">
<defs>
<path id="[[UNIQUE ID]]-path-1"/>
<rect id="[[UNIQUE ID]]-path-3" />
<pattern id="[[UNIQUE ID]]-pattern-4">
<use transform="scale(13.1875)" xlink:href="#[[UNIQUE ID]]-image-5"/>
</pattern>
<image id="[[UNIQUE ID]]-image-5" href="[[IMAGE LINK THAT IS INSERTED AFTER LOAD]]"/>
</defs>
<g fill="none" fill-rule="evenodd">
<rect fill="#fff" stroke="#2D8EFF" />
<g >
<mask id="[[UNIQUE ID]]-mask-2" fill="#fff">
<use xlink:href="#[[UNIQUE ID]]-path-1"/>
</mask>
<g mask="url(#[[UNIQUE ID]]-mask-2)">
<mask id="mask-6" fill="#fff">
<use xlink:href="#[[UNIQUE ID]]-path-3"/>
</mask>
</g>
</g>
</g>
</svg>
</div>
Right now - both ID's (first and second) gets added to each SVG element. I also
$('.device').each(function() {
//we get the needed id using $(this) that refer to actual device
var id = $(this).data('name');
//we check all the element with ID
$(this).find("path, rect, pattern, image, mask").each(function() {
//now (this) refer to the actual element
if($(this).attr("id"))
$(this).attr("id", id+"-"+$(this).attr("id"));
});
//we update the <use>
$(this).find("use").each(function() {
//now (this) refer to the actual element
$(this).attr("xlink:href","#"+id+"-"+$(this).attr("xlink:href").substring(1));
});
// Also, hoping to combine g[mask], u[fill], etc into 1 function.
// Basically any attribute that starts with "url(#"
$(this).find("g[mask^='url']").each(function() {
$(this).attr("mask","url(#"+id+"-"+$(this).attr("mask").substring(5));
});
$(this).find("use[fill^='url']").each(function() {
$(this).attr("fill","url(#"+id+"-"+$(this).attr("fill").substring(5));
});
$(this).find("use[filter^='url']").each(function() {
$(this).attr("filter","url(#"+id+"-"+$(this).attr("filter").substring(5));
});
// grab data-screen value
var data = $(this).data('screen');
// replace this with the link inside svg
if (data != '') {
$(this).find("svg defs image").attr("href", data).attr("xlink:href", data);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="device" data-name="first" data-screen="image-1.png">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<defs>
<rect id="w-circle-stroke-a" width="24" height="24"/>
<path id="w-circle-stroke-b" d="M12,2 C17.52,2 22,6.48 22,12 C22,17.52 17.52,22 12,22 C6.48,22 2,17.52 2,12 C2,6.48 6.48,2 12,2 Z M12,3.81818182 C7.48415409,3.81818182 3.81818182,7.48415409 3.81818182,12 C3.81818182,16.5158459 7.48415409,20.1818182 12,20.1818182 C16.5158459,20.1818182 20.1818182,16.5158459 20.1818182,12 C20.1818182,7.48415409 16.5158459,3.81818182 12,3.81818182 Z M10.5553177,13.4773237 L15.155405,8.80967806 C15.5597962,8.4027095 16.222261,8.39598875 16.6350615,8.79466684 C16.6382917,8.79778661 16.6600317,8.81952282 16.7002813,8.85987545 C17.0999062,9.26113743 17.0999062,9.90402237 16.7002813,10.3052843 L10.5553177,16.5 L7.29971874,13.2228714 C6.90252847,12.8240541 6.8997633,12.1859262 7.29348277,11.7837778 L7.33224151,11.7441893 C7.73340831,11.3344341 8.39555055,11.3228774 8.8111776,11.7183766 C8.81566955,11.722651 9.39704957,12.3089667 10.5553177,13.4773237 Z"/>
<image id="image-5" href="image-to-be-inserted.jpg"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="w-circle-stroke-c" fill="#fff">
<use xlink:href="#w-circle-stroke-b"/>
</mask>
<g fill="#2D8EFF" mask="url(#w-circle-stroke-c)">
<rect width="24" height="24"/>
</g>
<use fill="url(#pattern-4)" xlink:href="#path-3"/>
<use fill="#000" filter="url(#filter-10)" xlink:href="#path-9"/>
</g>
</svg>
</div>
<div class="device" data-name="second" data-screen="image-1.png">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<defs>
<rect id="w-circle-stroke-a" width="24" height="24"/>
<path id="w-circle-stroke-b" d="M12,2 C17.52,2 22,6.48 22,12 C22,17.52 17.52,22 12,22 C6.48,22 2,17.52 2,12 C2,6.48 6.48,2 12,2 Z M12,3.81818182 C7.48415409,3.81818182 3.81818182,7.48415409 3.81818182,12 C3.81818182,16.5158459 7.48415409,20.1818182 12,20.1818182 C16.5158459,20.1818182 20.1818182,16.5158459 20.1818182,12 C20.1818182,7.48415409 16.5158459,3.81818182 12,3.81818182 Z M10.5553177,13.4773237 L15.155405,8.80967806 C15.5597962,8.4027095 16.222261,8.39598875 16.6350615,8.79466684 C16.6382917,8.79778661 16.6600317,8.81952282 16.7002813,8.85987545 C17.0999062,9.26113743 17.0999062,9.90402237 16.7002813,10.3052843 L10.5553177,16.5 L7.29971874,13.2228714 C6.90252847,12.8240541 6.8997633,12.1859262 7.29348277,11.7837778 L7.33224151,11.7441893 C7.73340831,11.3344341 8.39555055,11.3228774 8.8111776,11.7183766 C8.81566955,11.722651 9.39704957,12.3089667 10.5553177,13.4773237 Z"/>
<image id="image-5" href="image-to-be-inserted.jpg"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="w-circle-stroke-c" fill="#fff">
<use xlink:href="#w-circle-stroke-b"/>
</mask>
<g fill="#2D8EFF" mask="url(#w-circle-stroke-c)">
<rect width="24" height="24"/>
</g>
<use fill="url(#pattern-4)" xlink:href="#path-3"/>
<use fill="#000" filter="url(#filter-10)" xlink:href="#path-9"/>
</g>
</svg>
</div>
The issue is that you don't have to use $('.device') when inside and you need to refer to $(this) and since you have 2 each() nested you need to pay attention to the scope of this.
$('.device').each(function() {
//we get the needed id using $(this) that refer to actual device
var id = $(this).data('name');
//we check all the element with ID
$(this).find("path, rect, pattern, image, mask").each(function() {
//now (this) refer to the actual element
if($(this).attr("id"))
$(this).attr("id", id+"-"+$(this).attr("id"));
});
//we update the <use>
$(this).find("use").each(function() {
//now (this) refer to the actual element
$(this).attr("xlink:href","#"+id+"-"+$(this).attr("xlink:href").substring(1));
});
// grab data-screen value
var data = $(this).data('screen');
// replace this with the link inside svg
if (data != '') {
$(this).find("svg defs image").attr("href", data).attr("xlink:href", data);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="device" data-screen="[[IMAGE TO USE]]" data-name="[[UNIQUE ID]]">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="635" height="420" viewBox="0 0 635 420">
<defs>
<path id="path-1"/>
<rect id="path-3" />
<pattern id="pattern-4">
<use transform="scale(13.1875)" xlink:href="#image-5"/>
</pattern>
<image id="image-5" href="[[IMAGE LINK THAT IS INSERTED AFTER LOAD]]"/>
</defs>
<g fill="none" fill-rule="evenodd">
<rect fill="#fff" stroke="#2D8EFF" />
<g >
<mask id="mask-2" fill="#fff">
<use xlink:href="#path-1"/>
</mask>
<g mask="url(#mask-2)">
<mask id="mask-6" fill="#fff">
<use xlink:href="#path-3"/>
</mask>
</g>
</g>
</g>
</svg>
</div>

How do I print a list in an SVG element in react?

I am trying to print a list inside of a rectangular element in React. Currently, the list is printing correctly (so I know am formatting everything correctly in regards to including li tags around the items, etc.) above the rectangle, and the rectangle prints below it. The text "Title Here" prints correctly inside the box. The problem is that the list must be represented by a state, and is of unknown size. How do I print this list inside the rectangle?
<div>
<ul>{this.state.ListText}</ul>
<svg width="100%" height="100%" viewBox="0 0 610 150" version="1.1">
<defs>
<linearGradient x1="51.7971499%" y1="47.5635228%" x2="52.4921324%" y2="48.1654036%" id="linearGradient-1">
<stop stopColor="#9198A1" offset="0%"></stop>
<stop stopColor="#888D95" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="610" height="150" rx="7.2"></rect>
</defs>
<g id="Patient-Page" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="Desktop-HD" transform="translate(-732.000000, -106.000000)">
<g id="Medications" transform="translate(732.000000, 106.000000)">
<g id="Rectangle-7">
<use fillOpacity="0.55" fill="url(#linearGradient-1)" fillRule="evenodd" xlinkHref="#path-2"></use>
</g>
<text fontFamily="Helvetica" fontSize="32" fontWeight="normal" fill="#000000">
<tspan x="165" y="39">Title Here</tspan>
</text>
</g>
</g>
</g>
</svg>
</div>
You can use a foreignObject to embed HTML in your SVG.
You can use jQuery to manipulate the foreignObject DOM properties and to append HTML such as your list.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul>{this.state.ListText}</ul>
<span id='cont'>
<svg width="100%" height="100%" viewBox="0 0 610 150" version="1.1">
<defs>
<linearGradient x1="51.7971499%" y1="47.5635228%" x2="52.4921324%" y2="48.1654036%" id="linearGradient-1">
<stop stopColor="#9198A1" offset="0%"></stop>
<stop stopColor="#888D95" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="610" height="150" rx="7.2"></rect>
</defs>
<g id="Patient-Page" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="Desktop-HD" transform="translate(-732.000000, -106.000000)">
<g id="Medications" transform="translate(732.000000, 106.000000)">
<g id="Rectangle-7">
<use fillOpacity="0.55" fill="url(#linearGradient-1)" fillRule="evenodd" xlinkHref="#path-2"></use>
</g>
<text fontFamily="Helvetica" fontSize="32" fontWeight="normal" fill="#000000" >
<tspan x="165" y="39">Title Here</tspan>
</text>
<foreignObject width="100" height="300"
requiredExtensions="http://www.w3.org/1999/xhtml">
<body xmlns="http://www.w3.org/1999/xhtml">
<p>Here is my list</p>
</body>
</foreignObject>
</g>
</g>
</g>
</svg>
</span>
</div>
<script>
var ul = $('<ul>');
["Item 1", "Item 2", "Item 3"].forEach(function(item) {
ul.append($("<li>").text(item));
});
$('foreignObject').append(ul);
$('foreignObject body').append(ul);
</script>

How to implement collapsible tree structure using svg g

I implemented a tree structure using svg g components - the reason for using svg is a long story that involves draggable nodes.
The following hides and displays when the parent node is clicked but it is not the same as collapsing. What will be the best approach to correctly implement collapsible/expandable functionality (when children are hidden, the lower siblings positions must come up etc.)
Should I iterates through the siblings and update their positions or is there a simpler way?
The tree structure - branches - and expand/collapse icons are to be added later.
d3.selectAll(".nested-group").each(function() {
var sib = d3.select(this).select(".nested-group");
d3.select(this).select(".parent-node").on("click", function() {
sib.style("display", function() {
return (sib.style("display") === "none" ? "inline" : "none");
});
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg class="canvas" width="1800" height="500">
<g id="input-container" transform="translate(0,0)">
<g id="input-container-fo" class="container-fo">
<rect width="317.5" y="20" x="40" class="container-title-outline" id="input-container-title-outline" height="20" fill="#77C1C0" stroke="black"></rect>
<text width="270" y="35" x="40" class="container-title" id="input-container-title" font-weight="bold">Input</text>
<rect stroke-width="1" width="317.5" y="20" x="40" class="container-outline" id="input-container-outline" height="360" fill="none" stroke="black"></rect>
</g>
<g class="nested-group">
<g width="170" height="20" class="node-element parent-node">
<text y="55" x="51" class="node-element-text">person:object</text>
</g>
<g class="nested-group">
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="75" x="93.5" class="node-element-text">first name:string</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="95" x="93.5" class="node-element-text">last name:string</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="115" x="93.5" class="node-element-text">age:number</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="135" x="93.5" class="node-element-text">birthday:string</text>
</g>
</g>
<g class="nested-group">
<g width="170" height="20" class="node-element parent-node">
<text y="155" x="93.5" class="node-element-text">address:object</text>
</g>
<g class="nested-group">
<g class="nested-group">
<g width="170" height="20" class="node-element parent-node">
<text y="175" x="136" class="node-element-text">street address:object</text>
</g>
<g class="nested-group">
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="195" x="178.5" class="node-element-text">house number:number</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="215" x="178.5" class="node-element-text">lane:string</text>
</g>
</g>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="235" x="136" class="node-element-text">city:string</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="255" x="136" class="node-element-text">state:string</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="275" x="136" class="node-element-text">country:string</text>
</g>
</g>
</g>
</g>
<g class="nested-group">
<g width="170" height="20" class="node-element parent-node">
<text y="295" x="93.5" class="node-element-text">phone number:array[object]</text>
</g>
<g class="nested-group">
<g class="nested-group">
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="315" x="136" class="node-element-text">location:string</text>
</g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="335" x="136" class="node-element-text">code:number</text>
</g>
</g>
</g>
</g>
</g>
<g class="nested-group">
<g width="170" height="20" class="node-element parent-node">
<text y="355" x="93.5" class="node-element-text">children:array[string]</text>
</g>
<g></g>
</g>
<g>
<g width="170" height="20" class="node-element leaf-node">
<text y="375" x="93.5" class="node-element-text">nickname:string</text>
</g>
</g>
</g>
</g>
</g>
</svg>
There is no automatic layout in SVG like there is in HTML. So there is no way for the position of later elements to automatically adjust when another element is shown or hidden.
So, to answer your question, yes, you will have to adjust the positions of other elements yourself.

there's a 'use' tag on the page, but I cannot find the 'def' tag

I saw those html code on this website:
<a href="https://medium.com/" class="siteNav-logo" data-log-event="home">
<svg viewBox="0 0 45 45" width="45" height="45" class="svgIcon svgIcon--logoNew svgIcon-size--45px">
<use class="svgIcon-use svgIcon-use--part0" xlink:href="#svg-logoNew-45px-p0"></use>
<use class="svgIcon-use svgIcon-use--part1" xlink:href="#svg-logoNew-45px-p1"></use>
<use class="svgIcon-use svgIcon-use--part2" xlink:href="#svg-logoNew-45px-p2"></use>
<use class="svgIcon-use svgIcon-use--part3" xlink:href="#svg-logoNew-45px-p3"></use>
</svg>
<svg viewBox="0 0 95 45" width="95" height="45" class="svgIcon svgIcon--logoWordmarkNew svgIcon-size--95x45px">
<use class="svgIcon-use svgIcon-use--part0" xlink:href="#svg-logoWordmarkNew-95x45px-p0"></use>
</svg><span class="u-textScreenReader">Homepage</span>
</a>
Usually when you have a use tag inside svg, you need to use the defs tag to specify the specific shape that use is referred to. Just as follows:
<svg>
<defs>
<g id="shape">
<rect x="50" y="50" width="50" height="50" />
<circle cx="50" cy="50" r="50" />
</g>
</defs>
<use xlink:href="#shape" x="50" y="50" />
<use xlink:href="#shape" x="200" y="50" />
</svg>
But I couldn't find any defs tag on the page, so where does the browser find these external svgs(#svg-logoNew-45px-p0, #svg-logoNew-45px-p1, etc)?
They use the <symbol> tag instead of <defs>:
<div style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg">
<symbol viewBox="-17 18 45 45" id="svg-logoNew-45px-p0">...</symbol>
</svg>
</div>

Categories

Resources