d3js zoom + drag causes conflict - javascript

I am trying to apply the zoom behaviour to a svg where certain elements in the svg are already bound with drag behaviour. without the zoom behaviour drag works fine, without the drag behaviour zoom works fine. When I have both of them it conflicts. When I drag a circle all the other circles starts to drag with it.
Here is the fiddle.
can anyone help me to figure out the issue?
<svg height="600" width="600" style="background: black">
<g>
<rect x="0" y="0" , width="600" height="40" style="fill:gold;"></rect>
<circle id='drag' cx="15" cy="20" init-cx="15" init-cy="20" r="10"
style="stroke: white; stroke-width: 2px; fill:blue"/>
</g>
<g id="playground">
<g>
<circle class='top' cx="180" cy="120" r="30" style="stroke: white; stroke-width: 2px; fill:white"/>
</g>
<g>
<circle class='top' cx="200" cy="220" r="30" style="stroke: white; stroke-width: 2px; fill:white"/>
</g>
<g>
<circle class='top' cx="320" cy="150" r="50" style="stroke: white; stroke-width: 2px; fill:white"/>
</g>
</g>
var zoom = d3.behavior.zoom()
.scaleExtent([-1, 8])
.on("zoom", function () {
var graph = d3.select('svg');
graph
.select('#playground')
.selectAll('circle')
.select(function () {
return this.parentNode;
})
.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
});
var move = d3.behavior.drag()
.on('drag', function () {
console.log('dragging');
var curr = d3.select(this)
.attr({
cx: d3.mouse(this)[0],
cy: d3.mouse(this)[1]
})
})
.on('dragend', function () {
var curr = d3.select(this);
d3.select('#playground')
.append('circle')
.attr({
cx: curr.attr('cx'),
cy: curr.attr('cy'),
r: curr.attr('r')
})
.style({
fill: 'white',
stroke: 'red',
'stroke-width': '2px'
})
;
curr.attr({
cx: curr.attr('init-cx'),
cy: curr.attr('init-cx')
});
})
;
d3.select('#drag').call(move);
d3.select('.top')
.call(d3.behavior.drag().on('drag', function () {
d3.select(this)
.attr({
cx: d3.mouse(this)[0],
cy: d3.mouse(this)[1]
})
;
}));
d3.select('svg').call(zoom);

I have implemented individual dragging of nodes working along with overall zooming and panning functionality. Used stopPropagation of the event in dragstart event of circles.
Hope this helps.
var move = d3.behavior.drag()
.on("dragstart", function() {
d3.event.sourceEvent.stopPropagation();
});
Working JSFiddle

Related

SVG Linear Gradient SVG Background

I am trying to use an SVG, which will be dynamically created from JavaScript, as the background image on another SVG. This works when the fill color of the object is a solid color, but not when I try to use a linear gradient. Run the code to see an example. Please help figure how to use the linear gradient!
const createElement = (tag, attributes) => {
const element = document.createElement(tag);
if (attributes) Object.keys(attributes).forEach(key => element.setAttribute(key, attributes[key]));
return element;
}
// Create background for first SVG using solid color fill:
const svg3bg = createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 50 50', width: 50, height: 50 });
svg3bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: '#00F' }));
const svg3 = document.getElementById('svg3');
svg3.style.backgroundImage = `url('data:image/svg+xml,${svg3bg.outerHTML.replace(/\#/g, '%23')}')`; // This does not display unless I replace the # signs with a hex code.
svg3.style.backgroundColor = 'palegreen';
// Create background for second SVG using linear gradient fill:
const svg4bg = createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 50 50', width: 50, height: 50 });
const lg4 = svg4bg.appendChild(createElement('linearGradient', { id: "lg4" }))
lg4.appendChild(createElement('stop', { offset: "0%", 'stop-color': '#d67ef5' }))
lg4.appendChild(createElement('stop', { offset: "50%", 'stop-color': '#2b78ba' }))
lg4.appendChild(createElement('stop', { offset: "100%", 'stop-color': '#4d79a9' }))
svg4bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: 'url(#lg4)' }));
const svg4 = document.getElementById('svg4');
svg4.style.backgroundImage = `url('data:image/svg+xml,${svg4bg.outerHTML.replace(/\#/g, '%23')}')`;
svg4.style.backgroundColor = 'palegreen';
This shows an SVG using another SVG (generated from JavaScript) of blue dots as its background image:
<div id="div3">
<svg id="svg3" iewBox="0 0 100 100" style="width: 150; height: 150;">
<rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
</svg>
</div><br>
When trying to do the same thing with a linear gradient to fill the object instead of a solid color, it does not
display:
<div id="div4">
<svg id="svg4" iewBox="0 0 100 100" style="width: 150; height: 150;">
<rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
</svg>
</div><br>
This shows what the background image with the linear gradient should look like:
<div id="div5">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 50 50" width="50" height="50">
<lineargradient id="lg5">
<stop offset="0%" stop-color="#d67ef5"></stop>
<stop offset="50%" stop-color="#2b78ba"></stop>
<stop offset="100%" stop-color="#4d79a9"></stop>
</lineargradient>
<circle cx="25" cy="25" r="20" fill="url(#lg5)"></circle>
</svg>
</div>
Seems OK to me once I correct all the typos.
viewBox is missing a v in some places
units are missing from CSS sizes where they are mandatory
use createElementNS to create SVG elements and use an XML serializer rather than HTML serialization to get namespaces in the output.
while not necessary in this case I've fixed the URI encoding properly rather than using replace
const createElement = (tag, attributes) => {
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
if (attributes) Object.keys(attributes).forEach(key => element.setAttribute(key, attributes[key]));
return element;
}
let s = new XMLSerializer();
// Create background for first SVG using solid color fill:
const svg3bg = createElement('svg', { viewBox: '0 0 50 50', width: 50, height: 50 });
svg3bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: '#00F' }));
const svg3 = document.getElementById('svg3');
svg3.style.backgroundImage = `url('data:image/svg+xml,${encodeURIComponent(s.serializeToString(svg3bg))}')`;
svg3.style.backgroundColor = 'palegreen';
// Create background for second SVG using linear gradient fill:
const svg4bg = createElement('svg', { viewBox: '0 0 50 50', width: 50, height: 50 });
const lg4 = svg4bg.appendChild(createElement('linearGradient', { id: "lg4" }))
lg4.appendChild(createElement('stop', { offset: "0%", 'stop-color': '#d67ef5' }))
lg4.appendChild(createElement('stop', { offset: "50%", 'stop-color': '#2b78ba' }))
lg4.appendChild(createElement('stop', { offset: "100%", 'stop-color': '#4d79a9' }))
svg4bg.appendChild(createElement('circle', { cx: 25, cy: 25, r: 20, fill: 'url(#lg4)' }));
const svg4 = document.getElementById('svg4');
svg4.style.backgroundImage = `url('data:image/svg+xml,${encodeURIComponent(s.serializeToString(svg4bg))}')`;
svg4.style.backgroundColor = 'palegreen';
This shows an SVG using another SVG (generated from JavaScript) of blue dots as its background image:
<div id="div3">
<svg id="svg3" viewBox="0 0 100 100" style="width: 150px; height: 150px;">
<rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
</svg>
</div><br>
When trying to do the same thing with a linear gradient to fill the object instead of a solid color, it does not
display:
<div id="div4">
<svg id="svg4" viewBox="0 0 100 100" style="width: 150px; height: 150px;">
<rect x="10" y="10" width="80" height="80" style="stroke: black; fill: none; stroke-width: 4"></rect>
</svg>
</div><br>
This shows what the background image with the linear gradient should look like:
<div id="div5">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50" height="50">
<linearGradient id="lg5">
<stop offset="0%" stop-color="#d67ef5"></stop>
<stop offset="50%" stop-color="#2b78ba"></stop>
<stop offset="100%" stop-color="#4d79a9"></stop>
</linearGradient>
<circle cx="25" cy="25" r="20" fill="url(#lg5)"></circle>
</svg>
</div>

Isolate section of SVG when mouse is hovered

