mirror of
https://github.com/heavyai/heavyai-charting.git
synced 2026-01-25 14:57:45 +00:00
162 lines
5.6 KiB
JavaScript
162 lines
5.6 KiB
JavaScript
document.addEventListener("DOMContentLoaded", function init() {
|
|
// var config = {
|
|
// table: "tweets_nov_feb",
|
|
// valueColumn: "tweets_nov_feb.tweet_count",
|
|
// joinColumn: "tweets_nov_feb.state_abbr",
|
|
// polyTable: "states",
|
|
// polyJoinColumn: "STATE_ABBR",
|
|
// timeColumn: "tweet_time",
|
|
// timeLabel: "Number of Tweets",
|
|
// domainBoundMin: 12196,
|
|
// domainBoundMax: 32586,
|
|
// numTimeBins: 288 // 288 * 5 = number of minutes in a day.
|
|
// }
|
|
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("http")
|
|
.host("forge.mapd.com")
|
|
.port("9092")
|
|
.dbName("mapd")
|
|
.user("mapd")
|
|
.password("HyperInteractive")
|
|
.connect(function(error, con) {
|
|
crossfilter.crossfilter(con, config.table).then(function(cf) {
|
|
createPolyMap(cf, con, dc, config)
|
|
createTimeChart(cf, dc, config)
|
|
})
|
|
})
|
|
|
|
|
|
function createPolyMap(crossFilter, con, dc, config) {
|
|
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(config.joinColumn) // Values to join on.
|
|
var grp = dim.group().reduceAvg(config.valueColumn) // 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, dim.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 polyMap = dc
|
|
.polyRasterChart(parent, true)
|
|
.con(con)
|
|
.height(height()/1.5)
|
|
.width(width())
|
|
.dimension(dim)
|
|
.group(grp)
|
|
.tableName(config.table)
|
|
.mapUpdateInterval(750) // ms
|
|
.othersGrouper(false)
|
|
.opacity(0.90)
|
|
.mapStyle("mapbox://styles/mapbox/light-v8")
|
|
.polyJoin({table: config.polyTable, keysColumn: config.polyJoinColumn})
|
|
.colors(d3.scale.linear().domain(colorDomain).range(colorRange))
|
|
.borderColor("white")
|
|
|
|
|
|
polyMap.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) {
|
|
getDomainBounds(config.timeColumn, crossFilter.groupAll(), function(timeChartBounds){
|
|
var timeChartDimension = crossFilter.dimension(config.timeColumn)
|
|
|
|
var timeChartGroup = timeChartDimension
|
|
.group()
|
|
.reduceCount("*")
|
|
.setBinParams({
|
|
numBins: config.numTimeBins,
|
|
binBounds: [timeChartBounds.minimum, timeChartBounds.maximum]
|
|
})
|
|
|
|
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)
|
|
|
|
timeChart.x(d3.time.scale.utc().domain([timeChartBounds.minimum, timeChartBounds.maximum]))
|
|
timeChart.yAxis().ticks(5)
|
|
timeChart.xAxis().orient("top")
|
|
|
|
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.renderAllAsync()
|
|
}
|
|
|
|
function noop () {}
|
|
})
|