preface
Let’s draw a line chart this time, so let’s analyze what it takes to draw a line chart?
- Coordinate axes (one vertical and one horizontal)
- A little grid line to make it look nice
- A line chart must have smooth curves
- It would be nice if I had another path to draw the lines
Good above is we want step by step to draw the line chart out of the steps !!!!
Let’s take a look at the effect first:
start
Start the tasks listed above
Step 1 (Draw the axes)
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const height = 500, width = 500, margin = 25;
// Define our SVG canvas space container
let svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height)
// Draw a horizontal axis
function drawXAxis() {
// To create a linear scale, use the axes required
const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);
// Create the x axis at the bottom
const xAxis = d3.axisBottom(xScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ height - margin }) `
}).call(xAxis);
}
// Draw a vertical axis
function drawYAxis() {
// To create a linear scale, use the axes required
const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
// Create the x axis at the bottom
const yAxis = d3.axisLeft(yScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ margin }) `
}).call(yAxis);
}
drawXAxis();
drawYAxis();
</script>
Copy the code
Effect presentation:
Code analysis; It’s just two coordinate axes, and then it’s shifted to staggered positions, our x and y axes. Is the model out !!!! Let’s keep going
Step 2 (Draw grid lines)
Previous DOM rendering diagram:
Let’s observe the DOM structure of our coordinate axis. It is wrapped in a G container, and then there are the small lines of our coordinate axis and the words of the scale.
Let’s put a link in there, so we don’t have to worry about translate
Code part:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const height = 500, width = 500, margin = 25;
// Define our SVG canvas space container
let svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height)
// Draw a horizontal axis
function drawXAxis() {
// To create a linear scale, use the axes required
const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);
// Create the x axis at the bottom
const xAxis = d3.axisBottom(xScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ height - margin }) `
}).call(xAxis);
}
// Draw a vertical axis
function drawYAxis() {
// To create a linear scale, use the axes required
const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
// Create the x axis at the bottom
const yAxis = d3.axisLeft(yScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ margin }) `
}).call(yAxis);
}
function drawGrid() {
// Draw the Y-axis line
d3.selectAll('.y-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
// Font-size: 16px! Important
.attr('x2',(height - margin * 2))
.attr('y2'.0)
.attr('stroke'.'#e4e4e4')
// Draw the X-axis line
d3.selectAll('.x-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
.attr('x2'.0)
.attr('y2',(- height + margin * 2))
.attr('stroke'.'#e4e4e4')} (async function draw() {
await drawXAxis();
await drawYAxis();
awaitdrawGrid(); }) ();</script>
Copy the code
Effect presentation:
Summary: Two lines drawn as grid, code changes part addeddrawGrid
methods
Step 3 (Draw path line)
Draw line graph line, in fact, is a day path path, some people should question this path calculation position is not good trouble ah? D3js has an API (d3.line()) to convert a set of [{x: 1, y: 1}, {x: 2, y:2}] to this type of path
Code drawing:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const height = 500, width = 500, margin = 25;
// Define our SVG canvas space container
let svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height);
// To create a linear scale, use the axes required
const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);
// Draw a horizontal axis
function drawXAxis() {
// Create the x axis at the bottom
const xAxis = d3.axisBottom(xScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ height - margin }) `
}).call(xAxis);
}
// Draw a vertical axis
function drawYAxis() {
// Create the x axis at the bottom
const yAxis = d3.axisLeft(yScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ margin }) `
}).call(yAxis);
}
function drawGrid() {
// Draw the Y-axis line
d3.selectAll('.y-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
// Font-size: 16px! Important
.attr('x2',(height - margin * 2))
.attr('y2'.0)
.attr('stroke'.'#e4e4e4')
// Draw the X-axis line
d3.selectAll('.x-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
.attr('x2'.0)
.attr('y2',(- height + margin * 2))
.attr('stroke'.'#e4e4e4')}// Data definition, two lines
const data = [
[
{x:0.y:6},
{x:1.y:5},
{x:2.y:3},
{x:3.y:5},
{x:4.y:5},
{x:6.y:4},
{x:7.y:3},
{x:8.y:3},
{x:9.y:2},
{x:10.y:10},
],
d3.range(10).map(function(i){
return {x:i,y:Math.min(i)}
})
]
function drawLine() {
//d3.line generates a path from the array coordinates
let line = d3.line()
.x(function(d){
M0,0, L, 1,2..... This sample
return xScale(d.x)
})
.y(function(d){
return yScale(d.y)
})
/ / add the path
svg.selectAll('path.path')
.data(data)
.enter()
.append('path')
.attr('class'.'path')
.attr('d'.function(d){
return line(d)
})
.attr('stroke'.'#2e6be6')
.attr('fill'.'none')
.attr('transform'.`translate(${margin}.${margin}) `)} (async function draw() {
await drawXAxis();
await drawYAxis();
await drawGrid();
awaitdrawLine(); }) ();</script>
Copy the code
Effect presentation:
Conclusion: Make use ofd3.line()
Help us generate path path, new functiondrawLine()
Does it feel like something’s missing? Yeah, it feels like the nodes aren’t obvious, but it would be nice if the curves were smooth, right?
Discount map rendering effect optimization
The nodes are not obvious, right? Smooth curve?
Analysis: Nodes not obvious? Let’s look at the chart and see that they have a circle at each point and the curve is smooth, right? Curve (d3.curvecardinal)
Code rendering:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const height = 500, width = 500, margin = 25;
// Define our SVG canvas space container
let svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height);
// To create a linear scale, use the axes required
const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);
// Draw a horizontal axis
function drawXAxis() {
// Create the x axis at the bottom
const xAxis = d3.axisBottom(xScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ height - margin }) `
}).call(xAxis);
}
// Draw a vertical axis
function drawYAxis() {
// Create the x axis at the bottom
const yAxis = d3.axisLeft(yScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ margin }) `
}).call(yAxis);
}
function drawGrid() {
// Draw the Y-axis line
d3.selectAll('.y-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
// Font-size: 16px! Important
.attr('x2',(height - margin * 2))
.attr('y2'.0)
.attr('stroke'.'#e4e4e4')
// Draw the X-axis line
d3.selectAll('.x-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
.attr('x2'.0)
.attr('y2',(- height + margin * 2))
.attr('stroke'.'#e4e4e4')}// Data definition, two lines
const data = [
[
{x:0.y:6},
{x:1.y:5},
{x:2.y:3},
{x:3.y:5},
{x:4.y:5},
{x:6.y:4},
{x:7.y:3},
{x:8.y:3},
{x:9.y:2},
{x:10.y:10},
],
d3.range(10).map(function(i){
return {x:i,y:Math.min(i)}
})
]
function drawLine() {
//d3.line generates a path from the array coordinates
let line = d3.line()
.x(function(d){
M0,0, L, 1,2..... This sample
return xScale(d.x)
})
.y(function(d){
return yScale(d.y)
})
.curve(d3.curveCardinal) // Curve effect
svg.selectAll('path.path')
.data(data)
.enter()
.append('path')
.attr('class'.'path')
.attr('d'.function(d){
return line(d)
})
.attr('stroke'.'#2e6be6')
.attr('fill'.'none')
.attr('transform'.`translate(${margin}.${margin}) `)}function drawCircle() {
data.forEach(item= > {
svg.append('g')
.selectAll('.circle')
.data(item)
.attr('class'.'circle')
.enter()
.append('circle')
.attr('cx'.function(d){return xScale(d.x)})
.attr('cy'.function(d){return yScale(d.y)})
.attr('r'.4)
.attr('transform'.`translate(${margin}.${margin}) `)
.attr('fill'.'#fff')
.attr('stroke'.'rgba(56, 8, 228, .5)')}); } (async function draw() {
await drawXAxis();
await drawYAxis();
await drawGrid();
await drawLine();
awaitdrawCircle(); }) ();</script>
Copy the code
Effect rendering (isn’t it much better) :
Summary: NewdrawCircle()
Draw a dot usingD3.line ().curve() Draws a curve
Step 4 (Get the wire moving)
How do I get wired animation to work?
For path animations using SVG’s stroke-Dashoffset and stroke-dasharray lines, delay is specified in batches for each point
Stroke-dasharray: used to draw dashed lines stroke-dasharray: Offset of dashed lines
So the question is, right? Can I draw a solid line with a dotted line? Of course you can animate it with this dotted line offset. In zhang Xinxu’s blog, I found an easy to understand explanation: In Chinese, a ham sausage is 12 cm long, and dotted lines should be drawn on it. The dotted lines are 15 cm apart. If there is no Dashoffset, the first 15 cm of ham sausage will be covered with chili sauce! It’s actually only 12 centimeters, so what we’re seeing is the whole ham sausage with chili sauce. Now, dashoffset is also 15cm, so the dotted line is shifted back 15cm. As a result, the chili sauce is spread on the ham sausage, which means there is no chili sauce at all. If you use the line SVG above, the line is invisible. When we reduce the Dashoffset value, we see that the chili sauce on the sausage appears little by little, as if it were applied from the root of the sausage.
Rendering effect:
Code implementation:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const height = 500, width = 500, margin = 25;
// Define our SVG canvas space container
let svg = d3.select('body')
.append('svg')
.attr('width',width)
.attr('height',height);
// To create a linear scale, use the axes required
const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);
// Draw a horizontal axis
function drawXAxis() {
// Create the x axis at the bottom
const xAxis = d3.axisBottom(xScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ height - margin }) `
}).call(xAxis);
}
// Draw a vertical axis
function drawYAxis() {
// Create the x axis at the bottom
const yAxis = d3.axisLeft(yScale);
// Insert the axes into SVG
svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
// Shift it to the bottom x pair, we need to draw the Y-axis
return `translate(${margin}.${ margin }) `
}).call(yAxis);
}
function drawGrid() {
// Draw the Y-axis line
d3.selectAll('.y-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
// Font-size: 16px! Important
.attr('x2',(height - margin * 2))
.attr('y2'.0)
.attr('stroke'.'#e4e4e4')
// Draw the X-axis line
d3.selectAll('.x-axis .tick')
.append('line')
.attr('x1'.0)
.attr('y1'.0)
.attr('x2'.0)
.attr('y2',(- height + margin * 2))
.attr('stroke'.'#e4e4e4')}// Data definition, two lines
const data = [
[
{x:0.y:6},
{x:1.y:5},
{x:2.y:3},
{x:3.y:5},
{x:4.y:5},
{x:6.y:4},
{x:7.y:3},
{x:8.y:3},
{x:9.y:2},
{x:10.y:10},
],
d3.range(10).map(function(i){
return {x:i,y:Math.min(i)}
})
]
function drawLine() {
//d3.line generates a path from the array coordinates
let line = d3.line()
.x(function(d){
M0,0, L, 1,2..... This sample
return xScale(d.x)
})
.y(function(d){
return yScale(d.y)
})
.curve(d3.curveCardinal) // Curve effect
svg.selectAll('path.path')
.data(data)
.enter()
.append('path')
.attr('class'.'path')
.attr('d'.function(d){
return line(d)
})
.attr('stroke'.'#2e6be6')
.attr('fill'.'none')
.attr('transform'.`translate(${margin}.${margin}) `)}function drawCircle() {
data.forEach(item= > {
svg.append('g')
.selectAll('.circle')
.data(item)
.enter()
.append('circle')
.attr('class'.'circle')
.attr('cx'.function(d){return xScale(d.x)})
.attr('cy'.function(d){return yScale(d.y)})
.attr('r'.4)
.attr('transform'.`translate(${margin}.${margin}) `)
.attr('fill'.'#fff')
.attr('stroke'.'rgba(56, 8, 228, .5)')
.style('stroke-width'.0);
});
}
function drawAnimations() {
// Line animation
svg.selectAll('path.path')
.attr('stroke'.'#2e6be6')
.attr('transform'.'translate (25, 25)')
.style('stroke-dasharray'.function(){
return d3.select(this).node().getTotalLength()
})
.style('stroke-dashoffset'.function(){
return d3.select(this).node().getTotalLength()
})
.transition()
.duration(2000)
.delay(200)
.ease(d3.easeLinear)
.style('stroke-dashoffset'.0);
/ / dot
svg.selectAll('.circle')
.style('stroke-width'.0)
.transition()
.duration(1000)
.delay(function(d,i){
return i * 100
})
.ease(d3.easeLinear)
.style('stroke-width'.1)} (async function draw() {
await drawXAxis();
await drawYAxis();
await drawGrid();
await drawLine();
await drawCircle();
awaitdrawAnimations(); }) ();</script>
Copy the code
Effect:
conclusion
Is the basic line chart already drawn? Tooltip, Legend….. Send it when I’m done with it.
conclusion
- Hi, I am Mihara and thank you for watching and I will work harder.
- Each method is typed out and verified, and can be copied if necessary.
- If you give help a thumbs-up 👍 is even better thank you ~~~~~
- We look forward to your attention