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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more