I am attempting to build an interactive map from scratch. I have an SVG of the map of Canada that has separate layers for each province. I'd like to highlight a specific province/territory when the mouse is hovered over it.
I have tried using a function that gets the live update of the mouse coordinates, but I am unsure as to how to figure out which section of the image it is on. I am unsure as to if this is the best method of doing it.
Through some of my research, I have found a method of gathering the pointer coordinates:
let x = 0;
let y = 0;
function showCoords() {
x = event.clientX;
y = event.clientY;
}
And I call it around the SVG using:
<div onmousemove="showCoords()">
...SVG HERE
</div>
I can select the different layers inside of the SVG, but the question is if I can find a way of checking which layer my mouse is currently over.
Thank you!
Edit:
I have reached a solution that accomplishes my goal, but I am unsure as to if it is efficient.
Using CSS, I fill each group upon hover:
#canada {
fill: hsl(0, 0%, 29%);
}
#canada g {
transition: .3s;
}
#canada g:hover {
fill: hsl(189, 88%, 59%);
}
I am also using the onClick option on each group to pull up their dialogue.
Maybe something like this? Just keep "data-name" attribute on each <g> inside svg code.
let x = 0;
let y = 0;
let svgCountry = document.querySelector("#states svg");
let svgStates = svgCountry.querySelectorAll("[data-name]");
let resContainer = document.getElementById("state-hovered-is");
// init tooltip
function showCoords(event) {
let x = event.clientX;
let y = event.clientY;
resContainer.setAttribute("style", "left:" + (x + 15) + "px;" + "top:" + (y - 50) + "px;");
}
// close tooltip
function clearCoor() {
resContainer.innerHTML = "";
}
// clear everything
function clearAllOn() {
svgStates.forEach(function(el) {
el.classList.remove("hover");
resContainer.innerHTML = "";
console.clear();
});
}
// display current state in div
function displayState(el) {
var res = el.getAttribute("data-name");
el.classList.add("hover");
resContainer.innerHTML = "<p>You're at" + " " + res + "</p>";
console.log(res);
}
svgStates.forEach(function(el) {
// mouse events
el.addEventListener("mouseenter", function() {
displayState(el);
});
el.addEventListener("mouseleave", function() {
clearAllOn();
});
// touch events
el.addEventListener("touchstart", function() {
clearAllOn();
displayState(el);
});
});
body {
background-color: #fff;
font-family: Arial, Helvetica, sans-serif;
color: #333;
}
g.hover {
opacity: 0.5;
}
#states {
margin: 0 auto;
width: 600px;
max-width: 100%;
position: relative;
}
#state-hovered-is {
text-align: center;
min-height: 50px;
position: fixed;
pointer-events: none;
background-color: rgba(0, 0, 0, 0.76);
border-radius: 6px;
}
#state-hovered-is p {
color: #fff;
margin: 0;
padding: 15px;
width: 180px;
}
<div id="states" onmousemove="showCoords(event)" onmouseout="clearCoor()">
<!-- State name here -->
<div id="state-hovered-is"></div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 961.38 830.7">
<defs>
<style>
.cls-1 { fill: #fff;}
.cls-2 {fill: #b8c4e6;}
.cls-3 {fill: #ce8080;}
.cls-4 {fill: #e99bd2;}
.cls-5 {fill: #acac90;}
.cls-6 {fill: #e6c0c0;}
.cls-7 {fill: #4d6ac1;}
.cls-8 {fill: #c9e6b8;}
.cls-9 {fill: #f3f3db;}
.cls-10 {fill: #cece71;}
.cls-11 {fill: #7188ce;}
.cls-12 {fill: #daa0a0;}
.cls-13 {fill: #91916b;}
.cls-14 {fill: #dada94;}
.cls-15 {fill: #916b86;}
</style>
</defs>
<title>Canada</title>
<g id="Layer_1">
<ellipse class="cls-1" cx="480.69" cy="415.35" rx="679.8" ry="587.39" />
<path class="cls-1" d="M539.84,220.75c-2.45,5-6.57,8.18-10.72,11.7l2-9.56C534.53,224.17,537,221.84,539.84,220.75Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M53,543.56c-1.09,2.13-2.18,4.23-3.52,6.84l-.51-10.68.56-.25Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M771.19,558.14c-.32-2.18-.77-4.36-.89-6.56a3.15,3.15,0,0,1,1.31-2.05,1.76,1.76,0,0,1,1.64.49,4.19,4.19,0,0,1,.17,2.5c-.48,1.84-1.18,3.62-1.79,5.43Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M40.77,527.77l-7-8.41.35-.18A76,76,0,0,1,40.4,524c.77.71.87,2.14,1.27,3.25Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M493.56,95.47l3.41,6L485.7,105a30.91,30.91,0,0,1,2.81-2.42C491.7,100.51,493.64,100.2,493.56,95.47Z" transform="translate(-0.06 -0.26)" />
</g>
<g id="Yukon" data-name="Yukon">
<path class="cls-3" d="M174.12,185.61c.91,1.61.88,2.8-.63,4.31-4.21,4.21-8.16,8.68-12.2,13.07-.34.38-.78,1-.72,1.39.58,3.9-2,6.08-4.31,8.53a6.48,6.48,0,0,0-1.84,3.83,5.33,5.33,0,0,0,1.79,3.5c1.85,1.68,4.07,2.94,6,4.53,3.45,2.83,3.47,5.7.33,9.15-2.19,2.39-4.41,4.77-6.37,7.34-1.76,2.3-1.12,4.05,1.42,5.49,1.4.81,2.66,1.88,4.19,3-2.18,1.51-3.35,2.81-2.33,5.22.45,1.05,0,2.31-1.73,2.4a17.09,17.09,0,0,0-3.62.83c-4.36,1.21-5.4,4.72-5.53,8.56a57.14,57.14,0,0,0,.5,10c.23,1.57,1.5,3,2.39,4.63-2.26,2.84-2.38,6.32-1.6,10.12a46.41,46.41,0,0,1,.52,7.56,1.6,1.6,0,0,1-.82,1.17c-2.55,1.24-3,3.61-3.48,6a9.38,9.38,0,0,1-1.27,3.48,10.68,10.68,0,0,0-1.7,8.87,2.39,2.39,0,0,1-.44,1.48c-.6,1-1.32,2-2,2.93-1.42,2.18-1.43,4,.77,5.24,3.32,1.83,3.1,4.7,2.57,7.41-.72,3.66-.45,6.87,2,9.78,1.47,1.77,1.39,3.3-.37,4.95a7.72,7.72,0,0,0-1.45,3.08c-.28.81-.27,1.71-.5,2.53-1.52,5.43,1,6.26,4.74,7.61,1.41.5,2.57,1.66,3.93,2.34a26.86,26.86,0,0,0,4.63,1.87c1.72.5,3.51.73,5.24,1.06.05.25.15.5.1.53-3,2.14-3,5.28-2.81,8.48.09,2,0,4,0,6.25A575.11,575.11,0,0,1,48.14,298a7.87,7.87,0,0,1,.58-.75c3.2-3.33,3.13-5.09-.71-7.55a38.29,38.29,0,0,0-6.52-3.12c-2.14-.86-3.05-5-1.32-6.73q13.23-13,26.49-26c6.81-6.67,13.65-13.31,20.46-20q13.26-13,26.5-26,10.56-10.35,21.15-20.68,11.07-10.83,22.16-21.66c1.92-1.87,3.87-3.74,6-5.43a2.44,2.44,0,0,1,2.34-.08,12.63,12.63,0,0,1,4.51,7.68c.95,5.52,2.44,10.95,3.73,16.42A5.64,5.64,0,0,0,174.12,185.61Z" transform="translate(-0.06 -0.26)" />
</g>
<g id="British_Columiba" data-name="British Columiba">
<g>
<path class="cls-4" d="M190.26,405.28c.27.14.53.31,1.06.62-1,1.88-2,3.69-2.9,5.53-5.64,11.14-11.24,22.3-16.9,33.43-4.43,8.73-8.92,17.42-13.38,26.13l-19.37,37.93c-.21.42-.68.84-.65,1.24.17,2.7,0,5.24-2.52,6.95.78,2,1.25,4.14,2.45,5.8.82,1.15,1.83,1.89,1.89,3.54s.46,3.46,2.33,4.55c2.39,1.41,1.92,4.19,2.3,6.41.31,1.81-.17,3.77-.35,5.66s.8,3.35,2.22,4.62a2.72,2.72,0,0,1,.81,2.17,5.54,5.54,0,0,0,1.49,5.42c.88,1,1.18,2.44,1.69,3.71.82,2,1.6,4,2.38,6,1,2.51,2,5,2.9,7.55.32.88.14,2.18.72,2.67,3.23,2.74,2.75,6.63,3,10.1a15.41,15.41,0,0,0,3.74,8.9c3.16,3.57,2.61,7,1.68,10.73-.83,3.31-1.92,6.57-3,9.84s-.35,6.2,1.21,9.74c-5.31-2.27-10.13-4.28-14.9-6.38-10.53-4.64-21.08-9.23-31.54-14-8.14-3.72-16.25-7.52-24.19-11.65-8.81-4.6-17.41-9.61-26.09-14.47a2,2,0,0,1-1-1.12,65.21,65.21,0,0,1-1-7.47c-.16-3.6-1.05-5-4.37-5.94,0-1.19,0-2.34,0-3.5a3.82,3.82,0,0,0-2.71-3.76c-1.17-.5-3.27-.93-3.32-1.53a9.88,9.88,0,0,1,.91-5.44c3.08-5.49,3.08-7.06-1-11.44-2.29-2.47-4.78-4.79-6.82-7.46a9.16,9.16,0,0,1-1.44-4.76c-.2-2.61-1.08-4.69-3.49-5.72-3.27-1.39-4.67-4.2-5.48-7.23a5.27,5.27,0,0,1,1-4.36,5.48,5.48,0,0,0,1.59-5.2c-.48-3.26,1.93-4.89,4.78-5.55a19.58,19.58,0,0,0,3.83-1c2.43-1.12,2.65-3.06.7-4.87a7.78,7.78,0,0,1-2-9.22c1.46-3.4,1.33-5.05-1-6.15-1.19-.56-2.78-.29-4.19-.39-.47,0-.93-.05-1.65-.09,1.67-3,3-5.78,6.86-6.28a4.12,4.12,0,0,0,3.2-2.73c.72-1.68,2.44-2.95,3.74-4.38,1.14-1.23,1.82-2.81.52-4a5.8,5.8,0,0,0-4-1A30.06,30.06,0,0,0,44.62,459c-1.84-6.08-.47-11.9,1.17-17.65A3.74,3.74,0,0,1,48,439.05c7.2-1.55,10.53-7,13.68-12.85a30.35,30.35,0,0,1,3.83-4.91c1.69-2,2.72-4.14,1.8-6.84s-1.71-5.51-2.66-8.23A52.51,52.51,0,0,0,62,399.51c-1.34-2.62-.9-5.19-.39-7.83q2.15-11.08,4.26-22.15c1.08-5.61,2.21-11.21,3.21-16.84a9.48,9.48,0,0,0-.36-2.74c-.16-1.32-.33-2.65-.44-4-.14-1.58-.18-3.17-.36-4.74a11.92,11.92,0,0,1,1.16-7.34c1.92-3.53,1.66-7.9-.48-9.87l1.06-1.21c7.65,6.68,15.29,13.38,23.2,19.74,8.69,7,17.59,13.76,26.79,20,13.27,9,26.71,17.88,40.42,26.24C169.85,394.8,180.18,399.83,190.26,405.28Z" transform="translate(-0.06 -0.26)" />
<path class="cls-4" d="M67.71,323.4c-4.2-2.13-8.84-4.21-13.43-1.55-2.84,1.64-5.18.87-8.06.13,2.21-2.52,1.9-5.53,1.88-8.49s0-6.08,0-9.44a8.14,8.14,0,0,1,1.68.85c5.42,4.9,10.73,9.92,16.24,14.72l3.65,3.2L68.61,324A4,4,0,0,0,67.71,323.4Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M52.34,580.17c.15,1.23-.68,2.57-1.25,4.47-2.23-1.77-4.17-2.89-5.53-4.5a75.63,75.63,0,0,1-5.85-8.23,3.32,3.32,0,0,1-.2-2.75c2.52-5.09,2.08-6.95-3.06-9.61-1.82-.94-2.5-1.94-2.32-4,.32-3.52.35-4.15-4.79-9.94,2-2.92,1.55-3.82-.24-7-1.32-2.35-1.69-5.31-2.07-8.06-.29-2.13-.63-4-2.58-5.25a2.26,2.26,0,0,1-.79-1.75c.24-3.45.6-6.89.93-10.33,2-.08,2.8,1.11,3.33,2.71A29.72,29.72,0,0,0,36,529,45.65,45.65,0,0,1,43,536.54c1.16,1.66,1.53,4.06,1.7,6.17a84.4,84.4,0,0,1,0,10.06c-.17,4.12,1.42,7.63,3.38,11.07a18,18,0,0,1,2.24,4.56A109.17,109.17,0,0,1,52.34,580.17Z" transform="translate(-0.06 -0.26)" />
<path class="cls-1" d="M17.57,426.81l6.17,8.48C16.39,441.78,11.81,449.73,11,459.7,10.41,448.18,12.87,437.39,17.57,426.81Z" transform="translate(-0.06 -0.26)" />
</g>
</g>
<g id="Alberta" data-name="Alberta">
<path class="cls-5" d="M194.56,407.63c27.17,14.46,55.83,25.35,85,35.57L214.1,643.67c-10.88-4-21.29-7.82-31.68-11.68-3.52-1.3-6.91-3-10.51-4s-5.08-3.41-6.18-6.74c-1.26-3.84-.43-7.18,1.12-10.59A26.88,26.88,0,0,0,169.13,597a4.52,4.52,0,0,0-1-2.58c-4.16-4.42-5.32-9.88-5.71-15.66-.07-1-.13-2.32-.75-2.88-2.84-2.56-2.45-6.26-3.65-9.38-.64-1.69-1.62-3.26-2.29-4.95-.84-2.14-1.52-4.35-2.27-6.53-.05-.15-.06-.35-.17-.44a6.25,6.25,0,0,1-2-7.07c.17-.6-1.07-1.75-1.85-2.43a2.33,2.33,0,0,1-1.08-2.43,28.92,28.92,0,0,0-.52-7.52c-.36-2.17,0-4.65-2.15-6.28-1.47-1.09-1.92-2.71-2.35-4.49-.35-1.45-1.6-2.69-2.47-4-.51-.77-1.07-1.51-1.72-2.42,2.55-1.41,2.87-3.59,2.69-6a5,5,0,0,1,.5-2.5q5-9.88,10-19.7c6.78-13.11,13.63-26.19,20.37-39.32,3.84-7.45,7.51-15,11.31-22.47C187.5,421.2,191,414.48,194.56,407.63Z" transform="translate(-0.06 -0.26)" />
</g>
</svg>
</div>
Here's how the full map looks: https://jsfiddle.net/darkosss/7umphzwn/

Center SVG group element

I am trying to center g element having text with tspan inside svg element using d3 using below code.
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="0">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>
As you can see after executing above code, the group element is not centered correctly on x and y coordinates. How can I make group element center inside svg?
I am using getBoundingClientRect becuase I want to get size of svg at initial stage after assigning width and height that is before anything is rendred inside svg.
You have to take into account the x and y position of both the SVG container and the group:
var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;
That way, you can have any value you want for alignment-baseline, dominant-baseline and text-anchor, it doesn't matter, the group will be always centered.
Here is your code with that change:
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="0">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>
I've made a few changes in the svg, the most important: I've changed some values for the tspan's dy. Also I'm using dominant-baseline="middle" instead of alignment-baseline="middle". I hope it helps.
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text dominant-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="-41">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>

appears text when mouse is over D3

Hi everyone I am using sunburst of D3.js I want to include a text element inside each element.
For that my code is like this
var path = g.append("path");
if (data_key != "used"){
svg.selectAll("g").append("text")
.attr("dx", function(d){return -50})
.attr("dy", function(d){return 20})
.attr("class", "all_users")
.style("display", "none")
.text("text");
}
and it works my structure is like this
<g>
<path style="stroke: rgb(255, 255, 255); stroke-width: 1; fill: transparent; opacity: 0.3;" d="M0,63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,-63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,63.58917920822171Z"></path>
<text dx="-50" dy="20" class="all_users" style="display: none;">text</text>
</g>
I add display none to my text style, and I want to change the style (appears the text when the mouse is over this path)
for that purpose I use this
var g = gs.enter().append("g")
.on("mouseover", mostrar)
like this
function mostrar(d){
...
$(this).closest('text').css("display", "inherit");
}
but this $(this).closest('text') return an empty array []. Any idea how to get the text when my mouse is over this part of the plot.
Thanks in advances
First of all: this mix of D3 and jQuery is definitely not the best practice.
That being said, you can easily get the hovered element with this, and select the text with a simple selection. After that, set the style with style
d3.select(this).select("text").style("display", "inherit");
Here is a demo with your paths and texts:
var g = d3.selectAll("g");
g.on("mouseover", show).on("mouseout", hide);
function show() {
d3.select(this).select("text").style("display", "inherit");
}
function hide() {
d3.select(this).select("text").style("display", "none");
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
<g transform="translate(50,75)">
<path style="stroke: black; stroke-width: 1; fill: transparent; opacity: 0.3;" d="M0,63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,-63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,63.58917920822171Z"></path>
<text dx="-50" dy="20" class="all_users" style="display: none;">text</text>
</g>
<g transform="translate(150,75)">
<path style="stroke: black; stroke-width: 1; fill: transparent; opacity: 0.3;" d="M0,63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,-63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,63.58917920822171Z"></path>
<text dx="-50" dy="20" class="all_users" style="display: none;">text</text>
</g>
<g transform="translate(250,75)">
<path style="stroke: black; stroke-width: 1; fill: transparent; opacity: 0.3;" d="M0,63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,-63.58917920822171A63.58917920822171,63.58917920822171 0 1,1 0,63.58917920822171Z"></path>
<text dx="-50" dy="20" class="all_users" style="display: none;">text</text>
</g>
</svg>

c3js d3 dash-stroke only one side of rect element

i have a rect element and i want to set up a dash stroke only in the right side, currently i've added the lines with css like this:
.c3-event-rect {
stroke: #ccc;
stroke-dasharray: 1,3;
stroke-width: 1px;
}
with javascritp is something like
d3.selectAll('.c3-event-rect')
.style('stroke-dasharray', ('2,3'))
.style('stroke', '#dedede')
but the dashed is covered all the sides
i've tried this post here but i don't get the result that i want
To achieve your expected result, use dashed line to the right of rectangle
var svgContainer = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 200);
//Draw the Rectangle
var rectangle = svgContainer.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 50)
.attr("height", 100);
svgContainer.append("line")
.style("stroke", "black")
.attr("x1", 60)
.attr("y1", 10)
.attr("x2", 60)
.attr("y2", 110)
.style("stroke-dasharray", ("2, 3"))
http://codepen.io/nagasai/pen/zBREmV
You just need to break up the 50 which forms the space into smaller dashes. Something like this perhaps.
rect { fill: none; stroke: black; }
.right { stroke-dasharray: 50,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,100 }
<svg height="300">
<rect x="0.5" y="0.5" width="50" height="50" class="right"/>
</svg>
or if you only want 1 side dashed add a zero at the beginning so the solid and dashed areas swap.
rect { fill: none; stroke: black; }
.right { stroke-dasharray: 0,50,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,100 }
<svg height="300">
<rect x="0.5" y="0.5" width="50" height="50" class="right"/>
</svg>
Alternatively draw the shape as 2 paths, one which is the solid 3 sided shape and the other which is a vertical dashed line.

Categories