How to create different colour shades to column bar in d3 [duplicate] - javascript

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.

If you want pattern that scales to the bar size, use a gradient pattern:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" 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="d3#3.5.3" 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>

Related

D3 v5 - how to set background color of text (only as wide as text)

Consider the code for some text I'm putting in some circles:
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 1080;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
//var tsvData = d3.tsv('circle-pack-data.tsv');
//tsvData.then(function(rawData) {
/*
var data = rawData.map(function(d) {
return {id:d.id, parentId:d.parentId, size:+d.size}
});
*/
var data = [
[
{'id':'3Q18'},
{'id':'Greater China','parentId':'3Q18','size':428.7,'sign':'negative'},
{'id':'Thematic','parentId':'3Q18', 'size':111.8,'sign':'positive'},
{'id':'US','parentId':'3Q18', 'size':418.3,'sign':'positive'},
{'id':'India','parentId':'3Q18', 'size':9.39,'sign':'negative'},
{'id':'Europe','parentId':'3Q18', 'size':94.0,'sign':'positive'},
{'id':'Japan','parentId':'3Q18', 'size':0,'sign':'positive'},
{'id':'Global','parentId':'3Q18', 'size':41.9,'sign':'negative'}
],
[
{'id':'4Q18'},
{'id':'Greater China','parentId':'4Q18','size':217.8,'sign':'negative'},
{'id':'Thematic','parentId':'4Q18', 'size':100.5,'sign':'positive'},
{'id':'US','parentId':'4Q18', 'size':127.9,'sign':'negative'},
{'id':'India','parentId':'4Q18', 'size':1.5,'sign':'negative'},
{'id':'Europe','parentId':'4Q18', 'size':1.5,'sign':'positive'},
{'id':'Japan','parentId':'4Q18', 'size':0,'sign':'positive'},
{'id':'Global','parentId':'4Q18', 'size':52.8,'sign':'negative'}
],
];
var colorMap = {
'3Q18':"#d9d9d9",
'4Q18':"#d9d9d9",
'3Q19':"#d9d9d9",
'4Q19':"#d9d9d9",
'Greater China':"#003366",
'Thematic':"#366092",
'US':"#4f81b9",
'India':"#95b3d7",
'Europe':"#b8cce4",
'Japan':"#e7eef8",
'Global':"#a6a6a6"
};
var defs = svg.append('svg:defs');
var blue1x = "Fills/blue-1-crosshatch-redo.svg";
var blue2x = "Fills/blue-2-crosshatch.svg";
var blue3x = "Fills/blue-3-crosshatch.svg";
var blue4x = "Fills/blue-4-crosshatch.svg";
var blue5x = "Fills/blue-5-crosshatch.svg";
var blue6x = "Fills/blue-6-crosshatch.svg";
var grayx = "Fills/gray-2-crosshatch.svg";
defs.append("svg:pattern")
.attr("id", "blue1_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue1x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue2_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue2x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue3_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue3x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue4_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue4x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue5_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue5x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue6_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue6x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "gray_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", grayx)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
var negativeMap = {
'3Q18':"#d9d9d9",
'4Q18':"#d9d9d9",
'3Q19':"#d9d9d9",
'4Q19':"#d9d9d9",
'Greater China':"url(#blue1_hatch)",
'Thematic':"url(#blue2_hatch)",
'US':"url(#blue3_hatch)",
'India':"url(#blue4_hatch)",
'Europe':"url(#blue5_hatch)",
'Japan':"url(#blue6_hatch)",
'Global':"url(#gray_hatch)"
};
var strokeMap = {
"Greater China":"#fff",
"Thematic":"#fff",
"US":"#fff",
'India':"#000",
'Europe':"#000",
'Japan':"#000",
'Global':"#000"
};
for (var j=0; j <(data.length); j++) {
var vData = d3.stratify()(data[j]);
var vLayout = d3.pack().size([250, 250]);
var vRoot = d3.hierarchy(vData).sum(function (d) { return d.data.size; });
var vNodes = vRoot.descendants();
vLayout(vRoot);
var thisClass = "circ"+String(j);
var vSlices = graphGroup.selectAll('.'+thisClass).data(vNodes).attr('class',thisClass).enter().append('g');
console.log(vNodes)
vSlices.append('circle')
.attr('cx', function(d, i) {
return d.x+(j*300)
})
.attr('cy', function (d) { return d.y; })
.attr('r', function (d) { return d.r; })
.style('fill', function(d) {
//console.log(d.data.id)
if (d.data.data.sign=='positive') {
return colorMap[d.data.id];
} else {
return negativeMap[d.data.id];
}
});
vSlices.append('text')
.attr('x', function(d,i) {return d.x+(j*300)})
.attr('y', function(d) {return d.y+5})
.attr('text-anchor','middle')
.style('fill', function(d) {return strokeMap[d.data.id]})
.style('background-color', function(d) {return colorMap[d.data.id]})
.text(function(d) {return d.data.data.size ? d.data.data.size : null});
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Since the fill of the circle can sometimes be a crosshatch (not a solid color), the readability of the text takes a hit. I also found that simply adding a text shadow wasn't quite enough. I'd like to go for the "nuclear" option and assign a solid background color to the text I append. I thought I could do that with the following:
vSlices.append('text')
.attr('x', function(d,i) {return d.x+(j*300)})
.attr('y', function(d) {return d.y+5})
.attr('text-anchor','middle')
.style('fill', function(d) {return strokeMap[d.data.id]})
.style('background-color', function(d) {return colorMap[d.data.id]})
.text(function(d) {return d.data.data.size ? d.data.data.size : null});
However this achieved nothing.
Question
What is the correct way to assign background color for svg text dynamically? (seeing as the background color will need to match the circle's color as per colorMap)
A <rect> can be added before the <text> and given a background color.
const parent = vSlices.append("g").attr("class", "vSlices");
const rect = parent.append("rect")
.attr("x", "-10")
.attr("y", "-15")
.attr("height", 30)
.attr("rx", 15)
.attr("ry", 15)
.style("fill", "#f1f1f1");
const text = parent.append('text')
.attr('x', function(d,i) {return d.x+(j*300)})
.attr('y', function(d) {return d.y+5})
.style('fill', function(d) {return strokeMap[d.data.id]})
.text(function(d) {return d.data.data.size ? d.data.data.size : null});
rect.attr("width", function(d){
return this.parentNode.childNodes[1].getComputedTextLength() + 50
});
The canvas will be rendered as
<g class="vSlices" transform="translate(1020,230)">
<rect x="-10" y="-15" height="30" rx="15" ry="15" style="fill: rgb(241, 241, 241);" width="50.578125"></rect>
<text x="13" dy=".35em" text-anchor="start" style="fill-opacity: 1;">Data Size</text>
</g>
YOu can do it with css like this
p {
display: inline-block;
background-color: tomato;
}
It will give color only to the background of text. You can also use display: inline but then you won't be able to do changes to element like margins or smth else.
So use display: inline-block
I hope it helped :)

D3 text-anchor won't append

var w = 300;
var h = 150;
var padding = 2;
var dataset =[5, 10, 15, 20, 25];
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
function colorPicker(v){
if (v<=20) { return "#666666"; }
else if (v>20) { return "#FF0033"; }
}
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) { return (i*(w/dataset.length)); })
.attr("y", function(d) { return h-(d*4); })
.attr("width", w/dataset.length-padding)
.attr("height", function(d) { return d*4;})
.attr("fill", function(d){
return colorPicker(d);
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {return d; })
.attr({"text-anchor": "middle"})
.attr({
x: function(d, i) {return i* (w / dataset.length);},
y: function(d) {return h - (d*4); }
});
I am following a D3.js tutorial and I'm trying to get the text-anchor to work, but it won't append. No text appears, can anyone shed any light into what I'm doing wrong?
It should display the number above every rectangle
In the new (not so new, actually) V4.x version, you cannot use objects to set the attr() method.
Besides that you have another problem, which will avoid the texts to be rendered: there is no value property in your dataset (which is just an array of numbers). Thus, it should be:
.text(function(d){return d})
Here is your code with the necessary changes:
var w = 300;
var h = 150;
var padding = 2;
var dataset = [5, 10, 15, 20, 25];
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
function colorPicker(v) {
if (v <= 20) {
return "#666666";
} else if (v > 20) {
return "#FF0033";
}
}
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * (w / dataset.length));
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - padding)
.attr("height", function(d) {
return d * 4;
})
.attr("fill", function(d) {
return colorPicker(d);
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("text-anchor", "middle")
.text(function(d) {
return d;
})
.attr("x", function(d, i) {
return i * (w / dataset.length) + ((w / dataset.length - padding) / 2);
})
.attr("y", function(d) {
return h - (d * 4);
});
<script src="https://d3js.org/d3.v4.min.js"></script>

d3 Bar Chart append text to bar

I've followed the tutorial to make a bar chart from Scott Murray from alignedleft. I'm having problem with my dataset and adding the dataset to a bar as text.
The image below: 1 bar chart: from the tutorial , 2nd bar chart: how I want to display the text.
Here's my code so far:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tutorial d3 bar chart!</title>
<script type="text/javascript" src="d3/d3.v3.js"></script>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 100;
var i = 0;
var barPadding = 1;
var dataset = [
{key:"Department1", value:6234490},
{key:"Department 2", value:9700},
{key:"Department 3", value:2954},
];
//Width and height
var w = 500;
var h = 100;
var barPadding = 1;
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
})
.attr("fill", function(d) {
return "rgb(0, 0, " + (d * 10) + ")";
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
for(int i = 0; i < dataset.length; i++){
return d[i].key;
}
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
})
.attr("y", function(d) {
return h - (d * 4) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
</script>
</body>
</html>
I've tried to add the text in this part:
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
for(int i = 0; i < dataset.length; i++){
return d[i].key;
}
})
But that just gives me this error:
I hope you guys can help me out.
Try changing int to var, int doesn't exist in javascript.
Every function in d3js provides access to data and the index.
Just use this
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d){return d.key;}
})
EDIT
svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
})
.attr("fill", function(d) {
return "rgb(0, 0, " + (d * 10) + ")";
})
.append("text")
.text(function(d) {
return d.key;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
})
.attr("y", function(d) {
return h - (d * 4) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");

D3.JS add zoom and listitems to rect

I want to achieve followings,
1 - Create a given column matrix with rectangles with provided colours
Done
2 - Make this matrix zoom able
3 - Add list items to each rectangle which will only show numbers of list items in it if completely zoomed out and on zoom in, it will show the list items e.g. there Titles.
Now I want to achieve Number 2 here, this is what I am trying,
http://jsfiddle.net/nhe613kt/25/
When I add code for zooming it fails,
var svgContainer = d3.select("body").append("svg")
.attr("width", 300)
.attr("height", 300)
.style("background-color", "black");
var zoomed = function () {
svgContainer.attr("transform", "translate("+ d3.event.translate + ")
scale(" + d3.event.scale + ")");
};
var zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);
.size([width, height]);
var rectangle1 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red")
.call(zoom);;
var rectangle2 = svgContainer.append("rect")
.attr("x", 100)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "yellow");
var rectangle3 = svgContainer.append("rect")
.attr("x", 200)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red");
var rectangle4 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 100)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "yellow");
var rectangle5 = svgContainer.append("rect")
.attr("x", 100)
.attr("y", 100)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red");
var rectangle6 = svgContainer.append("rect")
.attr("x", 200)
.attr("y", 100)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "yellow");
var rectangle7 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 200)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red");
var rectangle8 = svgContainer.append("rect")
.attr("x", 100)
.attr("y", 200)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "yellow");
var rectangle9 = svgContainer.append("rect")
.attr("x", 200)
.attr("y", 200)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red");
My desired result will be this,
http://bl.ocks.org/mbostock/3680957
The code you provided has several problems:
1. There is a syntax error in definition of zoom (.on("zoom", zoomed);)
2. You haven't defined width and height.
3. zoomed function possibly couldn't be parsed because of wrong line breaks (notice point where you define scale of transformation).
Here is JSFiddle, where zoom works correctly for first element of matrix. Main points is:
// don't forget about width and height
var width = 960,
height = 500;
// make sure that string defining transform attribute is correct. scale isn't a method, but part of string
var zoomed = function () {
svgContainer.attr("transform", "translate("+ d3.event.translate + ")scale(" + d3.event.scale + ")");
};
// don't place semicolon after on("zoom", zoomed)
var zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed)
.size([width, height]);
// add zoom behaviour to desired rectangle
var rectangle1 = svgContainer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 100)
.attr("height", 100)
.attr("fill", "red")
.call(zoom);

