|
@@ -0,0 +1,530 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+<head>
|
|
|
+<title>three.js webgl - geometry - extrude shapes from geodata</title>
|
|
|
+<meta charset="utf-8">
|
|
|
+<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
|
|
+<style>
|
|
|
+body {
|
|
|
+ font-family: Monospace;
|
|
|
+ background-color: #f0f0f0;
|
|
|
+ margin: 0px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+</style>
|
|
|
+</head>
|
|
|
+
|
|
|
+<body>
|
|
|
+<canvas id="debug" style="position:absolute; left:100px"></canvas>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+'use strict';
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script type="text/javascript" src="../build/three.js"></script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+// From d3-threeD.js
|
|
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
+
|
|
|
+function d3threeD(exports) {
|
|
|
+
|
|
|
+const DEGS_TO_RADS = Math.PI / 180,
|
|
|
+ UNIT_SIZE = 100;
|
|
|
+
|
|
|
+const DIGIT_0 = 48, DIGIT_9 = 57, COMMA = 44, SPACE = 32, PERIOD = 46,
|
|
|
+ MINUS = 45;
|
|
|
+exports.transformSVGPath =
|
|
|
+function transformSVGPath(pathStr) {
|
|
|
+ var path = new THREE.Shape();
|
|
|
+
|
|
|
+ var idx = 1, len = pathStr.length, activeCmd,
|
|
|
+ x = 0, y = 0, nx = 0, ny = 0, firstX = null, firstY = null,
|
|
|
+ x1 = 0, x2 = 0, y1 = 0, y2 = 0,
|
|
|
+ rx = 0, ry = 0, xar = 0, laf = 0, sf = 0, cx, cy;
|
|
|
+
|
|
|
+ function eatNum() {
|
|
|
+ var sidx, c, isFloat = false, s;
|
|
|
+ // eat delims
|
|
|
+ while (idx < len) {
|
|
|
+ c = pathStr.charCodeAt(idx);
|
|
|
+ if (c !== COMMA && c !== SPACE)
|
|
|
+ break;
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+ if (c === MINUS)
|
|
|
+ sidx = idx++;
|
|
|
+ else
|
|
|
+ sidx = idx;
|
|
|
+ // eat number
|
|
|
+ while (idx < len) {
|
|
|
+ c = pathStr.charCodeAt(idx);
|
|
|
+ if (DIGIT_0 <= c && c <= DIGIT_9) {
|
|
|
+ idx++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else if (c === PERIOD) {
|
|
|
+ idx++;
|
|
|
+ isFloat = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ s = pathStr.substring(sidx, idx);
|
|
|
+ return isFloat ? parseFloat(s) : parseInt(s);
|
|
|
+ }
|
|
|
+
|
|
|
+ s = pathStr.substring(sidx);
|
|
|
+ return isFloat ? parseFloat(s) : parseInt(s);
|
|
|
+ }
|
|
|
+
|
|
|
+ function nextIsNum() {
|
|
|
+ var c;
|
|
|
+ // do permanently eat any delims...
|
|
|
+ while (idx < len) {
|
|
|
+ c = pathStr.charCodeAt(idx);
|
|
|
+ if (c !== COMMA && c !== SPACE)
|
|
|
+ break;
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+ c = pathStr.charCodeAt(idx);
|
|
|
+ return (c === MINUS || (DIGIT_0 <= c && c <= DIGIT_9));
|
|
|
+ }
|
|
|
+
|
|
|
+ var canRepeat;
|
|
|
+ activeCmd = pathStr[0];
|
|
|
+ while (idx <= len) {
|
|
|
+ canRepeat = true;
|
|
|
+ switch (activeCmd) {
|
|
|
+ // moveto commands, become lineto's if repeated
|
|
|
+ case 'M':
|
|
|
+ x = eatNum();
|
|
|
+ y = eatNum();
|
|
|
+ path.moveTo(x, y);
|
|
|
+ activeCmd = 'L';
|
|
|
+ firstX = x;
|
|
|
+ firstY = y;
|
|
|
+ break;
|
|
|
+ case 'm':
|
|
|
+ x += eatNum();
|
|
|
+ y += eatNum();
|
|
|
+ path.moveTo(x, y);
|
|
|
+ activeCmd = 'l';
|
|
|
+ firstX = x;
|
|
|
+ firstY = y;
|
|
|
+ break;
|
|
|
+ case 'Z':
|
|
|
+ case 'z':
|
|
|
+ canRepeat = false;
|
|
|
+ if (x !== firstX || y !== firstY)
|
|
|
+ path.lineTo(firstX, firstY);
|
|
|
+ break;
|
|
|
+ // - lines!
|
|
|
+ case 'L':
|
|
|
+ case 'H':
|
|
|
+ case 'V':
|
|
|
+ nx = (activeCmd === 'V') ? x : eatNum();
|
|
|
+ ny = (activeCmd === 'H') ? y : eatNum();
|
|
|
+ path.lineTo(nx, ny);
|
|
|
+ x = nx;
|
|
|
+ y = ny;
|
|
|
+ break;
|
|
|
+ case 'l':
|
|
|
+ case 'h':
|
|
|
+ case 'v':
|
|
|
+ nx = (activeCmd === 'v') ? x : (x + eatNum());
|
|
|
+ ny = (activeCmd === 'h') ? y : (y + eatNum());
|
|
|
+ path.lineTo(nx, ny);
|
|
|
+ x = nx;
|
|
|
+ y = ny;
|
|
|
+ break;
|
|
|
+ // - cubic bezier
|
|
|
+ case 'C':
|
|
|
+ x1 = eatNum(); y1 = eatNum();
|
|
|
+ case 'S':
|
|
|
+ if (activeCmd === 'S') {
|
|
|
+ x1 = 2 * x - x2; y1 = 2 * y - y2;
|
|
|
+ }
|
|
|
+ x2 = eatNum();
|
|
|
+ y2 = eatNum();
|
|
|
+ nx = eatNum();
|
|
|
+ ny = eatNum();
|
|
|
+ path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
|
|
|
+ x = nx; y = ny;
|
|
|
+ break;
|
|
|
+ case 'c':
|
|
|
+ x1 = x + eatNum();
|
|
|
+ y1 = y + eatNum();
|
|
|
+ case 's':
|
|
|
+ if (activeCmd === 's') {
|
|
|
+ x1 = 2 * x - x2;
|
|
|
+ y1 = 2 * y - y2;
|
|
|
+ }
|
|
|
+ x2 = x + eatNum();
|
|
|
+ y2 = y + eatNum();
|
|
|
+ nx = x + eatNum();
|
|
|
+ ny = y + eatNum();
|
|
|
+ path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
|
|
|
+ x = nx; y = ny;
|
|
|
+ break;
|
|
|
+ // - quadratic bezier
|
|
|
+ case 'Q':
|
|
|
+ x1 = eatNum(); y1 = eatNum();
|
|
|
+ case 'T':
|
|
|
+ if (activeCmd === 'T') {
|
|
|
+ x1 = 2 * x - x1;
|
|
|
+ y1 = 2 * y - y1;
|
|
|
+ }
|
|
|
+ nx = eatNum();
|
|
|
+ ny = eatNum();
|
|
|
+ path.quadraticCurveTo(x1, y1, nx, ny);
|
|
|
+ x = nx;
|
|
|
+ y = ny;
|
|
|
+ break;
|
|
|
+ case 'q':
|
|
|
+ x1 = x + eatNum();
|
|
|
+ y1 = y + eatNum();
|
|
|
+ case 't':
|
|
|
+ if (activeCmd === 't') {
|
|
|
+ x1 = 2 * x - x1;
|
|
|
+ y1 = 2 * y - y1;
|
|
|
+ }
|
|
|
+ nx = x + eatNum();
|
|
|
+ ny = y + eatNum();
|
|
|
+ path.quadraticCurveTo(x1, y1, nx, ny);
|
|
|
+ x = nx; y = ny;
|
|
|
+ break;
|
|
|
+ // - elliptical arc
|
|
|
+ case 'A':
|
|
|
+ rx = eatNum();
|
|
|
+ ry = eatNum();
|
|
|
+ xar = eatNum() * DEGS_TO_RADS;
|
|
|
+ laf = eatNum();
|
|
|
+ sf = eatNum();
|
|
|
+ nx = eatNum();
|
|
|
+ ny = eatNum();
|
|
|
+ if (rx !== ry) {
|
|
|
+ console.warn("Forcing elliptical arc to be a circular one :(",
|
|
|
+ rx, ry);
|
|
|
+ }
|
|
|
+ // SVG implementation notes does all the math for us! woo!
|
|
|
+ // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
|
|
+ // step1, using x1 as x1'
|
|
|
+ x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
|
|
|
+ y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
|
|
|
+ // step 2, using x2 as cx'
|
|
|
+ var norm = Math.sqrt(
|
|
|
+ (rx*rx * ry*ry - rx*rx * y1*y1 - ry*ry * x1*x1) /
|
|
|
+ (rx*rx * y1*y1 + ry*ry * x1*x1));
|
|
|
+ if (laf === sf)
|
|
|
+ norm = -norm;
|
|
|
+ x2 = norm * rx * y1 / ry;
|
|
|
+ y2 = norm * -ry * x1 / rx;
|
|
|
+ // step 3
|
|
|
+ cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
|
|
|
+ cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
|
|
|
+
|
|
|
+ var u = new THREE.Vector2(1, 0),
|
|
|
+ v = new THREE.Vector2((x1 - x2) / rx,
|
|
|
+ (y1 - y2) / ry);
|
|
|
+ var startAng = Math.acos(u.dot(v) / u.length() / v.length());
|
|
|
+ if (u.x * v.y - u.y * v.x < 0)
|
|
|
+ startAng = -startAng;
|
|
|
+
|
|
|
+ // we can reuse 'v' from start angle as our 'u' for delta angle
|
|
|
+ u.x = (-x1 - x2) / rx;
|
|
|
+ u.y = (-y1 - y2) / ry;
|
|
|
+
|
|
|
+ var deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
|
|
|
+ // This normalization ends up making our curves fail to triangulate...
|
|
|
+ if (v.x * u.y - v.y * u.x < 0)
|
|
|
+ deltaAng = -deltaAng;
|
|
|
+ if (!sf && deltaAng > 0)
|
|
|
+ deltaAng -= Math.PI * 2;
|
|
|
+ if (sf && deltaAng < 0)
|
|
|
+ deltaAng += Math.PI * 2;
|
|
|
+
|
|
|
+ path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
|
|
|
+ x = nx;
|
|
|
+ y = ny;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new Error("weird path command: " + activeCmd);
|
|
|
+ }
|
|
|
+ // just reissue the command
|
|
|
+ if (canRepeat && nextIsNum())
|
|
|
+ continue;
|
|
|
+ activeCmd = pathStr[idx++];
|
|
|
+ }
|
|
|
+
|
|
|
+ return path;
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+var $d3g = {};
|
|
|
+d3threeD($d3g);
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+/// Graphic Engine and Geo Data Init Functions
|
|
|
+
|
|
|
+var addGeoObject = function( group, svgObject ) {
|
|
|
+ var i,j, len, len1;
|
|
|
+ var path, mesh, color, material, amount, simpleShapes, simpleShape, shape3d, x, toAdd, results = [];
|
|
|
+ var thePaths = svgObject.paths;
|
|
|
+ var theAmounts = svgObject.amounts;
|
|
|
+ var theColors = svgObject.colors;
|
|
|
+ var theCenter = svgObject.center;
|
|
|
+
|
|
|
+ len = thePaths.length;
|
|
|
+ for (i = 0; i < len; ++i) {
|
|
|
+ path = $d3g.transformSVGPath( thePaths[i] );
|
|
|
+ color = new THREE.Color( theColors[i] );
|
|
|
+ material = new THREE.MeshLambertMaterial({
|
|
|
+ color: color,
|
|
|
+ ambient: color,
|
|
|
+ emissive: color,
|
|
|
+ });
|
|
|
+ amount = theAmounts[i];
|
|
|
+ simpleShapes = path.toShapes(true);
|
|
|
+ len1 = simpleShapes.length;
|
|
|
+ for (j = 0; j < len1; ++j) {
|
|
|
+ simpleShape = simpleShapes[j];
|
|
|
+ shape3d = simpleShape.extrude({
|
|
|
+ amount: amount,
|
|
|
+ bevelEnabled: false
|
|
|
+ });
|
|
|
+ mesh = new THREE.Mesh(shape3d, material);
|
|
|
+ mesh.rotation.x = Math.PI;
|
|
|
+ mesh.translateZ( - amount - 1);
|
|
|
+ mesh.translateX( - theCenter.x);
|
|
|
+ mesh.translateY( - theCenter.y);
|
|
|
+ group.add(mesh);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+var init3d = function(){
|
|
|
+ var near = 1.0;
|
|
|
+ var far = 10000.0;
|
|
|
+
|
|
|
+ /// Global : renderer
|
|
|
+ renderer = new THREE.WebGLRenderer( { antialias: true } );
|
|
|
+ renderer.setClearColor( 0xb0b0b0 );
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+
|
|
|
+ /// Global : scene
|
|
|
+ scene = new THREE.Scene();
|
|
|
+
|
|
|
+ /// Global : camera
|
|
|
+ camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, near, far );
|
|
|
+ camera.position.set( 0, 0, 200 );
|
|
|
+
|
|
|
+ /// Global : group
|
|
|
+ group = new THREE.Object3D();
|
|
|
+ group.position.x = 0.0;
|
|
|
+ group.position.y = 0.0;
|
|
|
+ group.position.z = 0.0;
|
|
|
+ scene.add( group );
|
|
|
+
|
|
|
+ /// direct light
|
|
|
+ var light = new THREE.DirectionalLight( 0x404040 );
|
|
|
+ light.position.set( 0.75, 0.75, 1.0 ).normalize();
|
|
|
+ scene.add( light );
|
|
|
+
|
|
|
+ /// ambient light
|
|
|
+ var ambientLight = new THREE.AmbientLight(0x404040);
|
|
|
+ scene.add( ambientLight );
|
|
|
+
|
|
|
+ /// backgroup grids
|
|
|
+ var plane = new THREE.Mesh(
|
|
|
+ new THREE.PlaneGeometry(160, 160, 20, 20),
|
|
|
+ new THREE.MeshBasicMaterial({ color: 0x7f7f7f, wireframe: true }));
|
|
|
+ plane.rotation.x = Math.PI;
|
|
|
+ group.add( plane );
|
|
|
+
|
|
|
+ var obj = initSVGObject();
|
|
|
+ addGeoObject( group, obj );
|
|
|
+};
|
|
|
+
|
|
|
+var initSVGObject = function() {
|
|
|
+ var obj = {};
|
|
|
+
|
|
|
+ /// The geo data from Taipei City, Keelung City, Taipei County in SVG form
|
|
|
+ obj.paths = [
|
|
|
+ /// Taipei City
|
|
|
+ "M366.2182,108.9780 L368.0329,110.3682 L367.5922,112.4411 L369.9258,116.0311 L368.9827,117.3543 " +
|
|
|
+ "L371.5686,119.8491 L370.5599,121.7206 L372.9314,124.8009 L368.8889,126.7603 L369.2695,130.7622 " +
|
|
|
+ "L366.1499,130.3388 L363.4698,128.1161 L362.9256,125.6018 L360.8153,126.4025 L360.2968,124.3588 " +
|
|
|
+ "L361.9519,121.1623 L360.4475,118.7162 L358.1163,117.8678 L358.7094,115.7577 L361.6243,112.4576 Z",
|
|
|
+ /// Keelung City
|
|
|
+ "M380.2689,113.3850 L383.5604,114.2370 L383.7404,114.2386 L385.4082,115.6247 L384.9725,117.4631 " +
|
|
|
+ "L381.6681,117.9439 L383.0209,121.0914 L379.4649,122.7061 L373.4987,118.8487 L372.0980,114.7589 " +
|
|
|
+ "L377.9716,112.0707 Z",
|
|
|
+ /// Taipei County
|
|
|
+ "M359.4486,155.6690 L357.0422,152.7420 L355.1688,148.0173 L357.1186,145.8045 L354.1323,141.2242 " +
|
|
|
+ "L351.1807,141.6609 L348.9387,140.5372 L349.5415,137.8396 L347.5174,136.1694 L347.6299,129.2327 " +
|
|
|
+ "L351.4192,128.8067 L354.2518,125.3113 L352.5805,121.8038 L349.3190,120.9429 L344.3277,116.7676 " +
|
|
|
+ "L350.9772,115.1221 L354.5759,112.5371 L354.5667,110.6949 L357.4098,105.7489 L362.3963,101.8443 " +
|
|
|
+ "L364.4415,101.0819 L364.5314,101.0828 L364.6209,101.1230 L364.7698,101.2029 L368.1221,101.5115 " +
|
|
|
+ "L371.7216,104.1338 L372.2958,106.7261 L375.5949,109.6971 L377.0415,108.8875 L377.0737,108.6526 " +
|
|
|
+ "L377.4037,108.6165 L376.8840,109.7091 L376.7323,109.9037 L377.9416,112.0705 L371.7970,114.8736 " +
|
|
|
+ "L374.0935,119.4031 L380.7848,122.7963 L382.6529,121.9897 L381.5792,117.8256 L385.0339,117.3069 " +
|
|
|
+ "L385.4082,115.6247 L388.7014,116.3969 L389.8697,116.6024 L390.0206,116.4860 L391.0396,116.6118 " +
|
|
|
+ "L394.6665,116.9929 L394.4694,119.2255 L394.3172,119.4987 L395.3792,121.8977 L395.2728,124.0526 " +
|
|
|
+ "L397.2123,125.6350 L401.1709,126.2516 L401.2612,126.2130 L401.4086,126.6060 L400.1992,127.7733 " +
|
|
|
+ "L399.7769,128.0446 L399.6247,128.3179 L398.1779,129.0521 L394.2418,129.2969 L388.7324,130.9385 " +
|
|
|
+ "L389.2782,134.0003 L383.7237,137.0111 L381.7445,139.9336 L379.7001,139.9546 L376.1539,143.0580 " +
|
|
|
+ "L371.3022,144.1094 L368.6009,146.5914 L368.7361,151.1399 L363.6153,154.4980 " +
|
|
|
+ /// Taipei County hole.
|
|
|
+ "M363.4600,128.3904 L366.6300,130.3829 L369.3732,129.3913 L369.5603,125.6695 L374.3989,125.1677 " +
|
|
|
+ "L370.8412,123.6440 L371.0684,118.8252 L369.0431,117.3157 L369.6882,115.7936 L367.8578,112.8749 " +
|
|
|
+ "L368.1217,110.4867 L366.5152,109.2554 L361.9554,112.3435 L358.1163,117.8678 L361.7218,120.2192 " +
|
|
|
+ "L360.7261,126.3232 L362.8064,125.5221 Z"];
|
|
|
+
|
|
|
+ obj.amounts = [ 19, 20, 21 ];
|
|
|
+ obj.colors = [ 0xC07000, 0xC08000, 0xC0A000 ];
|
|
|
+ obj.center = { x:365, y:125 };
|
|
|
+
|
|
|
+ return obj;
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+ /// Events from extrude shapes example
|
|
|
+
|
|
|
+ function onWindowResize() {
|
|
|
+
|
|
|
+ windowHalfX = window.innerWidth / 2;
|
|
|
+ windowHalfY = window.innerHeight / 2;
|
|
|
+
|
|
|
+ camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentMouseDown( event ) {
|
|
|
+
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ document.addEventListener( 'mousemove', onDocumentMouseMove, false );
|
|
|
+ document.addEventListener( 'mouseup', onDocumentMouseUp, false );
|
|
|
+ document.addEventListener( 'mouseout', onDocumentMouseOut, false );
|
|
|
+
|
|
|
+ mouseXOnMouseDown = event.clientX - windowHalfX;
|
|
|
+ targetRotationOnMouseDown = targetRotation;
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentMouseMove( event ) {
|
|
|
+
|
|
|
+ mouseX = event.clientX - windowHalfX;
|
|
|
+
|
|
|
+ targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentMouseUp( event ) {
|
|
|
+
|
|
|
+ document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
|
|
|
+ document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
|
|
|
+ document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentMouseOut( event ) {
|
|
|
+
|
|
|
+ document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
|
|
|
+ document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
|
|
|
+ document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentTouchStart( event ) {
|
|
|
+
|
|
|
+ if ( event.touches.length == 1 ) {
|
|
|
+
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
|
|
|
+ targetRotationOnMouseDown = targetRotation;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ function onDocumentTouchMove( event ) {
|
|
|
+
|
|
|
+ if ( event.touches.length == 1 ) {
|
|
|
+
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ mouseX = event.touches[ 0 ].pageX - windowHalfX;
|
|
|
+ targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ function animate() {
|
|
|
+
|
|
|
+ /// compatibility : http://caniuse.com/requestanimationframe
|
|
|
+ requestAnimationFrame( animate );
|
|
|
+
|
|
|
+ render();
|
|
|
+ };
|
|
|
+
|
|
|
+ function render() {
|
|
|
+
|
|
|
+ group.rotation.y += ( targetRotation - group.rotation.y ) * 0.05;
|
|
|
+ renderer.render( scene, camera );
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+ /// Main
|
|
|
+
|
|
|
+ var renderer;
|
|
|
+ var scene, camera, group;
|
|
|
+
|
|
|
+ var targetRotation = 0;
|
|
|
+ var targetRotationOnMouseDown = 0;
|
|
|
+
|
|
|
+ var mouseX = 0;
|
|
|
+ var mouseXOnMouseDown = 0;
|
|
|
+
|
|
|
+ var windowHalfX = window.innerWidth / 2;
|
|
|
+ var windowHalfY = window.innerHeight / 2;
|
|
|
+
|
|
|
+ var container = document.createElement( 'div' );
|
|
|
+ document.body.appendChild( container );
|
|
|
+
|
|
|
+ var info = document.createElement( 'div' );
|
|
|
+ info.style.position = 'absolute';
|
|
|
+ info.style.top = '10px';
|
|
|
+ info.style.width = '100%';
|
|
|
+ info.style.textAlign = 'center';
|
|
|
+ info.innerHTML = 'Shapes Extrusion via Geo Data<br/>Drag to spin';
|
|
|
+ container.appendChild( info );
|
|
|
+
|
|
|
+ init3d();
|
|
|
+
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
+ document.addEventListener( 'mousedown', onDocumentMouseDown, false );
|
|
|
+ document.addEventListener( 'touchstart', onDocumentTouchStart, false );
|
|
|
+ document.addEventListener( 'touchmove', onDocumentTouchMove, false );
|
|
|
+ window.addEventListener( 'resize', onWindowResize, false );
|
|
|
+
|
|
|
+ animate();
|
|
|
+</script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+</body>
|
|
|
+</html>
|