Built with blockbuilder.org
Last active
April 16, 2018 00:41
-
-
Save wboykinm/d1dbded3fe2c8cb94b207904c7c4c73d to your computer and use it in GitHub Desktop.
Mapbox equalizer
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
license: mit |
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>Animate 3D buildings based on ambient sounds</title> | |
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> | |
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.js'></script> | |
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.2/mapbox-gl.css' rel='stylesheet' /> | |
<style> | |
body { margin:0; padding:0; } | |
#map { position:absolute; top:0; bottom:0; width:100%; } | |
</style> | |
</head> | |
<body> | |
<div id='map'></div> | |
<script> | |
mapboxgl.accessToken = 'pk.eyJ1IjoibGFuZHBsYW5uZXIiLCJhIjoiY2pnMWljenh6MWx2ajJxcnExbXh5eHozMCJ9.9I7FpVaap_j_qj5X8fodbw'; | |
/* global Promise */ | |
// Use a minimal variant of the Mapbox Dark style, with certain features removed. | |
var map = new mapboxgl.Map({ | |
style: 'mapbox://styles/examples/cj68bstx01a3r2rndlud0pwpv', | |
center: { | |
lng: -73.216409, | |
lat: 44.478559 | |
}, | |
zoom: 15, | |
pitch: 55, | |
container: 'map' | |
}); | |
map.addControl(new mapboxgl.FullscreenControl()); | |
map.on('load', function() { | |
var bins = 16; | |
var maxHeight = 200; | |
var binWidth = maxHeight / bins; | |
// Divide the buildings into 16 bins based on their true height, using a layer filter. | |
for (var i = 0; i < bins; i++) { | |
map.addLayer({ | |
'id': '3d-buildings-' + i, | |
'source': 'composite', | |
'source-layer': 'building', | |
'filter': ['all', ['==', 'extrude', 'true'], ['>', 'height', i * binWidth], ['<=', 'height', (i + 1) * binWidth]], | |
'type': 'fill-extrusion', | |
'minzoom': 15, | |
'paint': { | |
'fill-extrusion-color': '#60AFFE', | |
'fill-extrusion-height-transition': { | |
duration: 0, | |
delay: 0 | |
}, | |
'fill-extrusion-opacity': .6 | |
} | |
}); | |
} | |
// Older browsers might not implement mediaDevices at all, so we set an empty object first | |
if (navigator.mediaDevices === undefined) { | |
navigator.mediaDevices = {}; | |
} | |
// Some browsers partially implement mediaDevices. We can't just assign an object | |
// with getUserMedia as it would overwrite existing properties. | |
// Here, we will just add the getUserMedia property if it's missing. | |
if (navigator.mediaDevices.getUserMedia === undefined) { | |
navigator.mediaDevices.getUserMedia = function (constraints) { | |
// First get ahold of the legacy getUserMedia, if present | |
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; | |
// Some browsers just don't implement it - return a rejected promise with an error | |
// to keep a consistent interface | |
if (!getUserMedia) { | |
return Promise.reject(new Error('getUserMedia is not implemented in this browser')); | |
} | |
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise | |
return new Promise(function (resolve, reject) { | |
getUserMedia.call(navigator, constraints, resolve, reject); | |
}); | |
}; | |
} | |
navigator.mediaDevices.getUserMedia({audio: true}) | |
.then(function (stream) { | |
// Set up a Web Audio AudioContext and AnalyzerNode, configured to return the | |
// same number of bins of audio frequency data. | |
var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
var analyser = audioCtx.createAnalyser(); | |
analyser.minDecibels = -90; | |
analyser.maxDecibels = -10; | |
analyser.smoothingTimeConstant = 0.85; | |
var source = audioCtx.createMediaStreamSource(stream); | |
source.connect(analyser); | |
analyser.fftSize = bins * 2; | |
var dataArray = new Uint8Array(bins); | |
function draw(now) { | |
analyser.getByteFrequencyData(dataArray); | |
// Use that data to drive updates to the fill-extrusion-height property. | |
var avg = 0; | |
for (var i = 0; i < bins; i++) { | |
avg += dataArray[i]; | |
map.setPaintProperty('3d-buildings-' + i, 'fill-extrusion-height', 10 + 4 * i + dataArray[i]); | |
} | |
avg /= bins; | |
// Animate the map bearing and light color over time, and make the light more | |
// intense when the audio is louder. | |
map.setBearing(now / 500); | |
map.setLight({ | |
color: "hsl(" + now / 100 % 360 + "," + Math.min(50 + avg / 4, 100) + "%,50%)", | |
intensity: Math.min(1, avg / 256 * 10) | |
}); | |
requestAnimationFrame(draw); | |
} | |
requestAnimationFrame(draw); | |
}) | |
.catch(function (err) { | |
console.log('The following gUM error occured: ' + err); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment