I was trying to understand the offset attribute of 'stop' svg element but couldn't get my head around it. Here's the code:
var vis = d3.select(scalecontainer)
.append("svg")
.attr('height', 30)
var gradient = vis.append("linearGradient")
.attr("y1", 0)
.attr("y2", 0)
.attr("x1", "0%")
.attr("x2", "100%")
.attr("id", "gradient")
.attr("gradientUnits", "userSpaceOnUse")
gradient
.append("stop")
.attr("offset", "0%")
.attr("stop-color", "red")
gradient
.append("stop")
.attr("offset","33%")
.attr("stop-color", "yellow")
gradient
.append("stop")
.attr("offset", "66%")
.attr("stop-color", "green")
var rect = vis.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 100)
.attr("height", 20)
.attr("fill", "url(#gradient)");
And here's the output that I get:
Shouldn't there be 3 different evenly spaced colour variations of 'red', 'yellow', and 'green'? What am I doing wrong here?
There are 3 different evenly spaced colour variatoins, but your rect has only an width of 100px whereas the linearGradient has the width of the svg element.
Set the two widths equally and your gradient will be fully visible.
The easiest way to get the full gradient inside your rect would be to set .attr("gradientUnits", "objectBoundingBox"). That way your gradient will be scaled to fit inside the element that references to the gradient.
A detailed explanation of all possible settings can be read on MDN.
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 –
I have an svg graph using d3.js, but I'm having trouble with the viewbox. As I have it now, the distance under the graph (30px) is fine, but there is still too much space between the text above the graph (48 px).
I don't have much experience with viewbox yet, so I researched and the best answer I found was at Find svg viewbox that trim whitespace around where the solution was to use the bounding box. That answer involves creating a button to click to show the graph correctly presented, but I want it to be positioned without additional user input.
Here is the html code above the graph:
<h1 class="h1_info">First Entry</h1><br>
<div class="zebra_01">This is the general text to describe the issue.<br><br>
With no further improvements:<ul><li>One item was this tall<br>
</li><li>Another item was that tall</li><li>
<span class="span_00">The first is taller than the second</span></li></ul>
</div>
<svg viewBox="0 0 700 100" preserveAspectRatio="xMinYMid meet" class="d3svg"></svg>
<script src="JS\D3_BarChart.js"></script>
Other html code starts here, 30px below the graph.
Here is the javascript:
var dataArray = [23, 13];
var colors = [ "red", "green" ];
var names = [ "First Name", "Second Name" ];
var widths = [ "5", "700" ]
var dists = ["45", "40"]
var svg = d3.select("svg.d3svg")
.attr("height", "auto")
.attr("width", "100%")
var bar = svg.selectAll("g")
.data(dataArray)
.enter().append("g")
var gradient = svg
.append("linearGradient")
.attr("y1", "0%")
.attr("y2", "20%")
.attr("x1", "0%")
.attr("x2", "25%")
.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 * dists[i]) + 30 })
.attr("x", "0")
.attr("fill", "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 * dists[i]) + 55 });
So my question is whether using bounding box is the correct solution, and how can it be set without using a button?
Thanks for any help on this.
Looking at the chart, the first element starts at y =30. You can change the viewBox to be consistent with this fact:
viewBox="0 30 700 100"
Alternatively, if you are not sure about the y coordinates of the first element, you can use d3 to programmatically adjust the viewBox. Here is the relevant piece of your code:
var rect = bar.append('rect')
.attr("height", "7")
.attr("width", function(d, i) { return widths[i] })
.attr("y", function(d, i) { return (i * dists[i]) + 30 })
.attr("x", "0")
.attr("fill", "url(#gradient)")
svg.attr("viewBox", `0 ${rect.attr("y")} 700 100`) //add this. It uses es6 way to interpolate a string
The last line takes the y attribute of the rect (the topmost element in this case) and changes the viewBox accordingly.
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 am successful in getting crosshair in D3.js chart but issue is I am only getting vertical line, how do I add code for horizontal line as well?
Image of chart
JSFiddle code chart is not plotting in JSFiddle
Basically code to add vertical line crosshair is as below:-
var vertical = d3.select("body")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "19")
.style("width", "1px")
.style("height", "450px")
.style("top", "47px")
.style("bottom", "1px")
.style("left", "8px")
.style("background", "#000");
Can I add horizontal crosshair as well same way?
P.S. also wanted a way to keep this vertical line only in chart area, but is coming in whole body, i.e. empty area next to chart in right and left.
Your approach is too complicated. This is simpler:
First, create a transparent rectangle to get the mouse movements:
var transpRect = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "white")
.attr("opacity", 0);
Then, create the lines:
var verticalLine = svg.append("line")
.attr("opacity", 0)
.attr("y1", 0)
.attr("y2", height)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("pointer-events", "none");
var horizontalLine = svg.append("line")
.attr("opacity", 0)
.attr("x1", 0)
.attr("x2", width)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("pointer-events", "none");
Finally, position the lines on mousemove:
transpRect.on("mousemove", function(){
mouse = d3.mouse(this);
mousex = mouse[0];
mousey = mouse[1];
verticalLine.attr("x1", mousex).attr("x2", mousex).attr("opacity", 1);
horizontalLine.attr("y1", mousey).attr("y2", mousey).attr("opacity", 1)
}).on("mouseout", function(){
verticalLine.attr("opacity", 0);
horizontalLine.attr("opacity", 0);
});
Here is your fiddle: https://jsfiddle.net/xrf1ro1a/
PS: to avoid killing your tooltips, I put the mousemove both on the rectangle and on the svg as well, which has the undesirable effect of making the lines going outside the chart area. To avoid this, set pointer-events = none to the elements outside the chart area.
I have a D3 bar chart as follows:
I want to color the bars that pass the horizontal line the color green. I can do this as follows:
.attr("fill", function(d) { return (d.the_value > 0.65 ? "green" : "orange"); })
which works great. But the height of the horizontal bar itself is set using the height of the plot.
svg.append("line")
.style("stroke", "black")
.attr("x1", 0)
.attr("y1", height/2)
.attr("x2", 600)
.attr("y2", height/2);
I want to set the height of the horizontal bar by using the value 0.65. How can I get the height in pixels that corresponds to 0.65 on the axis?
I presume you have something in your code like
yScale = d3.scale()
.domain(...)
.range([0, 600])
and that you use it to size and position the bars.
With that scale you can get the y-coordinate you're after using yScale(0.65). I.e.:
svg.append("line")
.style("stroke", "black")
.attr("x1", 0)
.attr("y1", yScale(0.65))
.attr("x2", 600)
.attr("y2", yScale(0.65));