Last active
July 13, 2019 17:23
-
-
Save vkuchinov/a8900e6f1f14255fdbcc22cd0de10ec9 to your computer and use it in GitHub Desktop.
D3.JS Pie Stacks Mockup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var svg, chart, background, g, defs, div, fulldata, data, w = 800, h = 600, dist, offset = 64, vratio = 1.0, radius = 18, zAxis, zValues, ratio = 0.3814, stacksData = [], filter = false, filtered = [true, true, true], maxRation;; | |
var offset = 64; | |
var days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; //could be German or whatever | |
var states = ["Red Zone", "Yellow Zone", "Red Zone"]; | |
var maxStack = Number.NEGATIVE_INFINITY; | |
var colors = ["#F0F0F0", "#FF652F", "#FFE400", "#14A76C"]; | |
var scale = 20.0; | |
var zl = { x: -11.070 * scale, y: -11.993 * scale }, | |
zm = { x: 0.0 * scale, y: -14.392 * scale }, | |
zr = { x: 12.749 * scale, y: -12.466 * scale }, | |
tp = { x: 0.0, y: 0.0 }, | |
rp = { x: 12.749 * scale, y: 5.044 * scale }, | |
bp = { x: 2.887 * scale, y: 14.904 * scale }, | |
lp = { x: -11.070 * scale, y: 6.277 * scale }; | |
d3.legend = function(){ | |
function legend(selection_){ | |
selection_.each(function(d_, i_) { | |
var g = d3.select(this).attr("transform", "translate(" + d_.x + "," + d_.y + ")") | |
var back = g.append("rect") | |
.attr("width", d_.w) | |
.attr("height", d_.h) | |
.attr("fill", "#DEDEDE") | |
.attr("opacity", 0.5); | |
var legendlabels = g.selectAll(".legendlabel") | |
.data(d_.states) | |
.enter() | |
.append("text") | |
.attr("class", function(d2_, j_){ return "legendText_" + j_; }) | |
.attr("dx", 40) | |
.attr("dy", function(d2_, j_){ return 25 + j_ * 25; }) | |
.text(function(d_){ return d_; }) | |
var boxes = g.selectAll(".box") | |
.data(d_.states) | |
.enter() | |
.append("rect") | |
.attr("class", function(d2_, j_){ return "legendRect_" + j_; }) | |
.attr("x", 20) | |
.attr("y", function(d2_, j_){ return 16 + j_ * 25; }) | |
.attr("width", 12) | |
.attr("height", 12) | |
.attr("fill", function(d2_, j_){ return colors[j_ + 1]; }); | |
var placeholder = g.selectAll(".box") | |
.data(d_.states) | |
.enter() | |
.append("rect") | |
.attr("x", 10) | |
.attr("y", function(d2_, j_){ return 11 + j_ * 25; }) | |
.attr("width", 108) | |
.attr("height", 22) | |
.attr("fill", "transparent") | |
.on("click", function(d2_, j_){ | |
filtered[j_] = !filtered[j_]; | |
if(filtered[j_]){ | |
d3.select(".legendText_" + j_).attr("fill", "#000000"); | |
d3.select(".legendRect_" + j_).attr("fill", colors[j_ + 1]); | |
drawPieStacks(); | |
}else{ | |
if(atLeastOneLeft()){ | |
d3.select(".legendText_" + j_).attr("fill", "#808080"); | |
d3.select(".legendRect_" + j_).attr("fill", "#808080"); | |
drawPieStacks(); | |
} | |
} | |
}) | |
}); | |
} | |
return legend; | |
} | |
d3.pieStack = function(){ | |
function pieStack(selection_){ | |
selection_.each(function(d_, i_) { | |
var g = d3.select(this).attr("transform", "translate(" + (128 + (800 - 128)/ 10 * d_.y) + "," + ( 64 + (600 - 64) / days.length * d_.x) + ")") | |
var total = d_.total / maxRatio; | |
var outer = total, inner = total * 0.5; | |
this.arc = d3.arc().innerRadius(inner).outerRadius(outer); | |
this.pie = d3.pie().value(function(d2_) { return d2_.size; }).sort(null); | |
this.path = g.selectAll("path") | |
.attr("class", "chartElement") | |
.data(this.pie(d_.pie.children)) | |
.enter() | |
.append("g") | |
.append("path") | |
.attr("d", this.arc) | |
.attr("fill", function(d2_) { return d2_.data.color; }) | |
.on("mouseover", function(d2_){ | |
var str = d2_.data.size + " tickets " + states[d2_.index] + " on " + d_.d + ", " + d_.a + " days old"; | |
div.transition().duration(500).style("opacity", 0.9); | |
div.html(str).style("left", (d3.event.pageX) + "px").style("top", (d3.event.pageY - 28) + "px"); | |
}) | |
.on("mouseout", function(d2_){ | |
div.transition().duration(500).style("opacity", 0); | |
}); | |
g.append("text") | |
.attr("class", "chartElement") | |
.text(function(d2_){ if(outer > 15) { return d_.total; }}) | |
.attr("text-anchor", "middle") | |
.attr("font-size", "8px") | |
.attr("dy", ".3em") | |
}); | |
} | |
function filterStack(stacks_){ | |
var out = []; | |
stacks_.forEach(function(d_, i_){ if(filtered[i_]) { out.push(d_); } }); | |
return out; | |
} | |
return pieStack; | |
} | |
d3.json("mockup.json", function(error_, data_) { | |
if (error_) throw error_; | |
fulldata = data_; | |
inits(); | |
}); | |
function inits(){ | |
console.log("%cWeekly Ticket Pie Grid β demo", "color: #494949; font-size: 18px; font-family: sans-serif;"); | |
console.log("%cby Vladimir V KUCHINOV", "color: #494949; font-size: 12px; font-style: italic;font-family: sans-serif;"); | |
svg = d3.select("body").append("svg") | |
.attr("preserveAspectRatio", "xMinYMin meet") | |
.attr("viewBox", "0 0 " + w + " " + h) | |
.classed("svg-content", true); | |
background = svg.append("rect").attr("width", w).attr("height", h).attr("fill", "transparent").on("click", function(){ filter = false, d3.selectAll(".cylinder").attr("opacity", 1.0); }); | |
defs = svg.append("defs"); | |
div = d3.select("#tooltip"); | |
var weekdays = svg.selectAll(".weekday") | |
.data(days) | |
.enter() | |
.append("text") | |
.attr("dx", 48) | |
.attr("dy", function(d_, i_) { return 64 + (600 - 64) / days.length * i_; }) | |
.attr("text-ancho", "end") | |
.text(function(d_) { return d_; }); | |
var ages = svg.selectAll(".age") | |
.data(new Array(10).fill(0)) | |
.enter() | |
.append("text") | |
.attr("dx", function(d_, i_) { return 128 + (800 - 128)/ 10 * i_; }) | |
.attr("dy", 24) | |
.attr("text-ancho", "end") | |
.text(function(d_, i_) { return i_ + 1; }) | |
drawPieStacks(); | |
var legend = svg.selectAll(".legendBox") | |
.data([{states: states, x: w - 38 - 128, y: 38, w: 128, h: 92 }]) | |
.enter().append("g") | |
.attr("class", "legendBox") | |
.call(d3.legend()); | |
} | |
function atLeastOneLeft(){ | |
var T = 0; | |
filtered.forEach(function(f_){ if(f_) { T++; } }); | |
return T > 0 ? true : false; | |
} | |
function drawPieStacks(){ | |
parseData(fulldata); | |
d3.selectAll("#chart").remove(); | |
d3.selectAll(".chartElement").remove(); | |
var g = svg.append("g").attr("id", "chart"); | |
var stacks = g.selectAll(".stack") | |
.data(stacksData) | |
.enter() | |
.append("g") | |
.call(d3.pieStack()) | |
} | |
function parseData(data_){ | |
stacksData = []; | |
maxStack = 0; | |
var EPS = 5; | |
var days = Object.keys(data_); | |
days.forEach(function(d_, i_){ | |
data_[d_].forEach(function(a_, j_){ | |
var total = 0.0; | |
data = { name: d_ + ", " + a_.age + " days old", children: [] }; | |
a_.stack.forEach(function(s_, k_){ | |
if(filtered[k_]){ data.children.push({ group: k_, name : states[k_], color: colors[k_ + 1], size: s_}); total += s_; } | |
}) | |
stacksData.push({ x: i_ , y: j_, d: d_, a: a_.age, stack: a_.stack, pie : data, total: total }) | |
maxStack = Math.max(maxStack, total); | |
}) | |
}); | |
maxRatio = maxStack / 34.0; | |
} | |
function average1D(v0_, v1_){ return (Number(v0_) + Number(v1_)) / 2.0; } | |
function remapFloat(v_, min0_, max0_, min1_, max1_) { | |
return min1_ + (v_ - min0_) / (max0_ - min0_) * (max1_ - min1_); | |
} | |
function distance(x0_, y0_, x1_, y1_){ | |
return Math.sqrt(Math.pow(x1_ - x0_, 2) + Math.pow(y1_ - y0_, 2)); | |
} | |
function distance2D(v0_, v1_){ | |
return Math.sqrt(Math.pow(v1_.x - v0_.x, 2) + Math.pow(v1_.y - v0_.y, 2)); | |
} | |
function lerp2D(v0_, v1_, t_){ | |
return { x: v0_.x * t_ + (1.0 - t_) * v1_.x, y: v0_.y * t_ + (1.0 - t_) * v1_.y }; | |
} | |
function lerp1D(f0_, f1_, t_){ return f0_ * t_ + (1.0 - t_) * f1_; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Weekly Ticket Pie Grid φ demo</title> | |
<script src="http://d3js.org/d3.v4.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script> | |
<style> | |
@import url("https://fonts.googleapis.com/css?family=Karla&display=swap"); | |
body{ margin: 0; font-family: 'Karla', sans-serif; font-size: 12px; } | |
#d3placeholder { | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
} | |
#tooltip { | |
position: absolute; | |
text-align: center; | |
padding: 8px; | |
font: 12px sans-serif; | |
background-color: #DEDEDE; | |
border: 0px; | |
border-radius: 8px; | |
pointer-events: none; | |
opacity: 0.0; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="d3placeholder"></div> | |
<script src="app.js"></script> | |
<div id="tooltip"></div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"Mon":[ | |
{ | |
"age": 1, | |
"stack":[ | |
23, | |
26, | |
32 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
15, | |
24, | |
44 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
124, | |
109, | |
200 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
151, | |
99, | |
151 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
197, | |
141, | |
279 | |
] | |
}, | |
{ | |
"age" :6, | |
"stack":[ | |
105, | |
111, | |
240 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
163, | |
101, | |
199 | |
] | |
} | |
], | |
"Tue":[ | |
{ | |
"age": 1, | |
"stack":[ | |
204, | |
131, | |
249 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
22, | |
21, | |
32 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
24, | |
24, | |
63 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
154, | |
100, | |
202 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
110, | |
100, | |
200 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
142, | |
132, | |
237 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
97, | |
68, | |
120 | |
] | |
}, | |
{ | |
"age":8, | |
"stack":[ | |
85, | |
55, | |
108 | |
] | |
} | |
], | |
"Wed":[ | |
{ | |
"age": 1, | |
"stack":[ | |
137, | |
109, | |
269 | |
] | |
}, | |
{ | |
"age":2, | |
"stack":[ | |
140, | |
132, | |
255 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
22, | |
21, | |
40 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
69, | |
24, | |
82 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
107, | |
114, | |
250 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
132, | |
98, | |
208 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
121, | |
122, | |
223 | |
] | |
}, | |
{ | |
"age": 8, | |
"stack":[ | |
75, | |
60, | |
135 | |
] | |
}, | |
{ | |
"age": 9, | |
"stack":[ | |
75, | |
50, | |
90 | |
] | |
} | |
], | |
"Thu":[ | |
{ | |
"age": 1, | |
"stack":[ | |
125, | |
120, | |
250 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
130, | |
105, | |
236 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
143, | |
102, | |
241 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
20, | |
20, | |
31 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
28, | |
22, | |
40 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
112, | |
65, | |
90 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
40, | |
50, | |
120 | |
] | |
}, | |
{ | |
"age": 8, | |
"stack":[ | |
75, | |
75, | |
100 | |
] | |
}, | |
{ | |
"age": 9, | |
"stack":[ | |
60, | |
40, | |
70 | |
] | |
}, | |
{ | |
"age": 10, | |
"stack":[ | |
50, | |
35, | |
75 | |
] | |
} | |
], | |
"Fri":[ | |
{ | |
"age": 1, | |
"stack":[ | |
128, | |
160, | |
200 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
100, | |
120, | |
225 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
130, | |
100, | |
225 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
175, | |
100, | |
200 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
20, | |
20, | |
40 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
25, | |
20, | |
25 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
100, | |
75, | |
100 | |
] | |
}, | |
{ | |
"age": 8, | |
"stack":[ | |
80, | |
50, | |
120 | |
] | |
}, | |
{ | |
"age": 9, | |
"stack":[ | |
71, | |
78, | |
90 | |
] | |
}, | |
{ | |
"age": 10, | |
"stack":[ | |
55, | |
40, | |
65 | |
] | |
} | |
], | |
"Sat":[ | |
{ | |
"age": 1, | |
"stack":[ | |
130, | |
100, | |
190 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
130, | |
115, | |
234 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
125, | |
115, | |
240 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
130, | |
100, | |
225 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
175, | |
100, | |
250 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
20, | |
15, | |
30 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
20, | |
10, | |
20 | |
] | |
}, | |
{ | |
"age": 8, | |
"stack":[ | |
80, | |
50, | |
80 | |
] | |
}, | |
{ | |
"age": 9, | |
"stack":[ | |
76, | |
50, | |
111 | |
] | |
}, | |
{ | |
"age": 10, | |
"stack":[ | |
65, | |
64, | |
83 | |
] | |
} | |
], | |
"Sun":[ | |
{ | |
"age": 1, | |
"stack":[ | |
59, | |
30, | |
55 | |
] | |
}, | |
{ | |
"age": 2, | |
"stack":[ | |
135, | |
90, | |
166 | |
] | |
}, | |
{ | |
"age": 3, | |
"stack":[ | |
130, | |
115, | |
240 | |
] | |
}, | |
{ | |
"age": 4, | |
"stack":[ | |
120, | |
115, | |
230 | |
] | |
}, | |
{ | |
"age": 5, | |
"stack":[ | |
130, | |
112, | |
222 | |
] | |
}, | |
{ | |
"age": 6, | |
"stack":[ | |
175, | |
113, | |
220 | |
] | |
}, | |
{ | |
"age": 7, | |
"stack":[ | |
20, | |
20, | |
32 | |
] | |
}, | |
{ | |
"age": 8, | |
"stack":[ | |
10, | |
15, | |
20 | |
] | |
}, | |
{ | |
"age": 9, | |
"stack":[ | |
78, | |
50, | |
80 | |
] | |
}, | |
{ | |
"age": 10, | |
"stack":[ | |
80, | |
49, | |
100 | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment