D3 Gradient starting point - javascript

I have this circual chart - https://jsfiddle.net/kyleopperman/aacgzxed/ - but i am struggling to get the gradient to start in the center of each segment and fill out to the edge. Can anyone help me with this?
var gradient = vis.append("defs")
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "100%")
.attr("spreadMethod", "pad");
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#61B5C3")
.attr("stop-opacity", 1);
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#5393AC")
.attr("stop-opacity", 1);

Okay I've managed to figure this one out using a radialGradient
var radialGradient = vis.append("defs")
.append("radialGradient")
.attr("id", "radialGradient")
.attr("cx", "0%")
.attr("cy", "0%")
.attr("r", "50%")
.attr("fx", "0%")
.attr("fy", "0%")
.attr("spreadMethod", "pad")
.attr("gradientUnits", "userSpaceOnUse");
Here is the working example: https://jsfiddle.net/kyleopperman/aacgzxed/1/

Related

d3.js: gradient fill is outline, how to make it solid?

I have a simple bar chart using d3.js with a linear gradient on two rect objects. The gradient is there, but the gradient appears as an outline (two thin lines on the top and bottom of the rectangles). I want solid fill with the gradient, not outline. After a lot of research, I still don't have the answer.
Here is the d3 javascript:
var dataArray = [23, 13];
var names = [ "Category1", "Category2" ];
var widths = [ "50", "700" ];
var svg = d3.select("svg.d3svg")
.attr("height", "20%")
.attr("width", "100%")
var bar = svg.selectAll("g")
.data(dataArray)
.enter().append("g")
var gradient = svg
.append("linearGradient")
.attr("y1", "0%")
.attr("y2", "100%")
.attr("x1", "0%")
.attr("x2", "100%")
.attr("id", "gradient")
.attr("gradientUnits", "userSpaceOnUse")
gradient
.append("stop")
.attr('class', 'start')
.attr("offset", "0%")
.attr("stop-color", "red")
.attr("stop-opacity", 1);
gradient
.append("stop")
.attr('class', 'end')
.attr("offset", "100%")
.attr("stop-color", "green")
.attr("stop-opacity", 1);
var rect = bar.append('rect')
.attr("height", "7")
.attr("width", function(d, i) { return widths[i] })
.attr("y", function(d, i) { return (i * 40) + 30 })
.attr("x", "0")
.attr("stroke", "url(#gradient)")
var text = bar.append('text')
.attr("class", "text-svg")
.text (function(d, i) { return names[i] })
.attr("x", "0")
.attr("y", function(d, i) { return (i * 40) + 50 });
var text = bar.append('text')
.attr("class", "text-svg-caption")
.text ("Text for this goes here")
.attr("x", "135")
.attr("y", "120");
So my question is how do I get a solid fill in the rectangles with a linear gradient?
Thanks for any help.

How to add half circle in D3 based on function arguments?

The basic example of my question builds on this chart. The goal is to fill only half the circle with the group color.
This SO question explains how to make half circles.
Here's a snippet of the original code
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
Here`s adding a half circle
var grad = svg.append("defs").append("linearGradient").attr("id", "grad")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
grad.append("stop").attr("offset", "50%").style("stop-color", "lightblue");
grad.append("stop").attr("offset", "50%").style("stop-color", "white");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
enter code here
How could I make this grad dependent on the d.group?
I tried
A get_grad() function and have it return the grad
A set_grad() function and have it set the fill attribute
However, I didn't manage to get either working. Who can help me?
If you want to have different elements with different gradients, you have to use the same data binding process to create the gradients themselves:
var defs = svg.append("defs")
.selectAll("foo")
.data(data)
.enter()
.append("linearGradient")
//etc...
Have in mind that IDs have to be unique. In the following demo I'm doing:
.attr("id", function(d) {
return "grad" + d
})
... to create unique IDs.
In the demo, this is the part that you probably are interested in:
defs.append("stop")
.attr("offset", "50%")
.style("stop-color", function(d) {
return colours(d)
})
As you can see, I'm applying the stop colours based on data.
Have a look at the demo (which is not a force directed chart, but simply a demo with elements using different gradients):
var svg = d3.select("svg");
var colours = d3.scaleOrdinal(d3.schemeCategory10);
var defs = svg.append("defs")
.selectAll("foo")
.data(d3.range(5))
.enter()
.append("linearGradient")
.attr("id", function(d) {
return "grad" + d
})
.attr("x1", "0%")
.attr("x2", "0%")
.attr("y1", "100%")
.attr("y2", "0%");
defs.append("stop")
.attr("offset", "50%")
.style("stop-color", function(d) {
return colours(d)
})
defs.append("stop")
.attr("offset", "50%")
.style("stop-color", "white");
var circles = svg.selectAll("foo")
.data(d3.range(5))
.enter()
.append("circle")
.attr("cy", 50)
.attr("cx", function(d) {
return 25 + d * 62
})
.attr("r", 25)
.attr("stroke", "dimgray")
.attr("fill", function(d) {
return "url(#grad" + d + ")"
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
You can also play with the offsets:
var svg = d3.select("svg");
var colours = d3.scaleOrdinal(d3.schemeCategory10);
var defs = svg.append("defs")
.selectAll("foo")
.data(d3.range(5))
.enter()
.append("linearGradient")
.attr("id", function(d) {
return "grad" + d
})
.attr("x1", "0%")
.attr("x2", "0%")
.attr("y1", "100%")
.attr("y2", "0%");
defs.append("stop")
.attr("offset", function(d) {
return 20 + d * 15 + "%"
})
.style("stop-color", function(d) {
return colours(d)
})
defs.append("stop")
.attr("offset", function(d) {
return 20 + d * 15 + "%"
})
.style("stop-color", "white");
var circles = svg.selectAll("foo")
.data(d3.range(5))
.enter()
.append("circle")
.attr("cy", 50)
.attr("cx", function(d) {
return 25 + d * 62
})
.attr("r", 25)
.attr("stroke", "dimgray")
.attr("fill", function(d) {
return "url(#grad" + d + ")"
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

d3 javascript draw line over circle

I am new to d3 javascript library. I am trying to draw line over a circle using d3. I am able to create circle but somehow line does not appear on circle. See sample code attached. Any help is highly appreciated.
diag_circles.data(circle_data)
.enter()
.append("circle")
.attr("cx", function (d) {
console.log("d.x", d.x);
return d.x
})
.attr("cy", function (d) {
return d.y
})
.attr("r", function (d) {
return d.r
})
.append('line')
.attr("x1", function(d){return d.x- d.r})
.attr("y1", function(d){return d.y})
.attr("x2", function (d) { return d.x+ d.r})
.attr("y2", function(d){return d.y})
.attr("stroke-width", 20)
.attr("stroke", "black");
https://jsfiddle.net/c58859xy/
In a nutshell: you cannot append a line element to a circle element.
When creating your SVG, you have to know which elements allow appended children and what children they can have.
Solution: You'll have to append the lines to the SVG:
var lines = svg.selectAll('line')
.data(circle_data)
.enter()
.append("line")
.attr("x1", function(d){return d.x- d.r})
.attr("y1", function(d){return d.y})
.attr("x2", function (d) { return d.x+ d.r})
.attr("y2", function(d){return d.y})
.attr("stroke-width", 20)
.attr("stroke", "black");
Here is the updated fiddle: https://jsfiddle.net/c58859xy/1/

D3 force layout - How to achieve 3D look of nodes?

Here is jsfiddle of D3 cluster force layout:
How to achieve 3D look of nodes similar to this picture: (don't pay attention on diagram itself, this is just illustration of "look" of circles)
Here is jsfiddle of the solution. It is based on SVG radial gradients.
For each node, a gradient is defined:
var grads = svg.append("defs").selectAll("radialGradient")
.data(nodes)
.enter()
.append("radialGradient")
.attr("gradientUnits", "objectBoundingBox")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", "100%")
.attr("id", function(d, i) { return "grad" + i; });
grads.append("stop")
.attr("offset", "0%")
.style("stop-color", "white");
grads.append("stop")
.attr("offset", "100%")
.style("stop-color", function(d) { return color(d.cluster); });
Then, instead of line:
.style("fill", function(d) { return color(d.cluster); })
this line is added in the code that creates circles:
.attr("fill", function(d, i) {
return "url(#grad" + i + ")";
})
This produces this effect:(animated gif that I used has some limitations for number of colors, so gradients are not smooth as in real example)
Create linear or radial gradient based on your requirement using different colors. Set fill attribute as gradient.
var gradient = svg.append("svg:defs")
.append("svg:linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "100%")
.attr("spreadMethod", "pad");
gradient.append("svg:stop")
.attr("offset", "0%")
.attr("stop-color", "#0c0")
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "100%")
.attr("stop-color", "#c00")
.attr("stop-opacity", 1);
var node = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.style("fill", "url(#gradient)")
.call(force.drag);

Image within circle object causes pixelation d3 js

It appears I've followed the steps properly to fill a circle with an external image. I've tried numerous different image links, yet still can't resolve this pixelation issue. Any help is appreciated, here's a link to my fiddle:
http://jsfiddle.net/SdN2F/7/
Code issue snipet:
var photoCircle = d3.select('svg')
.append("circle")
.attr("cx", width-160)
.attr("cy", height-140)
.attr("r", radius-35)
.style("fill", "url(#photo)");
var image = d3.select('svg')
.append("pattern")
.attr("id", "photo")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-160)
.attr("height", height-140)
.append("image")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-160)
.attr("height", height-140)
.attr("xlink:href", "http://static-1.nexusmods.com/15/mods/110/images/50622-1-1391287636.jpeg");
You need to set the patternUnits attribute of pattern.
var image = d3.select('svg').append('defs')
.append("pattern")
.attr("id", "photo")
.attr("patternUnits","userSpaceOnUse")
.attr("x", 0)
.attr("y", 0)
.attr("width", 2*radius)
.attr("height", 2*radius)
.append("image")
.attr("x", 0)
.attr("y", 0)
.attr("width", 2*radius)
.attr("height", 2*radius)
.attr("xlink:href", "http://static-1.nexusmods.com/15/mods/110/images/50622-1-1391287636.jpeg");
jsFiddle: http://jsfiddle.net/chrisJamesC/SdN2F/11/

Categories