I have managed to apply a gradient to my bar chart and the gradient effect gives the desired result.
var gradient = svg.append("defs")
.data(data)
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", function(d) {
return colors(d.name);
})
.attr("stop-opacity", 1);
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", function(d) {
return colors(d.name);
})
.attr("stop-opacity", 0.3);
I also have a color scale that I'm using to assign colors to each category (name)
var colors = d3.scale.ordinal()
.range(["#C1D42F", "#2b328c", "#5AB88D", "#8F1F61", "#00A5D3", "#EC5D20", "#F59C28"])
This was working fine before I started to use gradient
However, now it appears that the function I'm using is only taking the first color (#C1D42F) from my range.
How can I apply the gradient as well as assign the ranged colors ?
Here is my fiddle
There are two issues related to this result
1) The gradient definition is missing the .enter() method
This is necessary to create a linearGradient element for each data point. Instead of:
var gradient = svg.append("defs")
.data(data)
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
You could use:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
Now, instead of having only one linearGradient element, you have one for each color. However, you will notice the problem persists, which leads to the second issue:
2) If all the linear gradients have the same ID, the code can not differentiate between colors.
Different linearGradient elements need different IDs in order to reference the data they represent. Continuing the previous example, instead of:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
You could use:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", d => `gradient${d.name}`) // Create a unique data-driven id for each linearGradient
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
And in the bars, the code can now reference the correct linearGradient according to the data:
bars.append("rect")
...
.style("fill", d => `url(#gradient${d.name})`); // picks the gradient that match the data
Related
Append a defs (for definition) element to your SVG
var defs = svg.append("defs");
//Append a linearGradient element to the defs and give it a unique id
var linearGradient = defs.append("linearGradient")
.attr("id123", "linear-gradient");
//Horizontal gradient
linearGradient
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%");
//Build a color scale
var colorScale = d3.scale.linear().range(["#2c7bb6", "#00a6ca","#00ccbc","#90eb9d","#ffff8c",
"#f9d057","#f29e2e","#e76818","#d7191c"]);
//Append multiple color stops by using D3's data/enter step
linearGradient.selectAll("stop")
.data( colorScale.range() )
.enter().append("stop")
.attr("offset", function(d,i) { return i/(colorScale.range().length-1); })
.attr("stop-color", function(d) { return d; });
I know this is something that isn't simple even using just D3, but at least there is examples online.
My question is: How to make gradient fills in a dc.barChart?
Something like ordinalColors seems to accept only RGB values.
What I want is to do something like this but with bars:
Thanks
ok, looks like I need to put the 'defs' in a renderlet.
So the code would be something like:
.renderlet(function (chart) {
const barBG = d3.select(divRef)
.select('svg')
.append('defs')
.append("linearGradient");
barBG
.attr("id", "barBg")
.attr("x1", "0")
.attr("x2", "0")
.attr("y1", "200")
.attr("y2", "00")
.attr("gradientUnits", "userSpaceOnUse");
barBG
.append("stop")
.attr("offset", "0%")
.attr("stop-color", "rgb(31, 119, 180)")
.attr("stop-opacity", "0.1");
barBG
.append("stop")
.attr("offset", "100%")
.attr("stop-color", "rgb(31, 119, 180)")
.attr("stop-opacity", "1");
chart.selectAll("g.x text")
.attr('dx', '30')
.attr('transform', "translate(-15,0) rotate(-90)")
.attr('display', 'none');
// chart.selectAll('.bar')
// .attr("fill", "url(#barBg)");
})
;
Then, you add the id of the the gradient in the color scale:
.ordinalColors(['url(#barBg)','rgb(255, 127, 14)'])
In my chart i have a rectangle with a gradient
barG.enter().append("rect")
.attr("id", "my_rectangle")
.attr("x", 0)
.attr("y", 50)
.attr("height", barHeight - 1)
.attr("width", rectWidth)
.attr("fill", rectColor);
Depends on data the function rectColor returns a gradient
function rectColor(d) {
//set bar color
if (d.value <= d.limit) {
return "url(#gradientRed)";
} else {
return "url(#gradientDefault)";
}
}
;
A gradient looks like this
var gradientDefault = defs
.append("linearGradient")
.attr("id", "gradientDefault")
.attr("x1", "0%")
.attr("x2", "0%")
.attr("y1", "0%")
.attr("y2", "100%")
.attr("spreadMethod", "pad");
gradientDefault.append("stop")
.attr("offset", "0%")
.attr("stop-color", defaultStyle.backgroundColor)
.attr("stop-opacity", 1);
gradientDefault.append("stop")
.attr("offset", "100%")
.attr("stop-color", defaultStyle.secondaryBackgroundColor)
.attr("stop-opacity", 1);
How can i make a transition from one gradient to another?
I have tried
// animation rectangle/bar
rect.transition()
.duration(1000)
.attr("fill", rectColor);
but it doesn't work...
Here is the jsfiddle-code. The data will be loaded dynamically.
For some reason, in the last block of this code append("g) us successful, but the data bind to append lines is not. I know should just print 10 lines on top of each other, but I cannot even get them to print into the page for some reason. Can anyone see the error? Thanks very much for your help!
var w = 300;
var dataset = 10;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", w);
svg.append("line")
.attr("x1", w/2)
.attr("y1", 0)
.attr("x2", w/2)
.attr("y2", w);
svg.append("line")
.attr("x1", 0)
.attr("y1", w/2)
.attr("x2", w)
.attr("y2", w/2);
svg.append("g")
.selectAll("line")
.data(dataset)
.enter()
.append("line")
.attr("x1", 0)
.attr("y1", w/4)
.attr("x2", w/2)
.attr("y2", w/4);
dataset in .data(dataset) has to be an array so you get nothing. If you use, for example .data([dataset]) you will get one line. If you want 10 lines you can use .data(d3.range(10)) and add some color to see it/them:
svg.append("g").selectAll("line")
.data(d3.range(10))
.enter()
.append("line")
.attr("x1", 0)
.attr("y1", w/4)
.attr("x2", w/2)
.attr("y2", w/4)
.style('stroke', 'green');
How to put two colors on the same link between nodes.
Here I need to put different color on link what I mentioned before with respect of value.
This color can place on two sides of the link.
So Half link one color and another half another one color.
So Please help me to do.
You can use an SVG gradient to do this. Here is an example using D3. The idea is to have a hard stop in the middle so it looks like two separate colours and not a gradient. The code would look something like this.
var gradient = svg.append("svg:defs")
.append("svg:linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%");
gradient.append("svg:stop")
.attr("offset", "0%")
.attr("stop-color", "green")
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "50%")
.attr("stop-color", "green")
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "50%")
.attr("stop-color", "red")
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", "100%")
.attr("stop-color", "red")
.attr("stop-opacity", 1);
You can use it exactly like in the example.