UNPKG

dc

Version:

A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js

145 lines (130 loc) 4.76 kB
<!DOCTYPE html> <html lang="en"> <head> <title>dc.js - Brushing on an Ordinal Bar Chart</title> <meta charset="UTF-8"> <link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="../css/dc.css"/> </head> <body> <div class="container"> <script type="text/javascript" src="header.js"></script> <p>This example demonstrates brushing on an ordinal bar chart, by mapping the values to integers and specifying a linear scale. The data is sorted by descending value in one fake group, and then another fake group provides the integer/ordinal mapping.</p> <div id="bar"></div> <div id="first-letters"></div> <script type="text/javascript" src="../js/promise-polyfill.js"></script> <script type="text/javascript" src="../js/fetch.umd.js"></script> <script type="text/javascript" src="../js/d3.js"></script> <script type="text/javascript" src="../js/crossfilter.js"></script> <script type="text/javascript" src="../js/dc.js"></script> <style> #bar .axis.x .tick text { text-anchor: end; transform: rotate(-60deg) translate(-10px,-12px); } #range.dc-chart .axis { display: none; } #range svg { display: block; /* default inline causes padding? */ } </style> <script type="text/javascript"> function sort_group(group, sort) { return { all: function() { return group.all().sort(sort); } }; } // index a group key -> i and i -> key function ordinal_to_linear_group(group, sort) { var _ord2int, _int2ord; return { all: function() { var ret = group.all(); _ord2int = {}; _int2ord = []; ret.forEach(function(d, i) { _ord2int[d.key] = i; _int2ord[i] = d.key; }); return ret; }, ord2int: function(o) { if(!_ord2int) this.all(); return _ord2int[o]; }, int2ord: function(i) { if(!_int2ord) this.all(); return _int2ord[i]; } }; } // phrases generated with https://www.fourmilab.ch/javascrypt/pass_phrase.html var bar; d3.json("wide-ordinal.json").then(function(wide) { var short = wide.slice(0, 50); // dummy crossfilter taking group data and regrouping it to the same thing var cf = crossfilter(short), dimension = cf.dimension(function(d) {return d.key;}), group = dimension.group().reduceSum(function(d) {return d.value;}); group = ordinal_to_linear_group(sort_group(group, function(a, b) { return d3.descending(a.value, b.value); })); bar = dc.barChart('#bar'); var linear_domain = [-0.5, short.length - 0.5]; bar .width(1000).height(300) .margins({left: 75, top: 0, right: 10, bottom: 140}) .x(d3.scaleLinear().domain(linear_domain)) .xUnits(dc.units.integers) .keyAccessor(kv => group.ord2int(kv.key)) .centerBar(true) .yAxisLabel('counts') .elasticY(true) .brushOn(true) .dimension(dimension) .group(group) .title(kv => kv.key); bar.xAxis() .tickValues(d3.range(short.length)) .tickFormat(function(d) { return group.int2ord(d); }); bar.filterHandler(function(dimension, filters) { if(!filters || !filters.length) { dimension.filter(null); return filters; } console.assert(filters.length === 1); console.assert(filters[0].filterType === 'RangedFilter'); var inside = group.all().filter(function(kv) { var i = group.ord2int(kv.key); return filters[0][0] <= i && i < filters[0][1]; }).map(function(kv) { return kv.key; }); dimension.filterFunction(function(d) { return inside.includes(d); }); return filters; }); // display a row chart of first letters, to test filtering var letterDimension = cf.dimension(function(d) { return d.key.split(' ').map(function(s) { return s[0]; }); }, true); var letterGroup = letterDimension.group(); var row = dc.rowChart('#first-letters'); row .width(1000) .height(350) .gap(1) .dimension(letterDimension) .group(letterGroup); dc.renderAll(); }); </script> </div> </body> </html>