diff --git a/assets/js/components/Chart.js b/assets/js/components/Chart.js index c1b5523..c9f996a 100644 --- a/assets/js/components/Chart.js +++ b/assets/js/components/Chart.js @@ -3,13 +3,39 @@ import { h, Component } from 'preact'; import Client from '../lib/client.js'; import { bind } from 'decko'; -import * as d3 from 'd3'; -function padData(data) { - for(let i=0; i { + 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); } - 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 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 max = d3.max(data, (d) => d.Pageviews); - - var h = 300, - padding = 20, - w = this.base.clientWidth - ( padding * 3), - x = d3.scaleBand().range([0, w]).padding(0.2).round(true), - y = d3.scaleLinear().range([h, 0]), - - yAxis = d3.axisLeft().scale(y), + + var x = d3.scaleBand().range([0, innerWidth]).padding(0.1), + y = d3.scaleLinear().range([innerHeight, 0]), + yAxis = d3.axisLeft().scale(y).ticks(3).tickSize(-innerWidth), xAxis = d3.axisBottom().scale(x); x.domain(data.map((d) => d.Date)) - y.domain([0, (max * 1.1)]) - - // clear all previous data - this.vis.selectAll('*').remove(); + y.domain([0, (max*1.155)]) // axes - this.vis.append("g") + graph.append("g") .attr("class", "y axis") .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('transform', 'translate(0,' + h + ')') + .attr('transform', 'translate(0,' + innerHeight + ')') .call(xAxis) - .selectAll('g') - - // bars - var bars = this.vis.selectAll('g.pageviews') + xTicks.selectAll('g text').style('display', (d, i) => { + return i % nxLabels != 0 ? 'none' : 'block' + }).attr("transform", "rotate(-50)").style("text-anchor", "end"); + xTicks.selectAll('g').style('display', (d, i) => { + return i % nxTicks != 0 ? 'none' : 'block'; + }); + + // pageview bars + var pageviewBars = graph.selectAll('g.pageviews') .data(data) .enter() .append('g') - .attr('class', 'pageviews') + .attr('class', 'pageviews') .attr('transform', function (d, i) { return "translate(" + x(d.Date) + ", 0)" }); - - bars.append('rect') - .attr('width', x.bandwidth()) - .attr('height', (d) => (h - y(d.Pageviews)) ) - .attr('y', (d) => y(d.Pageviews)) + + pageviewBars.append('rect') + .attr('width', x.bandwidth() * 0.5) + .attr("y", innerHeight) + .attr("height", 0) + .transition(t) + .attr('y', d => y(d.Pageviews)) + .attr('height', (d) => innerHeight - y(d.Pageviews) ) + // visitors - var visitorBars = this.vis.selectAll('g.visitors') + var visitorBars = graph.selectAll('g.visitors') .data(data) .enter() .append('g') .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') .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)) } @@ -117,7 +158,7 @@ class Chart extends Component { this.setState({ loading: false, - data: padData(d), + data: padData(after, before, d), }); this.redrawChart(); @@ -126,7 +167,7 @@ class Chart extends Component { render(props, state) { return ( -
+
) } } diff --git a/assets/js/pages/dashboard.js b/assets/js/pages/dashboard.js index fe4e713..b0b05dc 100644 --- a/assets/js/pages/dashboard.js +++ b/assets/js/pages/dashboard.js @@ -47,7 +47,7 @@ class Dashboard extends Component {
-
+
diff --git a/assets/sass/chart.scss b/assets/sass/chart.scss index 1af29c4..519b0c1 100644 --- a/assets/sass/chart.scss +++ b/assets/sass/chart.scss @@ -1,3 +1,10 @@ +.box-graph { + background: white; +} + +#chart { +} + g.pageviews { fill: #88ffc6; } @@ -7,6 +14,17 @@ g.visitors { } .axis { - font-size: 12px; - fill: #6c7680; + .domain{ + stroke: none; + } + + line { + stroke: rgb(218, 218, 218); + } + + text { + font-size: 12px; + fill: #6c7680; + } } + diff --git a/package.json b/package.json index 5339aaf..2ef2db5 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "cookies-js": "^1.2.3", "d3": "^5.4.0", + "d3-transition": "^1.1.1", "decko": "^1.2.0", "gulp-uglify": "^3.0.0", "pikaday": "^1.7.0",