d3.js text disappearing when rotating - javascript

I have fought half a day with seemingly simple problem with no avail so I'd love to get some good advice from stackoverflow geniuses.
I have a demo at http://62.165.130.126/d3-question
I tried to put it into jsfiddle but couldn't get the libraries right, hope this still allows you to dive in.
The problem is demonstrating itself in a d3.js javascript code when rotating text disappears. Or actually part of the rotating text.
Each pair of bars on the page should have two lines of the text rotated 45 degrees (downhill) not to write over the neighbors. If I don't rotate text everything is visible (but overlapping), but if I do, only the first pair of lines is OK. After that the first text disappears (or on some version was misplaced by some tens of pixels seemingly haphazard) but the second text sits right where it should using exactly the same code structure. I have exchanged the values and the problem isn't connected with the values but the order.
Here is the main code in javascript I have written.
$.each(data, function(a_key,a_val){
$.each(a_val, function(form_key,form_val){
$.each(form_val, function(person_key,person_val){
svg.append("rect")
.attr("x", start*2*width+width)
.attr("y", 420-person_val.val1/person_val.val1_max*400)
.attr("width", width-5)
.attr("height", person_val.val1/person_val.val1_max*400)
.style("fill", "red");
svg.append("rect")
.attr("x", start*2*width)
.attr("y", 420-person_val.val2/person_val.val2_max*400)
.attr("width", width-5)
.attr("height", person_val.val2/person_val.val2_max*400)
.style("fill", "green");
svg.append("text")
.attr("text-anchor", "start")
.attr("transform","translate(" + start*2*width+20 + ",430) rotate(45)")
.style("font-size","0.85em")
.text(person_val.pname);
svg.append("text")
.attr("text-anchor", "start")
.attr("transform","translate(" + start*2*width + ",430) rotate(45)")
.style("font-size","0.85em")
.text(person_val.ptype);
start++;
});
});
The application is just a mockup of the real solution but should show the essential problem without distractions. Each pair of bars should have the describing text below them. Currently they aren't centered yet but if things sort out that change should be straightforward.
Anybody any idea how to correct the code?

The problem is with "translate(" + start*2*width+20 + ",430) rotate(45)" code.
One of the results is translate(8020,430) rotate(45). Javascript turned 20 into string. Try to put braces around start*2*width+20 expression.

Related

Brush functionality in my d3 line chart is not working as expected

My implementation for Brush & Zoom functionality in my d3 line chart is not working as expected,
I followed this link - https://bl.ocks.org/EfratVil/92f894ac0ba265192411e73f633a3e2f,
Problems what I am facing is -
chart is not showing all the values, I have 4 data but it only shows 3 data
onClick of dot I am showing the rect which is not moving with the brush functionality
minor thing but chart always goes out of the box
My code sandbox - https://codesandbox.io/s/proud-firefly-xy1py
Can someone point out what I am doing wrong? thanks.
Please suggest me what I am doing wrong, thanks.
Your first point is going behind your clip area. For example, if you right click on the first visible circle and inspect element you will see all 4 circle elements are present in the dom. The first circle element is behind the axis.
This means you have to move your plot to the right. Unfortunately, the way you have coded the chart you have not appended a g element for the main chart and then appended the circles and path to that g element. As a result this has to be done in multiple places.
First we adjust your clip path as:
svg
.append("defs")
.append("SVG:clipPath")
.attr("id", "clip")
.append("SVG:rect")
.attr("width", containerWidth)
.attr("height", height)
.attr("x", 40)
.attr("y", 0);
next we adjust your circles
scatter
.selectAll(".foo")
.data(data)
.enter()
.append("circle")
.attr("class", "foo")
.attr("transform", "translate(40,0)")
and then your line
scatter
.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.attr("transform", "translate(40,0)");
You will have to account for this 40 px translate for your other elements as well. Although I am having a hard time destructuring your svg. I think this should give you the idea though. Check the axis matches the time points as well.
Check the code sand box
Update
To make the rectangles move with the brush, you will have to add code to your brushed const function to recalculate the x, y, width and height using the updated scales.
Update2
After going through the codesandbox presented in the comments I was able to add the code to update the rectangles to the brushed const as below to make the rects also move with the brushing:
// update rectangles
scatter
.selectAll(".rect-elements")
.attr("x", d => {
console.log(d);
return xScale(d.startTime) - 12.5;
})
.attr("y", 0)
.attr("width", 24)
.attr("height", height + 5);
Full working Code Sandbox.

Rect in in d3js svg disappears after routing to another page in AngularJS

I have a very strange behave in my angularjs application.
1) I'm using d3js to draw a nice bar chart
graphG.append("rect")
.attr("id", function (d, i) {
return "bar_" + i;
})
.attr("x", 0)
.attr("y", 0)
.attr("height", barHeight - 1)
.attr("width", function (d, i) {
return rectWidth(d, i);
})
.attr("fill", rectColor);
2) After a data update there is a transition
barG.select("#bar_" + i)
.transition()
.duration(duration)
.attr("fill", rectColor(d))
.attr("width", rectWidth(d, i));
So far the width transition works fine. The color transitions with gradient doesn't work, but this is an another question. It changes the color but without smooth transition.
If i reroute to another page and come back the rect will not be rendered any more. The rect is in the dom. Width attribute got changes. No bar.
After F5 reload every thing is fine again.
And more strange behave: it happens in Chrome, it works fine in Firefox.
Anybody some ideas?
I have found the problem:
the error was that the gradient id (return of rectColor function) was same in both directives. So it seems that there is some caching in Chrome.
Rename the gradient id in one directive fixes the issue.

