-
ChristopherApril 11, 2016 at 6:53 pm #6096
I was able to make the Halo component responsive just calling the changeSize() function on window.Resize. However, when adding labels to the arcs and nodes, when the resize occurs, it screws up the drawing of the chart. My assumption is I am not adding the labels correctly. I started with the adding items to the update function. The goal is to add Labels to the arcs after the paths are created.
I tried by appending a text/textPath to after arcs have been setup. This does render correctly(sort of) but once the resize is called, the mouseover doesn’t work correctly.
haloGroup.enter().append("text") .attr("x", function (d) { switch (d.data.key) { case "2": return 400; case "4": return 60; case "5": return 20 case "128": return 60 case "162": return "images/fx.png"; } }) .attr("dy", -10); haloGroup.append("textPath") .attr("stroke", "black") .attr("xlink:href", function (d) { return "#parentBrand_" + d.data.key }) .text(function (d) { if (d.data.values[0].parentBrand == "NULL") { return "OTHER" } else return d.data.values[0].parentBrand }) haloGroup.exit().remove();
Any insight into adding text to arc and well as inside the nodes would be greatly appreciated.
vizulyApril 11, 2016 at 7:30 pm #6097Hi Christopher,
It looks like you are on the right track. Sometimes these issues can be tricky to debug as the layout can be a little complex.
What I might suggest is that instead of piggy-backing on the
haloGroup
(which is being used to generate path elements) that you do the following and create a completely different layer to put the labels on (I suspect the text elements are getting in the way of the mouse-over being triggered by the paths.)1. In the initialize routine add a new
g
element named something likelabelPlot
. You can insert thisg
element before thehaloPlot
so it doesn’t interfere with the mouse events.2. In the update routine create a new group called
labelGroup
and follow the same pattern as the haloGroup.enter()/exit()… But instead of adding path elements, add yourtext
elements andtextpaths
You can use the same data to populate this new group for its measurements and layout.Doing the above should keep things separate and easier to debug. If this doesn’t help and you want to send me over your code I can take a stab at trying to see what is going on.
– Tom
ChristopherApril 11, 2016 at 8:24 pm #6099Thanks for the quick response Tom,
I tried what you said and it still renders but now when you hover over the arc, the text disappears and when you re-size, the text comes back. Also, hovering over the nodes is still a bit messed up after resize.
Below is what I changed in halo.js:
var svg,g,background, plot, plotBackground, labelPlot, haloPlot, nodePlot, linkPlot, defs;
…
function initialize() {
svg = scope.selection.append(“svg”).attr(“id”, scope.id).style(“overflow”,”visible”).attr(“class”,”vizuly”);
defs = vizuly.util.getDefs(viz);
background = svg.append(“rect”).attr(“class”,”vz-background”);
g = svg.append(“g”).attr(“class”,”vz-halo-viz”);
plot = g.append(“g”).attr(“class”,”vz-halo-plot”).attr(“clip-path”,”url(#” + scope.id + “_plotClipPath)”);
plotBackground = plot.append(“rect”).attr(“class”,”vz-plot-background”);
linkPlot = plot.append(“g”).attr(“class”,”vz-halo-link-plot”);
nodePlot = plot.append(“g”).attr(“class”, “vz-halo-node-plot”);
labelPlot = plot.append(“g”).attr(“class”, “vz-halo-label-plot”);
haloPlot = plot.append(“g”).attr(“class”, “vz-halo-arc-plot”);// Tell everyone we are done initializing
scope.dispatch.initialize();
}…
function update() {
// Call measure each time before we update to make sure all our our layout properties are set correctly
measure();// Update our major place holder elements
svg.attr(“width”, scope.width).attr(“height”, scope.height);
background.attr(“width”, scope.width).attr(“height”, scope.height);
plot.style(“width”,size.width).style(“height”,size.height).attr(“transform”,”translate(” + size.left + “,” + size.top + “)”);
haloPlot.attr(“transform”, “translate(” + size.width / 2 + “,” + size.height / 2 + “)”);
labelPlot.attr(“transform”, “translate(” + size.width / 2 + “,” + size.height / 2 + “)”);
linkPlot.attr(“transform”,”translate(” + size.width/2 + “,” + size.height/2 + “)”);
nodePlot.attr(“transform”,”translate(” + (size.width-innerRadius*2)/2 + “,” + (size.height-innerRadius*2)/2 + “)”);// Create the primary halo arcs based on the halo groups and add our event dispatches
var haloGroup = haloPlot.selectAll(“.vz-halo-arc”).data(haloLayout(haloArcs));
haloGroup.enter().append(“path”);
haloGroup.attr(“class”, function (d) {
return “vz-halo-arc ” + “halo-key_” + d.data.key
})
haloGroup.attr(“id”,function (d) {
return “parentBrand_”+d.data.key});
haloGroup.on(“mouseover”, function (d, i) { scope.dispatch.arcover(this, d, i) });
haloGroup.on(“mouseout”, function (d, i) { scope.dispatch.arcout(this, d, i) });
haloGroup.exit().remove();haloGroup.attr(“d”,function (d,i) {
return haloArc(d,i);
});// Store the centroids for each arc group.
// Themes or page developers can use these stored centroids to place data tips or other information in the
// center of the group.
haloGroup.each(function (haloSection) {
var angle=(haloSection.startAngle + (haloSection.endAngle-haloSection.startAngle)/2)-90*radian;
haloSection.x=innerRadius * Math.cos(angle);
haloSection.y = innerRadius * Math.sin(angle);
});//Add Labels to the Arcs
var lableGroup = labelPlot.selectAll(“.vz-halo-label”).data(haloLayout(haloArcs))
lableGroup.enter().append(“text”);
lableGroup.attr(“class”, function (d) {
return “vz-halo-label ” + “label-key_” + d.data.key
})
lableGroup.on(“mouseover”, function (d, i) { scope.dispatch.arcover(this, d, i) });
lableGroup.on(“mouseout”, function (d, i) { scope.dispatch.arcout(this, d, i) });
lableGroup.exit().remove()
lableGroup.attr(“x”, function (d) {
switch (d.data.key) {
case “2”:
return 400;
case “4”:
return 60;
case “5”:
return 20
case “128”:
return 60
case “162”:
return “images/fx.png”;
}
}).attr(“dy”, -10);
lableGroup.append(“textPath”).attr(“stroke”, “black”)
.attr(“xlink:href”, function (d) {
return “#parentBrand_” + d.data.key
})
.text(function (d) {
if (d.data.values[0].parentBrand == “NULL”) {
return “NON-MAJOR BRAND”
}
else
return d.data.values[0].parentBrand
})lableGroup.each(function (haloSection) {
var angle = (haloSection.startAngle + (haloSection.endAngle – haloSection.startAngle) / 2) – 90 * radian;
haloSection.x = innerRadius * Math.cos(angle);
haloSection.y = innerRadius * Math.sin(angle);
});…
I am also going to need to the same thing on the Nodes… Text in the center of the circles … based on value.
Thanks Again!
ChrisvizulyApril 12, 2016 at 6:28 am #6100Hi Christoper,
This is looking good. You can remove the following lines, as they are not needed.
lableGroup.each(function (haloSection) {
var angle = (haloSection.startAngle + (haloSection.endAngle – haloSection.startAngle) / 2) – 90 * radian;
haloSection.x = innerRadius * Math.cos(angle);
haloSection.y = innerRadius * Math.sin(angle);
});The next place to look is the halo.js theme file. That is what is probably making the changes on hover that are interfering with your text. Without actually seeing what is going on and having access to the source code it is a little hard for me to tell you exactly what the problem is.
What I use to debug issues like this is run it in chrome and open up the developer tools, select the element in question and then do the mouseover to see what happens. This will help you track down why things are occurring.
Let me know if that helps.
– Tom
Christopher M GreenApril 12, 2016 at 4:27 pm #6101Thanks again for your help with this… D3 and SVG are new to me!
I actually named the labels with the same CSS class as the Data Tool tip. So when this was called…
function onMouseOut(d,i) {
d3.selectAll(“.vz-halo-label”).remove();
}The code I should you works… but on resize
However, my issue is still this: Whenever I try to append an element after the enter().append(<element>), when the page is resized, it adds more of the second append. Example – with the labels to go with the arcs, on resize, it will add more textpaths to each text element.
For the Circle Nodes, I wanted to add each circle to a group <g> and and append the Name of that node in a text element on top of the circle. Once, resize occurs, it continues to append more circles which then causes the hover to not work correct.
What I am missing?
vizulyApril 12, 2016 at 4:44 pm #6102Hi Christopher. For someone new to D3 and SVG you are doing some more advanced stuff!
Okay, so what is happening is that EACH time you resize you are calling the update routine and it is appending that textPath.
Enter() is called each time a new data element is paired with the selection. That is when you want to do your append statements. For just updating values you do that outside of the enter event, and just use a select statement. So once you have paired data with a corresponding DOM element you simply select it and modify it. Like this.
d3.selectAll(“.myElementClass”).attr(“some-attribute”,”some-value”);
This assumes that “myElementClass” already has been attached to the DOM.
For this code look at the way the halo component adds halo groups in the original source code:
haloGroup.enter().append("path") .attr("class",function(d) { return "vz-halo-arc " + "halo-key_" + d.data.key }) .on("mouseover",function (d,i) { scope.dispatch.arcover(this,d,i) }) .on("mouseout",function (d,i) { scope.dispatch.arcout(this,d,i) }); haloGroup.exit().remove(); haloGroup.attr("d",function (d,i) { return haloArc(d,i); });
In the above code you notice we use the function chain from the ENTER event to append our path and set the class and event handlers. Below that we tell D3 to remove the element if the data disappears and below that we issue its update statement. Your code is slightly different. You are not using the function chain for the enter event other than to append the FIRST text element. You are prefexing all your calls with labelGroup, which actually does something a little different. It is executed for each time it is called versus just the first time data is added.
But your bug appears to be on this line:
.attr(“dy”, -10); lableGroup.append(“textPath”)
This line is getting called EVERY time you hit the update event of the viz. What you want to do is only call this once, when you first add the label on the enter(), so something like this.
lableGroup.enter().append(“text”); .attr(“class”, function (d) { return “vz-halo-label ” + “label-key_” + d.data.key}) .on(“mouseover”, function (d, i) { scope.dispatch.arcover(this, d, i) }); .on(“mouseout”, function (d, i) { scope.dispatch.arcout(this, d, i) }) .append("textPath").attr("class","vz-halo-label-textPath") ....;
See how I am using the function chain off the enter event to create the labels and nest one inside the other?
Later if you want to just alter the text path you can do something like this.
labelGroup.selectAll(".vz-halo-label-textPath").style("stroke","#FFF");
Once you understand how D3 does the select/enter/exit it all makes more sense. Hope this helps.
– Tom
-
|
You must be logged in to reply to this topic.