Published
Edited
Mar 28, 2019
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
graphName = "kickstarter-graph"
Insert cell
graphID = "#"+graphName
Insert cell
toggle = {
// Initial rendering of the chart should trigger this block, so that data-dataset is set to 0
chart
// And whenever the user select a different option for the graph, this block should also run
compositionChoice
let areas = d3.selectAll('.categories')
if (compositionChoice === '0') {
areas.data(stackedDataNumOfAllProjects);
d3.select(graphID).attr("data-dataset", "0")
} else if (compositionChoice === '1') {
areas.data(stackedDataNumOfSuccessfulProjects);
d3.select(graphID).attr("data-dataset", "1")
} else {
areas.data(stackedDataTotalFunding);
d3.select(graphID).attr("data-dataset", "2")
}
d3.selectAll(".categories")
.transition("morph").duration(1500)
.attr("d", stackedAreaGenerator());

}
Insert cell
legend = legendContainer => {
const legendItem =
legendContainer
.selectAll("g")
.data(projectCategories)
.join("g")
.attr("transform", (d, i) => `translate(0,${i * (svgHeight-margin.bottom-29)/14})`);

legendItem
.append("text")
.attr("x", 5)
.attr("y", 9.5)
.attr("dy", "0.35em")
.text(d => d);
legendItem
.append("rect")
.attr("x", -19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", d => colorMapping(d));
}
Insert cell
areaTooltip = (d) => `${d.key}`
Insert cell
function onMouseOutArea (d) {
tooltip.text("");
// d3.selectAll(`circle.outlier[data-pid="${ d.pid }"]`).classed('active', false);
// Hide rectYearHighlight
// d3.select("#rectYearHighlight")
// .style("visibility", "hidden");
return tooltip.style("visibility", "hidden");
}
Insert cell
function onMouseMoveArea (d) {
// Find your root SVG element
let svg = document.getElementById(graphName)
// Calculate from mouse position and svg width the index of the year that's being pointed at
// index is from 0 (2009) to 8 (2017)
// console.log(`${d3.mouse(svg)[0]} / ${svg.getBoundingClientRect().width}`);
let x = d3.mouse(svg)[0] - margin.left
let y = (svg.getBoundingClientRect().width - margin.left - margin.right)/16.0
let mouseOverYearIndex = Math.floor((Math.floor(x/y) + 1 )/2)
let year = dataTotalFundingPerc[mouseOverYearIndex]['launch_year']
let currentYearPercentage
switch(d3.select(graphID).attr("data-dataset")) {
case '0':
currentYearPercentage =
(dataNumOfAllProjectsPerc[mouseOverYearIndex][this.dataset.tooltip]*100).toFixed(2)+"%";
break;
case '1':
currentYearPercentage =
(dataNumOfSuccessfulProjectsPerc[mouseOverYearIndex][this.dataset.tooltip]*100).toFixed(2)+"%";
break;
case '2':
currentYearPercentage =
(dataTotalFundingPerc[mouseOverYearIndex][this.dataset.tooltip]*100).toFixed(2)+"%";
break;
default:
// shouldn't reach here. something is wrong
}
// Show and reposition rectYearHighlight
d3.select("#rectYearHighlight")
.attr("x", margin.left-5+y*2*mouseOverYearIndex)
.style("visibility", "visible");
let tooltipText = this.dataset.tooltip + '\n' + currentYearPercentage + ' in ' + year;
switch(d3.select(graphID).attr("data-dataset")) {
case '0':
tooltipText += "\n" + (dataNumOfAllProjects[mouseOverYearIndex][this.dataset.tooltip]) + " projects launched";
break;
case '1':
tooltipText += "\n" + (dataNumOfSuccessfulProjects[mouseOverYearIndex][this.dataset.tooltip]) + " projects funded";
break;
case '2':
tooltipText += "\n" + "$" + d3.format(",.0f")(dataTotalFunding[mouseOverYearIndex][this.dataset.tooltip]);
break;
default:
// shouldn't reach here. something is wrong
}
tooltip.text(tooltipText)
return tooltip.style("top", (d3.event.pageY+20)+"px").style("left",(d3.event.pageX+10)+"px");
}
Insert cell
function onMouseOverArea (d) {
// 'this' is the path (area) DOM element
// console.log(this)
// The dataset property on the HTMLElement interface provides read/write access to all the custom data attributes
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset
tooltip.text(this.dataset.tooltip);
// d3.selectAll(`circle.outlier[data-pid="${ d.pid }"]`).classed('active', true);
return tooltip.style("visibility", "visible");
}
Insert cell
tooltip = d3.select("body").append("div")
.attr("class", "svg-tooltip")
.text("")
Insert cell
projectCategories = dataNumOfAllProjectsPerc.columns.slice(1)
Insert cell
Insert cell
interpolatedColors = d3.quantize(t => d3.interpolateSpectral(t * 1 + 0.0), projectCategories.length)
Insert cell
// interpolatedColorsShuffled = shuffle(interpolatedColors)
Insert cell
colorMapping = d3.scaleOrdinal()
.domain(projectCategories)
.range(interpolatedColors)
.unknown("#ccc")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dataNumOfAllProjects = d3.csvParse(csvNumOfAllProjects, d => {
return {
launch_year: new Date(d.launch_year, 1, 1, 0, 0, 0, 0).getFullYear(),
Art: +d.Art,
Comics: +d.Comics,
Crafts: +d.Crafts,
Dance: +d.Dance,
Design: +d.Design,
Fashion: +d.Fashion,
"Film & Video": +d["Film & Video"],
Food: +d.Food,
Games: +d.Games,
Journalism: +d.Journalism,
Music: +d.Music,
Photography: +d.Photography,
Publishing: +d.Publishing,
Technology: +d.Technology,
Theater: +d.Theater
}
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// the -5 and +5 below are for showing a full width rectYearHighlight bar for year 2009 and 2017
xScale = d3.scaleLinear()
.domain([2009, 2017])
.range([margin.left-5, graphWidth+margin.left+5]);
Insert cell
yScale = d3.scaleLinear()
.domain([0, 1])
.range([margin.top, graphHeight+margin.top]);
Insert cell
xAxis = d3.axisBottom(xScale).tickSize(0).tickPadding(10).tickFormat(d3.format("d"));
Insert cell
yAxis = d3.axisLeft(yScale).tickSize(0).tickPadding(10);
Insert cell
stackedAreaGenerator = function(reality) {
return d3.area()
.curve(d3.curveLinear)
.x(d => xScale(d.data.launch_year))
.y0(d => yScale(d[0]) )
.y1(d => yScale(d[1]) );
}
Insert cell
stackedDataNumOfAllProjects = {
const keys = dataNumOfAllProjectsPerc.columns.slice(1);
const stack = d3.stack()
.keys(keys)
.order(d3.stackOrderAescending);
return stack(dataNumOfAllProjectsPerc);
}
Insert cell
stackedDataNumOfSuccessfulProjects = {
const keys = dataNumOfSuccessfulProjectsPerc.columns.slice(1);
const stack = d3.stack()
.keys(keys)
.order(d3.stackOrderAescending);
return stack(dataNumOfSuccessfulProjectsPerc);
}
Insert cell
stackedDataTotalFunding = {
const keys = dataTotalFundingPerc.columns.slice(1);
const stack = d3.stack()
.keys(keys)
.order(d3.stackOrderAescending);
return stack(dataTotalFundingPerc);
}
Insert cell
Insert cell
// document.getElementsByClassName("observablehq")[0].parentElement.clientWidth;
Insert cell
// svgWidth = document.getElementsByClassName("observablehq")[0].parentElement.clientWidth;
Insert cell
svgWidth= width
Insert cell
svgHeight = svgWidth * 0.55
Insert cell
margin = ({ top:10, right:135, bottom:50, left:30 })
Insert cell
graphWidth = svgWidth - margin.left - margin.right
Insert cell
graphHeight = svgHeight - margin.top - margin.bottom
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
styles = html`
<style>
.y-axis-label,
.x-axis-label {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 12px;
text-transform: uppercase;
}

.y-axis line {
stroke-dasharray: 2 2;
stroke: #bababa;
}

.y-axis .domain {
fill-opacity: 0;
stroke-opacity: 0;
}

.svg-tooltip {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background: rgba(69,77,93,.9);
border-radius: .1rem;
color: #fff;
display: block;
font-size: 11px;
max-width: 320px;
padding: .2rem .4rem;
position: absolute;
text-overflow: ellipsis;
white-space: pre;
z-index: 300;
visibility: hidden;
}
</style>`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more