mirror of
https://github.com/status-im/fathom.git
synced 2025-03-01 03:20:27 +00:00
fill dates with no data with zeroes & add d3-transition
This commit is contained in:
parent
7adc5d3bec
commit
0101afdc9f
135
assets/js/components/Chart.js
vendored
135
assets/js/components/Chart.js
vendored
@ -3,13 +3,39 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import Client from '../lib/client.js';
|
import Client from '../lib/client.js';
|
||||||
import { bind } from 'decko';
|
import { bind } from 'decko';
|
||||||
import * as d3 from 'd3';
|
|
||||||
|
|
||||||
function padData(data) {
|
import * as d3 from 'd3';
|
||||||
for(let i=0; i<data.length; i++) {
|
import 'd3-transition';
|
||||||
data[i].Date = data[i].Date.substring(0, 10);
|
|
||||||
|
|
||||||
|
function padZero(s) {
|
||||||
|
return s < 10 ? "0" + s : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function padData(startUnix, endUnix, data) {
|
||||||
|
let startDate = new Date(startUnix * 1000);
|
||||||
|
let endDate = new Date(endUnix * 1000);
|
||||||
|
let datamap = [];
|
||||||
|
let newData = [];
|
||||||
|
|
||||||
|
data.forEach((d) => {
|
||||||
|
d.Date = d.Date.substring(0, 10);
|
||||||
|
datamap[d.Date] = d;
|
||||||
|
});
|
||||||
|
|
||||||
|
while(startDate < endDate) {
|
||||||
|
let date = startDate.getFullYear() + "-" + padZero(startDate.getMonth() + 1) + "-" + padZero(startDate.getDate());
|
||||||
|
let data = datamap[date] ? datamap[date] : {
|
||||||
|
"Date": date,
|
||||||
|
"Pageviews": 0,
|
||||||
|
"Visitors": 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
newData.push(data);
|
||||||
|
startDate.setDate(startDate.getDate() + 1);
|
||||||
}
|
}
|
||||||
return data;
|
|
||||||
|
return newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,74 +58,89 @@ class Chart extends Component {
|
|||||||
this.fetchData(newProps.before, newProps.after);
|
this.fetchData(newProps.before, newProps.after);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
var padding = 20,
|
|
||||||
h = 300,
|
|
||||||
w = this.base.clientWidth - ( padding * 3);
|
|
||||||
|
|
||||||
this.vis = d3.select(this.base)
|
|
||||||
.append('svg')
|
|
||||||
.attr('width', w + (padding * 2))
|
|
||||||
.attr('height', h + (padding * 2))
|
|
||||||
.append('g')
|
|
||||||
.attr('transform', 'translate(' + (2*padding) + ',' + padding + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
redrawChart() {
|
redrawChart() {
|
||||||
|
let padding = { top: 10, right: 24, bottom: 48, left: 40 },
|
||||||
|
h = 240,
|
||||||
|
w = this.base.clientWidth;
|
||||||
|
|
||||||
|
let height = h, width = w;
|
||||||
|
let innerWidth = width - padding.left - padding.right;
|
||||||
|
let innerHeight = height - padding.top - padding.bottom;
|
||||||
|
|
||||||
|
if( this.previousGraph ) {
|
||||||
|
this.previousGraph.selectAll('*').remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
let graph = this.previousGraph = d3.select(this.base)
|
||||||
|
graph
|
||||||
|
.append('svg').attr('width', width)
|
||||||
|
.attr('height', height)
|
||||||
|
.append('g').attr('transform', 'translate(' + padding.left + ', 0)');
|
||||||
|
graph = graph.select('g');
|
||||||
|
|
||||||
|
var t = d3.transition().duration(500).ease(d3.easeQuadOut);
|
||||||
var data = this.state.data;
|
var data = this.state.data;
|
||||||
var max = d3.max(data, (d) => d.Pageviews);
|
var max = d3.max(data, (d) => d.Pageviews);
|
||||||
|
|
||||||
var h = 300,
|
var x = d3.scaleBand().range([0, innerWidth]).padding(0.1),
|
||||||
padding = 20,
|
y = d3.scaleLinear().range([innerHeight, 0]),
|
||||||
w = this.base.clientWidth - ( padding * 3),
|
yAxis = d3.axisLeft().scale(y).ticks(3).tickSize(-innerWidth),
|
||||||
x = d3.scaleBand().range([0, w]).padding(0.2).round(true),
|
|
||||||
y = d3.scaleLinear().range([h, 0]),
|
|
||||||
|
|
||||||
yAxis = d3.axisLeft().scale(y),
|
|
||||||
xAxis = d3.axisBottom().scale(x);
|
xAxis = d3.axisBottom().scale(x);
|
||||||
|
|
||||||
x.domain(data.map((d) => d.Date))
|
x.domain(data.map((d) => d.Date))
|
||||||
y.domain([0, (max * 1.1)])
|
y.domain([0, (max*1.155)])
|
||||||
|
|
||||||
// clear all previous data
|
|
||||||
this.vis.selectAll('*').remove();
|
|
||||||
|
|
||||||
// axes
|
// axes
|
||||||
this.vis.append("g")
|
graph.append("g")
|
||||||
.attr("class", "y axis")
|
.attr("class", "y axis")
|
||||||
.call(yAxis);
|
.call(yAxis);
|
||||||
|
|
||||||
this.vis.append("g")
|
let nxTicks = Math.max(1, Math.round(data.length / 60));
|
||||||
|
let nxLabels = Math.max(1, Math.round(data.length / 15));
|
||||||
|
let xTicks = graph.append("g")
|
||||||
.attr("class", "x axis")
|
.attr("class", "x axis")
|
||||||
.attr('transform', 'translate(0,' + h + ')')
|
.attr('transform', 'translate(0,' + innerHeight + ')')
|
||||||
.call(xAxis)
|
.call(xAxis)
|
||||||
.selectAll('g')
|
xTicks.selectAll('g text').style('display', (d, i) => {
|
||||||
|
return i % nxLabels != 0 ? 'none' : 'block'
|
||||||
// bars
|
}).attr("transform", "rotate(-50)").style("text-anchor", "end");
|
||||||
var bars = this.vis.selectAll('g.pageviews')
|
xTicks.selectAll('g').style('display', (d, i) => {
|
||||||
|
return i % nxTicks != 0 ? 'none' : 'block';
|
||||||
|
});
|
||||||
|
|
||||||
|
// pageview bars
|
||||||
|
var pageviewBars = graph.selectAll('g.pageviews')
|
||||||
.data(data)
|
.data(data)
|
||||||
.enter()
|
.enter()
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'pageviews')
|
.attr('class', 'pageviews')
|
||||||
.attr('transform', function (d, i) { return "translate(" + x(d.Date) + ", 0)" });
|
.attr('transform', function (d, i) { return "translate(" + x(d.Date) + ", 0)" });
|
||||||
|
|
||||||
bars.append('rect')
|
pageviewBars.append('rect')
|
||||||
.attr('width', x.bandwidth())
|
.attr('width', x.bandwidth() * 0.5)
|
||||||
.attr('height', (d) => (h - y(d.Pageviews)) )
|
.attr("y", innerHeight)
|
||||||
.attr('y', (d) => y(d.Pageviews))
|
.attr("height", 0)
|
||||||
|
.transition(t)
|
||||||
|
.attr('y', d => y(d.Pageviews))
|
||||||
|
.attr('height', (d) => innerHeight - y(d.Pageviews) )
|
||||||
|
|
||||||
|
|
||||||
// visitors
|
// visitors
|
||||||
var visitorBars = this.vis.selectAll('g.visitors')
|
var visitorBars = graph.selectAll('g.visitors')
|
||||||
.data(data)
|
.data(data)
|
||||||
.enter()
|
.enter()
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'visitors')
|
.attr('class', 'visitors')
|
||||||
.attr('transform', function (d, i) { return "translate(" + ( x(d.Date) + 0.25 * x.bandwidth() ) + ", 0)" });
|
.attr('transform', function (d, i) { return "translate(" + ( x(d.Date) + 0.5 * x.bandwidth() ) + ", 0)" });
|
||||||
|
|
||||||
visitorBars.append('rect')
|
visitorBars.append('rect')
|
||||||
.attr('width', x.bandwidth() * 0.5)
|
.attr('width', x.bandwidth() * 0.5)
|
||||||
.attr('height', (d) => (h - y(d.Visitors)) )
|
.attr("y", innerHeight)
|
||||||
|
.attr("height", 0)
|
||||||
|
.transition(t)
|
||||||
|
.attr('height', (d) => (innerHeight - y(d.Visitors)) )
|
||||||
.attr('y', (d) => y(d.Visitors))
|
.attr('y', (d) => y(d.Visitors))
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -117,7 +158,7 @@ class Chart extends Component {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
data: padData(d),
|
data: padData(after, before, d),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.redrawChart();
|
this.redrawChart();
|
||||||
@ -126,7 +167,7 @@ class Chart extends Component {
|
|||||||
|
|
||||||
render(props, state) {
|
render(props, state) {
|
||||||
return (
|
return (
|
||||||
<div></div>
|
<div id="chart"></div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ class Dashboard extends Component {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="boxes">
|
<div class="boxes">
|
||||||
<div class="box box-graph animated fadeInUp delayed_03s" style="padding: 0;">
|
<div class="box box-graph">
|
||||||
<Chart before={state.before} after={state.after} />
|
<Chart before={state.before} after={state.after} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
.box-graph {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chart {
|
||||||
|
}
|
||||||
|
|
||||||
g.pageviews {
|
g.pageviews {
|
||||||
fill: #88ffc6;
|
fill: #88ffc6;
|
||||||
}
|
}
|
||||||
@ -7,6 +14,17 @@ g.visitors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.axis {
|
.axis {
|
||||||
font-size: 12px;
|
.domain{
|
||||||
fill: #6c7680;
|
stroke: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
line {
|
||||||
|
stroke: rgb(218, 218, 218);
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 12px;
|
||||||
|
fill: #6c7680;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookies-js": "^1.2.3",
|
"cookies-js": "^1.2.3",
|
||||||
"d3": "^5.4.0",
|
"d3": "^5.4.0",
|
||||||
|
"d3-transition": "^1.1.1",
|
||||||
"decko": "^1.2.0",
|
"decko": "^1.2.0",
|
||||||
"gulp-uglify": "^3.0.0",
|
"gulp-uglify": "^3.0.0",
|
||||||
"pikaday": "^1.7.0",
|
"pikaday": "^1.7.0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user