2016-11-23 18:40:35 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
import { h, render, Component } from 'preact';
|
2016-12-04 12:23:09 +00:00
|
|
|
import * as d3 from 'd3';
|
|
|
|
import tip from 'd3-tip';
|
|
|
|
|
|
|
|
d3.tip = tip;
|
2016-11-23 18:40:35 +00:00
|
|
|
|
2016-12-04 12:23:09 +00:00
|
|
|
const dayInSeconds = 60 * 60 * 24;
|
2016-11-23 19:30:09 +00:00
|
|
|
|
2016-11-23 18:40:35 +00:00
|
|
|
class Graph extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
|
|
|
|
this.state = {
|
2016-11-23 19:30:09 +00:00
|
|
|
visitorData: [],
|
|
|
|
pageviewData: []
|
2016-11-23 18:40:35 +00:00
|
|
|
}
|
2016-12-04 12:23:09 +00:00
|
|
|
|
2016-11-23 18:40:35 +00:00
|
|
|
this.fetchData = this.fetchData.bind(this);
|
2016-12-04 12:23:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.fetchData(this.props.period);
|
2016-11-23 20:29:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillReceiveProps(newProps) {
|
|
|
|
if(this.props.period != newProps.period) {
|
|
|
|
this.fetchData(newProps.period)
|
|
|
|
}
|
2016-11-23 18:40:35 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 19:30:09 +00:00
|
|
|
refreshChart() {
|
2016-12-05 14:31:34 +00:00
|
|
|
var padt = 20, padb = 40, padr = 40, padl = 40,
|
2016-12-04 12:23:09 +00:00
|
|
|
h = 300,
|
2016-12-05 14:31:34 +00:00
|
|
|
w = document.getElementById('graph').parentNode.clientWidth - padl - padr,
|
|
|
|
x = d3.scaleBand().range([0, w]).padding(0.2),
|
2016-12-04 12:23:09 +00:00
|
|
|
y = d3.scaleLinear().range([h, 0]),
|
|
|
|
yAxis = d3.axisLeft().scale(y).tickSize(-w + padl + padr),
|
2016-12-05 14:31:34 +00:00
|
|
|
xAxis = d3.axisBottom().scale(x),
|
|
|
|
xTick = Math.round(this.state.visitorData.length / 7);
|
2016-12-04 12:23:09 +00:00
|
|
|
|
|
|
|
var tip = d3.tip()
|
|
|
|
.attr('class', 'd3-tip')
|
|
|
|
.html(function(d) { return '<span>' + d.Count + '</span>' + ' visitors' })
|
|
|
|
.offset([-12, 0]);
|
|
|
|
|
|
|
|
var vis = d3.select('#graph')
|
|
|
|
.append('svg')
|
|
|
|
.attr('width', w)
|
|
|
|
.attr('height', h + padt + padb)
|
|
|
|
.append('g')
|
|
|
|
.attr('transform', 'translate(' + padl + ',' + padt + ')');
|
|
|
|
|
|
|
|
vis.call(tip);
|
|
|
|
|
|
|
|
var max = d3.max(this.state.visitorData, function(d) { return d.Count });
|
2016-12-05 14:31:34 +00:00
|
|
|
x.domain(this.state.visitorData.map((d) => d.Label))
|
2016-12-04 12:23:09 +00:00
|
|
|
y.domain([0, max])
|
|
|
|
|
|
|
|
// axes
|
|
|
|
vis.append("g")
|
|
|
|
.attr("class", "y axis")
|
|
|
|
.call(yAxis);
|
|
|
|
|
|
|
|
vis.append("g")
|
|
|
|
.attr("class", "x axis")
|
|
|
|
.attr('transform', 'translate(0,' + h + ')')
|
|
|
|
.call(xAxis)
|
2016-12-05 14:31:34 +00:00
|
|
|
.selectAll('g')
|
|
|
|
.style('display', (d, i) => i % xTick != 0 ? 'none' : 'block')
|
2016-12-04 12:23:09 +00:00
|
|
|
|
|
|
|
// bars
|
|
|
|
var data = this.state.visitorData;
|
|
|
|
var bars = vis.selectAll('g.bar')
|
|
|
|
.data(data)
|
|
|
|
.enter().append('g')
|
|
|
|
.attr('class', 'bar')
|
2016-12-05 14:31:34 +00:00
|
|
|
.attr('transform', function (d, i) { return "translate(" + x(d.Label) + ", 0)" });
|
2016-12-04 12:23:09 +00:00
|
|
|
|
|
|
|
bars.append('rect')
|
2016-12-05 14:31:34 +00:00
|
|
|
.attr('width', () => x.bandwidth() )
|
2016-12-04 12:23:09 +00:00
|
|
|
.attr('height', (d) => (h - y(d.Count)) )
|
|
|
|
.attr('y', (d) => y(d.Count))
|
|
|
|
.on('mouseover', tip.show)
|
|
|
|
.on('mouseout', tip.hide)
|
2016-11-23 18:40:35 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 20:29:54 +00:00
|
|
|
fetchData(period) {
|
2016-11-26 16:19:15 +00:00
|
|
|
const before = Math.round((+new Date() ) / 1000);
|
|
|
|
const after = before - ( period * dayInSeconds );
|
|
|
|
|
2016-11-23 19:30:09 +00:00
|
|
|
// fetch visitor data
|
2016-11-26 16:19:15 +00:00
|
|
|
fetch(`/api/visits/count/day?before=${before}&after=${after}`, {
|
2016-11-23 19:30:09 +00:00
|
|
|
credentials: 'include'
|
2016-11-25 15:30:38 +00:00
|
|
|
}).then((r) => {
|
|
|
|
if( r.ok ) {
|
|
|
|
return r.json();
|
|
|
|
}
|
|
|
|
throw new Error();
|
|
|
|
}).then((data) => {
|
|
|
|
this.setState({ visitorData: data })
|
|
|
|
window.requestAnimationFrame(this.refreshChart.bind(this));
|
2016-11-23 19:30:09 +00:00
|
|
|
});
|
|
|
|
|
2016-12-04 12:23:09 +00:00
|
|
|
// // fetch pageview data
|
|
|
|
// fetch(`/api/pageviews/count/day?before=${before}&after=${after}`, {
|
|
|
|
// credentials: 'include'
|
|
|
|
// }).then((r) => {
|
|
|
|
// if( r.ok ) {
|
|
|
|
// return r.json();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// throw new Error();
|
|
|
|
// }).then((data) => {
|
|
|
|
// this.setState({ pageviewData: data })
|
|
|
|
// window.requestAnimationFrame(this.refreshChart.bind(this));
|
|
|
|
// });
|
2016-11-23 18:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div class="block">
|
2016-12-04 12:23:09 +00:00
|
|
|
<div id="graph"></div>
|
2016-11-23 18:40:35 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Graph
|