replace chartjs with d3

This commit is contained in:
Danny van Kooten 2016-12-04 13:23:09 +01:00
parent acd9e99855
commit e314d0971f
8 changed files with 394 additions and 94 deletions

View File

@ -5,6 +5,7 @@ This is a general draft document for thoughts and todo's, without any structure
### What's cooking?
- Replace chart with custom D3 chart.
- Allow setting custom limit in table overviews.
- Allow sorting in table overviews.
- Choose a OS license & settle on name.

View File

@ -13,8 +13,8 @@ type Datapoint struct {
Percentage float32 `json:",omitempty"`
}
var defaultPeriod = 7
var defaultLimit = 10
const defaultPeriod = 7
const defaultLimit = 10
// log fatal errors
func checkError(err error) {

View File

@ -1,12 +1,12 @@
'use strict';
import { h, render, Component } from 'preact';
import Chart from 'chart.js'
const dayInSeconds = 60 * 60 * 24;
import * as d3 from 'd3';
import tip from 'd3-tip';
Chart.defaults.global.tooltips.xPadding = 10;
Chart.defaults.global.tooltips.yPadding = 10;
Chart.defaults.global.layout = { padding: 10 }
d3.tip = tip;
const dayInSeconds = 60 * 60 * 24;
class Graph extends Component {
constructor(props) {
@ -16,8 +16,12 @@ class Graph extends Component {
visitorData: [],
pageviewData: []
}
this.fetchData = this.fetchData.bind(this);
this.fetchData(props.period);
}
componentDidMount() {
this.fetchData(this.props.period);
}
componentWillReceiveProps(newProps) {
@ -27,37 +31,58 @@ class Graph extends Component {
}
refreshChart() {
if( ! this.canvas ) { return; }
var w = 800,
h = 300,
padt = 20, padr = 20, padb = 60, padl = 30,
x = d3.scaleBand().rangeRound([0, w - padl - padr]).padding(0.1),
y = d3.scaleLinear().range([h, 0]),
yAxis = d3.axisLeft().scale(y).tickSize(-w + padl + padr),
xAxis = d3.axisBottom().scale(x);
// clear canvas
var newCanvas = document.createElement('canvas');
this.canvas.parentNode.style.minHeight = this.canvas.parentNode.clientHeight + "px";
this.canvas.parentNode.replaceChild(newCanvas, this.canvas);
this.canvas = newCanvas;
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) { return '<span>' + d.Count + '</span>' + ' visitors' })
.offset([-12, 0]);
if( this.chart ) { this.chart.clear(); }
this.chart = new Chart(this.canvas, {
type: 'line',
data: {
labels: this.state.visitorData.map((d) => d.Label),
datasets: [
{
label: '# of Visitors',
data: this.state.visitorData.map((d) => d.Count),
backgroundColor: 'rgba(255, 155, 0, .6)',
pointStyle: 'rect',
pointBorderWidth: 0.1,
},
{
label: '# of Pageviews',
data: this.state.pageviewData.map((d) => d.Count),
backgroundColor: 'rgba(0, 155, 255, .4)',
pointStyle: 'rect',
pointBorderWidth: 0.1,
}
],
}
});
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 });
x.domain(d3.range(this.state.visitorData.length))
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)
.selectAll('.x.axis g')
.style('display', function (d, i) { return i % 3 != 0 ? 'none' : 'block' });
// bars
var data = this.state.visitorData;
var bars = vis.selectAll('g.bar')
.data(data)
.enter().append('g')
.attr('class', 'bar')
.attr('transform', function (d, i) { return "translate(" + x(i) + ", 0)" });
bars.append('rect')
.attr('width', () => x.bandwidth())
.attr('height', (d) => (h - y(d.Count)) )
.attr('y', (d) => y(d.Count))
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
}
fetchData(period) {
@ -77,25 +102,25 @@ class Graph extends Component {
window.requestAnimationFrame(this.refreshChart.bind(this));
});
// 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));
});
// // 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));
// });
}
render() {
return (
<div class="block">
<canvas height="100" ref={(el) => { this.canvas = el; }} />
<div id="graph"></div>
</div>
)
}

80
assets/sass/_graphs.scss Normal file
View File

@ -0,0 +1,80 @@
.d3-tip span {
color: #ff00c7;
}
.domain {
display: none;
}
.axis line {
stroke-width: 1px;
stroke: #eee;
shape-rendering: crispedges;
}
.axis text {
fill: #888;
}
rect {
fill: #339cff;
fill-opacity: 0.7;
}
rect:hover {
fill-opacity: 1;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
pointer-events: none;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
position: absolute;
pointer-events: none;
}
.d3-tip span {
color: lightgreen;
}
/* Northward tooltips */
.d3-tip.n:after {
content: "\25BC";
margin: -1px 0 0 0;
top: 100%;
left: 0;
text-align: center;
}
/* Eastward tooltips */
.d3-tip.e:after {
content: "\25C0";
margin: -4px 0 0 0;
top: 50%;
left: -8px;
}
/* Southward tooltips */
.d3-tip.s:after {
content: "\25B2";
margin: 0 0 1px 0;
top: -8px;
left: 0;
text-align: center;
}
/* Westward tooltips */
.d3-tip.w:after {
content: "\25B6";
margin: -4px 0 0 -1px;
top: 50%;
left: 100%;
}

