Text Alignment in d3 - javascript

var data =
[{"seq":"1","start":"Account","end":"Order","relation":"Account","rows":"1"},
{"seq":"2","start":"Account","end":"Attachment","relation":"Parent","rows":"10"}
,{"seq":"3","start":"Order","end":"Account","relation":"Account","rows":"15"}
,{"seq":"4","start":"Attachment","end":"Account","relation":"Parent","rows":"55"}
,{"seq":"5","start":"Attachment","end":"Campaign","relation":"Parent","rows":"45"}
,{"seq":"6","start":"Attachment","end":"Lead","relation":"Parent","rows":"47"}
,{"seq":"7","start":"Lead","end":"Attachment","relation":"Parent","rows":"75"}
,{"seq":"8","start":"Campaign","end":"Attachment","relation":"Parent","rows":"34"},
{"seq":"9","start":"Order","end":"Account","relation":"Account","rows":"99"}
,{"seq":"10","start":"Attachment","end":"Account","relation":"Parent","rows":"12"}
,{"seq":"11","start":"Attachment","end":"Campaign","relation":"Parent","rows":"5"}
,{"seq":"12","start":"Attachment","end":"Lead","relation":"Parent","rows":"75"}];
var ellipseSelected, pathSelected, parentNodeX, parentNodeY, relationshipName, indexEdge, fromData, toData, nodeSelected, startNodeSelected;
//flag =1 ,when we have both src and trg
var flag = 1;
var newCount = 0;
var edges = d3.selectAll('.edge');
var path = d3.selectAll('.path')
var allEllipse = d3.selectAll('ellipse');
var allNodes = d3.selectAll('.node');
var theGraph = document.getElementById('graph0') //getContainer
var polygon = document.getElementsByTagName('polygon')[0] //getPolygon to insert after
var allEdgesJS = document.getElementsByClassName("edge"); //select all Edges
for (var i = 0; i < allEdgesJS.length; i++) { //Loop through edges to move
theGraph.insertBefore(allEdgesJS[i], polygon.nextSibling); //insert after polygon
}
function ellipseAdd() {
d3.select(ellipseSelected.parentNode)
.append("circle")
.attr('cx', parentNodeX) //thisParentBBox.left + thisParentBBox.width/2)
.attr('cy', parentNodeY)
.attr("r", 10)
.attr("stroke-width", 1)
.attr("stroke", "white")
.style('fill', '#CE2029');
d3.select(ellipseSelected.parentNode)
.data([toData])
.append("text")
.attr('x', parentNodeX - 8)
.attr('y', parentNodeY + 4).text(0).style('fill', 'white')
.attr("font-size", "8px")
.transition()
.duration(3000)
.tween("text", function(d) {
var i = d3.interpolate(fromData, d),
prec = (d + "").split("."),
round = (prec.length > 1) ? Math.pow(10, prec[1].length) : 1;
return function(t) {
this.textContent = Math.round(i(t) * round) / round;
};
});
}
function blinker() {
if (flag == 0) {
//for adding ellipse and text to it
ellipseAdd();
} else {
//blink 3 things\
//ellipse
ellipseAdd();
d3.select('#' + indexAndEdge[indexEdge].id + ' path').style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('stroke-width', 1).duration(300).style('opacity', 1)
.transition().style('stroke', "#ff800e").style('stroke-width', 1); //select current id from array //select current id from array
d3.select('#' + indexAndEdge[indexEdge].id + ' polygon')
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('stroke', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('stroke', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('fill', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').style('stroke-width', 1).duration(300).style('opacity', 1)
.transition().style('stroke', "#ff800e").style('fill', "#ff800e").style('stroke-width', 1); //select current id from array
d3.select('#' + indexAndEdge[indexEdge].id + ' text').style('opacity', 0)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', "#ff800e");
}
}
edges.style('opacity', 1);
allNodes.style('fill', "white");
path.style('fill', "yellow");
var indexAndEdge = [];
var countOnNode = [];
edges.each(function(d, i) {
var thisEdgeCount = this.id.substring(4);
debugger
indexAndEdge.push({ //push index you are at, the edge count worked out above and the id
index: i,
count: thisEdgeCount,
id: this.id,
start: String(this.childNodes[0].childNodes[0].nodeValue).split("->")[0],
destination: String(this.childNodes[0].childNodes[0].nodeValue).split("->")[1],
relation: this.childNodes[6].childNodes[0]
})
d3.select('#' + indexAndEdge[i].id + ' polygon').style('fill', 'grey').style('stroke', 'grey');
d3.select('#' + indexAndEdge[i].id + ' path').style('stroke', 'grey');
});
d3.selectAll('.node').each(function(d, i) {
var thisNodeCount = this.id;
debugger
countOnNode.push({ //push index you are at, the edge count worked out above and the id
id: thisNodeCount,
prevData: 0,
incrementData: 0,
title: this.childNodes[0].childNodes[0].nodeValue,
name: String(this.childNodes[4].childNodes[0].nodeValue)
})
});
function timer() {
setTimeout(function(d) {
if (newCount < data.length) { //if we havent gone through all edges
if (data[newCount].end.length == 0) {
flag = 0;
for (j = 0; j < allNodes[0].length; j++) {
//if sourseName matches
if (String(allNodes[0][j].childNodes[4].childNodes[0].nodeValue) == data[newCount].start) {
ellipseSelected = d3.selectAll('.node')[0][j].childNodes[2];
parentNodeX = ellipseSelected.attributes.cx.value - ellipseSelected.attributes.rx.value + (2 * ellipseSelected.attributes.rx.value);
parentNodeY = ellipseSelected.attributes.cy.value - (ellipseSelected.attributes.ry.value / 2);
//send the data to interpolate
//match id and update prevData ,incrementData
for (var l = 0; l < countOnNode.length; l++) {
if (countOnNode[l].id == d3.selectAll('.node')[0][j].id) {
countOnNode[l].prevData = countOnNode[l].incrementData;
countOnNode[l].incrementData = data[newCount].rows;
fromData = countOnNode[l].prevData;
toData = countOnNode[l].incrementData;
}
}
blinker();
flag = 1;
if (flag == 1) {
break;
}
}
}
} else {
//check relation and targetNode
//check target
flag = 1;
for (var j = 0; j < allNodes[0].length; j++) {
if (String(allNodes[0][j].childNodes[4].childNodes[0].nodeValue) == data[newCount].end) {
ellipseSelected = d3.selectAll('.node')[0][j].childNodes[2];
parentNodeX = ellipseSelected.attributes.cx.value - ellipseSelected.attributes.rx.value + (2 * ellipseSelected.attributes.rx.value);
parentNodeY = ellipseSelected.attributes.cy.value - (ellipseSelected.attributes.ry.value / 2);
for (var l = 0; l < countOnNode.length; l++) {
if (countOnNode[l].id == d3.selectAll('.node')[0][j].id) {
countOnNode[l].prevData = countOnNode[l].incrementData;
countOnNode[l].incrementData = +data[newCount].rows + +countOnNode[l].prevData;
fromData = countOnNode[l].prevData;
toData = countOnNode[l].incrementData;
nodeSelected = l;
// console.log(" j =" + j + "l "+l+ " fromData " + fromData + " toData "+toData);
}
}
debugger
for (var ll = 0; ll < countOnNode.length; ll++) {
if (countOnNode[ll].name == data[newCount].start) {
debugger;
// console.log(data[newCount]);
startNodeSelected = ll;
}
}
debugger
//set the edge by checking relation
for (var k = 0; k < indexAndEdge.length; k++) {
//if(edges[0][k].childNodes[7].childNodes[0] == indexAndEdge)
if ((data[newCount].relation.trim() == (String(indexAndEdge[k].relation.nodeValue).trim()) &&
(((countOnNode[nodeSelected].title == indexAndEdge[k].destination) && (countOnNode[startNodeSelected].title == indexAndEdge[k].start)) || ((countOnNode[nodeSelected].title == indexAndEdge[k].start) && (countOnNode[startNodeSelected].title == indexAndEdge[k].destination))))) {
indexEdge = k;
}
}
blinker();
flag = 0;
if (flag == 0) {
break;
}
}
}
}
//allEllipse
newCount++;
timer();
} else {
// count =0 ;
timer()
console.log('end') //end
}
}, 3000)
}
timer();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: graphname Pages: 1 -->
<svg width="308pt" height="131pt"
viewBox="0.00 0.00 308.09 131.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 127)">
<title>graphname</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-127 304.095,-127 304.095,4 -4,4"/>
<!-- 0 -->
<g id="node1" class="node"><title>0</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="51.4971" cy="-105" rx="42.4939" ry="18"/>
<text text-anchor="middle" x="51.4971" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Account</text>
</g>
<!-- 1 -->
<g id="node2" class="node"><title>1</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="177.497" cy="-18" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="177.497" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Attachment</text>
</g>
<!-- 0->1 -->
<g id="edge1" class="edge"><title>0->1</title>
<path fill="none" stroke="#cd0000" d="M81.6636,-83.6496C104.156,-68.4764 134.397,-48.0758 154.846,-34.2806"/>
<polygon fill="#cd0000" stroke="#cd0000" points="79.4899,-80.894 73.1573,-89.388 83.4047,-86.697 79.4899,-80.894"/>
<text text-anchor="middle" x="143.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
<!-- 2 -->
<g id="node3" class="node"><title>2</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="32.4971" cy="-18" rx="32.4942" ry="18"/>
<text text-anchor="middle" x="32.4971" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Order</text>
</g>
<!-- 0->2 -->
<g id="edge2" class="edge"><title>0->2</title>
<path fill="none" stroke="#cd0000" d="M36.6269,-78.2339C35.365,-75.1966 34.2755,-72.0805 33.4971,-69 30.8171,-58.3937 30.5329,-46.1155 30.9355,-36.3806"/>
<polygon fill="#cd0000" stroke="#cd0000" points="33.6008,-80.0185 41.0756,-87.527 39.9146,-76.9959 33.6008,-80.0185"/>
<text text-anchor="middle" x="61.4971" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Account </text>
</g>
<!-- 3 -->
<g id="node4" class="node"><title>3</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="177.497" cy="-105" rx="47.3916" ry="18"/>
<text text-anchor="middle" x="177.497" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Campaign</text>
</g>
<!-- 3->1 -->
<g id="edge3" class="edge"><title>3->1</title>
<path fill="none" stroke="#cd0000" d="M177.497,-76.7339C177.497,-63.4194 177.497,-47.806 177.497,-36.1754"/>
<polygon fill="#cd0000" stroke="#cd0000" points="173.997,-76.7989 177.497,-86.799 180.997,-76.799 173.997,-76.7989"/>
<text text-anchor="middle" x="198.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
<!-- 4 -->
<g id="node5" class="node"><title>4</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="271.497" cy="-105" rx="28.6953" ry="18"/>
<text text-anchor="middle" x="271.497" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Lead</text>
</g>
<!-- 4->1 -->
<g id="edge4" class="edge"><title>4->1</title>
<path fill="none" stroke="#cd0000" d="M251.874,-81.4584C243.735,-72.5603 233.988,-62.4628 224.497,-54 216.904,-47.2291 208.071,-40.4074 200.126,-34.6078"/>
<polygon fill="#cd0000" stroke="#cd0000" points="249.277,-83.8042 258.567,-88.8979 254.481,-79.1226 249.277,-83.8042"/>
<text text-anchor="middle" x="259.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
</g>
</svg>
Here,circle is added to .svg file.And then text to that circle is added. I want to add text at centre of circle and also if number is bigger like 10000 ,it should fit to that circle.
I tried with
.attr('height', 'auto')
.attr('text-anchor', 'middle')
But,as position of text is decided on which node is added(present in .svg file) and not on circle position,it is not working.

Create SVG groups to hold the circles and text labels. Adjust the position of both circles and text using transform attribute of group elements. Set text-anchor attribute of text element as middle.
var circles = d3.select(ellipseSelected.parentNode)
.append("g")
.attr("transform","translate("+parentNodeX+","+parentNodeY+")")
circles.append("circle")
.attr("r", 10)
.attr("stroke-width", 1)
.attr("stroke", "white")
.style('fill', '#CE2029');
d3.select(ellipseSelected.parentNode)
.data([toData]);
circles.data([toData]).append("text")
.style("dominant-baseline","central")
.attr("dx", 0)
.attr('text-anchor',"middle")
.attr("font-size", "8px")
.transition()
.duration(3000)
.tween("text", function(d) {
var i = d3.interpolate(fromData, d),
prec = (d + "").split("."),
round = (prec.length > 1) ? Math.pow(10, prec[1].length) : 1;
return function(t) {
this.textContent = Math.round(i(t) * round) / round;
//Update node radius based on text length.
var rad = this.textContent.length>3?(this.textContent.length/3)*10:10;
d3.select(this.parentNode).select("circle").attr("r",rad);
};
});
var data =
[{"seq":"1","start":"Account","end":"Order","relation":"Account","rows":"1"},
{"seq":"2","start":"Account","end":"Attachment","relation":"Parent","rows":"10"}
,{"seq":"3","start":"Order","end":"Account","relation":"Account","rows":"15"}
,{"seq":"4","start":"Attachment","end":"Account","relation":"Parent","rows":"55"}
,{"seq":"5","start":"Attachment","end":"Campaign","relation":"Parent","rows":"45"}
,{"seq":"6","start":"Attachment","end":"Lead","relation":"Parent","rows":"47"}
,{"seq":"7","start":"Lead","end":"Attachment","relation":"Parent","rows":"75"}
,{"seq":"8","start":"Campaign","end":"Attachment","relation":"Parent","rows":"34"},
{"seq":"9","start":"Order","end":"Account","relation":"Account","rows":"99"}
,{"seq":"10","start":"Attachment","end":"Account","relation":"Parent","rows":"12"}
,{"seq":"11","start":"Attachment","end":"Campaign","relation":"Parent","rows":"5"}
,{"seq":"12","start":"Attachment","end":"Lead","relation":"Parent","rows":"75"}];
var ellipseSelected, pathSelected, parentNodeX, parentNodeY, relationshipName, indexEdge, fromData, toData, nodeSelected, startNodeSelected;
//flag =1 ,when we have both src and trg
var flag = 1;
var newCount = 0;
var edges = d3.selectAll('.edge');
var path = d3.selectAll('.path')
var allEllipse = d3.selectAll('ellipse');
var allNodes = d3.selectAll('.node');
var theGraph = document.getElementById('graph0') //getContainer
var polygon = document.getElementsByTagName('polygon')[0] //getPolygon to insert after
var allEdgesJS = document.getElementsByClassName("edge"); //select all Edges
for (var i = 0; i < allEdgesJS.length; i++) { //Loop through edges to move
theGraph.insertBefore(allEdgesJS[i], polygon.nextSibling); //insert after polygon
}
function ellipseAdd() {
var circles = d3.select(ellipseSelected.parentNode)
.append("g")
.attr("transform","translate("+parentNodeX+","+parentNodeY+")")
circles.append("circle")
.attr("r", 10)
.attr("stroke-width", 1)
.attr("stroke", "white")
.style('fill', '#CE2029');
d3.select(ellipseSelected.parentNode)
.data([toData]);
circles.data([toData]).append("text")
.style("dominant-baseline","central")
.attr("dx", 0)
.attr('text-anchor',"middle")
.attr("font-size", "8px")
.transition()
.duration(3000)
.tween("text", function(d) {
var i = d3.interpolate(fromData, d),
prec = (d + "").split("."),
round = (prec.length > 1) ? Math.pow(10, prec[1].length) : 1;
return function(t) {
this.textContent = Math.round(i(t) * round) / round;
var rad = this.textContent.length>3?(this.textContent.length/3)*10:10;
d3.select(this.parentNode).select("circle").attr("r",rad);
};
});
}
function blinker() {
if (flag == 0) {
//for adding ellipse and text to it
ellipseAdd();
} else {
//blink 3 things\
//ellipse
ellipseAdd();
d3.select('#' + indexAndEdge[indexEdge].id + ' path').style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('stroke-width', 1)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('stroke-width', 1).duration(300).style('opacity', 1)
.transition().style('stroke', "#ff800e").style('stroke-width', 1); //select current id from array //select current id from array
d3.select('#' + indexAndEdge[indexEdge].id + ' polygon')
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('stroke', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('stroke', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('stroke', '#CE2029').style('fill', '#CE2029').style('stroke-width', 2)
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('stroke', 'grey').style('fill', 'grey').style('stroke-width', 1).duration(300).style('opacity', 1)
.transition().style('stroke', "#ff800e").style('fill', "#ff800e").style('stroke-width', 1); //select current id from array
d3.select('#' + indexAndEdge[indexEdge].id + ' text').style('opacity', 0)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', '#CE2029').style('fill', '#CE2029')
.transition().duration(300).duration(300).style('opacity', 1)
.transition().style('fill', 'grey').duration(300).style('opacity', 1)
.transition().style('fill', "#ff800e");
}
}
edges.style('opacity', 1);
allNodes.style('fill', "white");
path.style('fill', "yellow");
var indexAndEdge = [];
var countOnNode = [];
edges.each(function(d, i) {
var thisEdgeCount = this.id.substring(4);
debugger
indexAndEdge.push({ //push index you are at, the edge count worked out above and the id
index: i,
count: thisEdgeCount,
id: this.id,
start: String(this.childNodes[0].childNodes[0].nodeValue).split("->")[0],
destination: String(this.childNodes[0].childNodes[0].nodeValue).split("->")[1],
relation: this.childNodes[6].childNodes[0]
})
d3.select('#' + indexAndEdge[i].id + ' polygon').style('fill', 'grey').style('stroke', 'grey');
d3.select('#' + indexAndEdge[i].id + ' path').style('stroke', 'grey');
});
d3.selectAll('.node').each(function(d, i) {
var thisNodeCount = this.id;
debugger
countOnNode.push({ //push index you are at, the edge count worked out above and the id
id: thisNodeCount,
prevData: 0,
incrementData: 0,
title: this.childNodes[0].childNodes[0].nodeValue,
name: String(this.childNodes[4].childNodes[0].nodeValue)
})
});
function timer() {
setTimeout(function(d) {
if (newCount < data.length) { //if we havent gone through all edges
if (data[newCount].end.length == 0) {
flag = 0;
for (j = 0; j < allNodes[0].length; j++) {
//if sourseName matches
if (String(allNodes[0][j].childNodes[4].childNodes[0].nodeValue) == data[newCount].start) {
ellipseSelected = d3.selectAll('.node')[0][j].childNodes[2];
parentNodeX = ellipseSelected.attributes.cx.value - ellipseSelected.attributes.rx.value + (2 * ellipseSelected.attributes.rx.value);
parentNodeY = ellipseSelected.attributes.cy.value - (ellipseSelected.attributes.ry.value / 2);
//send the data to interpolate
//match id and update prevData ,incrementData
for (var l = 0; l < countOnNode.length; l++) {
if (countOnNode[l].id == d3.selectAll('.node')[0][j].id) {
countOnNode[l].prevData = countOnNode[l].incrementData;
countOnNode[l].incrementData = data[newCount].rows;
fromData = countOnNode[l].prevData;
toData = countOnNode[l].incrementData;
}
}
blinker();
flag = 1;
if (flag == 1) {
break;
}
}
}
} else {
//check relation and targetNode
//check target
flag = 1;
for (var j = 0; j < allNodes[0].length; j++) {
if (String(allNodes[0][j].childNodes[4].childNodes[0].nodeValue) == data[newCount].end) {
ellipseSelected = d3.selectAll('.node')[0][j].childNodes[2];
parentNodeX = ellipseSelected.attributes.cx.value - ellipseSelected.attributes.rx.value + (2 * ellipseSelected.attributes.rx.value);
parentNodeY = ellipseSelected.attributes.cy.value - (ellipseSelected.attributes.ry.value / 2);
for (var l = 0; l < countOnNode.length; l++) {
if (countOnNode[l].id == d3.selectAll('.node')[0][j].id) {
countOnNode[l].prevData = countOnNode[l].incrementData;
countOnNode[l].incrementData = +data[newCount].rows + +countOnNode[l].prevData;
fromData = countOnNode[l].prevData;
toData = countOnNode[l].incrementData;
nodeSelected = l;
// console.log(" j =" + j + "l "+l+ " fromData " + fromData + " toData "+toData);
}
}
debugger
for (var ll = 0; ll < countOnNode.length; ll++) {
if (countOnNode[ll].name == data[newCount].start) {
debugger;
// console.log(data[newCount]);
startNodeSelected = ll;
}
}
debugger
//set the edge by checking relation
for (var k = 0; k < indexAndEdge.length; k++) {
//if(edges[0][k].childNodes[7].childNodes[0] == indexAndEdge)
if ((data[newCount].relation.trim() == (String(indexAndEdge[k].relation.nodeValue).trim()) &&
(((countOnNode[nodeSelected].title == indexAndEdge[k].destination) && (countOnNode[startNodeSelected].title == indexAndEdge[k].start)) || ((countOnNode[nodeSelected].title == indexAndEdge[k].start) && (countOnNode[startNodeSelected].title == indexAndEdge[k].destination))))) {
indexEdge = k;
}
}
blinker();
flag = 0;
if (flag == 0) {
break;
}
}
}
}
//allEllipse
newCount++;
timer();
} else {
// count =0 ;
timer()
// console.log('end') //end
}
}, 3000)
}
timer();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: graphname Pages: 1 -->
<svg width="308pt" height="131pt"
viewBox="0.00 0.00 308.09 131.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 127)">
<title>graphname</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-127 304.095,-127 304.095,4 -4,4"/>
<!-- 0 -->
<g id="node1" class="node"><title>0</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="51.4971" cy="-105" rx="42.4939" ry="18"/>
<text text-anchor="middle" x="51.4971" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Account</text>
</g>
<!-- 1 -->
<g id="node2" class="node"><title>1</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="177.497" cy="-18" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="177.497" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Attachment</text>
</g>
<!-- 0->1 -->
<g id="edge1" class="edge"><title>0->1</title>
<path fill="none" stroke="#cd0000" d="M81.6636,-83.6496C104.156,-68.4764 134.397,-48.0758 154.846,-34.2806"/>
<polygon fill="#cd0000" stroke="#cd0000" points="79.4899,-80.894 73.1573,-89.388 83.4047,-86.697 79.4899,-80.894"/>
<text text-anchor="middle" x="143.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
<!-- 2 -->
<g id="node3" class="node"><title>2</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="32.4971" cy="-18" rx="32.4942" ry="18"/>
<text text-anchor="middle" x="32.4971" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Order</text>
</g>
<!-- 0->2 -->
<g id="edge2" class="edge"><title>0->2</title>
<path fill="none" stroke="#cd0000" d="M36.6269,-78.2339C35.365,-75.1966 34.2755,-72.0805 33.4971,-69 30.8171,-58.3937 30.5329,-46.1155 30.9355,-36.3806"/>
<polygon fill="#cd0000" stroke="#cd0000" points="33.6008,-80.0185 41.0756,-87.527 39.9146,-76.9959 33.6008,-80.0185"/>
<text text-anchor="middle" x="61.4971" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Account </text>
</g>
<!-- 3 -->
<g id="node4" class="node"><title>3</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="177.497" cy="-105" rx="47.3916" ry="18"/>
<text text-anchor="middle" x="177.497" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Campaign</text>
</g>
<!-- 3->1 -->
<g id="edge3" class="edge"><title>3->1</title>
<path fill="none" stroke="#cd0000" d="M177.497,-76.7339C177.497,-63.4194 177.497,-47.806 177.497,-36.1754"/>
<polygon fill="#cd0000" stroke="#cd0000" points="173.997,-76.7989 177.497,-86.799 180.997,-76.799 173.997,-76.7989"/>
<text text-anchor="middle" x="198.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
<!-- 4 -->
<g id="node5" class="node"><title>4</title>
<ellipse fill="#b2dfee" stroke="#b2dfee" cx="271.497" cy="-105" rx="28.6953" ry="18"/>
<text text-anchor="middle" x="271.497" y="-101.3" font-family="Times New Roman,serif" font-size="14.00">Lead</text>
</g>
<!-- 4->1 -->
<g id="edge4" class="edge"><title>4->1</title>
<path fill="none" stroke="#cd0000" d="M251.874,-81.4584C243.735,-72.5603 233.988,-62.4628 224.497,-54 216.904,-47.2291 208.071,-40.4074 200.126,-34.6078"/>
<polygon fill="#cd0000" stroke="#cd0000" points="249.277,-83.8042 258.567,-88.8979 254.481,-79.1226 249.277,-83.8042"/>
<text text-anchor="middle" x="259.997" y="-57.8" font-family="Times New Roman,serif" font-size="14.00"> Parent </text>
</g>
</g>
</svg>

Related

JQuery draggable element controlling a SVG object jumping for the first time

I have to adjust a SVG's position and scale using DIV having handles.
Everything is working as expected except SVG is jumping the first time at the time of dragging the div handles. Only the SVG is jumping.
See here that the class "selection" is a DIV controlling the selected SVG with attribute ("[selection=true]")
$( ".selector" ).resizable({
aspectRatio: false,
handles: {
'nw': '#nwgrip',
'ne': '#negrip',
'sw': '#swgrip',
'se': '#segrip' },
resize: function(event, ui) {
console.log(ui.size.width);
$('#posW').text('Width: ' + Math.round(ui.size.width) );
$('#posH').text('Height: ' + Math.round(ui.size.height) );
$("[selection=true]").attr("width", Math.round(ui.size.width) );
$("[selection=true]").attr("height", Math.round(ui.size.height) );
$("[selection=true]").attr("x", Math.round(ui.position.left) );
$("[selection=true]").attr("y", Math.round(ui.position.top) );
}
}).draggable({
drag: function(event, ui) {
var offset = $(this).offset();
var xPos = offset.left;
var yPos = offset.top;
$("[selection=true]").attr("x", Math.round(xPos) );
$("[selection=true]").attr("y", Math.round(yPos) );
$('#posX').text('x: ' + xPos);
$('#posY').text('y: ' + yPos);
}
}
);
Please check jsfiddle link
Is this a bug that can be fixed?
Here's a working version of your original. It handles all clicking, dragging, and selector box behaviour within the "canvas" SVG.
It uses pure JS and manipulates the badge <svg> and selector box elements using DOM methods.
Hopefully it is fairly easily to follow what is going on.
let selectedBadge = null;
let isDraggingRect = null;
let isDraggingHandle = null;
let dragOffsetX = 0;
let dragOffsetY = 0;
// Event handlers for the badges
let badges = document.querySelectorAll(".canvas > .badge");
badges.forEach(b => b.addEventListener("click", select));
// Event handlers for selector box and handles
let selectorRect = document.querySelector("#selector rect");
selectorRect.addEventListener("mousedown", selectorMouseDown);
let handleNW = document.getElementById("nwgrip");
let handleNE = document.getElementById("negrip");
let handleSW = document.getElementById("swgrip");
let handleSE = document.getElementById("segrip");
let grips = document.querySelectorAll("#selector > circle");
grips.forEach(g => {
g.addEventListener("mousedown", gripMouseDown);
});
// Attach mousemove and mouseup events to SVG for dragging purposes
// We attach to the parent SVG because mouse events on small elements
// will be missed if you move the mouse outside the element.
let canvasSVG = document.querySelector("#svg_obj > .canvas");
canvasSVG.addEventListener("mousemove", mouseMove);
canvasSVG.addEventListener("mouseup", mouseUp);
// select a badge
function select(evt) {
hideSelector(selectedBadge);
selectedBadge = evt.target.ownerSVGElement;
showSelector(selectedBadge)
}
function showSelector(badge) {
setSelectorDimensionsTo({x: badge.x.baseVal.value,
y: badge.y.baseVal.value,
width: badge.width.baseVal.value,
height: badge.height.baseVal.value});
document.getElementById("selector").classList.add("show");
}
function hideSelector(badge) {
if (selectedBadge) {
document.getElementById("selector").classList.remove("show");
selectedBadge = null;
}
}
function setSelectorDimensionsTo(bounds) {
selectorRect.x.baseVal.value = bounds.x;
selectorRect.y.baseVal.value = bounds.y;
selectorRect.width.baseVal.value = bounds.width;
selectorRect.height.baseVal.value = bounds.height;
handleNW.cx.baseVal.value = bounds.x;
handleNW.cy.baseVal.value = bounds.y;
handleNE.cx.baseVal.value = bounds.x + bounds.width;
handleNE.cy.baseVal.value = bounds.y;
handleSW.cx.baseVal.value = bounds.x;
handleSW.cy.baseVal.value = bounds.y + bounds.height;
handleSE.cx.baseVal.value = bounds.x + bounds.width;
handleSE.cy.baseVal.value = bounds.y + bounds.height;
}
function moveSelectorTo(x, y) {
selectorRect.x.baseVal.value = x;
selectorRect.y.baseVal.value = y;
let w = selectorRect.width.baseVal.value;
let h = selectorRect.height.baseVal.value;
handleNW.cx.baseVal.value = x;
handleNW.cy.baseVal.value = y;
handleNE.cx.baseVal.value = x + w;
handleNE.cy.baseVal.value = y;
handleSW.cx.baseVal.value = x;
handleSW.cy.baseVal.value = y + h;
handleSE.cx.baseVal.value = x + w;
handleSE.cy.baseVal.value = y + h;
}
function moveSelectedBadgeTo(x, y) {
selectedBadge.x.baseVal.value = x;
selectedBadge.y.baseVal.value = y;
}
function selectorMouseDown(evt) {
isDraggingRect = selectedBadge;
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
dragOffsetX = mousePos.x - selectedBadge.x.baseVal.value;
dragOffsetY = mousePos.y - selectedBadge.y.baseVal.value;
}
function mouseUp(evt) {
isDraggingRect = null;
isDraggingHandle = null;
}
// Handles both:
// - dragging selector rect
// - dragging selector grip/handle
function mouseMove(evt) {
if (isDraggingRect)
{
// Move selector
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
moveSelectorTo(mousePos.x - dragOffsetX, mousePos.y - dragOffsetY);
// Move badge
moveSelectedBadgeTo(mousePos.x - dragOffsetX, mousePos.y - dragOffsetY);
}
else if (isDraggingHandle)
{
gripMouseMove(evt);
}
}
// Convert page mouse coords to SVG coords.
// Takes into account any scaling due to the presence of a viewBox.
function mouseCoordsToSVGCoords(mouseX, mouseY) {
var pt = canvasSVG.createSVGPoint();
pt.x = mouseX;
pt.y = mouseY;
return pt.matrixTransform(canvasSVG.getScreenCTM().inverse());
}
function gripMouseDown(evt) {
isDraggingHandle = evt.target;
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
dragOffsetX = mousePos.x - isDraggingHandle.cx.baseVal.value;
dragOffsetY = mousePos.y - isDraggingHandle.cy.baseVal.value;
}
function gripMouseUp(evt) {
isDraggingHandle = null;
}
function gripMouseMove(evt) {
// Move handle thus resizing selector
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
mousePos.x -= dragOffsetX;
mousePos.y -= dragOffsetY;
let bounds = {};
let oldX = selectorRect.x.baseVal.value;
let oldY = selectorRect.y.baseVal.value;
let oldW = selectorRect.width.baseVal.value;
let oldH = selectorRect.height.baseVal.value;
switch (isDraggingHandle.id) {
case "nwgrip":
bounds = {x: mousePos.x, y: mousePos.y, width: oldX + oldW - mousePos.x, height: oldY + oldH - mousePos.y};
break;
case "negrip":
bounds = {x: oldX, y: mousePos.y, width: mousePos.x - oldX, height: oldY + oldH - mousePos.y};
break;
case "swgrip":
bounds = {x: mousePos.x, y: oldY, width: oldX + oldW - mousePos.x, height: mousePos.y - oldY};
break;
case "segrip":
bounds = {x: oldX, y: oldY, width: mousePos.x - oldX, height: mousePos.y - oldY};
break;
}
setSelectorDimensionsTo(bounds);
// Resize badge
resizeBadgeTo(bounds);
}
function resizeBadgeTo(bounds) {
selectedBadge.x.baseVal.value = bounds.x;
selectedBadge.y.baseVal.value = bounds.y;
selectedBadge.width.baseVal.value = bounds.width;
selectedBadge.height.baseVal.value = bounds.height;
}
.canvas {
background-color: #cecece;
border: 2px solid #cecece;
width: 400px;
height: 400px;
position: relative;
}
#svg_obj {
position: absolute;
width: 100px;
height: 100px;
background: yellow;
}
#selector {
display: none;
}
#selector.show {
display: block;
}
#selector rect {
fill: transparent;
stroke: #f50;
stroke-width: 1px;
}
#nwgrip, #negrip, #swgrip, #segrip, #ngrip, #egrip, #sgrip, #wgrip {
fill: #ffffff;
stroke: #000000;
stroke-width: 1px;
}
<div id='svg_obj'>
<svg class="canvas" viewBox="0 0 400 400" width="400" height="400" >
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#21574B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#F1F74B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#81579B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<g id="selector">
<rect width="20" height="20"/>
<circle cx="0" cy="0" r="5" id="nwgrip"/>
<circle cx="20" cy="0" r="5" id="negrip"/>
<circle cx="0" cy="20" r="5" id="swgrip"/>
<circle cx="20" cy="20" r="5" id="segrip"/>
</g>
</svg>
</div>

