UNPKG

8.46 kBJavaScriptView Raw
1var domready = require('domready')
2 , pretty = require('prettysize')
3 , schemes = require('./schemes')
4 , d3 = require('d3')
5
6var arc = d3.svg.arc()
7 .startAngle(function(d) { return angle(d.x) })
8 .endAngle(function(d) { return angle(d.x + Math.max(d.dx - 0.025, 0.0125)) })
9 .innerRadius(function(d) { return Math.sqrt(d.y) })
10 .outerRadius(function(d) { return Math.sqrt(d.y + d.dy * 0.65) })
11
12var initArc = d3.svg.arc()
13 .startAngle(function(d) { return angle(d.x) })
14 .endAngle(function(d) { return angle(d.x + d.dx) })
15 .innerRadius(function(d) { return Math.sqrt(d.y) })
16 .outerRadius(function(d) { return Math.sqrt(d.y) })
17
18domready(function() {
19 var root = window.disc
20 , width = window.innerWidth
21 , height = Math.max(window.innerHeight - 100, 100)
22 , radius = Math.min(width, height) * 0.45
23 , deg = 120
24
25 var svg = d3.select('.chart').append('svg')
26 .attr('width', width)
27 .attr('height', height)
28 .append('g')
29 .attr('transform', 'translate(' + width / 2 + ',' + height * .52 + ')')
30
31 var palettes = d3.select('.palette-wrap')
32 .style('top', String(window.innerHeight - (schemes.length - 1) * 56 - 16) + 'px')
33 .selectAll('.palette')
34 .data(schemes)
35 .enter()
36 .append('svg')
37 .style('display', 'inline-block')
38 .classed('palette', true)
39 .on('click', function(d, i) {
40 useScheme(i, path.transition()
41 .duration(600)
42 .ease(bounce_high, 1000)
43 .delay(function(d, i) {
44 return d.x * 100 + d.y / maxdepth * 0.06125
45 })
46 )
47 })
48
49 palettes.append('rect')
50 .attr('width', 23)
51 .attr('height', 48)
52 .style('fill', function(d) {
53 return d.background
54 })
55
56 palettes.selectAll('.color')
57 .data(function(d) { return d.all })
58 .enter()
59 .append('rect')
60 .style('fill', function(d) { return d })
61 .attr('x', 25)
62 .attr('y', function(d, i, j) {
63 return 48 * i / schemes[j].all.length - 1
64 })
65 .attr('width', 22)
66 .attr('height', function(d, i, j) {
67 return 48 / schemes[j].all.length - 1
68 })
69
70 var partition = d3.layout.partition()
71 .sort(null)
72 .size([2 * Math.PI, radius * radius])
73 .value(function(d) { return 1 })
74
75 //
76 // Creates the title text in
77 // the center of the rings.
78 //
79 var title = svg.append('text')
80 .text(root.name)
81 .attr('x', 0)
82 .attr('y', -5)
83 .style('font-size', '12px')
84 .style('fill', 'white')
85 .style('font-weight', 500)
86 .style('alignment-baseline', 'middle')
87 .style('text-anchor', 'middle')
88
89 //
90 // Likewise, this is the file
91 // size stat below the title
92 //
93 var size = svg.append('text')
94 .text(pretty(root.size))
95 .attr('x', 0)
96 .attr('y', 15)
97 .style('fill', 'white')
98 .style('font-size', '10px')
99 .style('alignment-baseline', 'middle')
100 .style('text-anchor', 'middle')
101
102 //
103 // Each arc is wrapped in a group element,
104 // to apply rotation transforms while
105 // changing size and shape.
106 //
107 var groups = svg.datum(root).selectAll('g')
108 .data(partition.nodes)
109 .enter()
110 .append('g')
111 .attr('transform', 'rotate(' + deg + ')')
112
113 var maxdepth = groups[0].reduce(function(max, el) {
114 return Math.max(max, el.__data__.depth)
115 }, 0)
116
117 //
118 // Actually create the arcs for each
119 // file.
120 //
121 var path = groups.append('path')
122 .attr('d', initArc)
123 .attr('display', function(d) {
124 return d.depth ? null : 'none'
125 })
126 .style('stroke', '#2B2B2B')
127 .style('stroke-width', '0')
128 .style('fill-rule', 'evenodd')
129 .each(function(d) {
130 d.x0 = d.x
131 d.dx0 = d.dx
132 d.el = this
133 })
134
135 //
136 // Colour scheme functionality.
137 //
138 // Triggered immediately with the default
139 // scheme, must be passed a d3 selection.
140 //
141 var background
142 , scheme = 0
143 , specials
144 , color
145
146 useScheme(scheme, path)
147 function useScheme(n, path) {
148 background = schemes[n].background
149 specials = schemes[n].specials
150
151 palettes
152 .transition()
153 .ease('bounce')
154 .duration(500)
155 .attr('height', function(d, i) {
156 return i === n ? 0 : 48
157 })
158
159 ;[d3.select('body')
160 , d3.select('html')].forEach(function(el) {
161 el.transition()
162 .ease('sin-in-out')
163 .duration(600)
164 .style('background', background)
165 })
166
167 var colors = schemes[n].main
168 Object.keys(specials).forEach(function(key) {
169 var idx = colors.indexOf(specials[key].toLowerCase())
170 if (idx === -1) return
171 colors.splice(idx, 1)
172 })
173
174 color = d3.scale
175 .ordinal()
176 .range(colors)
177
178 path.style('fill', function(d) {
179 var name = d.children ? d.name : d.parent.name
180 return d.c = schemes[n].modifier.call(d, specials[name] || color(name), root)
181 })
182 }
183
184 path.transition()
185 .duration(1000)
186 .ease('elastic', 2, 1)
187 .delay(function(d, i) {
188 return d.x * 100 + (i % 4) * 250 + d.y / maxdepth * 0.25
189 })
190 .attr('d', arc)
191
192 //
193 // Rotates the newly created
194 // arcs back towards their original
195 // position.
196 //
197 groups.transition()
198 .duration(3250)
199 .delay(function(d, i) {
200 return d.x * 100 + (i % 4) * 250 + d.y / maxdepth * 0.25 + 250
201 })
202 .attrTween('transform', rotateTween(deg))
203
204 groups.on('mouseover', function(d) {
205 highlight(d)
206 title.text(d.name)
207 size.text(pretty(d.size))
208 }).on('mouseout', function(d) {
209 unhighlight(d)
210 title.text(root.name)
211 size.text(pretty(root.size))
212 })
213
214 highlight.tween = hoverTween(1)
215 function highlight(d) {
216 if (d.el) d3.select(d.el)
217 .transition()
218 .delay(function(d) { return (d.depth - 1) * 300 / maxdepth })
219 .ease('back-out', 10)
220 .duration(500)
221 .attrTween('d', highlight.tween)
222 .style('fill', function(d) { return d.c })
223
224 if (d.children) {
225 var i = d.children.length
226 while (i--) highlight(d.children[i])
227 }
228 }
229
230 unhighlight.tween = hoverTween(0)
231 function unhighlight(d) {
232 if (d.el) d3.select(d.el)
233 .transition()
234 .delay(function(d) { return (d.depth - 1) * 300 / maxdepth })
235 .ease('back-out', 4)
236 .duration(500)
237 .attrTween('d', unhighlight.tween)
238 .style('fill', function(d) { return d.c })
239
240 if (d.children) {
241 var i = d.children.length
242 while (i--) unhighlight(d.children[i])
243 }
244 }
245
246 var modes = d3.selectAll('[data-mode]')
247 modes.on('click', function change() {
248 var value
249 switch (this.getAttribute('data-mode')) {
250 case 'count':
251 default:
252 value = function() { return 1 }
253 break
254 case 'size':
255 value = function(d) { return d.size }
256 break
257 }
258
259 modes.style('opacity', null)
260 d3.select(this).style('opacity', 1)
261
262 groups
263 .data(partition.value(value).nodes)
264 .select('path')
265 .transition()
266 .duration(1500)
267 .attrTween('d', arcTween)
268 })
269})
270
271function angle(x) {
272 return x
273}
274
275// Modified version of d3's built-in bounce easing method:
276// https://github.com/mbostock/d3/blob/51228ccc4b54789f2d92d268e94716d1c016c774/src/interpolate/ease.js#L105-110
277function bounce_high(t) {
278 return t < 1 / 2.75 ? 7.5625 * t * t
279 : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .65
280 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .85
281 : 7.5625 * (t -= 2.625 / 2.75) * t + .975
282}
283
284function arcTween(a) {
285 var i = d3.interpolate({x: a.x0, dx: a.dx0}, a)
286 return function(t) {
287 var b = i(t)
288 a.x0 = b.x
289 a.dx0 = b.dx
290 return arc(b)
291 }
292}
293
294//
295// A more complex arc tween for handling
296// hover states. Returns a tween function
297// which returns an interpolator for each
298// datum.
299//
300function hoverTween(z) {
301 var ht = 0
302 var harc = d3.svg.arc()
303 .startAngle(function(d) {
304 return angle(d.x)
305 })
306 .endAngle(function(d) {
307 return angle(d.x
308 + (1 - ht) * Math.max(d.dx - 0.025, 0.0125)
309 + ht * (d.dx + 0.00005)
310 )
311 })
312 .innerRadius(function(d) {
313 return Math.sqrt(d.y)
314 })
315 .outerRadius(function(d) {
316 return Math.sqrt(d.y + d.dy * (ht * 0.35 + 0.65)) + ht
317 })
318
319 return function(a) {
320 a.t0 = a.t3 = a.t0 || 0
321 a.t1 = z
322 a.t2 = a.t1 - a.t0
323 return function(_t) {
324 ht = a.t2 * _t + a.t3
325 a.t0 = ht
326 return harc(a)
327 }
328 }
329}
330
331//
332// Makes it possible to rotate
333// angles greater than 180 degrees :)
334//
335function rotateTween(deg) {
336 return function(d) {
337 return function(t) {
338 return 'rotate(' + (1-t) * deg + ')'
339 }
340 }
341}