View File

@ -105,3 +105,5 @@ h4 {
small {
font-size: 70%;
}
@import "graphs"

View File

@ -51,5 +51,5 @@ gulp.task('sass', function () {
gulp.task('watch', ['default'], function() {
gulp.watch(['./assets/js/**/*.js'], ['browserify', 'tracker'] );
gulp.watch(['./assets/sass/**/*.scss'], ['sass'] );
gulp.watch(['./assets/sass/**/**/*.scss'], ['sass'] );
});

View File

@ -1,5 +1,8 @@
{
"devDependencies": {
"babel-plugin-transform-react-jsx": "^6.8.0",
"babel-preset-es2015": "^6.18.0",
"babelify": "^7.3.0",
"browserify": "^13.1.1",
"gulp": "^3.9.1",
"gulp-rename": "^1.2.2",
@ -9,11 +12,8 @@
"vinyl-source-stream": "^1.1.0"
},
"dependencies": {
"babel-plugin-transform-react-jsx": "^6.8.0",
"babel-preset-es2015": "^6.18.0",
"babelify": "^7.3.0",
"chart.js": "^2.4.0",
"mithril": "^0.2.5",
"d3": "^4.4.0",
"d3-tip": "^0.7.1",
"preact": "^6.4.0"
}
}

266
yarn.lock
View File

@ -795,26 +795,6 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chart.js:
version "2.4.0"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.4.0.tgz#44198073f0f43e5e16662e108420d92652a3c9a3"
dependencies:
chartjs-color "^2.0.0"
moment "^2.10.6"
chartjs-color-string@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.4.0.tgz#57748d4530ae28d8db0a5492182ba06dfdf2f468"
dependencies:
color-name "^1.0.0"
chartjs-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.0.0.tgz#7f60c7256589b24914814ece757659117381e35b"
dependencies:
chartjs-color-string "^0.4.0"
color-convert "^0.5.3"
cipher-base@^1.0.0, cipher-base@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
@ -845,14 +825,6 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
color-name@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
combine-source-map@~0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e"
@ -868,7 +840,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
commander@^2.9.0:
commander@^2.9.0, commander@2:
version "2.9.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
dependencies:
@ -979,6 +951,222 @@ d@^0.1.1, d@~0.1.1:
dependencies:
es5-ext "~0.10.2"
d3, d3@^4.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/d3/-/d3-4.4.0.tgz#aec4ad0fd574304a909b012fac4783fbbcf9f096"
dependencies:
d3-array "1.0.2"
d3-axis "1.0.4"
d3-brush "1.0.3"
d3-chord "1.0.3"
d3-collection "1.0.2"
d3-color "1.0.2"
d3-dispatch "1.0.2"
d3-drag "1.0.2"
d3-dsv "1.0.3"
d3-ease "1.0.2"
d3-force "1.0.4"
d3-format "1.0.2"
d3-geo "1.4.0"
d3-hierarchy "1.0.3"
d3-interpolate "1.1.2"
d3-path "1.0.3"
d3-polygon "1.0.2"
d3-quadtree "1.0.2"
d3-queue "3.0.3"
d3-random "1.0.2"
d3-request "1.0.3"
d3-scale "1.0.4"
d3-selection "1.0.3"
d3-shape "1.0.4"
d3-time "1.0.4"
d3-time-format "2.0.3"
d3-timer "1.0.3"
d3-transition "1.0.3"
d3-voronoi "1.1.0"
d3-zoom "1.1.0"
d3-array@1, d3-array@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.0.2.tgz#174237bf356a852fadd6af87743d928631de7655"
d3-axis@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.4.tgz#bdfdcf5e859824062e0f17ad920f76236e72512c"
d3-brush@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.0.3.tgz#4fa5374cc3b755d0990bf76b71b7a66417751c74"
dependencies:
d3-dispatch "1"
d3-drag "1"
d3-interpolate "1"
d3-selection "1"
d3-transition "1"
d3-chord@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.3.tgz#a398bae7cb632a3c4ea687a555a6b9ee4609d990"
dependencies:
d3-array "1"
d3-path "1"
d3-collection@1, d3-collection@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.2.tgz#df5acb5400443e9eabe9c1379896c67e52426b39"
d3-color@1, d3-color@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.2.tgz#83cb4b3a9474e40795f009d97e97a15649830bbc"
d3-dispatch@1, d3-dispatch@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.2.tgz#5b511e79a46a1f89492841c0a8f656687d5daa0a"
d3-drag@1, d3-drag@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.0.2.tgz#d634cc3f7689f99dd03fd7eb1af2945c0f4339ad"
dependencies:
d3-dispatch "1"
d3-selection "1"
d3-dsv@1, d3-dsv@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.0.3.tgz#049fe43c0f5f60c7ff7d376616bc76d6fc9d378f"
dependencies:
commander "2"
iconv-lite "0.4"
rw "1"
d3-ease@1, d3-ease@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.2.tgz#b486f8f3ca308ca7be38197d65622b6e30983377"
d3-force@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.0.4.tgz#f84dcbb3200be41de7bc30fa71923143156758bf"
dependencies:
d3-collection "1"
d3-dispatch "1"
d3-quadtree "1"
d3-timer "1"
d3-format@1, d3-format@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.0.2.tgz#138618320b4bbeb43b5c0ff30519079fbbd7375e"
d3-geo@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.4.0.tgz#15e58c414b5bafa1a960eeeb29059c94a60d8408"
dependencies:
d3-array "1"
d3-hierarchy@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.0.3.tgz#986b4925e81f1e0b4087e9442850f950cf27d338"
d3-interpolate@1, d3-interpolate@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.2.tgz#b52e6927a04fe1fe2a4cffc139e5389ed3e5e790"
dependencies:
d3-color "1"
d3-path@1, d3-path@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.3.tgz#60103d0dea9a6cd6ca58de86c6d56724002d3fde"
d3-polygon@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.2.tgz#6552c0fb03aa2d05023351da6e0e8adc4df0202b"
d3-quadtree@1, d3-quadtree@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.2.tgz#e7e873af06aaa427eaa4af094cc4cbfb350b9e38"
d3-queue@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/d3-queue/-/d3-queue-3.0.3.tgz#10ee4dd0574a1affaabfb931d0ba4f117926edc6"
d3-random@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.0.2.tgz#83ff6a391206209c30565299e43c6549866db269"
d3-request@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-request/-/d3-request-1.0.3.tgz#63fc7dfd784607db0df5d535d7cb898fceba755a"
dependencies:
d3-collection "1"
d3-dispatch "1"
d3-dsv "1"
xmlhttprequest "1"
d3-scale@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.4.tgz#50e28bf6a193b706745528515ed9b3d44205a033"
dependencies:
d3-array "1"
d3-collection "1"
d3-color "1"
d3-format "1"
d3-interpolate "1"
d3-time "1"
d3-time-format "2"
d3-selection@1, d3-selection@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.0.3.tgz#e63e51416172427854c1bcdfa066eb5fe872c108"
d3-shape@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.0.4.tgz#145ee100ccbec42f8e3f1996cd05c786f79fe1c6"
dependencies:
d3-path "1"
d3-time-format@2, d3-time-format@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.0.3.tgz#3241569b74ddc9c42e0689c0e8a903579fd6280a"
dependencies:
d3-time "1"
d3-time@1, d3-time@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.4.tgz#2ceba09a76b7450c992a1ded4e10fc6195e69649"
d3-timer@1, d3-timer@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.3.tgz#7a308a10c8524778e6b32d1d6c1c329209ae0ebf"
d3-tip:
version "0.7.1"
resolved "https://registry.yarnpkg.com/d3-tip/-/d3-tip-0.7.1.tgz#78cbf554f67b720a70e3b0f191e14cffe68cdd79"
dependencies:
d3 "^4.2"
d3-transition@1, d3-transition@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.0.3.tgz#91dc986bddb30973639320a85db72ce4ab1a27bb"
dependencies:
d3-color "1"
d3-dispatch "1"
d3-ease "1"
d3-interpolate "1"
d3-selection "1"
d3-timer "1"
d3-voronoi@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.0.tgz#69ea59563cf1e75d1c6c45edc803c6583768f628"
d3-zoom@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.1.0.tgz#29869cfd164928dd238aaa4365145741dcf1301f"
dependencies:
d3-dispatch "1"
d3-drag "1"
d3-interpolate "1"
d3-selection "1"
d3-transition "1"
dashdash@^1.12.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.0.tgz#29e486c5418bf0f356034a993d51686a33e84141"
@ -1630,6 +1818,10 @@ https-browserify@~0.0.0:
version "0.0.1"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
iconv-lite@0.4:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
@ -2195,10 +2387,6 @@ minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mithril@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/mithril/-/mithril-0.2.5.tgz#c1a50438a93ac23f11ada91188bb784c755404c2"
mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0":
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@ -2225,10 +2413,6 @@ module-deps@^4.0.8:
through2 "^2.0.0"
xtend "^4.0.0"
moment@^2.10.6:
version "2.17.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.0.tgz#a4c292e02aac5ddefb29a6eed24f51938dd3b74f"
ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
@ -2750,6 +2934,10 @@ ripemd160@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e"
rw@1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.2.tgz#14ef5137ff7547c73ecf0e0af1f0aee07e5401ee"
sass-graph@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b"
@ -3165,6 +3353,10 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
xmlhttprequest@1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
xtend@^4.0.0, "xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"