Skip to content

Instantly share code, notes, and snippets.

@fbreitwieser
Last active March 25, 2018 23:57
Show Gist options
  • Save fbreitwieser/da749e9a672329f05666e692688ad4d8 to your computer and use it in GitHub Desktop.
Save fbreitwieser/da749e9a672329f05666e692688ad4d8 to your computer and use it in GitHub Desktop.
Hierarchical visualizations with D3
size path
d3
d3/d3-array
d3/d3-array/threshold
d3/d3-axis
d3/d3-brush
d3/d3-chord
d3/d3-collection
d3/d3-color
d3/d3-dispatch
d3/d3-drag
d3/d3-dsv
d3/d3-ease
d3/d3-force
d3/d3-format
d3/d3-geo
d3/d3-geo/clip
d3/d3-geo/path
d3/d3-geo/projection
d3/d3-hierarchy
d3/d3-hierarchy/hierarchy
d3/d3-hierarchy/pack
d3/d3-hierarchy/treemap
d3/d3-interpolate
d3/d3-interpolate/transform
d3/d3-path
d3/d3-polygon
d3/d3-quadtree
d3/d3-queue
d3/d3-random
d3/d3-request
d3/d3-scale
d3/d3-selection
d3/d3-selection/selection
d3/d3-shape
d3/d3-shape/curve
d3/d3-shape/offset
d3/d3-shape/order
d3/d3-shape/symbol
d3/d3-time-format
d3/d3-time
d3/d3-timer
d3/d3-transition
d3/d3-transition/selection
d3/d3-transition/transition
d3/d3-voronoi
d3/d3-zoom
90 d3/d3-array/array.js
86 d3/d3-array/ascending.js
238 d3/d3-array/bisect.js
786 d3/d3-array/bisector.js
72 d3/d3-array/constant.js
86 d3/d3-array/descending.js
135 d3/d3-array/deviation.js
553 d3/d3-array/extent.js
1876 d3/d3-array/histogram.js
43 d3/d3-array/identity.js
451 d3/d3-array/max.js
362 d3/d3-array/mean.js
452 d3/d3-array/median.js
339 d3/d3-array/merge.js
451 d3/d3-array/min.js
63 d3/d3-array/number.js
182 d3/d3-array/pairs.js
161 d3/d3-array/permute.js
416 d3/d3-array/quantile.js
344 d3/d3-array/range.js
357 d3/d3-array/scan.js
285 d3/d3-array/shuffle.js
295 d3/d3-array/sum.js
361 d3/d3-array/threshold/freedmanDiaconis.js
180 d3/d3-array/threshold/scott.js
96 d3/d3-array/threshold/sturges.js
672 d3/d3-array/ticks.js
356 d3/d3-array/transpose.js
540 d3/d3-array/variance.js
99 d3/d3-array/zip.js
42 d3/d3-axis/array.js
5239 d3/d3-axis/axis.js
43 d3/d3-axis/identity.js
15778 d3/d3-brush/brush.js
72 d3/d3-brush/constant.js
127 d3/d3-brush/event.js
202 d3/d3-brush/noevent.js
42 d3/d3-chord/array.js
3178 d3/d3-chord/chord.js
72 d3/d3-chord/constant.js
159 d3/d3-chord/math.js
2340 d3/d3-chord/ribbon.js
137 d3/d3-collection/entries.js
104 d3/d3-collection/keys.js
1988 d3/d3-collection/map.js
2021 d3/d3-collection/nest.js
800 d3/d3-collection/set.js
115 d3/d3-collection/values.js
9276 d3/d3-color/color.js
1855 d3/d3-color/cubehelix.js
340 d3/d3-color/define.js
3167 d3/d3-color/lab.js
72 d3/d3-color/math.js
2729 d3/d3-dispatch/dispatch.js
72 d3/d3-drag/constant.js
4297 d3/d3-drag/drag.js
430 d3/d3-drag/event.js
857 d3/d3-drag/nodrag.js
202 d3/d3-drag/noevent.js
199 d3/d3-dsv/csv.js
3582 d3/d3-dsv/dsv.js
200 d3/d3-dsv/tsv.js
653 d3/d3-ease/back.js
521 d3/d3-ease/bounce.js
261 d3/d3-ease/circle.js
210 d3/d3-ease/cubic.js
1309 d3/d3-ease/elastic.js
251 d3/d3-ease/exp.js
43 d3/d3-ease/linear.js
596 d3/d3-ease/poly.js
192 d3/d3-ease/quad.js
236 d3/d3-ease/sin.js
654 d3/d3-force/center.js
2447 d3/d3-force/collide.js
72 d3/d3-force/constant.js
69 d3/d3-force/jiggle.js
3213 d3/d3-force/link.js
3181 d3/d3-force/manyBody.js
3444 d3/d3-force/simulation.js
1030 d3/d3-force/x.js
1030 d3/d3-force/y.js
361 d3/d3-format/defaultLocale.js
134 d3/d3-format/exponent.js
656 d3/d3-format/formatDecimal.js
368 d3/d3-format/formatDefault.js
475 d3/d3-format/formatGroup.js
611 d3/d3-format/formatPrefixAuto.js
458 d3/d3-format/formatRounded.js
1589 d3/d3-format/formatSpecifier.js
846 d3/d3-format/formatTypes.js
5247 d3/d3-format/locale.js
119 d3/d3-format/precisionFixed.js
190 d3/d3-format/precisionPrefix.js
186 d3/d3-format/precisionRound.js
906 d3/d3-geo/adder.js
1958 d3/d3-geo/area.js
5361 d3/d3-geo/bounds.js
929 d3/d3-geo/cartesian.js
3816 d3/d3-geo/centroid.js
2373 d3/d3-geo/circle.js
2897 d3/d3-geo/clip/antimeridian.js
470 d3/d3-geo/clip/buffer.js
5956 d3/d3-geo/clip/circle.js
5527 d3/d3-geo/clip/extent.js
3813 d3/d3-geo/clip/index.js
1099 d3/d3-geo/clip/line.js
2802 d3/d3-geo/clip/polygon.js
250 d3/d3-geo/compose.js
72 d3/d3-geo/constant.js
229 d3/d3-geo/distance.js
3034 d3/d3-geo/graticule.js
43 d3/d3-geo/identity.js
911 d3/d3-geo/interpolate.js
1309 d3/d3-geo/length.js
880 d3/d3-geo/math.js
34 d3/d3-geo/noop.js
945 d3/d3-geo/path/area.js
485 d3/d3-geo/path/bounds.js
2033 d3/d3-geo/path/centroid.js
914 d3/d3-geo/path/context.js
1690 d3/d3-geo/path/index.js
1149 d3/d3-geo/path/string.js
139 d3/d3-geo/pointEqual.js
2491 d3/d3-geo/polygonContains.js
235 d3/d3-geo/projection/albers.js
3986 d3/d3-geo/projection/albersUsa.js
502 d3/d3-geo/projection/azimuthal.js
447 d3/d3-geo/projection/azimuthalEqualArea.js
443 d3/d3-geo/projection/azimuthalEquidistant.js
402 d3/d3-geo/projection/conic.js
1017 d3/d3-geo/projection/conicConformal.js
871 d3/d3-geo/projection/conicEqualArea.js
771 d3/d3-geo/projection/conicEquidistant.js
314 d3/d3-geo/projection/cylindricalEqualArea.js
253 d3/d3-geo/projection/equirectangular.js
910 d3/d3-geo/projection/fit.js
387 d3/d3-geo/projection/gnomonic.js
1922 d3/d3-geo/projection/identity.js
3752 d3/d3-geo/projection/index.js
1119 d3/d3-geo/projection/mercator.js
376 d3/d3-geo/projection/orthographic.js
3275 d3/d3-geo/projection/resample.js
436 d3/d3-geo/projection/stereographic.js
762 d3/d3-geo/projection/transverseMercator.js
2509 d3/d3-geo/rotation.js
2305 d3/d3-geo/stream.js
701 d3/d3-geo/transform.js
166 d3/d3-hierarchy/accessors.js
2093 d3/d3-hierarchy/cluster.js
120 d3/d3-hierarchy/constant.js
138 d3/d3-hierarchy/hierarchy/ancestors.js
121 d3/d3-hierarchy/hierarchy/descendants.js
381 d3/d3-hierarchy/hierarchy/each.js
353 d3/d3-hierarchy/hierarchy/eachAfter.js
282 d3/d3-hierarchy/hierarchy/eachBefore.js
1819 d3/d3-hierarchy/hierarchy/index.js
164 d3/d3-hierarchy/hierarchy/leaves.js
246 d3/d3-hierarchy/hierarchy/links.js
606 d3/d3-hierarchy/hierarchy/path.js
151 d3/d3-hierarchy/hierarchy/sort.js
264 d3/d3-hierarchy/hierarchy/sum.js
2452 d3/d3-hierarchy/pack/enclose.js
1917 d3/d3-hierarchy/pack/index.js
389 d3/d3-hierarchy/pack/shuffle.js
3497 d3/d3-hierarchy/pack/siblings.js
1266 d3/d3-hierarchy/partition.js
1934 d3/d3-hierarchy/stratify.js
7060 d3/d3-hierarchy/tree.js
1184 d3/d3-hierarchy/treemap/binary.js
309 d3/d3-hierarchy/treemap/dice.js
2810 d3/d3-hierarchy/treemap/index.js
1029 d3/d3-hierarchy/treemap/resquarify.js
166 d3/d3-hierarchy/treemap/round.js
309 d3/d3-hierarchy/treemap/slice.js
170 d3/d3-hierarchy/treemap/sliceDice.js
1868 d3/d3-hierarchy/treemap/squarify.js
372 d3/d3-interpolate/array.js
600 d3/d3-interpolate/basis.js
360 d3/d3-interpolate/basisClosed.js
697 d3/d3-interpolate/color.js
72 d3/d3-interpolate/constant.js
760 d3/d3-interpolate/cubehelix.js
134 d3/d3-interpolate/date.js
547 d3/d3-interpolate/hcl.js
547 d3/d3-interpolate/hsl.js
447 d3/d3-interpolate/lab.js
100 d3/d3-interpolate/number.js
390 d3/d3-interpolate/object.js
163 d3/d3-interpolate/quantize.js
1277 d3/d3-interpolate/rgb.js
112 d3/d3-interpolate/round.js
1758 d3/d3-interpolate/string.js
672 d3/d3-interpolate/transform/decompose.js
2064 d3/d3-interpolate/transform/index.js
980 d3/d3-interpolate/transform/parse.js
598 d3/d3-interpolate/value.js
1387 d3/d3-interpolate/zoom.js
4089 d3/d3-path/path.js
243 d3/d3-polygon/area.js
346 d3/d3-polygon/centroid.js
411 d3/d3-polygon/contains.js
402 d3/d3-polygon/cross.js
1710 d3/d3-polygon/hull.js
375 d3/d3-polygon/length.js
2441 d3/d3-quadtree/add.js
1667 d3/d3-quadtree/cover.js
170 d3/d3-quadtree/data.js
206 d3/d3-quadtree/extent.js
1696 d3/d3-quadtree/find.js
134 d3/d3-quadtree/quad.js
2077 d3/d3-quadtree/quadtree.js
1898 d3/d3-quadtree/remove.js
51 d3/d3-quadtree/root.js
155 d3/d3-quadtree/size.js
695 d3/d3-quadtree/visit.js
773 d3/d3-quadtree/visitAfter.js
138 d3/d3-quadtree/x.js
138 d3/d3-quadtree/y.js
29 d3/d3-queue/array.js
2870 d3/d3-queue/queue.js
168 d3/d3-random/bates.js
113 d3/d3-random/exponential.js
137 d3/d3-random/irwinHall.js
178 d3/d3-random/logNormal.js
503 d3/d3-random/normal.js
236 d3/d3-random/uniform.js
101 d3/d3-request/csv.js
517 d3/d3-request/dsv.js
157 d3/d3-request/html.js
127 d3/d3-request/json.js
4593 d3/d3-request/request.js
109 d3/d3-request/text.js
118 d3/d3-request/tsv.js
370 d3/d3-request/type.js
174 d3/d3-request/xml.js
90 d3/d3-scale/array.js
2637 d3/d3-scale/band.js
119 d3/d3-scale/category10.js
179 d3/d3-scale/category20.js
179 d3/d3-scale/category20b.js
179 d3/d3-scale/category20c.js
101 d3/d3-scale/colors.js
72 d3/d3-scale/constant.js
3328 d3/d3-scale/continuous.js
188 d3/d3-scale/cubehelix.js
463 d3/d3-scale/identity.js
1206 d3/d3-scale/linear.js
3273 d3/d3-scale/log.js
340 d3/d3-scale/nice.js
44 d3/d3-scale/number.js
1116 d3/d3-scale/ordinal.js
1000 d3/d3-scale/pow.js
1280 d3/d3-scale/quantile.js
1066 d3/d3-scale/quantize.js
536 d3/d3-scale/rainbow.js
717 d3/d3-scale/sequential.js
802 d3/d3-scale/threshold.js
1203 d3/d3-scale/tickFormat.js
4565 d3/d3-scale/time.js
379 d3/d3-scale/utcTime.js
6471 d3/d3-scale/viridis.js
72 d3/d3-selection/constant.js
662 d3/d3-selection/creator.js
536 d3/d3-selection/local.js
533 d3/d3-selection/matcher.js
224 d3/d3-selection/mouse.js
303 d3/d3-selection/namespace.js
254 d3/d3-selection/namespaces.js
448 d3/d3-selection/point.js
259 d3/d3-selection/select.js
282 d3/d3-selection/selectAll.js
235 d3/d3-selection/selection/append.js
1460 d3/d3-selection/selection/attr.js
134 d3/d3-selection/selection/call.js
1740 d3/d3-selection/selection/classed.js
3597 d3/d3-selection/selection/data.js
132 d3/d3-selection/selection/datum.js
869 d3/d3-selection/selection/dispatch.js
289 d3/d3-selection/selection/each.js
53 d3/d3-selection/selection/empty.js
792 d3/d3-selection/selection/enter.js
176 d3/d3-selection/selection/exit.js
546 d3/d3-selection/selection/filter.js
520 d3/d3-selection/selection/html.js
2216 d3/d3-selection/selection/index.js
468 d3/d3-selection/selection/insert.js
171 d3/d3-selection/selection/lower.js
575 d3/d3-selection/selection/merge.js
258 d3/d3-selection/selection/node.js
140 d3/d3-selection/selection/nodes.js
3119 d3/d3-selection/selection/on.js
367 d3/d3-selection/selection/order.js
617 d3/d3-selection/selection/property.js
138 d3/d3-selection/selection/raise.js
153 d3/d3-selection/selection/remove.js
653 d3/d3-selection/selection/select.js
550 d3/d3-selection/selection/selectAll.js
98 d3/d3-selection/selection/size.js
681 d3/d3-selection/selection/sort.js
71 d3/d3-selection/selection/sparse.js
889 d3/d3-selection/selection/style.js
528 d3/d3-selection/selection/text.js
152 d3/d3-selection/selector.js
171 d3/d3-selection/selectorAll.js
175 d3/d3-selection/sourceEvent.js
407 d3/d3-selection/touch.js
323 d3/d3-selection/touches.js
218 d3/d3-selection/window.js
8831 d3/d3-shape/arc.js
2917 d3/d3-shape/area.js
42 d3/d3-shape/array.js
81 d3/d3-shape/constant.js
1436 d3/d3-shape/curve/basis.js
1530 d3/d3-shape/curve/basisClosed.js
1069 d3/d3-shape/curve/basisOpen.js
1081 d3/d3-shape/curve/bundle.js
1633 d3/d3-shape/curve/cardinal.js
1605 d3/d3-shape/curve/cardinalClosed.js
1288 d3/d3-shape/curve/cardinalOpen.js
2637 d3/d3-shape/curve/catmullRom.js
2083 d3/d3-shape/curve/catmullRomClosed.js
1760 d3/d3-shape/curve/catmullRomOpen.js
738 d3/d3-shape/curve/linear.js
514 d3/d3-shape/curve/linearClosed.js
3203 d3/d3-shape/curve/monotone.js
1761 d3/d3-shape/curve/natural.js
655 d3/d3-shape/curve/radial.js
1367 d3/d3-shape/curve/step.js
86 d3/d3-shape/descending.js
43 d3/d3-shape/identity.js
1516 d3/d3-shape/line.js
106 d3/d3-shape/math.js
29 d3/d3-shape/noop.js
319 d3/d3-shape/offset/expand.js
310 d3/d3-shape/offset/none.js
314 d3/d3-shape/offset/silhouette.js
740 d3/d3-shape/offset/wiggle.js
305 d3/d3-shape/order/ascending.js
112 d3/d3-shape/order/descending.js
545 d3/d3-shape/order/insideOut.js
120 d3/d3-shape/order/none.js
97 d3/d3-shape/order/reverse.js
2336 d3/d3-shape/pie.js
81 d3/d3-shape/point.js
934 d3/d3-shape/radialArea.js
396 d3/d3-shape/radialLine.js
1432 d3/d3-shape/stack.js
186 d3/d3-shape/symbol/circle.js
476 d3/d3-shape/symbol/cross.js
307 d3/d3-shape/symbol/diamond.js
137 d3/d3-shape/symbol/square.js
609 d3/d3-shape/symbol/star.js
255 d3/d3-shape/symbol/triangle.js
733 d3/d3-shape/symbol/wye.js
1160 d3/d3-shape/symbol.js
867 d3/d3-time-format/defaultLocale.js
284 d3/d3-time-format/isoFormat.js
319 d3/d3-time-format/isoParse.js
13876 d3/d3-time-format/locale.js
462 d3/d3-time/day.js
164 d3/d3-time/duration.js
569 d3/d3-time/hour.js
1845 d3/d3-time/interval.js
668 d3/d3-time/millisecond.js
437 d3/d3-time/minute.js
414 d3/d3-time/month.js
440 d3/d3-time/second.js
397 d3/d3-time/utcDay.js
399 d3/d3-time/utcHour.js
412 d3/d3-time/utcMinute.js
453 d3/d3-time/utcMonth.js
979 d3/d3-time/utcWeek.js
808 d3/d3-time/utcYear.js
963 d3/d3-time/week.js
754 d3/d3-time/year.js
400 d3/d3-timer/interval.js
250 d3/d3-timer/timeout.js
2771 d3/d3-timer/timer.js
484 d3/d3-transition/active.js
665 d3/d3-transition/interrupt.js
245 d3/d3-transition/selection/index.js
138 d3/d3-transition/selection/interrupt.js
1090 d3/d3-transition/selection/transition.js
2473 d3/d3-transition/transition/attr.js
904 d3/d3-transition/transition/attrTween.js
510 d3/d3-transition/transition/delay.js
528 d3/d3-transition/transition/duration.js
348 d3/d3-transition/transition/ease.js
574 d3/d3-transition/transition/filter.js
1892 d3/d3-transition/transition/index.js
340 d3/d3-transition/transition/interpolate.js
653 d3/d3-transition/transition/merge.js
853 d3/d3-transition/transition/on.js
284 d3/d3-transition/transition/remove.js
4792 d3/d3-transition/transition/schedule.js
826 d3/d3-transition/transition/select.js
883 d3/d3-transition/transition/selectAll.js
174 d3/d3-transition/transition/selection.js
2119 d3/d3-transition/transition/style.js
607 d3/d3-transition/transition/styleTween.js
473 d3/d3-transition/transition/text.js
691 d3/d3-transition/transition/transition.js
2026 d3/d3-transition/transition/tween.js
4381 d3/d3-voronoi/Beach.js
4087 d3/d3-voronoi/Cell.js
1632 d3/d3-voronoi/Circle.js
72 d3/d3-voronoi/constant.js
3415 d3/d3-voronoi/Diagram.js
3634 d3/d3-voronoi/Edge.js
81 d3/d3-voronoi/point.js
5302 d3/d3-voronoi/RedBlackTree.js
1420 d3/d3-voronoi/voronoi.js
72 d3/d3-zoom/constant.js
137 d3/d3-zoom/event.js
202 d3/d3-zoom/noevent.js
1336 d3/d3-zoom/transform.js
12133 d3/d3-zoom/zoom.js
hierD3 = new function() {
"use strict";
var self = this;
const defaults = {
viz: "sunburst",
rootName: "root",
title: "100vw", // 100% viewport width
width: "100vh", // 100% viewport height
height: null,
valueField: "size",
colorField: null,
stat: "identity", // possible choices: identity, sum, and count
buttons: false, // show buttons to switch layout
transitionDuration: 350,
showNumbers: false,
numberFormat: ",d",
sunburstLabelsRadiate: false,
circleNumberFormat: ".2s",
stratify: false,
stratifyId: "id",
stratifyParentId: "parent"
};
var opts = defaults;
var root = null;
var nodes = null;
var totalSize = null;
var svg = null;
var boundingBox = null;
var width, height, maxRadius = null;
//var el = null;
//var colorScale = null;
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
var formatNumber = null;
var formatCircleNumber = null;
self.viz = function(svg1, data, viz, o = null) {
for (var opt in o) { opts[opt] = o[opt]; }
formatNumber = d3.format(opts.numberFormat);
formatCircleNumber = d3.format(opts.circleNumberFormat);
//svg = d3.select(el).append('svg')
// .style("width", opts.width).style("height", opts.height)
// .attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`);
svg = d3.select(svg1);
console.log("boundingbox");
//boundingBox = svg.node().getBBox(); // doesn't work in observablehq
boundingBox = { width: 1000, height: 1000 };
console.log(boundingBox);
width = boundingBox.width;
height = boundingBox.height;
maxRadius = Math.min(width, height)/2 -5;
// .style("width", "100%")
// .style("height", "auto")
svg.append("style").text(`
.slice { cursor: pointer; }
.slice .main-arc { stroke: #fff; stroke-width: 1px; }
.slice .hidden-arc { fill: none; }
.slice text { pointer-events: none; dominant-baseline: middle; text-anchor: middle; }
.slice .text-countour { fill: none; stroke: #fff; stroke-width: 5; stroke-linejoin: round; }
rect { stroke: #fff; }
`);
//attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`);
//svg = d3.select(el).append('svg')
// .attr("width", width).attr("height", height);
if (opts.stratify) {
var stratify = d3.stratify()
.id(d => d[opts.stratifyId])
.parentId(d => d[opts.stratifyParentId]);
console.log(data)
data = stratify(data)
}
root = d3.hierarchy(data);
nodes = root.descendants();
//TODO: Check that root.data.children[0] has field valueField!
switch(opts.stat) {
case "sum":
root.sum(d => typeof d[opts.valueField] !== undefined? d[opts.valueField] : 0);
break;
case "count":
root.count();
break;
default: //identity by default
root.each(function(node) { node.value = node.data[opts.valueField]; });
root.value = d3.sum(root.children, d => d.value);
break;
}
root.data.name = opts.rootName;
totalSize = root.value;
const visualizations = [ "icicle", "treemap", "partition", "pack", "sunburst" ];
//button_form = d3.select(el).append('form')
switch(viz) {
case "icicle":
this.icicle();
break;
case "treemap":
this.treemap();
break;
case "partition":
this.partition();
break;
case "pack":
this.pack();
break;
//case sunburst:
default:
this.sunburst();
break;
}
return svg.node();
}
self.pack = function() {
// from Bostock - Zoomable circle packing
const margin = 20,
diameter = width
const pack1 = svg.append("g")
.attr("transform", "translate("+diameter/2+","+diameter/2+")")
var pack = d3.pack().size([diameter, diameter]).padding(2);
var circle = pack1.selectAll("circle")
.data(pack(root).descendants())
.enter().append("circle")
.style("fill", color)
}
self.treemap = function() {
// Make it look nicer - see ganeshv's block
self.icicle(false, true)
}
self.partition = function() {
self.icicle(true);
}
self.icicle = function(horizontal=false, is_treemap=false) {
if (is_treemap) {
const treemap = d3.treemap()
.tile(d3.treemapResquarify)
.size([width, height])
.round(true)
.paddingInner(1);
treemap(root);
nodes = root.leaves()
} else {
var partition = d3.partition()
.padding(0)
.round(true);
if (horizontal) {
partition.size([height, width])
} else {
partition.size([width, height])
}
partition(root);
}
const x = d3.scaleLinear()
.range([0, width]);
const y = d3.scaleLinear()
.range([0, height]);
var icicle = svg.selectAll(".node")
.data(nodes).enter().append("g")
var x0 = "x0",
x1 = "x1",
y0 = "y0",
y1 = "y1"
if (horizontal) {
x0 = "y0"
x1 = "y1"
y0 = "x0"
y1 = "x1"
}
var rect = icicle.append("rect")
.attr("id", (_, i) => "rect-" + i)
.attr("x", d => d[x0] )
.attr("y", d => d[y0] )
.attr("width", d => d[x1] - d[x0])
.attr("height", d => d[y1] - d[y0])
.attr('fill', color)
.style("cursor", "pointer")
.on("click", clicked);
rect.append('title')
.text(d => d.data.name + '\n' + formatNumber(d.value));
icicle.append("clipPath")
.attr("id", (d, i) => "clip-" + i)
.append("use")
.attr("xlink:href", (_, i) => "#rect-" + i);
var text = icicle.append("text")
.attr("clip-path", (_, i) => "url(#clip-" + i + ")")
.attr("x", d => d[x0] )
.attr("y", d => d[y0] )
.style("cursor", "pointer")
.style("dominant-baseline", "hanging")
.text(d => d.data.name)
.on("click", clicked)
text.append('title')
.text(d => d.data.name + '\n' + formatNumber(d.value));
function clicked(d) {
if (horizontal) {
x.domain([d[x0], width]).range([d.depth? width / 10 : 0, width]);
y.domain([d[y0], d[y1]]);
} else {
x.domain([d[x0], d[x1]]);
y.domain([d[y0], height]).range([d.depth? height / 10 : 0, height]);
}
rect.transition().duration(opts.transitionDuration)
.attr("x", d => x(d[x0]))
.attr("y", d => y(d[y0]))
.attr("width", d => x(d[x1]) - x(d[x0]))
.attr("height", d => y(d[y1]) - y(d[y0]));
text.transition().duration(opts.transitionDuration)
.attr("x", d => x(d[x0]))
.attr("y", d => y(d[y0]))
}
}
self.sunburst = function() {
var partition = d3.partition();
partition(root);
svg.attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`);
svg.on('click', () => focusOn()); // Reset zoom on canvas click
const x = d3.scaleLinear()
.range([0, 2 * Math.PI])
.clamp(true);
const y = d3.scaleSqrt()
.range([maxRadius*.1, maxRadius]);
const arc = d3.arc()
.startAngle(d => x(d.x0))
.endAngle(d => x(d.x1))
.innerRadius(d => Math.max(0, y(d.y0)))
.outerRadius(d => Math.max(0, y(d.y1)));
const middleArcLine = d => {
const halfPi = Math.PI/2;
const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi];
const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);
const middleAngle = (angles[1] + angles[0]) / 2;
const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw
if (invertDirection) { angles.reverse(); }
const path = d3.path();
path.arc(0, 0, r, angles[0], angles[1], invertDirection);
return path.toString();
};
const slice = svg.selectAll('g.slice').data(nodes);
slice.exit().remove();
const newSlice = slice.enter()
.append('g').attr('class', 'slice')
.on('click', d => {
d3.event.stopPropagation();
focusOn(d);
});
newSlice.append('title')
.text(d => d.data.name + '\n' + formatNumber(d.value));
newSlice.append('path')
.attr('id', (_, i) => `mainArc-${i}`)
.attr('class', 'main-arc')
.style('fill', color)
.attr('d', arc);
newSlice.append("clipPath")
.attr("id", (_, i) => "clip-" + i)
.append("use")
.attr("xlink:href", (_, i) => "#mainArc-" + i);
newSlice.append('path')
.attr('class', 'hidden-arc')
.attr('id', (_, i) => `hiddenArc${i}`)
.attr('d', middleArcLine);
const text = newSlice.append('text');
if (opts.sunburstContour) {
// Add white contour
text.append('textPath')
.attr('startOffset','50%')
.attr('xlink:href', (_, i) => `#hiddenArc${i}` )
.text(d => d.data.name)
.attr('class', 'text-contour');
}
if (opts.sunburstLabelsRadiate) {
// TODO: fix that
text
.attr("transform", function(d) {
var angle = (x(d.x0) + x(d.x1))*90/Math.PI - 90
var res= "translate("+arc.centroid(d)+")rotate("+ ((angle > 90 || angle < -90)? angle - 180 : angle) +")"
return res;
})
.text(d => opts.showNumbers? (d.data.name + '\n' + formatCircleNumber(d.value)) : d.data.name);
} else {
text
.attr("clip-path", (_, i) => "url(#clip-" + i + ")")
.append('textPath')
.attr('startOffset','50%')
.attr('xlink:href', (_, i) => `#hiddenArc${i}` )
.text(d => opts.showNumbers? (d.data.name + '\n' + formatCircleNumber(d.value)) : d.data.name);
}
function focusOn(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) {
// Reset to top-level if no data point specified
const transition = svg.transition()
.duration(opts.transitionDuration)
.tween('scale', () => {
const xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
yd = d3.interpolate(y.domain(), [d.y0, 1]);
return t => { x.domain(xd(t)); y.domain(yd(t)); };
});
transition.selectAll('path.main-arc')
.attrTween('d', d => () => arc(d));
transition.selectAll('path.hidden-arc')
.attrTween('d', d => () => middleArcLine(d));
moveStackToFront(d);
function moveStackToFront(elD) {
svg.selectAll('.slice').filter(d => d === elD)
.each(function(d) {
this.parentNode.appendChild(this);
if (d.parent) { moveStackToFront(d.parent); }
})
}
}
function computeTextRotation(d) {
return ((d.x0 + d.x1)/2 - Math.PI / 2) / Math.PI * 180;
}
}
// Internal functions and constants
const CHAR_SPACE = 6;
const color = function(d) {
if (opts.colorField !== null) {
return d.data[opts.colorField];
}
return(colorScale(d.data.name));
/*else if (d.children) {
return d3.rgb(colorScale(d.data.name)).brighter(d.depth/5);
} else {
return d3.rgb(colorScale(d.parent.data.name)).brighter(d.depth/5);
} */
};
}
<!DOCTYPE html>
<svg width="960" height="960"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="hierD3.js"></script>
<svg id="h1" width=960 height=960> </svg>
<svg id="h2" width=960 height=960> </svg>
<svg id="h3" width=960 height=960> </svg>
<script>
hierD3.viz("svg#h1", data, "partition", {valueField: "size", stat: "sum"})
hierD3.viz("svg#h2", data, "sunburst", {valueField: "size", stat: "sum"})
hierD3.viz("svg#h3", data, "icicle", {valueField: "size", stat: "sum"})
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment