Skip to content

Instantly share code, notes, and snippets.

@jamesmosier
Forked from erwaller/README.md
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesmosier/becda06a56cfe4cabbb0 to your computer and use it in GitHub Desktop.
Save jamesmosier/becda06a56cfe4cabbb0 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
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