why subrect of rect can not show in d3.js

what graph i want to generate is nested rect,but the sub rect cant show.
My partial code is :
_chart.renderFeatureAxisInner = function(svg=_svg){
feature_name = svg.select('.Feat_0_name').text();
nest_data = d3.nest()
.key(function(d){
return d[feature_name];
}).key(function(d){
return d['Label'];
}).entries(_chart._l1_inner_data);
var updateRect = svg.selectAll('#Feature_0')
.data(nest_data);
var enterRect = updateRect.enter();
var exitRect = updateRect.exit();
updateRect.append('g')
.attr('id',function(d_l0,i){
return 'Feature0_value_'+i;
})
.selectAll('rect')
.data(function(d_l0,i){
//console.log(i);
return d_l0.values;
}).enter() //nest_data[0].values
.append('rect');
var i_l0 = 0;
var offsety = 0;
var offsety_arr=[0];
updateRect.selectAll('rect')
.data(function(d_l0,i_l0){
//i_l0=i_l0;
offsety=0;
return d_l0.values;
}) //nest_data[0].values
//.append('rect')
.attr('id',function(d_l1,i_l1){
if(d_l1.values[0]['Sepal Length'] == '(4.296, 6.1]')
i_l0 = 0;
else i_l0 = 1;
return 'Feature0_v'+i_l0+'_'+i_l1;
})
.attr('stroke','black')
.attr('fill',function(d_l1,i_l1){
//nest_data[0].values[0]
return _colors[d_l1.key];
})
//.attr('stroke','blue')
.attr('width',function(d_l1,i_l1){
if(d_l1.values[0]['Sepal Length'] == '(4.296, 6.1]')
i_l0 = 0;
else i_l0 = 1;
return svg.select('.Feature0_value_'+i_l0)
.attr('width');
}).attr('height',function(d_l1,i_l1){
var h=_base_height * d_l1.values[0]['1'];
offsety_arr.push(h);
return h;
})
.attr('x',function(d_l1,i_l1){
//cls = d.values[0]['Sepal Length'];
if(d_l1.values[0]['Sepal Length'] == '(4.296, 6.1]')
i_l0 = 0;
else i_l0 = 1;
//console.log(i_l0);
return svg.select('.Feature0_value_'+i_l0)
.attr('x');
}).attr('y',function(d_l1,i_l1){
if(d_l1.values[0]['Sepal Length'] == '(4.296, 6.1]')
i_l0 = 0;
else i_l0 = 1;
offsety=offsety + offsety_arr.splice(0,1)[0];
console.log(offsety);
var basey=parseFloat(svg.select('.Feature0_value_0')
.attr('y'));
y=offsety+basey;
return y+'';
});
offsety_arr=[0];
}
I think the generated rects element is not wrong.
And the result html is :
<!DOCTYPE html>
<html>
<body>
<svg width="1200" height="500">
<path stroke-width="3px" stroke="red" class="baseline1" d="M187.5,100L187.5,400"></path>
<text dy="-1em" y="100" x="187.5" text-anchor="middle" font-size="12px" fill="white" class="Feat_0_name">Sepal Length</text>
<g class="Feature0_frame">
<rect height="60" width="94.999999995" y="190" x="140.0000000025" stroke="blue" fill-opacity="0.3" fill="none" class="Feature0_value_0" id="Feature_0">
<g id="Feature0_value_0">
<rect y="190" x="140.0000000025" height="31.57894737" width="94.999999995" fill="yellow" stroke="black" id="Feature0_v0_0"></rect>
<rect y="221.57894737" x="140.0000000025" height="21.473684208" width="94.999999995" fill="blue" stroke="black" id="Feature0_v0_1"></rect>
<rect y="243.052631578" x="140.0000000025" height="6.947368422" width="94.999999995" fill="red" stroke="black" id="Feature0_v0_2"></rect></g></rect>
<rect height="60" width="55.000000005" y="250" x="159.9999999975" stroke="blue" fill-opacity="0.3" fill="none" class="Feature0_value_1" id="Feature_0">
<g id="Feature0_value_1">
<rect y="250" x="159.9999999975" height="17.454545454" width="55.000000005" fill="blue" stroke="black" id="Feature0_v1_0"></rect>
<rect y="267.454545454" x="159.9999999975" height="42.545454546" width="55.000000005" fill="red" stroke="black" id="Feature0_v1_1"></rect></g></rect>
</g>
</svg>
</body>
</html>
and the result is result image
However,Run it in Browser,just show 2 rects ranther than 7 rects,in other words, the sub rects are not shown. What is wrong? can somebody help ?
what i want to realize is the figure 1 figure 1 and 2
and any suggestion on figure 2 realization, for example ,what layout should i use(maybe Treemap?) or just the same method on figure1 ?

Pausing JS Typewriter

I'm using a script on Codepen that mimics a type effect. http://codepen.io/hi-im-si/pen/DHoup.
Trying to create a simple start/stop button. I've added the pause svg button and class, but not quite sure how to get it to pause.
Thanks for any assistance!
Here's the script:
var TxtType = function(el, toRotate, period) {
this.toRotate = toRotate;
this.el = el;
this.loopNum = 0;
this.period = parseInt(period, 10) || 2000;
this.txt = '';
this.tick();
this.isDeleting = false;
};
TxtType.prototype.tick = function() {
var i = this.loopNum % this.toRotate.length;
var fullTxt = this.toRotate[i];
if (this.isDeleting) {
this.txt = fullTxt.substring(0, this.txt.length - 1);
} else {
this.txt = fullTxt.substring(0, this.txt.length + 1);
}
this.el.innerHTML = '<span class="wrap">'+this.txt+'</span>';
var that = this;
var delta = 200 - Math.random() * 100;
if (this.isDeleting) { delta /= 2; }
if (!this.isDeleting && this.txt === fullTxt) {
delta = this.period;
this.isDeleting = true;
} else if (this.isDeleting && this.txt === '') {
this.isDeleting = false;
this.loopNum++;
delta = 500;
}
setTimeout(function() {
that.tick();
}, delta);
};
window.onload = function() {
var elements = document.getElementsByClassName('typewrite');
for (var i=0; i<elements.length; i++) {
var toRotate = elements[i].getAttribute('data-type');
var period = elements[i].getAttribute('data-period');
if (toRotate) {
new TxtType(elements[i], JSON.parse(toRotate), period);
}
}
// INJECT CSS
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = ".typewrite > .wrap { border-right: 0.08em solid #fff}";
document.body.appendChild(css);
};
body {
background-color:#ce3635;
text-align: center;
color:#fff;
padding-top:10em;
font-family:Helvetica;
}
* { color:#fff; text-decoration: none;}
<div class="type-wrap">
<h2>
<a href="" class="typewrite" data-period="2000" data-type='[ "Hi, My name is Justin.", "I am Creative.", "I Love Design.", "I Love to Develop." ]'>
<span class="wrap"></span></a>
</h2>
</div>
<div class="controls">
<a href="#" class="stop-start-btn"><span class="icon-pause"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 24 24"><g transform="translate(0, 0)">
<line data-color="color-2" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" x1="9" y1="16" x2="9" y2="8" stroke-linejoin="miter"/>
<line data-color="color-2" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" x1="15" y1="16" x2="15" y2="8" stroke-linejoin="miter"/>
<circle fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" cx="12" cy="12" r="11" stroke-linejoin="miter"/>
</g></svg></span></a>
</div>
var TxtType = function(el, toRotate, period) {
this.toRotate = toRotate;
this.el = el;
this.loopNum = 0;
this.period = parseInt(period, 10) || 2000;
this.txt = '';
this.tick();
this.lastDeletingStatus=0;
this.isDeleting = 0;
};
var timer;
TxtType.prototype.tick = function() {
var i = this.loopNum % this.toRotate.length;
var fullTxt = this.toRotate[i];
if (this.isDeleting===1) {
this.txt = fullTxt.substring(0, this.txt.length - 1);
} else {
this.txt = fullTxt.substring(0, this.txt.length + 1);
}
this.el.innerHTML = '<span class="wrap">'+this.txt+'</span>';
var that = this;
var delta = 200 - Math.random() * 100;
if (this.isDeleting===1) { delta /= 2; }
if (this.isDeleting===0 && this.txt === fullTxt) {
delta = this.period;
this.isDeleting = 1;
} else if (this.isDeleting===1 && this.txt === '') {
this.isDeleting = 0;
this.loopNum++;
delta = 500;
}
if(this.isDeleting!==2){
timer=setTimeout(function() {
that.tick();
}, delta);
}
};
TxtType.prototype.toggleStart=function(){
//start back up
if(this.isDeleting===2){
this.isDeleting=this.lastDeletingStatus;
this.lastDeletingStatus=2;
}
//stop
else{
this.lastDeletingStatus=this.isDeleting;
this.isDeleting=2;
clearTimeout(timer);
}
}
var toggleStart=function(){
txtType.toggleStart();
txtType.tick();
}
var txtType;
window.onload = function() {
var elements = document.getElementsByClassName('typewrite');
for (var i=0; i<elements.length; i++) {
var toRotate = elements[i].getAttribute('data-type');
var period = elements[i].getAttribute('data-period');
if (toRotate) {
txtType=new TxtType(elements[i], JSON.parse(toRotate), period);
}
}
// INJECT CSS
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = ".typewrite > .wrap { border-right: 0.08em solid #fff}";
document.body.appendChild(css);
};
body {
background-color:#ce3635;
text-align: center;
color:#fff;
padding-top:10em;
font-family:Helvetica;
}
* { color:#fff; text-decoration: none;}
<div class="type-wrap">
<h2>
<a href="" class="typewrite" data-period="2000" data-type='[ "Hi, My name is Justin.", "I am Creative.", "I Love Design.", "I Love to Develop." ]'>
<span class="wrap"></span></a>
</h2>
</div>
<div class="controls">
<a href="#" class="stop-start-btn"><span class="icon-pause" ><svg onclick="toggleStart()" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 24 24"><g transform="translate(0, 0)">
<line data-color="color-2" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" x1="9" y1="16" x2="9" y2="8" stroke-linejoin="miter"/>
<line data-color="color-2" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" x1="15" y1="16" x2="15" y2="8" stroke-linejoin="miter"/>
<circle fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" cx="12" cy="12" r="11" stroke-linejoin="miter"/>
</g></svg></span></a>
</div>
isDeleting shouldn't be a boolean. It should be able to hold three values. isDeleting=0, isDeleting=1, isDeleting=2 (which is the stopped state).
Then create a function TxtType.prototype.toggleStart that sets this.isDeleting to 2 if it isn't 2, and sets it to the previous value of this.isDeleting if it is two.
To implement this, do the following:
1) Create a global variable, called txtType. In window.onload, set it equal to new TxtType(...). This way, you can access the object from other functions. It would look something like this:
var txtType;
window.onload = function() {
var elements = document.getElementsByClassName('typewrite');
for (var i=0; i<elements.length; i++) {
var toRotate = elements[i].getAttribute('data-type');
var period = elements[i].getAttribute('data-period');
if (toRotate) {
txtType=new TxtType(elements[i], JSON.parse(toRotate), period);
}
}
...
};
2)Create a global timer variable that you set equal to the timeout call in tick(). That way, you can clear the timer from other functions. That would look something like this:
var timer;
TxtType.prototype.tick = function() {
......
timer=setTimeout(function() {
that.tick();
}, delta);
}
3)Wherever isDeleting=false, set isDeleting=0. Whenever isDeleting=true, set isDeleting=1. Put an if statement around setTimeout() so that it only runs if isDeleting!==2 (ie. it is not in the stopped state. If it's in the stopped state we do not want this timer to run).
4)Create a function on the prototype of TxtType called toggleStart as follows:
TxtType.prototype.toggleStart=function(){
//start back up
if(this.isDeleting===2){
this.isDeleting=this.lastDeletingStatus;
this.lastDeletingStatus=2;
}
//stop
else{
this.lastDeletingStatus=this.isDeleting;
this.isDeleting=2;
clearTimeout(timer);
}
}
(Initialize this.lastDeletingStatus to 0 in the constructor of TxtType)
5)Create a global function called toggleStart that you can call from html as follows:
var toggleStart=function(){
txtType.toggleStart();
txtType.tick();
}
6)Last step, add onclick="toggleStart()" from the pause svg in your html like this:
<svg onclick="toggleStart()" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 24 24">
Tada!!!!

