Skip to content

Instantly share code, notes, and snippets.

@jamesmosier
Forked from erwaller/README.md
Last active August 29, 2015 14:19
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!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>
// 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()}}};
// 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