Reputation: 1998
I have created a D3 bar chart, which takes in my data, applies a scale and then draws my rectangles. Here's my current output:
I would like to make it more visual. The values are temperatures, so I'd like to create something like the first bar here:
Basically I want to make a bar that is made up of many rectangles of different colors.
After considering several options, I decided to try to inject a pattern into my bars. I tried making my pattern from paths, and then I attempted rectangles, but no success.
I'm not tied to the 'pattern' approach, so an different approach, or how I can make this pattern, is what I'm after. Here's my code:
// Set variables.
var dataset = // an array of objects, each with two properties: location and temperature
w = 500,
h = 800,
xScale = d3.scale.linear()
.domain([-30, 40])
.range([5, 350]),
yScale = d3.scale.ordinal();
// Create SVG element.
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
/* svg.append("defs")
.append("pattern")
.attr("id", "heatHatch")
.attr("patternUnits", "userSpaceOnUse")
.attr("width", 350)
.attr("height", 25);
.append("path")
.attr("d", "M10 0 L10 20 L0 20 L0 0 Z M22 0 L22 20 L12 20 L12 0 Z")
.attr("fill", "pink")
.append("path")
.attr("d", "M22 0 L22 20 L12 20 L12 0 Z")
.attr("fill", "red");
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 10)
.attr("height", 20)
.attr("fill", "pink"); */
// Create bars.
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", function(d, i) {
return i * 25;
})
.attr("width", function(d) {
return xScale(d[1]);
})
.attr("height", 20);
/*.attr("fill", "url(#heatHatch)"); */
Thanks.
Upvotes: 2
Views: 1031
Reputation: 108517
If you want pattern that scales to the bar size, use a gradient pattern:
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var w = 500,
h = 500;
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
var color = d3.scale.category10();
var gradient = svg.append("svg:defs")
.append("svg:linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "50%")
.attr("x2", "100%")
.attr("y2", "50%")
.attr("spreadMethod", "pad");
d3.range(10).forEach(function(d, i) {
var c = color(i);
gradient.append("svg:stop")
.attr("offset", (i * 10) + "%")
.attr("stop-color", c)
.attr("stop-opacity", 1);
gradient.append("svg:stop")
.attr("offset", ((i + 1) * 10) + "%")
.attr("stop-color", c)
.attr("stop-opacity", 1);
});
svg.selectAll("bar")
.data(d3.range(10))
.enter()
.append("rect")
.attr("class", "bar")
.attr("width", function(d,i){
return (w / 10) * i;
})
.attr("height", (h / 10) - 10)
.attr("y", function(d,i){
return (h / 10) * i;
})
.style("fill", "url(#gradient)");
</script>
</body>
</html>
If you want a pattern with statically sized colors, create a pattern of rects:
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var w = 500,
h = 500;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var color = d3.scale.category10();
var pattern = svg.append("svg:defs")
.append("svg:pattern")
.attr("width", w)
.attr("height", 4)
.attr("id", "myPattern")
.attr("patternUnits","userSpaceOnUse");
d3.range(10).forEach(function(d, i) {
var c = color(i);
pattern.append("rect")
.attr("height", "4px")
.attr("width", w / 10)
.attr("x", (w / 10) * i)
.attr("fill", c);
});
svg.selectAll("bar")
.data(d3.range(10))
.enter()
.append("rect")
.attr("class","bar")
.attr("width", function(d,i){
return (w / 10) * i;
})
.attr("height", (h / 10) - 10)
.attr("y", function(d,i){
return (h / 10) * i;
})
.style("fill", "url(#myPattern)");
</script>
</body>
</html>
Upvotes: 2