Initial Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
33
app.js
Normal file
33
app.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const express = require('express')
|
||||
const handlebars = require('express-handlebars')
|
||||
const path = require('path')
|
||||
const routes = require('./routes/index')
|
||||
|
||||
const port = 3000
|
||||
|
||||
const app = express()
|
||||
app.engine('.hbs', handlebars({defaultLayout: 'layout', extname: '.hbs'}))
|
||||
|
||||
app.set('views', path.join(__dirname, 'views'))
|
||||
app.set('view engine', '.hbs')
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public')))
|
||||
app.use('/', routes)
|
||||
|
||||
app.use((request, response, next) => {
|
||||
const err = new Error('Not Found')
|
||||
err.status = 404
|
||||
next(err)
|
||||
})
|
||||
|
||||
app.use((err, req, res, next) => {
|
||||
res.locals.message = err.message
|
||||
res.locals.error = req.app.get('env') === 'development' ? err : {}
|
||||
|
||||
res.status(err.status || 500)
|
||||
res.render('error')
|
||||
})
|
||||
|
||||
app.listen(port, () => console.log(`Listening on port : ${port}!`))
|
||||
|
||||
module.exports = app
|
||||
1153
package-lock.json
generated
Normal file
1153
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "d3",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"express-handlebars": "^5.2.1"
|
||||
}
|
||||
}
|
||||
20
public/css/area-chart.css
Normal file
20
public/css/area-chart.css
Normal file
@@ -0,0 +1,20 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(21, 22, 26);
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis path{
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis text{
|
||||
color: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
|
||||
19
public/css/basic-line-chart.css
Normal file
19
public/css/basic-line-chart.css
Normal file
@@ -0,0 +1,19 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis path{
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis text{
|
||||
color: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
|
||||
15
public/css/flower-chart.css
Normal file
15
public/css/flower-chart.css
Normal file
@@ -0,0 +1,15 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: hsl(201, 81%, 8%);
|
||||
}
|
||||
|
||||
.text {
|
||||
fill: white;
|
||||
font-family: Work Sans;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
text-anchor: middle;
|
||||
text-shadow: 2px 2px hsl(201, 81%, 8%);
|
||||
}
|
||||
|
||||
0
public/css/index.css
Normal file
0
public/css/index.css
Normal file
15
public/css/montly-bills.css
Normal file
15
public/css/montly-bills.css
Normal file
@@ -0,0 +1,15 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: hsl(200, 77%, 5%);
|
||||
}
|
||||
|
||||
.text {
|
||||
fill: white;
|
||||
font-family: Work Sans;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
text-anchor: middle;
|
||||
text-shadow: 2px 2px hsl(200, 77%, 5%);
|
||||
}
|
||||
|
||||
6
public/css/peace-sign.css
Normal file
6
public/css/peace-sign.css
Normal file
@@ -0,0 +1,6 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: hsl(84, 77%, 82%);
|
||||
}
|
||||
|
||||
26
public/css/planets.css
Normal file
26
public/css/planets.css
Normal file
@@ -0,0 +1,26 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(21, 22, 26);
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis path{
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis text{
|
||||
color: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
|
||||
.text{
|
||||
fill: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
26
public/css/scores.css
Normal file
26
public/css/scores.css
Normal file
@@ -0,0 +1,26 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(21, 22, 26);
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis path{
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis text{
|
||||
color: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
|
||||
.text{
|
||||
fill: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
26
public/css/time-chart.css
Normal file
26
public/css/time-chart.css
Normal file
@@ -0,0 +1,26 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(21, 22, 26);
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis path{
|
||||
stroke: #C1A1DF;
|
||||
}
|
||||
|
||||
.axis text {
|
||||
color: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
.title {
|
||||
fill: #C1A1DF;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
11
public/css/updated-circle.css
Normal file
11
public/css/updated-circle.css
Normal file
@@ -0,0 +1,11 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: hsl(35, 100%, 91%);
|
||||
}
|
||||
|
||||
.circle {
|
||||
fill: hsl(29, 100%, 50%);
|
||||
stroke: hsl(15, 78%, 26%);
|
||||
stroke-width: 10;
|
||||
}
|
||||
32
public/css/updating-bar-chart.css
Normal file
32
public/css/updating-bar-chart.css
Normal file
@@ -0,0 +1,32 @@
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: hsl(71, 59%, 89%);
|
||||
font-size: 16px;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: hsl(170, 18%, 13%);
|
||||
fill: hsl(170, 18%, 13%);
|
||||
}
|
||||
|
||||
.axis path {
|
||||
stroke: hsl(170, 18%, 13%);
|
||||
}
|
||||
|
||||
.axis-grid line {
|
||||
stroke: hsl(70, 60%, 96%);
|
||||
}
|
||||
|
||||
.axis text {
|
||||
color: hsl(170, 18%, 13%);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: hsl(170, 18%, 13%);
|
||||
font-size: 1.3rem;
|
||||
text-anchor: 'middle';
|
||||
}
|
||||
|
||||
21
public/css/updating-pie-chart.css
Normal file
21
public/css/updating-pie-chart.css
Normal file
@@ -0,0 +1,21 @@
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: #293241;
|
||||
|
||||
color: #e0fbfc;
|
||||
font-size: 16px;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.3rem;
|
||||
text-anchor: 'middle';
|
||||
}
|
||||
|
||||
.arc {
|
||||
stroke: #293241;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
32
public/css/user-updating-bar-chart.css
Normal file
32
public/css/user-updating-bar-chart.css
Normal file
@@ -0,0 +1,32 @@
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: hsl(71, 59%, 89%);
|
||||
font-size: 16px;
|
||||
font-family: Work Sans;
|
||||
}
|
||||
|
||||
.axis line {
|
||||
stroke: hsl(170, 18%, 13%);
|
||||
fill: hsl(170, 18%, 13%);
|
||||
}
|
||||
|
||||
.axis path {
|
||||
stroke: hsl(170, 18%, 13%);
|
||||
}
|
||||
|
||||
.axis-grid line {
|
||||
stroke: hsl(70, 60%, 96%);
|
||||
}
|
||||
|
||||
.axis text {
|
||||
color: hsl(170, 18%, 13%);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: hsl(170, 18%, 13%);
|
||||
font-size: 1.3rem;
|
||||
text-anchor: 'middle';
|
||||
}
|
||||
|
||||
6
public/data/bills.csv
Normal file
6
public/data/bills.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
type,cost_percent
|
||||
Auto,14.5
|
||||
Food,28
|
||||
Student Loan,17
|
||||
Rent,32.5
|
||||
Insurance,8
|
||||
|
36
public/data/planets.json
Normal file
36
public/data/planets.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"planetDiameters": [
|
||||
{
|
||||
"planet": "Mercury",
|
||||
"diameter": 4879
|
||||
},
|
||||
{
|
||||
"planet": "Venus",
|
||||
"diameter": 12104
|
||||
},
|
||||
{
|
||||
"planet": "Earth",
|
||||
"diameter": 12756
|
||||
},
|
||||
{
|
||||
"planet": "Mars",
|
||||
"diameter": 6792
|
||||
},
|
||||
{
|
||||
"planet": "Jupiter",
|
||||
"diameter": 142984
|
||||
},
|
||||
{
|
||||
"planet": "Saturn",
|
||||
"diameter": 120536
|
||||
},
|
||||
{
|
||||
"planet": "Uranus",
|
||||
"diameter": 51118
|
||||
},
|
||||
{
|
||||
"planet": "Neptune",
|
||||
"diameter": 49528
|
||||
}
|
||||
]
|
||||
}
|
||||
11
public/data/scorecard.csv
Normal file
11
public/data/scorecard.csv
Normal file
@@ -0,0 +1,11 @@
|
||||
player,points
|
||||
Steven,150
|
||||
Manisha,220
|
||||
Nicole,85
|
||||
Jaime,109
|
||||
Crystal,99
|
||||
Alexa,186
|
||||
Bethany,201
|
||||
Marie,197
|
||||
Seth,112
|
||||
Nick,215
|
||||
|
13
public/data/timeScaleData.csv
Normal file
13
public/data/timeScaleData.csv
Normal file
@@ -0,0 +1,13 @@
|
||||
date,value
|
||||
2019-00-20,1000
|
||||
2019-01-04,536
|
||||
2019-02-19,106
|
||||
2019-03-11,478
|
||||
2019-04-13,391
|
||||
2019-05-01,99
|
||||
2019-06-20,963
|
||||
2019-07-26,223
|
||||
2019-08-14,701
|
||||
2019-09-03,111
|
||||
2019-10-22,388
|
||||
2019-11-07,604
|
||||
|
40
public/js/animated-scaled-line.js
Normal file
40
public/js/animated-scaled-line.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = (window.innerHeight / 2) - margin.top - margin.bottom
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.style('background-color', 'rgb(255, 218, 241)')
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const data = Array(100).fill().map(() => d3.randomUniform(1)())
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, data.length-1])
|
||||
.range([0, width])
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data)])
|
||||
.range([height, 0])
|
||||
|
||||
const line = d3.line()
|
||||
.x((d, i) => xScale(i))
|
||||
.y((d, i) => yScale(d))
|
||||
.curve(d3.curveNatural)
|
||||
|
||||
const path = svg.append('path')
|
||||
.datum(data)
|
||||
.style('fill', 'none')
|
||||
.style('stroke', 'darkblue')
|
||||
.style('stroke-width', 1)
|
||||
.attr('d', line)
|
||||
|
||||
const totalLength = path.node().getTotalLength()
|
||||
path.attr('stroke-dasharray', `${totalLength} ${totalLength}`)
|
||||
.attr('stroke-dashoffset', totalLength)
|
||||
.transition().duration(5000).ease(d3.easeQuad)
|
||||
.attr('stroke-dashoffset', 0)
|
||||
|
||||
70
public/js/area-chart.js
Normal file
70
public/js/area-chart.js
Normal file
@@ -0,0 +1,70 @@
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
const data = Array(11).fill().map(() => d3.randomUniform(100)())
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, data.length-1])
|
||||
.range([0, width])
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data)])
|
||||
.range([height, 0])
|
||||
|
||||
const area = d3.area()
|
||||
.x((d, i) => xScale(i))
|
||||
.y0(yScale(0))
|
||||
.y1((d, i) => yScale(d))
|
||||
|
||||
const xAxis = svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.call(d3.axisBottom(xScale))
|
||||
|
||||
const yAxis = svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(d3.axisLeft(yScale))
|
||||
|
||||
const path = svg.append('path')
|
||||
.datum(data)
|
||||
.attr('class', 'data-line')
|
||||
.style('stroke', 'white')
|
||||
.style('stroke-width', 2)
|
||||
.style('fill', 'white')
|
||||
.style('fill-opacity', 0.15)
|
||||
.attr('d', area)
|
||||
|
||||
const circles = svg.selectAll('.circle')
|
||||
.data(data).enter().append('circle')
|
||||
.attr('class', 'circle')
|
||||
.attr('cx', (d, i) => xScale(i))
|
||||
.attr('cy', -300)
|
||||
.attr('r', 8)
|
||||
.style('fill', 'white')
|
||||
.style('stroke', 'rgb(51, 57, 68)')
|
||||
.style('stroke-width', 3)
|
||||
|
||||
circles.transition()
|
||||
.duration(1000)
|
||||
.delay((d, i) => i * 80)
|
||||
.attr('cy', (d, i) => yScale(d))
|
||||
|
||||
|
||||
circles.on('mouseover', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', 14)
|
||||
})
|
||||
|
||||
circles.on('mouseout', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', 8)
|
||||
})
|
||||
63
public/js/basic-line-chart.js
Normal file
63
public/js/basic-line-chart.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
const data = Array(11).fill().map(() => d3.randomUniform(100)())
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.style('background-color', 'rgb(51, 57, 68)')
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, data.length-1])
|
||||
.range([0, width])
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data)])
|
||||
.range([height, 0])
|
||||
|
||||
const line = d3.line()
|
||||
.x((d, i) => xScale(i))
|
||||
.y((d, i) => yScale(d))
|
||||
.curve(d3.curveCatmullRom)
|
||||
|
||||
const xAxis = svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.call(d3.axisBottom(xScale))
|
||||
|
||||
const yAxis = svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(d3.axisLeft(yScale))
|
||||
|
||||
const path = svg.append('path')
|
||||
.datum(data)
|
||||
.style('fill', 'none')
|
||||
.style('stroke', 'white')
|
||||
.style('stroke-width', 2)
|
||||
.attr('d', line)
|
||||
|
||||
const circles = svg.selectAll('.circle')
|
||||
.data(data).enter().append('circle')
|
||||
.attr('class', 'circle')
|
||||
.attr('cx', (d, i) => xScale(i))
|
||||
.attr('cy', (d, i) => yScale(d))
|
||||
.attr('r', '5')
|
||||
.style('fill', 'white')
|
||||
.style('stroke', 'rgb(51, 57, 68)')
|
||||
.style('stroke-width', 3)
|
||||
|
||||
circles.on('mouseover', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', '10')
|
||||
})
|
||||
|
||||
circles.on('mouseout', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', '5')
|
||||
})
|
||||
29
public/js/confetti.js
Normal file
29
public/js/confetti.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
|
||||
const svg = d3.select('body').style('margin', 0)
|
||||
.append('svg')
|
||||
.style('width', width)
|
||||
.style('height', height)
|
||||
//.style('background', 'darkblue')
|
||||
|
||||
const data = Array(3000).fill().map(_ => {
|
||||
return {
|
||||
cx: Math.round(Math.random() * width),
|
||||
cy: Math.round(Math.random() * height)
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
const color = d3.scaleOrdinal(d3.schemePastel1)
|
||||
|
||||
const circle = svg.selectAll('circle')
|
||||
.data(data).enter()
|
||||
.append('circle')
|
||||
.attr('cx', d => d.cx)
|
||||
.attr('cy', d => d.cy)
|
||||
.attr('r', (d, i) => i % 2 == 0 ? 10 : 5)
|
||||
.style('stroke', (d, i) => color(i))
|
||||
.style('stroke-width', 2)
|
||||
.style('fill', 'none')
|
||||
|
||||
52
public/js/flower-chart.js
Normal file
52
public/js/flower-chart.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const data = [12, 6, 15, 4, 28, 5, 14, 4, 7, 5]
|
||||
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight - 200
|
||||
const radius = Math.min(width, height) * .50
|
||||
const colorScale = d3.scaleOrdinal(d3.schemeSet3)
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height)
|
||||
.attr('width', width)
|
||||
.append('g').attr('transform', `translate(${width / 2}, ${height / 2})`)
|
||||
|
||||
const pie = d3.pie().value(d => d).sort(null)
|
||||
|
||||
const zeroArc = d3.arc().outerRadius(1).innerRadius(0).cornerRadius(1)
|
||||
const arc = d3.arc().outerRadius(radius).innerRadius(0).cornerRadius(radius)
|
||||
const hoverArc = d3.arc().outerRadius(radius + 30).innerRadius(0).cornerRadius(radius)
|
||||
const labelArc = d3.arc().outerRadius(radius * 1.7).innerRadius(0)
|
||||
|
||||
const g = svg.selectAll('.arc')
|
||||
.data(pie(data))
|
||||
.enter().append('g').attr('class', 'arc')
|
||||
|
||||
g.append('path')
|
||||
.attr('d', zeroArc)
|
||||
.attr('class', 'arc')
|
||||
.style('fill', (d, i) => colorScale(i))
|
||||
.style('fill-opacity', .7)
|
||||
.style('stroke', 'hsl(201, 81%, 8%)')
|
||||
.style('stroke-width', 4)
|
||||
.on('mouseover', function(d, i) {
|
||||
d3.select(this)
|
||||
.style('fill-opacity', 1)
|
||||
.transition().duration(250)
|
||||
.attr('d', hoverArc)
|
||||
})
|
||||
.on('mouseout', function(d, i) {
|
||||
d3.select(this)
|
||||
.style('fill-opacity', .7)
|
||||
.transition().duration(250)
|
||||
.attr('d', arc)
|
||||
})
|
||||
.transition().duration(500).delay((d, i) => i * 100)
|
||||
.attr('d', arc)
|
||||
|
||||
g.append('text')
|
||||
.attr('transform', d => `translate(${labelArc.centroid(d)})`)
|
||||
.text(d => `${d.data}%`)
|
||||
.attr('class', 'text')
|
||||
.attr('fill-opacity', 0)
|
||||
.transition().duration(500).delay((d, i) => i * 100)
|
||||
.attr('fill-opacity', 1)
|
||||
0
public/js/index.js
Normal file
0
public/js/index.js
Normal file
52
public/js/montly-bills.js
Normal file
52
public/js/montly-bills.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const data = d3.csv('/data/bills.csv').then(rawData => {
|
||||
const data = rawData.map(d => {
|
||||
return {
|
||||
type: d.type,
|
||||
cost_percent: +d.cost_percent
|
||||
}
|
||||
})
|
||||
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
|
||||
const radius = Math.min(width, height) / 2
|
||||
const colorScale = d3.scaleOrdinal(['#7326AB', '#2A59A9', '#E5A1D4', '#00A0B0', '#1C9FE9'])
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height)
|
||||
.attr('width', width)
|
||||
.append('g').attr('transform', `translate(${width / 2}, ${height / 2})`)
|
||||
|
||||
const pie = d3.pie().value(d => d.cost_percent).sort(null)
|
||||
const arc = d3.arc().outerRadius(radius * .75).innerRadius(0)
|
||||
const hoverArc = d3.arc().outerRadius(radius * .85).innerRadius(0)
|
||||
|
||||
const g = svg.selectAll('.arc')
|
||||
.data(pie(data))
|
||||
.enter().append('g').attr('class', 'arc')
|
||||
|
||||
g.append('path')
|
||||
.attr('d', arc)
|
||||
.attr('class', 'arc')
|
||||
.style('fill', (d, i) => colorScale(i))
|
||||
.style('fill-opacity', 0.8)
|
||||
.style('stroke', 'hsl(200, 77%, 5%)')
|
||||
.style('stroke-width', 4)
|
||||
.on('mouseover', function(d, i) {
|
||||
d3.select(this)
|
||||
.style('fill-opacity', 1)
|
||||
.transition().duration(500)
|
||||
.attr('d', hoverArc)
|
||||
})
|
||||
.on('mouseout', function(d, i) {
|
||||
d3.select(this)
|
||||
.style('fill-opacity', .8)
|
||||
.transition().duration(500)
|
||||
.attr('d', arc)
|
||||
})
|
||||
|
||||
g.append('text')
|
||||
.attr('transform', d => `translate(${arc.centroid(d)})`)
|
||||
.text(d => `${d.data.type} ${d.data.cost_percent}%`)
|
||||
.attr('class', 'text')
|
||||
})
|
||||
15
public/js/one-box.js
Normal file
15
public/js/one-box.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const svg = d3.select('body')
|
||||
.attr('margin', 0)
|
||||
.append('svg')
|
||||
.style('width', window.innerWidth)
|
||||
.style('height', window.innerHeight)
|
||||
.style('background', 'darkblue')
|
||||
|
||||
svg.append('rect')
|
||||
.attr('x', (window.innerWidth / 2) - 100)
|
||||
.attr('y', (window.innerHeight / 2) - 150)
|
||||
.attr('width', 100)
|
||||
.attr('height', 150)
|
||||
.style('fill', 'white')
|
||||
.style('stroke', 'yellow')
|
||||
.style('stroke-width', 5)
|
||||
32
public/js/one-circle.js
Normal file
32
public/js/one-circle.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const width = 1000
|
||||
const height = 700
|
||||
|
||||
const svg = d3.select('body')
|
||||
.attr('margin', 0)
|
||||
.append('svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
|
||||
const circle = svg.append('circle')
|
||||
.attr('cx', width / 2)
|
||||
.attr('cy', height / 2)
|
||||
.attr('r', 100)
|
||||
.style('fill', 'purple')
|
||||
|
||||
circle.on('click', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(1000).ease(d3.easeQuad)
|
||||
.attr('r', 200)
|
||||
})
|
||||
|
||||
circle.on('mouseover', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(1000).ease(d3.easeQuad)
|
||||
.style('fill', 'red')
|
||||
})
|
||||
|
||||
circle.on('mouseout', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(1000).ease(d3.easeQuad)
|
||||
.style('fill', 'purple')
|
||||
})
|
||||
25
public/js/one-line.js
Normal file
25
public/js/one-line.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
|
||||
const svg = d3.select('body')
|
||||
.attr('margin', 0)
|
||||
.append('svg')
|
||||
|
||||
svg
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.style('background-color', '#8AF2F7')
|
||||
|
||||
const coordinates = [
|
||||
{ x: width / 4, y: height / 2 },
|
||||
{ x: (width / 4) * 3, y: height / 2 }
|
||||
]
|
||||
|
||||
const line = d3.line().x(d => d.x).y(d => d.y)
|
||||
|
||||
const path = svg.append('path')
|
||||
.datum(coordinates)
|
||||
.style('fill', 'none')
|
||||
.style('stroke', '#0e0e0e')
|
||||
.style('stroke-width', '5')
|
||||
.attr('d', line)
|
||||
27
public/js/peace-sign.js
Normal file
27
public/js/peace-sign.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const data = [35, 15, 15, 35]
|
||||
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
|
||||
const radius = Math.min(width, height) / 2
|
||||
const colorScale = d3.scaleOrdinal(['#7326AB', '#2A59A9', '#E5A1D4', '#00A0B0'])
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height)
|
||||
.attr('width', width)
|
||||
.append('g').attr('transform', `translate(${width / 2}, ${height / 2})`)
|
||||
|
||||
const pie = d3.pie().value(d => d).sort(null)
|
||||
const arc = d3.arc().outerRadius(radius * .75).innerRadius(0)
|
||||
|
||||
const g = svg.selectAll('.arc')
|
||||
.data(pie(data))
|
||||
.enter().append('g').attr('class', 'arc')
|
||||
|
||||
g.append('path')
|
||||
.attr('d', arc)
|
||||
.attr('class', 'arc')
|
||||
.style('fill', (d, i) => colorScale(i))
|
||||
.style('stroke', 'hsl(84, 77%, 82%)')
|
||||
.style('stroke-width', 4)
|
||||
|
||||
98
public/js/planets.js
Normal file
98
public/js/planets.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const data = d3.json('/data/planets.json').then(data => {
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
|
||||
const planets = data.planetDiameters
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const xScale = d3.scaleBand()
|
||||
.domain(planets.map(d => d.planet))
|
||||
.range([0, width])
|
||||
.padding(0.1)
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(planets.map(d => d.diameter))])
|
||||
.rangeRound([height, 0])
|
||||
|
||||
const xAxis = svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.call(d3.axisBottom(xScale))
|
||||
.append('text')
|
||||
.attr('class', 'text')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', 30)
|
||||
.style('text-anchor', 'middle')
|
||||
.text('Planets')
|
||||
|
||||
const yAxis = svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(d3.axisLeft(yScale))
|
||||
.append('text').attr('class', 'text')
|
||||
.style('text-anchor', 'end')
|
||||
.attr('class', 'text')
|
||||
.attr('y', 6)
|
||||
.attr('dy', '0.75em')
|
||||
.attr('transform', 'rotate(-90)')
|
||||
.text('Diameter (km)')
|
||||
|
||||
const bars = svg.selectAll('.bar')
|
||||
.data(planets)
|
||||
.enter().append('rect')
|
||||
.attr('class', 'bar')
|
||||
.style('fill', 'white')
|
||||
.style('fill-opacity', .2)
|
||||
.style('stroke', 'white')
|
||||
.style('stroke-width', 2)
|
||||
|
||||
bars.on('mouseover', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.style('fill-opacity', 1)
|
||||
})
|
||||
|
||||
bars.on('mouseout', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.style('fill-opacity', .2)
|
||||
})
|
||||
|
||||
bars.attr('x', d => xScale(d.planet))
|
||||
.attr('y', height)
|
||||
.attr('width', xScale.bandwidth())
|
||||
.transition().duration(250).delay((d, i) => i * 200)
|
||||
.attr('y', d => yScale(d.diameter))
|
||||
.attr('height', d => height - yScale(d.diameter))
|
||||
|
||||
const formatter = d3.format(',')
|
||||
|
||||
const barText = svg.selectAll('.diameters')
|
||||
.data(planets).enter().append('text')
|
||||
.attr('class', 'diameters text')
|
||||
.attr('x', d => xScale(d.planet))
|
||||
.attr('dx', d => xScale.bandwidth() / 2)
|
||||
.attr('y', d => yScale(d.diameter))
|
||||
.attr('dy', "-0.75em")
|
||||
.style('fill', 'white')
|
||||
.style('text-anchor', 'middle')
|
||||
.style('opacity', 0)
|
||||
.text(d => formatter(d.diameter))
|
||||
.transition().duration(500).delay((d, i) => i * 200)
|
||||
.style('opacity', 1)
|
||||
|
||||
const title = svg.append('text')
|
||||
.attr('class', 'text')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', -100)
|
||||
.style('text-anchor', 'middle')
|
||||
.style('text-decoration', 'underline')
|
||||
.style('fill', 'white')
|
||||
.text('Planet diameters')
|
||||
})
|
||||
32
public/js/scaled-line.js
Normal file
32
public/js/scaled-line.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const data = Array(25).fill().map(() => d3.randomUniform(1)())
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, data.length-1])
|
||||
.range([0, width])
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain(d3.extent(data))
|
||||
.range([0, height])
|
||||
|
||||
const line = d3.line()
|
||||
.x((d, i) => xScale(i))
|
||||
.y((d, i) => yScale(d))
|
||||
.curve(d3.curveNatural)
|
||||
|
||||
svg.append('path')
|
||||
.datum(data)
|
||||
.style('fill', 'none')
|
||||
.style('stroke', 'darkblue')
|
||||
.style('stroke-width', 1)
|
||||
.attr('d', line)
|
||||
100
public/js/scores.js
Normal file
100
public/js/scores.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const data = d3.csv('/data/scorecard.csv').then(rawData => {
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
|
||||
const data = rawData.map(d => {
|
||||
return {
|
||||
player: d.player,
|
||||
points: +d.points
|
||||
}
|
||||
})
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data.map(d => d.points))])
|
||||
.rangeRound([0, width])
|
||||
|
||||
const yScale = d3.scaleBand()
|
||||
.domain(data.map(d => d.player))
|
||||
.range([height, 0])
|
||||
.padding(0.1)
|
||||
|
||||
const xAxis = svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.call(d3.axisBottom(xScale))
|
||||
.append('text')
|
||||
.attr('class', 'text')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', 30)
|
||||
.attr('dy', '.75em')
|
||||
.style('text-anchor', 'middle')
|
||||
.text('Points')
|
||||
|
||||
const yAxis = svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(d3.axisLeft(yScale))
|
||||
.append('text').attr('class', 'text')
|
||||
.style('text-anchor', 'end')
|
||||
.attr('class', 'text')
|
||||
.attr('y', -20)
|
||||
.text('Players')
|
||||
|
||||
const bars = svg.selectAll('.bar')
|
||||
.data(data)
|
||||
.enter().append('rect')
|
||||
.attr('class', 'bar')
|
||||
.style('fill', 'white')
|
||||
.style('fill-opacity', .2)
|
||||
.style('stroke', 'white')
|
||||
.style('stroke-width', 2)
|
||||
|
||||
bars.on('mouseover', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.style('fill-opacity', .75)
|
||||
})
|
||||
|
||||
bars.on('mouseout', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.style('fill-opacity', .2)
|
||||
})
|
||||
|
||||
bars
|
||||
.attr('x', 0)
|
||||
.attr('y', d => yScale(d.player))
|
||||
.attr('height', yScale.bandwidth())
|
||||
.transition().duration(250).delay((d, i) => i * 100)
|
||||
.attr('width', d => xScale(d.points))
|
||||
|
||||
const barText = svg.selectAll('.points')
|
||||
.data(data).enter().append('text')
|
||||
.attr('class', 'points text')
|
||||
.attr('x', d => xScale(d.points))
|
||||
.attr('dx', -30)
|
||||
.attr('y', d => yScale(d.player))
|
||||
.attr('dy', yScale.bandwidth() / 2 + 5)
|
||||
.text(d => d.points)
|
||||
.style('fill', 'white')
|
||||
.style('text-anchor', 'middle')
|
||||
.style('opacity', 0)
|
||||
.transition().duration(250).delay((d, i) => i * 100)
|
||||
.style('opacity', 1)
|
||||
|
||||
const title = svg.append('text')
|
||||
.attr('class', 'text')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', -100)
|
||||
.style('text-anchor', 'middle')
|
||||
.style('text-decoration', 'underline')
|
||||
.style('fill', 'white')
|
||||
.text('Game 1 Final Scores')
|
||||
})
|
||||
57
public/js/stacked-circles.js
Normal file
57
public/js/stacked-circles.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const width = 1000
|
||||
const height = 700
|
||||
|
||||
const svg = d3.select('body').style('margin', 0)
|
||||
.append('svg')
|
||||
.style('width', width)
|
||||
.style('height', height)
|
||||
|
||||
const data = Array(1000).fill().map(_ => {
|
||||
return {
|
||||
cx: Math.round(Math.random() * width),
|
||||
cy: Math.round(Math.random() * height)
|
||||
}
|
||||
});
|
||||
|
||||
const color = d3.scaleOrdinal(d3.schemeSet3)
|
||||
|
||||
const circles_1 = svg.selectAll('.circle_1')
|
||||
.data(data).enter()
|
||||
.append('circle')
|
||||
.attr('class', '.circle_1')
|
||||
.attr('cx', d => d.cx)
|
||||
.attr('cy', -10)
|
||||
.style('fill', 'none')
|
||||
.attr('r', 10)
|
||||
|
||||
circles_1.transition().duration(1000).delay((d, i) => i).ease(d3.easeElastic)
|
||||
.attr('cy', d => d.cy)
|
||||
.style('fill', (d, i) => color(i))
|
||||
|
||||
const circles_2 = svg.selectAll('.circle_2')
|
||||
.data(data).enter()
|
||||
.append('circle')
|
||||
.attr('class', '.circle_2')
|
||||
.attr('cx', d => d.cx)
|
||||
.attr('cy', -10)
|
||||
.style('stroke', 'none')
|
||||
.attr('r', 20)
|
||||
.style('fill', 'none')
|
||||
.style('stroke-width', 2)
|
||||
|
||||
circles_2.transition().duration(1000).delay((d, i) => i).ease(d3.easeElastic)
|
||||
.attr('cy', d => d.cy)
|
||||
.style('stroke', (d, i) => color(i))
|
||||
|
||||
|
||||
circles_1.on('click', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(1000)
|
||||
.style('fill', 'red')
|
||||
})
|
||||
|
||||
circles_2.on('click', function(d, i) {
|
||||
d3.select(this)
|
||||
.transition().duration(1000)
|
||||
.style('stroke', 'red')
|
||||
})
|
||||
86
public/js/time-chart.js
Normal file
86
public/js/time-chart.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const data = d3.csv('/data/timeScaleData.csv').then(data => {
|
||||
const margin = { top: 200, right: 200, bottom: 200, left: 200 }
|
||||
const width = window.innerWidth - margin.right - margin.left
|
||||
const height = window.innerHeight - margin.top - margin.bottom
|
||||
|
||||
const parseDate = d3.timeParse('%Y-%m-%d')
|
||||
const formatedData = data.map(d => { return {
|
||||
date: parseDate(d.date),
|
||||
value: +d.value
|
||||
}});
|
||||
|
||||
const div = d3.select('body')
|
||||
|
||||
const svg = div.append('svg')
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.append('g').attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const xScale = d3.scaleTime()
|
||||
.domain(d3.extent(formatedData.map(d => d.date)))
|
||||
.range([0, width])
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(formatedData.map(d => d.value))])
|
||||
.range([height, 0])
|
||||
|
||||
const xAxis = svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.call(d3.axisBottom(xScale))
|
||||
|
||||
const yAxis = svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(d3.axisLeft(yScale))
|
||||
.append('text')
|
||||
.attr('x', 0)
|
||||
.attr('y', -25)
|
||||
.text('Orders')
|
||||
|
||||
const title = svg.append('text')
|
||||
.attr('class', 'title')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', -25)
|
||||
.text('Orders in 2019')
|
||||
|
||||
const line = d3.line()
|
||||
.x(d => xScale(d.date))
|
||||
.y(d => yScale(d.value))
|
||||
.curve(d3.curveCardinal)
|
||||
|
||||
svg.append('path')
|
||||
.datum(formatedData)
|
||||
.attr('class', 'line')
|
||||
.attr('d', line)
|
||||
.style('stroke', 'white')
|
||||
.style('fill', 'none')
|
||||
.style('stroke-width', 2)
|
||||
|
||||
const circles = svg.selectAll('.circle')
|
||||
.data(formatedData).enter().append('circle')
|
||||
.attr('class', 'circle')
|
||||
.attr('cx', d => xScale(d.date))
|
||||
.attr('cy', d => -400)
|
||||
.attr('r', '5')
|
||||
.style('fill', 'white')
|
||||
.style('stroke', 'rgb(51, 57, 68)')
|
||||
.style('stroke-width', 3)
|
||||
|
||||
circles.transition()
|
||||
.duration(1000)
|
||||
.delay((d, i) => xScale(d.date))
|
||||
.attr('cy', (d, i) => yScale(d.value))
|
||||
|
||||
circles.on('mouseover', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', '10')
|
||||
})
|
||||
|
||||
circles.on('mouseout', function(d) {
|
||||
d3.select(this)
|
||||
.transition().duration(500)
|
||||
.attr('r', '5')
|
||||
})
|
||||
})
|
||||
|
||||
33
public/js/updated-circle.js
Normal file
33
public/js/updated-circle.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight - 200
|
||||
const radius = Math.min(width, height) * .50
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height)
|
||||
.attr('width', width)
|
||||
.append('g')
|
||||
|
||||
const update = (data) => {
|
||||
const circle = svg.selectAll('.circle').data(data)
|
||||
|
||||
circle.enter().append('circle')
|
||||
.merge(circle)
|
||||
.attr('class', 'circle')
|
||||
.attr('cx', (d, i) => (i + 1) * 350)
|
||||
.attr('cy', height / 2)
|
||||
.transition().duration(600)
|
||||
.attr('r', d => d)
|
||||
|
||||
circle.exit().remove()
|
||||
}
|
||||
|
||||
d3.interval(() => {
|
||||
update([
|
||||
d3.randomUniform(50, 300)(),
|
||||
d3.randomUniform(50, 300)(),
|
||||
d3.randomUniform(50, 300)(),
|
||||
d3.randomUniform(50, 300)()
|
||||
])
|
||||
}, 600)
|
||||
|
||||
|
||||
73
public/js/updating-bar-chart.js
Normal file
73
public/js/updating-bar-chart.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const margin = { top: 100, right: 100, bottom: 100, left: 100 }
|
||||
const width = window.innerWidth - margin.left - margin.right
|
||||
const height = window.innerHeight - margin.bottom - margin.top
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height + margin.left + margin.right)
|
||||
.attr('width', width + margin.bottom + margin.top)
|
||||
.append('g')
|
||||
.attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const stores = ['Walmart', 'Sams Club', 'Target', 'Costco', 'BJs']
|
||||
const getData = () => stores.map((store) => {
|
||||
return {
|
||||
store: stores[Math.floor(Math.random() * stores.length)],
|
||||
profit: Math.round(d3.randomUniform(100000000)())
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const colorScale = d3.scaleOrdinal().domain(stores).range(d3.schemePastel2)
|
||||
const xScale = d3.scaleBand().rangeRound([0, width]).padding(.1)
|
||||
const yScale = d3.scaleLinear().range([height, 0])
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
const yAxis = d3.axisLeft(yScale)
|
||||
|
||||
svg.append('g').attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.append('text').attr('class', 'title')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', 50)
|
||||
.text('Stores')
|
||||
|
||||
svg.append('g').attr('class', 'y axis')
|
||||
.append('text').attr('class', 'title')
|
||||
.attr('x', 0)
|
||||
.attr('y', -20)
|
||||
.text('Profit (USD)')
|
||||
|
||||
const update = (data) => {
|
||||
xScale.domain(data.map(d => d.store))
|
||||
yScale.domain([0, d3.max(data.map(d => d.profit))])
|
||||
|
||||
svg.select('.x.axis')
|
||||
.transition().duration(1000)
|
||||
.call(xAxis)
|
||||
|
||||
svg.select('.y.axis')
|
||||
.transition().duration(1000)
|
||||
.call(yAxis)
|
||||
|
||||
const bar = svg.selectAll('.bar').data(data)
|
||||
|
||||
bar.enter().append('rect')
|
||||
.merge(bar).attr('class', 'bar')
|
||||
|
||||
.attr('x', d => xScale(d.store))
|
||||
.attr('y', d => yScale(0))
|
||||
|
||||
.attr('width', xScale.bandwidth())
|
||||
.attr('height', 0)
|
||||
|
||||
.transition().duration(500)
|
||||
|
||||
.attr('y', d => yScale(d.profit))
|
||||
.attr('height', d => height - yScale(d.profit))
|
||||
|
||||
.attr('fill', d => colorScale(d.store))
|
||||
|
||||
bar.exit().remove()
|
||||
}
|
||||
|
||||
update(getData())
|
||||
d3.interval(() => update(getData()), 5000)
|
||||
49
public/js/updating-pie-chart.js
Normal file
49
public/js/updating-pie-chart.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const width = 800
|
||||
const height = 600
|
||||
|
||||
const radius = Math.min(width, height) / 2
|
||||
const colorScale = d3.scaleOrdinal(['#9b5de5', '#f15bb5', '#fee440', '#00bbf9', '#00f5d4'])
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height)
|
||||
.attr('width', width)
|
||||
.append('g').attr('transform', `translate(${width / 2}, ${height / 2})`)
|
||||
|
||||
const pie = d3.pie().value(d => d).sort(null)
|
||||
const arc = d3.arc().outerRadius(radius * .75).innerRadius(0)
|
||||
|
||||
const data = [
|
||||
[2.380952380952381+ 16.666666666666664, 5.714285714285714, 8.095238095238095, 36.666666666666664, 30.476190476190478],
|
||||
[6.451612903225806+ 14.336917562724013, 11.469534050179211, 32.97491039426524, 21.863799283154123, 12.903225806451612],
|
||||
[5.405405405405405+ 13.127413127413126, 25.482625482625483, 15.444015444015443, 31.27413127413127, 9.266409266409266],
|
||||
[14.24802110817942+ 19.788918205804748, 16.62269129287599, 17.41424802110818, 12.66490765171504, 19.261213720316622],
|
||||
[12.558139534883722+ 10.930232558139535, 10.0, 22.790697674418606, 22.55813953488372, 21.16279069767442],
|
||||
[18.663594470046082+ 22.350230414746544, 23.04147465437788, 9.67741935483871, 17.972350230414747, 8.294930875576037],
|
||||
[21.38364779874214+ 21.38364779874214, 5.031446540880504, 30.81761006289308, 13.836477987421384, 7.547169811320755],
|
||||
[34.78260869565217+ 9.565217391304348, 38.69565217391304, 0.43478260869565216, 6.086956521739131, 10.434782608695652]
|
||||
]
|
||||
|
||||
function arcTween(a) {
|
||||
const i = d3.interpolate(this._current, a)
|
||||
this._current = i(1)
|
||||
return t => arc(i(t))
|
||||
}
|
||||
|
||||
const update = data => {
|
||||
const path = svg.selectAll('path').data(pie(data))
|
||||
path.transition().duration(700).attrTween('d', arcTween)
|
||||
|
||||
path.enter().append('path')
|
||||
.attr('class', 'arc')
|
||||
.attr('d', arc)
|
||||
.each(function(d) { this._current = d })
|
||||
.style('fill', (d, i) => colorScale(i))
|
||||
}
|
||||
|
||||
update(data[0])
|
||||
|
||||
let i = 1
|
||||
d3.interval(() => {
|
||||
update(data[i++])
|
||||
i %= data.length
|
||||
}, 1000)
|
||||
105
public/js/user-updating-bar-chart.js
Normal file
105
public/js/user-updating-bar-chart.js
Normal file
@@ -0,0 +1,105 @@
|
||||
const margin = { top: 100, right: 100, bottom: 100, left: 100 }
|
||||
const width = window.innerWidth - margin.left - margin.right
|
||||
const height = window.innerHeight - margin.bottom - margin.top
|
||||
|
||||
const svg = d3.select('body').append('svg')
|
||||
.attr('height', height + margin.left + margin.right)
|
||||
.attr('width', width + margin.bottom + margin.top)
|
||||
.append('g')
|
||||
.attr('transform', `translate(${margin.left}, ${margin.bottom})`)
|
||||
|
||||
const stores = ['Walmart', 'Sams Club', 'Target', 'Costco', 'BJs']
|
||||
const years = ['2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021']
|
||||
|
||||
const getData = () => {
|
||||
return new Array(5000).fill().map(_ => {
|
||||
return {
|
||||
store: stores[Math.floor(Math.random() * stores.length)],
|
||||
profit: Math.round(d3.randomUniform(100000000)()),
|
||||
year: years[Math.floor(Math.random() * years.length)],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const filterDataByYear = data => year => data.filter(d => d.year === year)
|
||||
|
||||
const formatData = data => {
|
||||
const obj = data.reduce((acc, d) => {
|
||||
|
||||
if(!acc[d.store]) acc[d.store] = { profit: 0, year: d.year, store: d.store }
|
||||
acc[d.store].profit += d.profit
|
||||
|
||||
return acc
|
||||
|
||||
}, {})
|
||||
|
||||
return Object.values(obj)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const colorScale = d3.scaleOrdinal().domain(stores).range(d3.schemeCategory10)
|
||||
const xScale = d3.scaleBand().rangeRound([0, width]).padding(.1)
|
||||
const yScale = d3.scaleLinear().range([height, 0])
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
const yAxis = d3.axisLeft(yScale)
|
||||
|
||||
svg.append('g').attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${height})`)
|
||||
.append('text').attr('class', 'title')
|
||||
.attr('x', width / 2)
|
||||
.attr('y', 50)
|
||||
.text('Stores')
|
||||
|
||||
svg.append('g').attr('class', 'y axis')
|
||||
.append('text').attr('class', 'title')
|
||||
.attr('x', 0)
|
||||
.attr('y', -20)
|
||||
.text('Profit (USD)')
|
||||
|
||||
const update = (data) => {
|
||||
xScale.domain(data.map(d => d.store))
|
||||
yScale.domain([0, d3.max(data.map(d => d.profit))])
|
||||
|
||||
svg.select('.x.axis')
|
||||
.transition().duration(1000)
|
||||
.call(xAxis)
|
||||
|
||||
svg.select('.y.axis')
|
||||
.transition().duration(1000)
|
||||
.call(yAxis)
|
||||
|
||||
const bar = svg.selectAll('.bar').data(data)
|
||||
|
||||
bar.enter().append('rect')
|
||||
.merge(bar).attr('class', 'bar')
|
||||
.attr('x', d => xScale(d.store))
|
||||
.attr('y', d => yScale(0))
|
||||
.attr('width', xScale.bandwidth())
|
||||
.attr('height', 0)
|
||||
.transition().duration(500)
|
||||
.attr('y', d => yScale(d.profit))
|
||||
.attr('height', d => height - yScale(d.profit))
|
||||
.attr('fill', d => colorScale(d.store))
|
||||
|
||||
bar.exit().remove()
|
||||
}
|
||||
|
||||
const select = d3.select('body')
|
||||
.append('select').attr('class', 'select')
|
||||
|
||||
const options = select.selectAll('option')
|
||||
.data(years).enter()
|
||||
.append('option').attr('class', 'option')
|
||||
.text(d => d)
|
||||
|
||||
const dataset = getData()
|
||||
const originalData = formatData(filterDataByYear(dataset)('2010'))
|
||||
update(originalData)
|
||||
|
||||
select.on('change', function(d, i) {
|
||||
const s = d3.select(this).node()
|
||||
const year = s.options[s.selectedIndex].textContent
|
||||
const updatedData = formatData(filterDataByYear(dataset)(year))
|
||||
update(updatedData)
|
||||
})
|
||||
16
routes/index.js
Normal file
16
routes/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const express = require('express')
|
||||
const pages = require('./pages')
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
pages.map(page => {
|
||||
router.get(page.location, (request, response, next) => {
|
||||
const p = page.page ? page.page : 'viz'
|
||||
response.render(p, {script : `/js/${page.file}.js`,
|
||||
style : `/css/${page.file}.css`})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
module.exports = router
|
||||
24
routes/pages.js
Normal file
24
routes/pages.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const pages = [
|
||||
{location: '/', file: 'index', page: 'index'},
|
||||
{location: '/one-circle', file: 'one-circle'},
|
||||
{location: '/one-line', file: 'one-line'},
|
||||
{location: '/one-box', file: 'one-box'},
|
||||
{location: '/confetti', file: 'confetti'},
|
||||
{location: '/stacked-circles', file: 'stacked-circles'},
|
||||
{location: '/scaled-line', file: 'scaled-line'},
|
||||
{location: '/animated-scaled-line', file: 'animated-scaled-line'},
|
||||
{location: '/basic-line-chart', file: 'basic-line-chart'},
|
||||
{location: '/area-chart', file: 'area-chart'},
|
||||
{location: '/time-chart', file: 'time-chart'},
|
||||
{location: '/planets', file: 'planets'},
|
||||
{location: '/scores', file: 'scores'},
|
||||
{location: '/peace-sign', file: 'peace-sign'},
|
||||
{location: '/montly-bills', file: 'montly-bills'},
|
||||
{location: '/flower-chart', file: 'flower-chart'},
|
||||
{location: '/updated-circle', file: 'updated-circle'},
|
||||
{location: '/updating-bar-chart', file: 'updating-bar-chart'},
|
||||
{location: '/user-updating-bar-chart', file: 'user-updating-bar-chart'},
|
||||
{location: '/updating-pie-chart', file: 'updating-pie-chart'},
|
||||
]
|
||||
|
||||
module.exports = pages
|
||||
3
views/error.hbs
Normal file
3
views/error.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<h1>{{message}}</h1>
|
||||
<h2>{{error.status}}</h2>
|
||||
<pre>{{error.stack}}</pre>
|
||||
25
views/index.hbs
Normal file
25
views/index.hbs
Normal file
@@ -0,0 +1,25 @@
|
||||
<h1 class="underline">D3.js Data Visualizations</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="one-circle">One Circle</a></li>
|
||||
<li><a href="one-line">One Line</a></li>
|
||||
<li><a href="one-box">One Box</a></li>
|
||||
<li><a href="confetti">Confetti</a></li>
|
||||
<li><a href="stacked-circles">Stacked Circles</a></li>
|
||||
<li><a href="scaled-line">Scaled Line</a></li>
|
||||
<li><a href="animated-scaled-line">Animated Scaled Line</a></li>
|
||||
<li><a href="basic-line-chart">Basic Line Chart</a></li>
|
||||
<li><a href="area-chart">Area Chart</a></li>
|
||||
<li><a href="time-chart">Time Chart</a></li>
|
||||
<li><a href="planets">Planets</a></li>
|
||||
<li><a href="scores">Scores</a></li>
|
||||
<li><a href="peace-sign">Peace Sign</a></li>
|
||||
<li><a href="montly-bills">Montly Bills</a></li>
|
||||
<li><a href="flower-chart">Flower Chart</a></li>
|
||||
<li><a href="updated-circle">Updated Circle</a></li>
|
||||
<li><a href="updating-bar-chart">Updating Bar Chart</a></li>
|
||||
<li><a href="user-updating-bar-chart">User Updating Bar Chart</a></li>
|
||||
<li><a href="updating-pie-chart">Updating Pie Chart</a></li>
|
||||
</ul>
|
||||
|
||||
<script type="module" src="{{ script }}"></script>
|
||||
10
views/layouts/layout.hbs
Normal file
10
views/layouts/layout.hbs
Normal file
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>D3.js Course</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js" integrity="sha512-0XfwGD1nxplHpehcSVI7lY+m/5L37PNHDt+DOc7aLFckwPXjnjeA1oeNbru7YeI4VLs9i+ADnnHEhP69C9CqTA==" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="{{ style }}" >
|
||||
</head>
|
||||
<body>
|
||||
{{{ body }}}
|
||||
</body>
|
||||
</html>
|
||||
6
views/viz.hbs
Normal file
6
views/viz.hbs
Normal file
@@ -0,0 +1,6 @@
|
||||
<a class="home-btn" href="/">Home</a>
|
||||
|
||||
<div id="app">
|
||||
</div>
|
||||
|
||||
<script type="module" src="{{ script }}"></script>
|
||||
Reference in New Issue
Block a user