I need to split multiple overlapping ellipses in an SVG by all path intersections. The purpose of this is for a venn diagram. Ben Fredrickson's venn diagram gets you part of the way there by computing intersections, but does not compute all possible intersections between an arbitrary number of ellipses. His methods do not compute convex (difference) areas, only intersections, and do not handle ellipses.
I've created a non-proportional, symmetric venn diagram layout in d3 and would like to generate paths for all the possible regions, not just intersections.
If there is not a javascript method available, if someone could help clarify the math that would also be acceptable.
My approach so far looks like this:
find intersection points of ellipse circumfrence paths (how?)
generate arc segments between those points using ellipse radii
join arc segments to new paths
So in the following fiddle, I would need to split these ellipses by every path intersection, generating 18 separate paths.
fiddle here
var width = 450,
height = 400
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("svg:ellipse")
.attr("cx", 100)
.attr("cy", 100)
.attr("rx", 50)
.attr("ry",100)
.style("fill", 'rgba(128,255,128,0.4)')
.style("stroke", "#777")
.style("stroke-width", '1px');
svg.append("svg:ellipse")
.attr("cx", 150)
.attr("cy", 100)
.attr("rx", 50)
.attr("ry",100)
.style("fill", 'rgba(255,128,128,0.4)')
.style("stroke", "#777")
.style("stroke-width", '1px');
svg.append("svg:ellipse")
.attr("cx", 150)
.attr("cy", 100)
.attr("rx", 100)
.attr("ry",50)
.style("fill", 'rgba(128,128,255,0.4)')
.style("stroke", "#777")
.style("stroke-width", '1px');
svg.append("svg:ellipse")
.attr("cx", 190)
.attr("cy", 130)
.attr("rx", 100)
.attr("ry",50)
.style("fill", 'rgba(255,128,255,0.4)')
.style("stroke", "#777")
.style("stroke-width", '1px');
Related
I am trying to convert a bubble chart from d3v3 to v4. Running into x,y,d missing variables?
In this version -- a rect is applied to the svg - and then a circle is cut -- so its like an inverse bubble chart.
I am keen to work out a set radius for the chart as a maxium -- if it should act like a score between 0 and 100? What kind of math to apply that a max radius has been reached to signify that the value is very big?
I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd
//version 3
https://jsfiddle.net/8ag1vf6e/1/
//current version 4
https://jsfiddle.net/d56g9r0y/
// filters go in defs element
var defs = innversebubble.append("defs");
var mask = defs.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.style("fill", "white")
.style("opacity", 1);
var invisiblebubble = mask.append("circle")
.data(data);
//create a fixed bubble first
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", function(d) {
return d.value - 20;
});
//now mask the fixed circle
var masker = defs.append(function() {
return mask.node().cloneNode(true)
})
.attr("id", "myMaskForPointer")
.select("rect")
.style("fill", "white")
.style("opacity", 1);
invisiblebubble
.attr("r", 10);
//apply the rest of the chart elements
var rect = innversebubble
.attr("class", "series")
.append("g")
.attr("transform", "translate(0,0)")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("mask", "url(#myMask)")
.style("fill", backcolor)
.style("opacity", backopacity);
//animate this circle
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.transition()
.duration(1800)
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
latest jsfiddle - 15th June -- needs fixing
https://jsfiddle.net/xmrtahns/
"I am keen to work out a set radius for the chart as a maxium -- if it should act like a score between 0 and 100? What kind of math to apply that a max radius has been reached to signify that the value is very big?
I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd"
I've fixed the conversion and the data source - but still need issues to resolve.
var backcolor = $this.data("color");
var backopacity = $this.data("opacity");
var width = $this.data("width");
var height = $this.data("height");
var data = [{
"label": $this.data("label-name"),
"centralLabel": $this.data("central-label"),
"xPer": $this.data("displace-left"),
"yPer": $this.data("displace-top"),
"value": $this.data("bubble-value")
}];
http://jsfiddle.net/hLymw8et/2/
--I am keen to work out a set radius for the chart as a maximum -- if it should act like a score between 0 and 100?
--What kind of math to apply that a max radius has been reached to signify that the value is very big?
--I also tried to have the svg mask adapt - if the browser or its container changed size -- ideally would want it to response during the change - rather than resizeEnd –
Can someone explain to me how to use clipping mask on the circle arc.
To explain what I'm doing. I have a circle and on this circle I add an arc that can be moved around. Now I would like to add like a linear gradient to this circle from left to right. But the gradient should only be seen on the arc, not the circle itself. Also I found one solution here https://www.freshconsulting.com/d3-js-gradients-the-easy-way/ but it's not what I want to do as my gradient should always be the same, but only the arc should display it. For example like this:
This is how you would draw a masked circle with a gradient fill with d3.
const svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500)
const defs = svg.append("defs")
const gradient = defs.append("linearGradient")
.attr("id", "exampleGradient")
gradient.append("stop")
.attr("offset", "10%")
.attr("stop-color", "white")
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "red")
const mask = defs.append("mask")
.attr("id", "donutMask")
mask.append("circle")
.attr("cx", 250)
.attr("cy", 250)
.attr("r", 150)
.attr("fill", "white")
mask.append("circle")
.attr("cx", 250)
.attr("cy", 250)
.attr("r", 120)
const circle = svg.append("circle")
.attr("r", 149)
.attr("cx", 250)
.attr("cy", 250)
.attr("stroke", "black")
.attr("mask", "url(#donutMask)")
.attr("fill", "url(#exampleGradient)")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I have the following code creating a circle:
SVGTTest.selectAll("circle")
.data(dataset)
.enter().append("circle")
.attr("cx", xScale(300))
.attr("cy", yScale(10))
.attr("r", xScale(100));
When I try to create an ellipse instead of a circle I try the following code, but nothing happens. Any help would be appretiated..
SVGTTest.selectAll("ellipse")
.data(dataset)
.enter().append("ellipse")
.attr("cx", yScale(300))
.attr("cy", yScale(10))
.attr("rx", xScale(100))
.attr("ry", 100);
I am using d3.js for graph. at some point i have to show data with some special part of graph for example if the values is cross some boundary then show that part with filling pattern. for more clear is there in and image.
i get the rect part that cross the boundary but how can i fill it with this pattern?
any css or canvas tricks?
Note : this image is just an example not the real one
How about this:
Live Demo
JS
var svg = d3.select("body").append("svg");
svg
.append('defs')
.append('pattern')
.attr('id', 'diagonalHatch')
.attr('patternUnits', 'userSpaceOnUse')
.attr('width', 4)
.attr('height', 4)
.append('path')
.attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2')
.attr('stroke', '#000000')
.attr('stroke-width', 1);
svg.append("rect")
.attr("x", 0)
.attr("width", 100)
.attr("height", 100)
.style("fill", 'yellow');
svg.append("rect")
.attr("x", 0)
.attr("width", 100)
.attr("height", 100)
.attr('fill', 'url(#diagonalHatch)');
Results
To change the color would be simple, just a conditional if statement. Here's an example i've used before:
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.style("fill", function(d) { // <== Add these
if (d.close >= 50) {return "red"} // <== Add these
else { return "black" } // <== Add these
;}) // <== Add these
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); });
To add a pattern would be a little more involved as you first have to add the defs element to your SVG and then add your pattern to it
//first create you SVG or select it
var svg = d3.select("#container").append("svg");
//then append the defs and the pattern
svg.append("defs").append("pattern")
.attr("width", 5)
.attr("height", 5);
I would like to add one simple arc in the chart section like a circle:
vis.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 50)
.attr("cy", 50);
The provided examples of D3 are working with data properties but i would like to see it without any underlying data.
D3 uses a path generator for arcs. If you don't want to data-drive your arc just define the arc generator and add some methods...
var arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(45 * (Math.PI/180)) //convert from degs to radians
.endAngle(3) //just radians
vis.append("path")
.attr("d", arc)
.attr("transform", "translate(50,50)")
You can see a demo here: http://jsfiddle.net/h9XNz/