Why must my D3 selection come before the D3 code itself?

I spent hours trying to figure out why my code was not working. I then arbitrarily moved my button code from after the D3 code (at the end between </script> and </body>) to the top (between <script type="text/javascript"> and <body>). It works now, but I don't know why. I don't want to make this mistake again or confuse myself in the future.
<body>
<button>Update</button>
<script type="text/javascript">
var w = 500;
var h = 500;
var barPadding = 1;
var dataset = [ ];
for (var i = 0; i < 14; i++) {var newNumber = Math.round(Math.random() * 70);
dataset.push(newNumber);}
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create Scales for Data conversion
var xScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d,i) {return d;})]) //input
.range([0,w]); // output
var yScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, h], 0.05); //Vertical separation + barpadding
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 3)
.attr("y", function (d,i) {return yScale(i);})
.attr("width", function(d,i) {return xScale(d);})
.attr("height", yScale.rangeBand())
.attr("fill", function(d) {return "rgb(" + (d * 10) + ", 0,0 )";});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {return d;})
.attr("x", function(d) {return xScale(d) -15;})
.attr("y", function(d, i) {return yScale(i) +5 +yScale.rangeBand() / 2;})
.attr("fill", "white")
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle");
//Create Data Update and transition
d3.select("button")
.on("click", function() {
//New values for dataset
dataset = [ ];
for (var i = 0; i < 14; i++) {var newNumber = Math.round(Math.random() * 70);
dataset.push(newNumber);}
//Update all rects, and color gradient
svg.selectAll("rect")
.data(dataset)
.transition()
.attr("x", 3)
.attr("width", function(d,i) {return xScale(d);})
.attr("fill", function(d) {return "rgb(" + (d * 10) + ", 0,0 )";});
//Update text label and position
svg.selectAll("text")
.data(dataset)
.text(function(d) {return d;})
.attr("x", function(d) {return xScale(d) -15;})
.attr("y", function(d, i) {return yScale(i) +5 + yScale.rangeBand() / 2;});
});
</script>
</body>
If you're saying that the code as shown in your question works, with the <button> element before the <script> element, it's because <script> elements are executed as the browser encounters them, top-to-bottom while parsing the page. Which means that any JavaScript that you use is only able to reference elements that are higher in the page source because the browser doesn't know about the later elements yet.
Unless you have code within functions that don't get called until after the DOM is complete, for example if you assign a DOM ready or onload event handler, or a delegated click handler or something.

Categories