Jonathan Huang af48ce6739 Geo Heatmap Example (#77)
* geoheatmap raster layer

set mapbox token in examples, set cap in example 3, raise poly point cap in other examples (#92)

include all css and js files in one bundle

bump tp webpack 2

begin raster heatmap example

basic heatmap raster layer mixin

fix lint

xyDim getter/setter for heatmap raster layer

raster heatmap layer example with sliders

example to use distinct lang

refactor

use mapd data layer

use webpack dev server for examples

update example build script

calculate proper gap size

update geoheatmap example image

update example image styling

dynamic number of bins on geoheatmap

vega-lite api for heat layer

implement hex binning

update aggregate

ability to switch mark types

update babelrx

manual pixel sizing

add destroy hook

dynamic color domain

linting

use layer.genSQL in genVega

handle aggregation parsing

rebuild

do not set null colordomain

fix test

update bundle

fix test

* tweak example
2017-08-28 15:03:01 -07:00

164 lines
5.8 KiB
JavaScript

document.addEventListener("DOMContentLoaded", function init() {
var config = {
table: "contributions_donotmodify",
valueColumn: "contributions_donotmodify.amount",
joinColumn: "contributions_donotmodify.contributor_zipcode",
polyTable: "zipcodes",
polyJoinColumn: "ZCTA5CE10",
timeColumn: "contrib_date",
timeLabel: "Number of Contributions",
domainBoundMin: 0,
domainBoundMax: 2600,
numTimeBins: 423
}
new MapdCon()
.protocol("https")
.host("metis.mapd.com")
.port("443")
.dbName("mapd")
.user("mapd")
.password("HyperInteractive")
.connect(function(error, con) {
crossfilter.crossfilter(con, ["contributions_donotmodify", "zipcodes"], [{
table1: "contributions_donotmodify",
attr1: "contributor_zipcode",
table2: "zipcodes",
attr2: "ZCTA5CE10"
}]).then(function(cf) {
crossfilter.crossfilter(con, "contributions_donotmodify").then(cf2 => {
createPolyMap(cf, con, dc, config, cf2)
createTimeChart(cf, dc, config, cf2)
})
})
})
function createPolyMap(crossFilter, con, dc, config, cf2) {
var parent = document.getElementById("polymap")
// The values in the table and column specified in crossFilter.dimension
// must correspond to values in the table and keysColumn specified in polyRasterChart.polyJoin.
var dim = crossFilter.dimension("zipcodes.rowid") // Values to join on.
var grp = dim.group().reduceAvg("contributions_donotmodify.amount", "avgContrib") // Values to color on.
// var dim = crossFilter.dimension("tweets_nov_feb.state_abbr") // Values to join on.
// var grp = dim.group().reduceAvg("tweets_nov_feb.tweet_count") // Values to color on.
// Can use getDomainBounds to dynamically find min and max of values that will be colored,
// or the domain [min, max] can be set directly
// (in which case nesting chart creation inside this callback is unnecessary).
getDomainBounds(config.valueColumn, cf2.groupAll(), function(domainBounds){
// Can set colorDomain directly or use domainFromBoundsAndRange to generate a .
var colorRange = ["#115f9a","#1984c5","#22a7f0","#48b5c4","#76c68f","#a6d75b","#c9e52f","#d0ee11","#d0f400"]
var colorDomain = domainFromBoundsAndRange(config.domainBoundMin, config.domainBoundMax, colorRange)
// var colorDomain = domainFromBoundsAndRange(domainBounds.minimum, domainBounds.maximum, colorRange)
var mapboxToken = "pk.eyJ1IjoibWFwZCIsImEiOiJjaWV1a3NqanYwajVsbmdtMDZzc2pneDVpIn0.cJnk8c2AxdNiRNZWtx5A9g";
var polyMap = dc
.rasterChart(parent, true)
.con(con)
.height(height()/1.5)
.width(width())
.mapUpdateInterval(750) // ms
.mapStyle("mapbox://styles/mapbox/light-v8")
.mapboxToken(mapboxToken) // need a mapbox accessToken for loading the tiles
var polyLayer = dc
.rasterLayer("polys")
.cap(Infinity)
.dimension(dim)
.group(grp)
.cap(1000000)
.fillColorAttr('avgContrib')
.defaultFillColor("green")
.fillColorScale(d3.scale.linear().domain(colorDomain).range(colorRange))
polyMap.pushLayer("polys", polyLayer).init().then(() => {
// polyMap.borderWidth(zoomToBorderWidth(polyMap.map().getZoom()))
// Keeps the border widths reasonable regardless of zoom level.
polyMap.map().on("zoom", function() {
// polyMap.borderWidth(zoomToBorderWidth(polyMap.map().getZoom()))
})
dc.renderAllAsync()
window.addEventListener("resize", _.debounce(function(){ resizeChart(polyMap, 1.5) }, 500))
})
})
}
function getDomainBounds (column, groupAll, callback) {
groupAll.reduce([
{expression: column, agg_mode: "min", name: "minimum"},
{expression: column, agg_mode: "max", name: "maximum"}
]).valuesAsync(true).then(callback)
}
function domainFromBoundsAndRange (min, max, range) {
return _.range(0, range.length).map((_, i) => min + Math.round(i * max / (range.length - 1)))
}
function zoomToBorderWidth (zoomLevel) {
var MIN_ZOOM = 0.8626373575587937
var ZOOM_BORDER_DIVISOR = 20
return zoomLevel / ZOOM_BORDER_DIVISOR - MIN_ZOOM / ZOOM_BORDER_DIVISOR
}
function createTimeChart(crossFilter, dc, config, cf2) {
getDomainBounds(config.timeColumn, cf2.groupAll(), function(timeChartBounds){
var timeChartDimension = crossFilter.dimension(config.timeColumn)
var timeChartGroup = timeChartDimension
.group()
.reduceCount("*")
var timeChart = dc.lineChart("#timechart")
.width(width())
.height(height()/2.5)
.elasticY(true)
.renderHorizontalGridLines(true)
.brushOn(true)
.xAxisLabel("Time")
.yAxisLabel(config.timeLabel)
.dimension(timeChartDimension)
.group(timeChartGroup)
.binParams({
numBins: config.numTimeBins,
binBounds: [timeChartBounds.minimum, timeChartBounds.maximum]
})
timeChart.x(d3.time.scale.utc().domain([timeChartBounds.minimum, timeChartBounds.maximum]))
timeChart.yAxis().ticks(5)
timeChart
.xAxis()
.scale(timeChart.x())
.tickFormat(dc.utils.customTimeFormat)
.orient('bottom');
dc.renderAllAsync()
window.addEventListener("resize", _.debounce(function () { resizeChart(timeChart, 2.5) }, 500))
})
}
function width () {
return document.documentElement.clientWidth - 30
}
function height () {
return (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - 200)
}
function resizeChart (chart, heightDivisor) {
if(typeof chart.map === "function"){
chart.map().resize()
chart.isNodeAnimate = false
}
chart
.width(width())
.height(height()/heightDivisor)
.renderAsync()
dc.redrawAllAsync()
}
function noop () {}
})