I'm trying to get this code I found for draggable SVGs to work

I found some interesting code on petercollingridge.co.uk for dragging SVGs.
After a while of trying to get it to work in my project, I decided to just try to get Peter's code to run in a fiddle.
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="200">
<style>
.draggable {
cursor: move;
}
</style>
<script type="text/ecmascript">
< ![CDATA[
var selectedElement = 0;
var currentX = 0;
var currentY = 0;
var currentMatrix = 0;
function selectElement(evt) {
selectedElement = evt.target;
currentX = evt.clientX;
currentY = evt.clientY;
currentMatrix = selectedElement.getAttributeNS(null, "transform").slice(7, -1).split(' ');
for (var i = 0; i < currentMatrix.length; i++) {
currentMatrix[i] = parseFloat(currentMatrix[i]);
}
selectedElement.setAttributeNS(null, "onmousemove", "moveElement(evt)");
selectedElement.setAttributeNS(null, "onmouseout", "deselectElement(evt)");
selectedElement.setAttributeNS(null, "onmouseup", "deselectElement(evt)");
}
function moveElement(evt) {
var dx = evt.clientX - currentX;
var dy = evt.clientY - currentY;
currentMatrix[4] += dx;
currentMatrix[5] += dy;
selectedElement.setAttributeNS(null, "transform", "matrix(" + currentMatrix.join(' ') + ")");
currentX = evt.clientX;
currentY = evt.clientY;
}
function deselectElement(evt) {
if (selectedElement != 0) {
selectedElement.removeAttributeNS(null, "onmousemove");
selectedElement.removeAttributeNS(null, "onmouseout");
selectedElement.removeAttributeNS(null, "onmouseup");
selectedElement = 0;
}
}
]] >
</script>
<rect x="0.5" y="0.5" width="399" height="199" fill="none" stroke="black" />
<rect class="draggable" x="30" y="30" width="80" height="80" fill="blue" transform="matrix(1 0 0 1 25 20)" onmousedown="selectElement(evt)" />
<rect class="draggable" x="160" y="50" width="50" height="50" fill="green" transform="matrix(1 0 0 1 103 -25)" onmousedown="selectElement(evt)" />
</svg>
I'm still getting the errors I was in my project, those being:
" Uncaught SyntaxError: Unexpected token <" and "Uncaught ReferenceError: selectElement is not defined "
I read something about invisible characters causing the first problem if you copy/paste code, but I haven't found any.
Thanks for any help you can offer.
Like others said, just remove the CDATA jumbo. Here is an updated fiddle:
https://jsfiddle.net/88pocqsr/1/
We've removed < ![CDATA[ and ]]>
Change the line
< ![CDATA[
to
<![CDATA[
(remove space between < and !)
and the line
]] >
to
]]>

