I have set up a clip path on a D3.js zoomable focus and context graph, but have a slight problem. http://nestoria.darkgreener.com/v2/
The clip path is cutting off some circles from the edge of the focus graph - you'll see that the top and right-hand circles are only half there!
It works well on zoom, though, as you'll see if you click and drag the context graph.
So I'm not sure how to create a clip path that doesn't cut off the edges of these circles. This is my code:
focus.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width - 200)
.attr("height", height);
var focus_dots = focus
.selectAll(".dot")
.data(mydata[j].data);
focus_dots.enter()
.append("circle")
.attr("clip-path", "url(#clip)");
Any ideas? Your help would be very much appreciated as I'm completely baffled about what to do here!
If you don't want the clipping to not be applied when hovering you can use a stylerule like this:
circle:hover { clip-path: none; }
I had the same problem and got around it using
.attr("transform", "translate(0,-20)")
.attr("height", height+20)
The Idea is a bit hacky, but if you simply move the clipping window up and add the same amount to its height, it should show (in the above case) 20px more on top. (same for left side; concerning the right and bottom side: simply add some pixels to hight/width).
I've used "transform",and the circles were cut to quarter.So use cx and cy instead, problem solved..
Related
Hi I am trying really hard to solve this problem. Initially I have an svg-element and inside of it a g-element to make zooming in D3 also possible in Safari. I append a D3 Force-Directed Graph to that g-element after generating it. Zooming works perfectly fine so far.
The Force-Directed Graphis generated as preserved here: https://observablehq.com/#d3/disjoint-force-directed-graph
Initial svg-element created:
svg.value = d3
.select("#network")
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.append("g");
Adding the chart:
d3.select("#network").selectAll("svg g > *").remove();
d3.select("#network").select("svg g").node().append(chart);
And the zoom-function afterwards:
const svgZoom = d3.select("#network svg");
const g = d3.select("#network svg g");
svgZoom.call(
d3
.zoom()
.on("zoom", function () {
g.attr("transform", d3.zoomTransform(this));
})
);
Now the issue is that the graph always gets cut. I already tried visibility:visible on each of those elements, still not working. Even if I set a viewBox much bigger than the actual content, or if I set the size of the graph to a minimum, the graph will always get cut to a rectangle.
What I want to accomplish is add the graph full-size and by zooming out the overflowing elements get visible. I do not want to get the height and width of the container and minimize the size of each graph drawn, because some graphs are much bigger than the other ones and I want to keep the initial size of the nodes.
How it currenty looks
Without Zooming Out
Zooming Out
The graph itself cuts the boundaries, adding overflow:visible to the Force-Directed Graph solved the problem.
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.
I tried http://bl.ocks.org/godds/ec089a2cf3e06a2cd5fc
However, I found when I used the brush, the main part of the stacked bar is out of boundary. How to fix it?
I think here is the reason:
some bars should not be shown in the main part but they are still in the scope of svg
Thank you for your help!
These types of zoom literally are just geometric zooms, all the bars are still being drawn, it's just that the vast majority are off-screen, some are within the chart limits and a few lie in the axis gap in-between which are the ones that look awkward.
Make a svg clip, and add it to the right 'g' element to get rid of this effect:
svg.append("defs").append("clipPath")
.attr("id", "myclip")
.append ("rect")
.attr({x: 0, width: width, y: margin.top, height: height});
... and later on in the code
// draw the bars
main.append("g")
.attr("clip-path", "url(#myclip)")
.attr("class", "bars")
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.
Here's the fiddle.
When I use the brush, the colored areas start off beyond the x axis defined.
For the line in the graph, I got a suggestion in this SO to add clip-path: url(#clip) to the line css. It works. After applying that, the line starts exactly from the 0 of x when using the brush.
But when I apply the same logic to the css of the .area.above and .area.below, it doesn't work.
The areas are clipped correctly but only one is actually displayed...from inspecting the elements in the browser developer tools, one of the areas is apparently overlaying the other.
Some one help me where I'm making the mistake?
Thanks in advance.
Here's a fiddle which I think does what you want: http://jsfiddle.net/henbox/jzPaq/
The problem was that you can only have one clip-path defined for an element. So adding the rectangular clipPath:
...append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
was over-writing the clip-below and clip-above ones (in <path class="area below"...> and <path class="area above"...> respectively.
The solution I used was based on this info: http://apike.ca/prog_svg_clip.html
For the 'below' I used the intersection of the rectangular (#clip) and 'below' clip paths, like this:
Give the path element an id (clipbelowshape):
focus.append("clipPath")
.attr("id", "clip-below")
.append("path")
.attr("id", "clipbelowshape")
.attr("d", area.y0(height));
Create the intersect of clip clipPath with clipbelowshape:
var clipbelowintersect = focus.append("clipPath")
.attr("id", "clipbelowintersect")
.attr("clip-path", "url(#clip)");
clipbelowintersect.append("use")
.attr("xlink:href", "#clipbelowshape");
Use the new intersect clip path
focus.append("path")
.attr("class", "area below")
.attr("clip-path", "url(#clipbelowintersect)")
.attr("d", area);
Do the same thing with the above path