Zooming issues with Force Directed

I've generated a D3 visualization (a force directed graph) that requires zooming and panning. I've got 2 problems however when it comes to zooming, and I can't find any decent examples on how I might overcome these problems:
The first problem is I've followed all the examples I can find about zooming, which involves adding groupings and adding a rectangle to ensure that the entire area is zoomeable. If I style the rectangle a slightly opaque blue then I get SVG that looks like this when I zoom out:
The problem with this is that I can zoom in/out absolutely fine while I've got my mouse over the blue rectangle area. The problem is I want this to be fully opaque, which means that when I zoom right out, it's very easy to place the cursor outside of this box and then you're unable to zoom in. Is there a way I can make the SVG itself zoomeable or pick up on these events?
This is how I go about generating the various layers and the zoomed function:
function zoomed() {
group2.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
svg = d3.select(target)
.attr("pointer-events", "all")
.append("svg");
group = svg.append('svg:g')
.call(d3.behavior.zoom().on('zoom', zoomed))
.on("dblclick.zoom", null);
group2 = group.append("g");
rect = group2.append('svg:rect')
.style("opacity", 0.3)
.attr('width', width)
.attr('height', height);
The second problem I have is that I'm trying to automatically size my text based on this http://bl.ocks.org/mbostock/1846692 example. When I've tried this however I seem to be getting text that renders really poorly. It seems to suffer from:
Being difficult to read
Not appearing contained within the circle
Being so small the entire thing compresses (image 2)
var texts = planets.append("text")
.text(function(d) { return d.name; })
.style("font-size", "24px") // initial guess
.style("font-size", function(d) {
return Math.min( 2 * d.size, (2 * d.size - 8) / this.getComputedTextLength() * 24) + "px";
})
.attr("dx", function(d) { return -d.size; })
.attr("dy", ".35em")
.style("fill", "white");
I thought that SVG would just handle this, I understand that some of the font-sizes can come out small, but if you zoom in should that not all sort itself out?
I've got a JSFiddle http://jsfiddle.net/IPWright83/vo7Lpefs/22/ to demonstrate.
I've not yet managed to work out a resolution to my first issue (regarding the zooming box) however I did manage to track down the text rendering issue.
This was actually because the each circle/node had a stroke property to provide the white border. This was also applying to the text element, and when the font was very small the stroke was much larger than the overall fill of the text. Removing the stroke from the text elements ensured that they rendered even when very small.

Display icons/image instead of circle/path on map made with d3.js

I can successfully display some points on a openlayers basemap using d3.js however I want to actually display icons (at the moment maki png icons) instead of an svg point.
is it possible to load a png/jpg/svg image to a map using d3.js?
So far I can load the icon directly onto the svg but all the markers locate on the same spot so I think I'm having a problem converting the coordinates properly.
var feature = svg.selectAll("path")
.data(amenities.features)
.enter()
.append("svg:image")
.attr("xlink:href", "maki/renders/post-18#2x.png")
.attr("x", function(d, i) {return amenities.features[i].geometry.coordinates[0]})
.attr("y", function(d, i) {return amenities.features[i].geometry.coordinates[1]})
.attr("width", "20")
.attr("height", "20")
.attr("class", "amenity");
Previously I have been able to create an svg with image background inside it using a 'pattern' to show the image so that is also a possibility but I couldn't translate the code to use it with the geographic aspect of d3.
I know I'm writing the icons at the moment to the 'svg' div, so they don't transform correctly when I zoom in and out. I'm aiming to write the images to the 'g' div, as in have code like:
var feature = g.selectAll("path")
but when I use this line, the elements appear on the document but the icons don't actually render on the map.
Thanks in advance.
There a few issues here. First, I'm not sure you fully grasp how d3 selections works, as indicated by the fact that you are binding amenities.features to your selection and then accessing it for the x and y attributes via an index. See How Selections Work for more details on this. In addition, you need to translate the geographic coordinates of the features to screen coordinates by passing them through your geographic projection function. This should get you close:
// more projections: https://github.com/d3/d3-geo-projection/
var projection = d3.geoAlbers();
var amenities = svg.selectAll('.amenities')
.data(amenities.features);
amenities.enter().append('image');
amenities
.attr("class", "amenities")
.attr("xlink:href", "maki/renders/post-18#2x.png")
// The data is already bound so use it instead of the index. Als,
// you need to translate geo coordinates to screen coordinates by
// passing them through your projection function.
.attr("x", function(d,i) {return projection(d.geometry.coordinates)[0];})
.attr("y", function(d,i) {return projection(d.geometry.coordinates)[1];})
.attr("width", "20")
.attr("height", "20")
I don't think I appropriately used groups but I think the key is having the transform then translate thing in there.
So my example is http://bl.ocks.org/mpmckenna8/b87df1c44243aa1575cb.
But because I didn't use groups properly I don't know that the icons would handle zooming like you seem to want. In my example I just append the images to the circles I've created.
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr('opacity',.3)
.attr('fill', '#fad959')

d3 js line breaks not working in text using html

Why doesn't the break tag render?
I've read several answers on SO, and tried a variety of different approaches, with no luck.
This fiddle shows the current fully functioning d3.js sample, with the problem of break tag not rendering:
http://jsfiddle.net/Xsnqx/1/
The relevant bit of code is here:
node.insert("text")
.attr("class", "text")
.style("text-anchor", "middle")
.html(function(d) {
var html = d.name.split(" ");
return html.join("<br>");
});
Note: if any of you d3 experts have additional comments / observations about the code I've constructed, please let me know. When I'm done, I want this code to be first-class.
You can't put HTML directly into SVG. You need to use the foreignObject element to embed HTML. Here's another question that addresses this: Auto line-wrapping in SVG text.
Just for completeness sake, I wanted to post the eventual d3 / js code that I ended up using to generate the XML (per #ScottCameron answer):
node.append("foreignObject")
.attr("class", "label")
.attr("width", "120")
.attr("height", "120")
.attr("transform", "translate(-60,-60)")
.html(function(d) {
var html = d.name.split(" ");
return html.join("<br>");
});

Categories

Resources