d3js transforming nested group images

I am working on [this][1] d3 project. Basically I am trying to create a SQL like query builder. I can drop boxes to the drawing area & other operators inside the box. Then I should be able to connect them all. I am trying to translate 2 images which are nested in groups. I want to move the small items inside the big box. I can transform the big box and small operators separately. Problem happens When I try to move the small operators first. I want to move the small operators, then big boxes. meanwhile I want to keep the relative position of small operators and big box same. But when I try to move the large box after moving one of the small box it resets its location. Here is a demo of my work in jsfiddle
<g id="draw">
<rect class="container" height="400" width="400" x="0" y="0" style="fill:gray"></rect>
<g class="qbox" id="qbox">
<line id="dummyLine" x1="0" x2="0" y1="0" y2="0" visibility="hidden"
style='stroke:red; stroke-width:4px'></line>
<image x="10" y="10" class="container" initial-x="10" initial-y="10" xlink:href="http://i60.tinypic.com/20ic9e.png"
width="110"
height="110"></image>
<circle class="left" id="qbox-left" initial-cx="10" initial-cy="65" cx="10" cy="65" r="5"
style="fill:red"></circle>
<circle class="right" id="qbox-right" initial-cx="120" initial-cy="65" cx="120" cy="65" r="5"
style="fill:red"></circle>
<g id="op1" class="op">
<image class="opim" x="10" y="10" class="container" initial-x="10" initial-y="10"
xlink:href="http://i58.tinypic.com/imlzs9.png" width="50"
height="50"></image>
<circle id="op1-left" class="left" initial-cx="10" initial-cy="35" cx="10" cy="35" r="5"
style="fill:red"></circle>
<circle id="op1-right" class="right" initial-cx="60" initial-cy="35" cx="60" cy="35" r="5"
style="fill:red"></circle>
</g>
<g id="op2" class="op">
<image class="opim" x="60" y="60" initial-x="60" initial-y="60"
xlink:href="http://i58.tinypic.com/imlzs9.png" width="50"
height="50"></image>
<circle id="op2-left" class="left" initial-cx="60" initial-cy="85" cx="60" cy="85" r="5"
style="fill:red"></circle>
<circle id="op2-right" class="right" initial-cx="110" initial-cy="85" cx="110" cy="85" r="5"
style="fill:red"></circle>
</g>
</g>
<g class="qbox" id="qbox2" >
<line id="dummyLine" x1="0" x2="0" y1="0" y2="0" visibility="hidden"
style='stroke:red; stroke-width:4px'></line>
<image x="110" y="110" class="container" initial-x="110" initial-y="110" xlink:href="http://i60.tinypic.com/20ic9e.png"
width="110"
height="110"></image>
<circle class="left" id="qbox-left" initial-cx="110" initial-cy="165" cx="110" cy="165" r="5"
style="fill:red"></circle>
<circle class="right" id="qbox-right" initial-cx="220" initial-cy="265" cx="220" cy="165" r="5"
style="fill:red"></circle>
<g id="op3" class="op">
<image class="opim" x="110" y="110" class="container" initial-x="110" initial-y="110"
xlink:href="http://i58.tinypic.com/imlzs9.png" width="50"
height="50"></image>
<circle id="op1-left" class="left" initial-cx="110" initial-cy="135" cx="110" cy="135" r="5"
style="fill:red"></circle>
<circle id="op1-right" class="right" initial-cx="160" initial-cy="135" cx="160" cy="135" r="5"
style="fill:red"></circle>
</g>
<g id="op4" class="op">
<image class="opim" x="160" y="160" initial-x="160" initial-y="160"
xlink:href="http://i58.tinypic.com/imlzs9.png" width="50"
height="50"></image>
<circle id="op2-left" class="left" initial-cx="160" initial-cy="185" cx="160" cy="185" r="5"
style="fill:red"></circle>
<circle id="op2-right" class="right" initial-cx="210" initial-cy="185" cx="210" cy="185" r="5"
style="fill:red"></circle>
</g>
</g>
</g>
var qBox = d3.selectAll('.qbox')
.on('dblclick', function () {
var g = d3.select(this);
var scale = 'scale(1.2,1.2)';
g.attr('transform', g.attr('transform') + ' ' + scale);
});
var opBox = d3.selectAll('.op');
var circles = d3.selectAll('circle');
var cDrag = d3.behavior.drag()
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var dummyLine = d3.select('#dummyLine');
var me = d3.select(this);
var transForm = me.node().getCTM();
var t2 = me.select(function () {
return this.parentNode;
}).select(function () {
return this.parentNode;
}).select('circle').node().getCTM();
var tC = d3.transform(d3.select(this).attr('transform')).translate;
var tP = d3.transform(d3.select(this).select(function () {
return this.parentNode;
}).attr('transform')).translate;
console.log(transForm);
var meX = t2['e'];
var meY = t2['f'];
dummyLine
.style('visibility', 'visible')
.attr('tx1', Number(me.attr('cx')))
.attr('x1', Number(me.attr('cx')) + (Number(transForm['e'] - Number(meX))))
.attr('ty1', Number(me.attr('cy')))
.attr('y1', Number(me.attr('cy')) + (Number(transForm['f'] - Number(meY))))
.attr('x2', Number(d3.event.x) )
.attr('tx2', Number(d3.event.x) + Number(tP[0]) - Number(tC[0]))
.attr('y2', Number(d3.event.y) )
.attr('ty2', Number(d3.event.y) + Number(tP[1]) - Number(tC[0]))
.attr('start', me.attr('id'))
;
})
.on('dragend', function () {
var g = d3.select(this).select(function () {
return this.parentNode;
}).select(function () {
return this.parentNode;
});
var dummyLine = d3.select('#dummyLine');
dummyLine.style('visibility', 'hidden');
d3.select('.qbox')
.append('line')
.attr('id', function () {
return dummyLine.attr('start') + '__' + circleID;
})
.attr('x1', dummyLine.attr('x1'))
.attr('ix1', dummyLine.attr('tx1'))
.attr('x2', dummyLine.attr('x2'))
.attr('ix2', d3.select('#' + circleID).attr('cx'))
.attr('y1', dummyLine.attr('y1'))
.attr('iy1', dummyLine.attr('ty1'))
.attr('y2', dummyLine.attr('y2'))
.attr('iy2', d3.select('#' + circleID).attr('cy'))
.attr('start', dummyLine.attr('start'))
.attr('end', circleID)
.style('stroke', 'green')
.style('stroke-width', '2px')
;
})
;
var svg = d3.select('svg').node();
var drag = d3.behavior.drag()
.origin(function () {
var t = d3.transform(d3.select(this).attr("transform")).translate;
return {x: t[0], y: t[1]};
}).on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
}).on('drag', function () {
var g = d3.select(this);
var mouse = {dx: d3.event.x, dy: d3.event.y};
var currentObj = {
x: g.select('image').attr('x'),
y: g.select('image').attr('y'),
width: g.select('image').attr('width'),
height: g.select('image').attr('height')
};
var parentObj = {
x: (Number(g.select(function () {
return this.parentNode;
}).select('.container').attr('x'))), // + Number(d3.transform(parent.attr('transform')).translate[0])),
y: (Number(g.select(function () {
return this.parentNode;
}).select('.container').attr('y'))), // + Number(d3.transform(parent.attr('transform')).translate[1])),
width: g.select(function () {
return this.parentNode;
}).select('.container').attr('width'),
height: g.select(function () {
return this.parentNode;
}).select('.container').attr('height')
};
var loc = getXY(mouse, currentObj, parentObj);
d3.select(this).attr('transform', 'translate(' + loc.x + ',' + loc.y + ')');
// d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');
var groupId = d3.select(this).attr('id');
var groupClass = d3.select(this).attr('class');
d3.selectAll('line')[0].forEach(function (e1) {
var line = d3.select(e1);
// console.log('groupId: ', groupId);
if (line.attr('id') != 'dummyLine' && groupClass != 'qbox') {
// console.log('--------------');
// console.log('lineId: ', line.attr('id'));
var lineStart = line.attr('start').split('-')[0];
var lineEnd = line.attr('end').split('-')[0];
// console.log('lineStatr : ', lineStart);
// console.log('lineEnd : ', lineEnd);
var t = d3.transform(d3.select('#' + groupId).attr('transform')).translate;
var t2 = d3.transform(d3.select('#' + groupId).select(function () {
return this.parentNode;
}).attr('transform')).translate;
console.log('groupID ', groupId);
if (lineStart == groupId) {
var t = d3.transform(d3.select('#' + lineStart).attr('transform')).translate;
line.attr('x1', Number(line.attr('ix1')) + (Number(t[0])));
line.attr('y1', Number(line.attr('iy1')) + Number(t[1]));
// line.attr('x1', Number(line.attr('ix1')) - (-Number(t[0])+Number(t2[0])));
// line.attr('y1', Number(line.attr('iy1')) - (-Number(t[1]+Number(t2[1]))));
}
if (lineEnd == groupId) {
var t = d3.transform(d3.select('#' + lineEnd).attr('transform')).translate;
line.attr('x2', Number(line.attr('ix2')) + Number(t[0]));
line.attr('y2', Number(line.attr('iy2')) + Number(t[1]));
// line.attr('x2', Number(line.attr('ix2')) - Number(t[0]));
// line.attr('y2', Number(line.attr('iy2')) - Number(t[1]));
// line.attr('x2', Number(line.attr('ix2')) - (Number(t[0]+Number(t2[0]))));
// line.attr('y2', Number(line.attr('iy2')) - (Number(t[1]+Number(t2[1]))));
}
}
});
})
;
opBox.call(drag);
qBox.call(drag);
circles.call(cDrag);
var circleID;
circles.on('mouseover', function () {
circleID = d3.select(this).attr('id');
}).on('mouseout', function () {
circleID = null;
})
PS : I connect two elements by dragging the circles and dropping into another circle.
Can anyone point out my mistake?
After all sort of troubles, I found my answer. Actually it is all about the coordinate system and where to put stuff and how to organize it. Once I fugured that out, Answer is pretty obvious.
<svg width="500" height="500" style="background-color: blue">
<g id="draw">
<rect class="container" height="500" width="500" x="0" y="0" style="fill:yellow"></rect>
<line class="dummyLineOutsideQbox"></line>
<g class="qbox" id="qbox">
<line class="dummyLineInsideQbox"></line>
<image x="10" y="10" class="container" initial-x="10" initial-y="10" xlink:href="images/query.png"
width="110"
height="110"></image>
<circle class="left" id="qbox-left" initial-cx="10" initial-cy="65" cx="10" cy="65" r="5"
style="fill:red"></circle>
<circle class="right" id="qbox-right" initial-cx="120" initial-cy="65" cx="120" cy="65" r="5"
style="fill:red"></circle>
<g id="op1" class="op">
<image class="opim" x="10" y="10" class="container" initial-x="10" initial-y="10"
xlink:href="images/filter.png" width="50"
height="50"></image>
<circle id="op1-left" class="left" initial-cx="10" initial-cy="35" cx="10" cy="35" r="5"
style="fill:red"></circle>
<circle id="op1-right" class="right" initial-cx="60" initial-cy="35" cx="60" cy="35" r="5"
style="fill:red"></circle>
</g>
<g id="op2" class="op">
<image class="opim" x="60" y="60" initial-x="60" initial-y="60"
xlink:href="images/filter.png" width="50"
height="50"></image>
<circle id="op2-left" class="left" initial-cx="60" initial-cy="85" cx="60" cy="85" r="5"
style="fill:red"></circle>
<circle id="op2-right" class="right" initial-cx="110" initial-cy="85" cx="110" cy="85" r="5"
style="fill:red"></circle>
</g>
</g>
<g class="qbox" id="qbox2">
<line class="dummyLineInsideQbox"></line>
<image x="110" y="110" class="container" initial-x="110" initial-y="110" xlink:href="images/query.png"
width="110"
height="110"></image>
<circle class="left" id="qbox2-left" initial-cx="110" initial-cy="165" cx="110" cy="165" r="5"
style="fill:red"></circle>
<circle class="right" id="qbox2-right" initial-cx="220" initial-cy="265" cx="220" cy="165" r="5"
style="fill:red"></circle>
<g id="op3" class="op">
<image class="opim" x="110" y="110" class="container" initial-x="110" initial-y="110"
xlink:href="images/filter.png" width="50"
height="50"></image>
<circle id="op3-left" class="left" initial-cx="110" initial-cy="135" cx="110" cy="135" r="5"
style="fill:red"></circle>
<circle id="op3-right" class="right" initial-cx="160" initial-cy="135" cx="160" cy="135" r="5"
style="fill:red"></circle>
</g>
<g id="op4" class="op">
<image class="opim" x="160" y="160" initial-x="160" initial-y="160"
xlink:href="images/filter.png" width="50"
height="50"></image>
<circle id="op4-left" class="left" initial-cx="160" initial-cy="185" cx="160" cy="185" r="5"
style="fill:red"></circle>
<circle id="op4-right" class="right" initial-cx="210" initial-cy="185" cx="210" cy="185" r="5"
style="fill:red"></circle>
</g>
</g>
</g>
</svg>
<script>
var qBox = d3.selectAll('.qbox')
.on('dblclick', function () {
var g = d3.select(this);
var scale = 'scale(1.2,1.2)';
g.attr('transform', g.attr('transform') + ' ' + scale);
});
var opBox = d3.selectAll('.op');
var circles = d3.selectAll('circle');
var cDrag = d3.behavior.drag()
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var thisCircle = d3.select(this);
var thisGroup = thisCircle.select(function () {
return this.parentNode;
});
var thisGroupTransform = d3.transform(thisGroup.attr('transform')).translate;
var thisGroupParent = d3.select(this).select(function () {
return this.parentNode;
}).select(function () {
return this.parentNode;
});
var thisGroupParentId = thisGroupParent.attr('id');
var thisGroupParentClass = thisGroupParent.attr('class');
if (thisGroupParentClass == 'qbox') {
dummyLine = d3.select('#' + thisGroupParentId).select('.dummyLineInsideQbox');
}
else {
dummyLine = d3.select('#' + thisGroupParentId).select('.dummyLineOutsideQbox');
}
console.log('dummyLine ', dummyLine.attr('class'));
dummyLine
.style('visibility', 'visible')
.style('stroke', 'red')
.style('stroke-width', '3px')
.attr('x1', Number(thisCircle.attr('cx')) + thisGroupTransform[0])
.attr('real-x1', thisCircle.attr('cx'))
.attr('y1', Number(thisCircle.attr('cy')) + thisGroupTransform[1])
.attr('real-y1', thisCircle.attr('cy'))
.attr('x2', d3.mouse(this)[0] + thisGroupTransform[0])
.attr('y2', d3.mouse(this)[1] + thisGroupTransform[1])
.attr('startGroup', thisGroup.attr('id'))
.attr('startCircleClass', thisCircle.attr('class'))
;
})
.on('dragend', function () {
var thisCircle = d3.select('#' + circleID);
var thisCircleClass = thisCircle.attr('class');
var thisGroup = thisCircle.select(function () {
return this.parentNode;
});
var thisGroupTransform = d3.transform(thisGroup.attr('transform')).translate;
var thisGroupParent = d3.select(this).select(function () {
return this.parentNode;
}).select(function () {
return this.parentNode;
});
var thisGroupParentId = thisGroupParent.attr('id');
var thisGroupParentClass = thisGroupParent.attr('class');
var sourceCircleClass = dummyLine.attr('startCircleClass');
var sourceGroup = d3.select('#' + dummyLine.attr('startGroup'));
console.log('SOURCE GROUP :', sourceGroup.attr('id'));
var targetLineGroup;
var lineClass;
var t = [0, 0];
var x1, x2, y1, y2;
if (( sourceGroup.attr('class') == 'op') || (thisGroup.attr('class') == 'op')) {
if (sourceGroup.attr('class') == 'op') {
targetLineGroup = sourceGroup.select(function () {
return this.parentNode;
});
// console.log('I am on line 185');
} else {
targetLineGroup = thisGroup.select(function () {
return this.parentNode;
});
// console.log('I am on line 190');
}
lineClass = 'in';
x1 = startCircle.attr('cx');
y1 = startCircle.attr('cy');
x2 = thisCircle.attr('cx');
y2 = thisCircle.attr('cy');
}
if ((sourceGroup.attr('class') == 'qbox') && (thisGroup.attr('class') == 'qbox')) {
targetLineGroup = sourceGroup.select(function () {
return this.parentNode;
});
lineClass = 'out';
x1 = dummyLine.attr('x1');
x2 = dummyLine.attr('x2');
y1 = dummyLine.attr('y1');
y2 = dummyLine.attr('y2');
}
targetLineGroup
.append('line')
.attr('class', lineClass)
.attr('id', function () {
return sourceCircleClass + '--' + sourceGroup.attr('id') + '__' + thisCircleClass + '--' + thisGroup.attr('id');
})
.attr('x1', dummyLine.attr('x1'))
.attr('real-x1', dummyLine.attr('x1'))
.attr('y1', dummyLine.attr('y1'))
.attr('real-y1', dummyLine.attr('y1'))
.attr('x2', dummyLine.attr('x2'))
.attr('real-x2', dummyLine.attr('x2'))
.attr('y2', dummyLine.attr('y2'))
.attr('real-y2', dummyLine.attr('y2'))
.attr('startGroup', dummyLine.attr('startGroup'))
.attr('endGroup', thisGroup.attr('id'))
.style('stroke', 'green')
.style('stroke-width', '3px')
;
dummyLine.style('visibility', 'hidden');
console.log('DRAWING LINE ON : ', targetLineGroup.attr('id'))
})
;
var svg = d3.select('svg').node();
var drag = d3.behavior.drag()
.origin(function () {
var t = d3.transform(d3.select(this).attr("transform")).translate;
return {x: t[0], y: t[1]};
}).on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
}).on('drag', function () {
var g = d3.select(this);
var mouse = {dx: d3.event.x, dy: d3.event.y};
var currentObj = {
x: g.select('image').attr('x'),
y: g.select('image').attr('y'),
width: g.select('image').attr('width'),
height: g.select('image').attr('height')
};
var parentObj = {
x: (Number(g.select(function () {
return this.parentNode;
}).select('.container').attr('x'))), // + Number(d3.transform(parent.attr('transform')).translate[0])),
y: (Number(g.select(function () {
return this.parentNode;
}).select('.container').attr('y'))), // + Number(d3.transform(parent.attr('transform')).translate[1])),
width: g.select(function () {
return this.parentNode;
}).select('.container').attr('width'),
height: g.select(function () {
return this.parentNode;
}).select('.container').attr('height')
};
var loc = getXY(mouse, currentObj, parentObj);
d3.select(this).attr('transform', 'translate(' + loc.x + ',' + loc.y + ')');
// d3.select(this).attr('transform', 'translate(' + d3.event.x + ',' + d3.event.y + ')');
var thisGroupId = d3.select(this).attr('id');
var groupClass = d3.select(this).attr('class');
var thisGroupClass = d3.select(this).attr('class');
var tLineClass;
if (thisGroupClass == 'qbox') {
tLineClass = 'out'
} else {
tLineClass = 'in'
}
d3.selectAll('line.' + tLineClass)[0].forEach(function (e1) {
var line = d3.select(e1);
var lineId = line.attr('id');
var lineStartGroup = lineId.split('__')[0].split('--')[1];
var lineStartSide = lineId.split('__')[0].split('--')[0];
var lineEndGroup = lineId.split('__')[1].split('--')[1];
var lineEndSide = lineId.split('__')[1].split('--')[0];
console.log('-------------------');
console.log(lineId);
console.log(lineStartGroup);
console.log(lineEndGroup);
console.log('-------------------');
var c;
var ctm;
if (thisGroupId == lineStartGroup) {
var t = d3.transform(d3.select('#' + thisGroupId).attr('transform')).translate;
if (lineStartSide == 'left') {
c = d3.select('#' + lineStartGroup).select('.left');
ctm = c.node().getCTM();
} else {
c = d3.select('#' + lineStartGroup).select('.right');
ctm = c.node().getCTM();
}
var x = d3.transform(c.select(function () {
return this.parentNode;
}).attr('transform')).translate;
console.log('START e'+ctm['e']);
console.log('START ex'+x[0]);
console.log('START f'+ctm['f']);
console.log('START fx'+x[0]);
line.attr('x1', Number(c.attr('cx')) + Number(x[0]));
line.attr('y1', Number(c.attr('cy')) + Number(x[1]));
}
if (thisGroupId == lineEndGroup) {
// var t = d3.transform(d3.select('#' + thisGroupId).attr('transform')).translate;
//
// line.attr('x2', Number(line.attr('real-x2')) + Number(t[0]));
// line.attr('y2', Number(line.attr('real-y2')) + Number(t[1]));
if (lineEndSide == 'left') {
c = d3.select('#' + lineEndGroup).select('.left');
} else {
c = d3.select('#' + lineEndGroup).select('.right');
}
var x = d3.transform(c.select(function () {
return this.parentNode;
}).attr('transform')).translate;
ctm = c.node().getCTM();
console.log('END circleId'+c.attr('id'));
line.attr('x2', Number(c.attr('cx')) + Number(x[0]));
line.attr('y2', Number(c.attr('cy')) + Number(x[1]));
}
});
})
;
opBox.call(drag);
qBox.call(drag);
circles.call(cDrag);
var circleID;
var dummyLine;
circles.on('mouseover', function () {
circleID = d3.select(this).attr('id');
}).on('mouseout', function () {
circleID = null;
})
function getXY(mouse, current, parent) {
var obj = {
x: 0,
y: 0
};
var dx = mouse.dx;
var dy = mouse.dy;
obj.x = dx;
obj.y = dy;
var xGap = current.x - parent.x;
var yGap = current.y - parent.y;
if (dx < 0) {
if ((dx + xGap) < 0) {
obj.x = -1 * xGap + 10;
}
} else {
if ((dx + xGap) > parent.width) {
obj.x = parent.width - xGap - current.width - 10;
}
}
if (dy < 0) {
if ((dy + yGap) < 0) {
obj.y = -1 * yGap + 10;
}
} else {
if ((dy + yGap) > parent.height) {
obj.y = parent.height - yGap - current.height - 10;
}
}
return obj;
}
</script>
From my experience developing visual editors, I can say that relative positions (such as x,y in Operator) can and shoud be managed as data.
Try changing that data (and not directly the x,y attributes of the svg element), and binding the data in a d3js way. It will be much more idiomatic and fast.
PS: I know about separation of model and view, and I know about the bad side of storing visual properties along the model, but if it will be only a view for that model, it is for sure the best approach.

Categories