-
-
Save jamesmosier/becda06a56cfe4cabbb0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<meta http-equiv="Content-Language" content="en" /> | |
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.6.3/leaflet.css" /> | |
</head> | |
<body> | |
<div id="map" style="position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px"></div> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.0/zepto.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.6.3/leaflet.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r58/three.min.js"></script> | |
<script src="tween.min.js"></script> | |
<script src="three-stats.min.js"></script> | |
<script> | |
L.CRS.SeatGeek = L.extend({}, L.CRS, { | |
projection: L.Projection.LonLat, | |
transformation: new L.Transformation(0.35, 0, 0.35, 0), | |
scale: function (zoom) { | |
return Math.pow(2, zoom); | |
} | |
}); | |
var map = L.map("map", { | |
minZoom: 1, | |
maxZoom: 4, | |
crs: L.CRS.SeatGeek | |
}).setView([500, 500], 1); | |
L.tileLayer('http://{s}.tiles.seatgeek.com/v3/maps/{mapId}/{z}/{x}/{y}.png', { | |
mapId: "v1-1-5", | |
tileSize: 350, | |
minZoom: 1, | |
maxZoom: 4, | |
noWrap: true | |
}).addTo(map); | |
L.SG3DLayer = L.Class.extend({ | |
map: null, | |
container: null, | |
data: null, | |
// I don't *think* it matters what we pick here | |
vFOV: 60, | |
// Distance of camera from plane of the scene | |
cameraHeight: 1000, | |
threeOrigin: null, | |
// At what coordinates was the sceneOrigin when we first layed everything out | |
initialSceneOriginLatLng: null, | |
heightScale: null, | |
initialize: function (options) { | |
options = L.Util.setOptions(this, options); | |
this.data = []; | |
this.material = new THREE.MeshLambertMaterial({ | |
color: 0xffffff, | |
shading: THREE.FlatShading, | |
opacity: 0.8, | |
overdraw: false, | |
wireframe: false | |
}); | |
}, | |
_move: function () { | |
}, | |
_initScene: function () { | |
this.camera = new THREE.PerspectiveCamera(this.vFOV, this.map._size.x / this.map._size.y, 1, 1000); | |
this.camera.position.x = 0; | |
this.camera.position.y = 0; | |
this.camera.position.z = this.cameraHeight; | |
this.scene = new THREE.Scene(); | |
// Lights | |
var ambientLight = new THREE.AmbientLight(0x8d8d8d); | |
this.scene.add(ambientLight); | |
this.directionalLight = new THREE.DirectionalLight(0xffffff, 0.65); | |
this.directionalLight.position.x = - 0.5; | |
this.directionalLight.position.y = - 0.5; | |
this.directionalLight.position.z = 0.6; | |
this.scene.add(this.directionalLight); | |
this.renderer = new THREE.CanvasRenderer(); | |
this._el = L.DomUtil.create('div', 'sg-3d-layer leaflet-zoom-hide'); | |
this._el.appendChild(this.renderer.domElement); | |
this.map.getPanes().overlayPane.appendChild(this._el); | |
}, | |
_resetScene: function () { | |
var that = this; | |
this.camera.aspect = this.map._size.x / this.map._size.y; | |
this.camera.updateProjectionMatrix(); | |
this.renderer.setSize(this.map._size.x, this.map._size.y); | |
// Helpers | |
function degToRad (angle) { return angle * Math.PI / 180; } | |
function radToDeg (angle) { return angle * 180 / Math.PI; } | |
// How many vertical scene units can we see? (https://github.com/mrdoob/three.js/issues/1239) | |
// Useful diagram: http://techpubs.sgi.com/library/dynaweb_docs/0650/SGI_Developer/books/Perf_PG/sgi_html/figures/04.3.frustum.gif | |
var visibleHeight = 2 * Math.tan(degToRad(this.vFOV) / 2) * this.cameraHeight; | |
var scale = that.map._size.y / visibleHeight; | |
this.threeOrigin = new L.Point(this.map._size.x / 2, this.map._size.y / 2); | |
// ScenePoint: x,y coord in the THREE scene | |
// LatLng: x,y coord in the reference system | |
// containerPoint: x,y coord on the screen | |
this.latLngToScenePoint = function latLngToScenePoint (latLng) { | |
var containerPoint = that.map.latLngToContainerPoint(latLng); | |
return new L.Point( | |
(containerPoint.x - that.threeOrigin.x) * (1 / scale), | |
// Need to flip the y-axis | |
-1 * (containerPoint.y - that.threeOrigin.y) * (1 / scale) | |
); | |
} | |
var degreesLatVisible = this.map.containerPointToLatLng([0, this.map._size.y]).lat - | |
this.map.containerPointToLatLng([0, 0]).lat; | |
this.heightScale = degreesLatVisible / visibleHeight; | |
this._drawObjects(); | |
}, | |
_startRenderLoop: function () { | |
var that = this; | |
var stats = new Stats(); | |
stats.domElement.style.cssText = 'position: absolute; top: 0px; right: 0px'; | |
document.body.appendChild(stats.domElement); | |
var lastPos = null | |
function render() { | |
requestAnimationFrame(render); | |
TWEEN.update(); | |
var scenePoint = that.latLngToScenePoint(that.initialSceneOriginLatLng); | |
that.group.position.x = scenePoint.x; | |
that.group.position.y = scenePoint.y; | |
that.renderer.render(that.scene, that.camera); | |
var curPos = that.map.containerPointToLayerPoint([0, 0]); | |
if (lastPos === null || !(lastPos.x === curPos.x && lastPos.y === curPos.x)) { | |
L.DomUtil.setPosition(that._el, lastPos = curPos); | |
} | |
stats.update(); | |
} | |
render(); | |
}, | |
addTo: function (map) { | |
map.addLayer(this); | |
return this; | |
}, | |
onAdd: function (map) { | |
var that = this; | |
this.map = map; | |
if (this.renderer) { | |
// TODO: re-adding behavior | |
} else { | |
this._initScene(); | |
this._resetScene(); | |
this._startRenderLoop(); | |
} | |
this.map.on({ | |
move: this._move, | |
viewreset: this._resetScene | |
}, this); | |
window.addEventListener('resize', function () { that._resetScene(); }, false); | |
}, | |
_geoJSONGeometryToShape: function (geometry) { | |
if (geometry.type !== "Polygon") { | |
throw "Only Polygons are currently supported"; | |
} | |
var vertices = geometry.coordinates[0]; | |
var pts = []; | |
for (var i = 0; i < vertices.length; ++i) { | |
var ppt = this.latLngToScenePoint(L.latLng(vertices[i][1], vertices[i][0]), 1) | |
pts.push(new THREE.Vector2(ppt.x, ppt.y)); | |
} | |
var shape = new THREE.Shape(); | |
shape.fromPoints(pts); | |
return shape; | |
}, | |
_drawObjects: function () { | |
if (this.group) { | |
this.scene.remove(this.group); | |
} | |
this.group = new THREE.Object3D(); | |
var building, geometry; | |
for (var i = 0; i < this.data.length; ++i) { | |
building = this.data[i]; | |
geometry = this._geoJSONGeometryToShape(building.geometry) | |
.extrude({ | |
amount: building.properties.height / this.heightScale, | |
bevelEnabled: false | |
}); | |
this.group.add(new THREE.Mesh(geometry, this.material)); | |
} | |
this.scene.add(this.group) | |
var sceneOrigin = new L.Point(this.map._size.x / 2, this.map._size.y / 2); | |
this.initialSceneOriginLatLng = this.map.containerPointToLatLng(sceneOrigin); | |
}, | |
_animateInObjects: function () { | |
var that = this; | |
var tween = new TWEEN.Tween({ z: 0.001 }) | |
.to({ z: 1 }, 600) | |
.easing(TWEEN.Easing.Cubic.Out) | |
.onUpdate(function () { | |
that.group.scale.z = this.z; | |
}) | |
.start(); | |
}, | |
_initStats: function () { | |
var container = document.createElement('div'); | |
document.body.appendChild(container); | |
this.stats = new Stats(); | |
this.stats.domElement.style.position = 'absolute'; | |
this.stats.domElement.style.top = '0px'; | |
container.appendChild(this.stats.domElement); | |
}, | |
onRemove: function (map) { | |
this.map = null; | |
map.off({ | |
move: this._move, | |
viewreset: this._resetScene | |
}, this); | |
this.container.parentNode.removeChild(this.container); | |
}, | |
geoJSON: function (x) { | |
this.data = x; | |
this._resetScene(); | |
this._animateInObjects(); | |
} | |
}); | |
var sg3DLayer = new L.SG3DLayer().addTo(map); | |
setTimeout(function () { | |
$.get("citi-field.geo.json", function (data) { | |
sg3DLayer.geoJSON(data.features); | |
}); | |
}, 500); | |
</script> | |
</body> | |
</html> |
This file contains hidden or 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
// stats.js - http://github.com/mrdoob/stats.js | |
var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; | |
i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); | |
k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= | |
"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= | |
a+"px",m=b,r=0);return b},update:function(){l=this.end()}}}; |
This file contains hidden or 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
// tween.js - http://github.com/sole/tween.js | |
'use strict';var TWEEN=TWEEN||function(){var a=[];return{REVISION:"10",getAll:function(){return a},removeAll:function(){a=[]},add:function(c){a.push(c)},remove:function(c){c=a.indexOf(c);-1!==c&&a.splice(c,1)},update:function(c){if(0===a.length)return!1;for(var b=0,d=a.length,c=void 0!==c?c:void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();b<d;)a[b].update(c)?b++:(a.splice(b,1),d--);return!0}}}(); | |
TWEEN.Tween=function(a){var c={},b={},d={},e=1E3,g=0,i=0,k=null,u=TWEEN.Easing.Linear.None,v=TWEEN.Interpolation.Linear,p=[],q=null,r=!1,s=null,t=null,j;for(j in a)c[j]=parseFloat(a[j],10);this.to=function(a,c){void 0!==c&&(e=c);b=a;return this};this.start=function(e){TWEEN.add(this);r=!1;k=void 0!==e?e:void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();k+=i;for(var f in b){if(b[f]instanceof Array){if(0===b[f].length)continue;b[f]=[a[f]].concat(b[f])}c[f]= | |
a[f];!1===c[f]instanceof Array&&(c[f]*=1);d[f]=c[f]||0}return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(a){i=a;return this};this.repeat=function(a){g=a;return this};this.easing=function(a){u=a;return this};this.interpolation=function(a){v=a;return this};this.chain=function(){p=arguments;return this};this.onStart=function(a){q=a;return this};this.onUpdate=function(a){s=a;return this};this.onComplete=function(a){t=a;return this};this.update=function(n){if(n<k)return!0; | |
!1===r&&(null!==q&&q.call(a),r=!0);var f=(n-k)/e,f=1<f?1:f,m=u(f),h;for(h in b){var j=c[h]||0,l=b[h];l instanceof Array?a[h]=v(l,m):("string"===typeof l&&(l=j+parseFloat(l,10)),a[h]=j+(l-j)*m)}null!==s&&s.call(a,m);if(1==f)if(0<g){isFinite(g)&&g--;for(h in d)"string"===typeof b[h]&&(d[h]+=parseFloat(b[h],10)),c[h]=d[h];k=n+i}else{null!==t&&t.call(a);f=0;for(m=p.length;f<m;f++)p[f].start(n);return!1}return!0}}; | |
TWEEN.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return 1>(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a* | |
a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1- | |
Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)* | |
2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1- | |
TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}}; | |
TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.Linear;return 0>c?g(a[0],a[1],d):1<c?g(a[b],a[b-1],b-d):g(a[e],a[e+1>b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,g=TWEEN.Interpolation.Utils.Bernstein,i;for(i=0;i<=d;i++)b+=e(1-c,d-i)*e(c,i)*a[i]*g(d,i);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),g(a[(e- | |
1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(g(a[0],a[0],a[1],a[1],-d)-a[0]):1<c?a[b]-(g(a[b],a[b],a[b-1],a[b-1],d-b)-a[b]):g(a[e?e-1:0],a[e],a[b<e+1?b:e+1],a[b<e+2?b:e+2],d-e)},Utils:{Linear:function(a,c,b){return(c-a)*b+a},Bernstein:function(a,c){var b=TWEEN.Interpolation.Utils.Factorial;return b(a)/b(c)/b(a-c)},Factorial:function(){var a=[1];return function(c){var b=1,d;if(a[c])return a[c];for(d=c;1<d;d--)b*=d;return a[c]=b}}(),CatmullRom:function(a,c,b,d,e){var a=0.5*(b-a),d=0.5*(d-c),g= | |
e*e;return(2*c-2*b+a+d)*e*g+(-3*c+3*b-2*a-d)*g+a*e+c}}}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment