diff --git a/3d.php b/3d.php new file mode 100644 index 0000000..b2233a0 --- /dev/null +++ b/3d.php @@ -0,0 +1,151 @@ + + + + + + + + +
+ +1 | ( function () {
+ |
2 |
+ |
3 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
+ |
4 | //
+ |
5 | // Orbit - left mouse / touch: one-finger move
+ |
6 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
+ |
7 | // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
+ |
8 |
+ |
9 | const _changeEvent = {
+ |
10 | type: 'change'
+ |
11 | };
+ |
12 | const _startEvent = {
+ |
13 | type: 'start'
+ |
14 | };
+ |
15 | const _endEvent = {
+ |
16 | type: 'end'
+ |
17 | };
+ |
18 |
+ |
19 | class OrbitControls extends THREE.EventDispatcher {
+ |
20 |
+ |
21 | constructor( object, domElement ) {
+ |
22 |
+ |
23 | super();
+ |
24 | if ( domElement === undefined ) console.warn( 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.' );
+ |
25 | if ( domElement === document ) console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' );
+ |
26 | this.object = object;
+ |
27 | this.domElement = domElement;
+ |
28 | this.domElement.style.touchAction = 'none'; // disable touch scroll
+ |
29 | // Set to false to disable this control
+ |
30 |
+ |
31 | this.enabled = true; // "target" sets the location of focus, where the object orbits around
+ |
32 |
+ |
33 | this.target = new THREE.Vector3(); // How far you can dolly in and out ( PerspectiveCamera only )
+ |
34 |
+ |
35 | this.minDistance = 0;
+ |
36 | this.maxDistance = Infinity; // How far you can zoom in and out ( OrthographicCamera only )
+ |
37 |
+ |
38 | this.minZoom = 0;
+ |
39 | this.maxZoom = Infinity; // How far you can orbit vertically, upper and lower limits.
+ |
40 | // Range is 0 to Math.PI radians.
+ |
41 |
+ |
42 | this.minPolarAngle = 0; // radians
+ |
43 |
+ |
44 | this.maxPolarAngle = Math.PI; // radians
+ |
45 | // How far you can orbit horizontally, upper and lower limits.
+ |
46 | // If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )
+ |
47 |
+ |
48 | this.minAzimuthAngle = - Infinity; // radians
+ |
49 |
+ |
50 | this.maxAzimuthAngle = Infinity; // radians
+ |
51 | // Set to true to enable damping (inertia)
+ |
52 | // If damping is enabled, you must call controls.update() in your animation loop
+ |
53 |
+ |
54 | this.enableDamping = false;
+ |
55 | this.dampingFactor = 0.05; // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
+ |
56 | // Set to false to disable zooming
+ |
57 |
+ |
58 | this.enableZoom = true;
+ |
59 | this.zoomSpeed = 1.0; // Set to false to disable rotating
+ |
60 |
+ |
61 | this.enableRotate = true;
+ |
62 | this.rotateSpeed = 1.0; // Set to false to disable panning
+ |
63 |
+ |
64 | this.enablePan = true;
+ |
65 | this.panSpeed = 1.0;
+ |
66 | this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up
+ |
67 |
+ |
68 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
+ |
69 | // Set to true to automatically rotate around the target
+ |
70 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
+ |
71 |
+ |
72 | this.autoRotate = false;
+ |
73 | this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60
+ |
74 | // The four arrow keys
+ |
75 |
+ |
76 | this.keys = {
+ |
77 | LEFT: 'ArrowLeft',
+ |
78 | UP: 'ArrowUp',
+ |
79 | RIGHT: 'ArrowRight',
+ |
80 | BOTTOM: 'ArrowDown'
+ |
81 | }; // Mouse buttons
+ |
82 |
+ |
83 | this.mouseButtons = {
+ |
84 | LEFT: THREE.MOUSE.ROTATE,
+ |
85 | MIDDLE: THREE.MOUSE.DOLLY,
+ |
86 | RIGHT: THREE.MOUSE.PAN
+ |
87 | }; // Touch fingers
+ |
88 |
+ |
89 | this.touches = {
+ |
90 | ONE: THREE.TOUCH.ROTATE,
+ |
91 | TWO: THREE.TOUCH.DOLLY_PAN
+ |
92 | }; // for reset
+ |
93 |
+ |
94 | this.target0 = this.target.clone();
+ |
95 | this.position0 = this.object.position.clone();
+ |
96 | this.zoom0 = this.object.zoom; // the target DOM element for key events
+ |
97 |
+ |
98 | this._domElementKeyEvents = null; //
+ |
99 | // public methods
+ |
100 | //
+ |
101 |
+ |
102 | this.getPolarAngle = function () {
+ |
103 |
+ |
104 | return spherical.phi;
+ |
105 |
+ |
106 | };
+ |
107 |
+ |
108 | this.getAzimuthalAngle = function () {
+ |
109 |
+ |
110 | return spherical.theta;
+ |
111 |
+ |
112 | };
+ |
113 |
+ |
114 | this.getDistance = function () {
+ |
115 |
+ |
116 | return this.object.position.distanceTo( this.target );
+ |
117 |
+ |
118 | };
+ |
119 |
+ |
120 | this.listenToKeyEvents = function ( domElement ) {
+ |
121 |
+ |
122 | domElement.addEventListener( 'keydown', onKeyDown );
+ |
123 | this._domElementKeyEvents = domElement;
+ |
124 |
+ |
125 | };
+ |
126 |
+ |
127 | this.saveState = function () {
+ |
128 |
+ |
129 | scope.target0.copy( scope.target );
+ |
130 | scope.position0.copy( scope.object.position );
+ |
131 | scope.zoom0 = scope.object.zoom;
+ |
132 |
+ |
133 | };
+ |
134 |
+ |
135 | this.reset = function () {
+ |
136 |
+ |
137 | scope.target.copy( scope.target0 );
+ |
138 | scope.object.position.copy( scope.position0 );
+ |
139 | scope.object.zoom = scope.zoom0;
+ |
140 | scope.object.updateProjectionMatrix();
+ |
141 | scope.dispatchEvent( _changeEvent );
+ |
142 | scope.update();
+ |
143 | state = STATE.NONE;
+ |
144 |
+ |
145 | }; // this method is exposed, but perhaps it would be better if we can make it private...
+ |
146 |
+ |
147 |
+ |
148 | this.update = function () {
+ |
149 |
+ |
150 | const offset = new THREE.Vector3(); // so camera.up is the orbit axis
+ |
151 |
+ |
152 | const quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
+ |
153 | const quatInverse = quat.clone().invert();
+ |
154 | const lastPosition = new THREE.Vector3();
+ |
155 | const lastQuaternion = new THREE.Quaternion();
+ |
156 | const twoPI = 2 * Math.PI;
+ |
157 | return function update() {
+ |
158 |
+ |
159 | const position = scope.object.position;
+ |
160 | offset.copy( position ).sub( scope.target ); // rotate offset to "y-axis-is-up" space
+ |
161 |
+ |
162 | offset.applyQuaternion( quat ); // angle from z-axis around y-axis
+ |
163 |
+ |
164 | spherical.setFromVector3( offset );
+ |
165 |
+ |
166 | if ( scope.autoRotate && state === STATE.NONE ) {
+ |
167 |
+ |
168 | rotateLeft( getAutoRotationAngle() );
+ |
169 |
+ |
170 | }
+ |
171 |
+ |
172 | if ( scope.enableDamping ) {
+ |
173 |
+ |
174 | spherical.theta += sphericalDelta.theta * scope.dampingFactor;
+ |
175 | spherical.phi += sphericalDelta.phi * scope.dampingFactor;
+ |
176 |
+ |
177 | } else {
+ |
178 |
+ |
179 | spherical.theta += sphericalDelta.theta;
+ |
180 | spherical.phi += sphericalDelta.phi;
+ |
181 |
+ |
182 | } // restrict theta to be between desired limits
+ |
183 |
+ |
184 |
+ |
185 | let min = scope.minAzimuthAngle;
+ |
186 | let max = scope.maxAzimuthAngle;
+ |
187 |
+ |
188 | if ( isFinite( min ) && isFinite( max ) ) {
+ |
189 |
+ |
190 | if ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;
+ |
191 | if ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;
+ |
192 |
+ |
193 | if ( min <= max ) {
+ |
194 |
+ |
195 | spherical.theta = Math.max( min, Math.min( max, spherical.theta ) );
+ |
196 |
+ |
197 | } else {
+ |
198 |
+ |
199 | spherical.theta = spherical.theta > ( min + max ) / 2 ? Math.max( min, spherical.theta ) : Math.min( max, spherical.theta );
+ |
200 |
+ |
201 | }
+ |
202 |
+ |
203 | } // restrict phi to be between desired limits
+ |
204 |
+ |
205 |
+ |
206 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
+ |
207 | spherical.makeSafe();
+ |
208 | spherical.radius *= scale; // restrict radius to be between desired limits
+ |
209 |
+ |
210 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); // move target to panned location
+ |
211 |
+ |
212 | if ( scope.enableDamping === true ) {
+ |
213 |
+ |
214 | scope.target.addScaledVector( panOffset, scope.dampingFactor );
+ |
215 |
+ |
216 | } else {
+ |
217 |
+ |
218 | scope.target.add( panOffset );
+ |
219 |
+ |
220 | }
+ |
221 |
+ |
222 | offset.setFromSpherical( spherical ); // rotate offset back to "camera-up-vector-is-up" space
+ |
223 |
+ |
224 | offset.applyQuaternion( quatInverse );
+ |
225 | position.copy( scope.target ).add( offset );
+ |
226 | scope.object.lookAt( scope.target );
+ |
227 |
+ |
228 | if ( scope.enableDamping === true ) {
+ |
229 |
+ |
230 | sphericalDelta.theta *= 1 - scope.dampingFactor;
+ |
231 | sphericalDelta.phi *= 1 - scope.dampingFactor;
+ |
232 | panOffset.multiplyScalar( 1 - scope.dampingFactor );
+ |
233 |
+ |
234 | } else {
+ |
235 |
+ |
236 | sphericalDelta.set( 0, 0, 0 );
+ |
237 | panOffset.set( 0, 0, 0 );
+ |
238 |
+ |
239 | }
+ |
240 |
+ |
241 | scale = 1; // update condition is:
+ |
242 | // min(camera displacement, camera rotation in radians)^2 > EPS
+ |
243 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
+ |
244 |
+ |
245 | if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) > EPS || 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
+ |
246 |
+ |
247 | scope.dispatchEvent( _changeEvent );
+ |
248 | lastPosition.copy( scope.object.position );
+ |
249 | lastQuaternion.copy( scope.object.quaternion );
+ |
250 | zoomChanged = false;
+ |
251 | return true;
+ |
252 |
+ |
253 | }
+ |
254 |
+ |
255 | return false;
+ |
256 |
+ |
257 | };
+ |
258 |
+ |
259 | }();
+ |
260 |
+ |
261 | this.dispose = function () {
+ |
262 |
+ |
263 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu );
+ |
264 | scope.domElement.removeEventListener( 'pointerdown', onPointerDown );
+ |
265 | scope.domElement.removeEventListener( 'pointercancel', onPointerCancel );
+ |
266 | scope.domElement.removeEventListener( 'wheel', onMouseWheel );
+ |
267 | scope.domElement.removeEventListener( 'pointermove', onPointerMove );
+ |
268 | scope.domElement.removeEventListener( 'pointerup', onPointerUp );
+ |
269 |
+ |
270 | if ( scope._domElementKeyEvents !== null ) {
+ |
271 |
+ |
272 | scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );
+ |
273 |
+ |
274 | } //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
+ |
275 |
+ |
276 | }; //
+ |
277 | // internals
+ |
278 | //
+ |
279 |
+ |
280 |
+ |
281 | const scope = this;
+ |
282 | const STATE = {
+ |
283 | NONE: - 1,
+ |
284 | ROTATE: 0,
+ |
285 | DOLLY: 1,
+ |
286 | PAN: 2,
+ |
287 | TOUCH_ROTATE: 3,
+ |
288 | TOUCH_PAN: 4,
+ |
289 | TOUCH_DOLLY_PAN: 5,
+ |
290 | TOUCH_DOLLY_ROTATE: 6
+ |
291 | };
+ |
292 | let state = STATE.NONE;
+ |
293 | const EPS = 0.000001; // current position in spherical coordinates
+ |
294 |
+ |
295 | const spherical = new THREE.Spherical();
+ |
296 | const sphericalDelta = new THREE.Spherical();
+ |
297 | let scale = 1;
+ |
298 | const panOffset = new THREE.Vector3();
+ |
299 | let zoomChanged = false;
+ |
300 | const rotateStart = new THREE.Vector2();
+ |
301 | const rotateEnd = new THREE.Vector2();
+ |
302 | const rotateDelta = new THREE.Vector2();
+ |
303 | const panStart = new THREE.Vector2();
+ |
304 | const panEnd = new THREE.Vector2();
+ |
305 | const panDelta = new THREE.Vector2();
+ |
306 | const dollyStart = new THREE.Vector2();
+ |
307 | const dollyEnd = new THREE.Vector2();
+ |
308 | const dollyDelta = new THREE.Vector2();
+ |
309 | const pointers = [];
+ |
310 | const pointerPositions = {};
+ |
311 |
+ |
312 | function getAutoRotationAngle() {
+ |
313 |
+ |
314 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
+ |
315 |
+ |
316 | }
+ |
317 |
+ |
318 | function getZoomScale() {
+ |
319 |
+ |
320 | return Math.pow( 0.95, scope.zoomSpeed );
+ |
321 |
+ |
322 | }
+ |
323 |
+ |
324 | function rotateLeft( angle ) {
+ |
325 |
+ |
326 | sphericalDelta.theta -= angle;
+ |
327 |
+ |
328 | }
+ |
329 |
+ |
330 | function rotateUp( angle ) {
+ |
331 |
+ |
332 | sphericalDelta.phi -= angle;
+ |
333 |
+ |
334 | }
+ |
335 |
+ |
336 | const panLeft = function () {
+ |
337 |
+ |
338 | const v = new THREE.Vector3();
+ |
339 | return function panLeft( distance, objectMatrix ) {
+ |
340 |
+ |
341 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
+ |
342 |
+ |
343 | v.multiplyScalar( - distance );
+ |
344 | panOffset.add( v );
+ |
345 |
+ |
346 | };
+ |
347 |
+ |
348 | }();
+ |
349 |
+ |
350 | const panUp = function () {
+ |
351 |
+ |
352 | const v = new THREE.Vector3();
+ |
353 | return function panUp( distance, objectMatrix ) {
+ |
354 |
+ |
355 | if ( scope.screenSpacePanning === true ) {
+ |
356 |
+ |
357 | v.setFromMatrixColumn( objectMatrix, 1 );
+ |
358 |
+ |
359 | } else {
+ |
360 |
+ |
361 | v.setFromMatrixColumn( objectMatrix, 0 );
+ |
362 | v.crossVectors( scope.object.up, v );
+ |
363 |
+ |
364 | }
+ |
365 |
+ |
366 | v.multiplyScalar( distance );
+ |
367 | panOffset.add( v );
+ |
368 |
+ |
369 | };
+ |
370 |
+ |
371 | }(); // deltaX and deltaY are in pixels; right and down are positive
+ |
372 |
+ |
373 |
+ |
374 | const pan = function () {
+ |
375 |
+ |
376 | const offset = new THREE.Vector3();
+ |
377 | return function pan( deltaX, deltaY ) {
+ |
378 |
+ |
379 | const element = scope.domElement;
+ |
380 |
+ |
381 | if ( scope.object.isPerspectiveCamera ) {
+ |
382 |
+ |
383 | // perspective
+ |
384 | const position = scope.object.position;
+ |
385 | offset.copy( position ).sub( scope.target );
+ |
386 | let targetDistance = offset.length(); // half of the fov is center to top of screen
+ |
387 |
+ |
388 | targetDistance *= Math.tan( scope.object.fov / 2 * Math.PI / 180.0 ); // we use only clientHeight here so aspect ratio does not distort speed
+ |
389 |
+ |
390 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
+ |
391 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
+ |
392 |
+ |
393 | } else if ( scope.object.isOrthographicCamera ) {
+ |
394 |
+ |
395 | // orthographic
+ |
396 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
+ |
397 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
+ |
398 |
+ |
399 | } else {
+ |
400 |
+ |
401 | // camera neither orthographic nor perspective
+ |
402 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
+ |
403 | scope.enablePan = false;
+ |
404 |
+ |
405 | }
+ |
406 |
+ |
407 | };
+ |
408 |
+ |
409 | }();
+ |
410 |
+ |
411 | function dollyOut( dollyScale ) {
+ |
412 |
+ |
413 | if ( scope.object.isPerspectiveCamera ) {
+ |
414 |
+ |
415 | scale /= dollyScale;
+ |
416 |
+ |
417 | } else if ( scope.object.isOrthographicCamera ) {
+ |
418 |
+ |
419 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
+ |
420 | scope.object.updateProjectionMatrix();
+ |
421 | zoomChanged = true;
+ |
422 |
+ |
423 | } else {
+ |
424 |
+ |
425 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+ |
426 | scope.enableZoom = false;
+ |
427 |
+ |
428 | }
+ |
429 |
+ |
430 | }
+ |
431 |
+ |
432 | function dollyIn( dollyScale ) {
+ |
433 |
+ |
434 | if ( scope.object.isPerspectiveCamera ) {
+ |
435 |
+ |
436 | scale *= dollyScale;
+ |
437 |
+ |
438 | } else if ( scope.object.isOrthographicCamera ) {
+ |
439 |
+ |
440 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
+ |
441 | scope.object.updateProjectionMatrix();
+ |
442 | zoomChanged = true;
+ |
443 |
+ |
444 | } else {
+ |
445 |
+ |
446 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
+ |
447 | scope.enableZoom = false;
+ |
448 |
+ |
449 | }
+ |
450 |
+ |
451 | } //
+ |
452 | // event callbacks - update the object state
+ |
453 | //
+ |
454 |
+ |
455 |
+ |
456 | function handleMouseDownRotate( event ) {
+ |
457 |
+ |
458 | rotateStart.set( event.clientX, event.clientY );
+ |
459 |
+ |
460 | }
+ |
461 |
+ |
462 | function handleMouseDownDolly( event ) {
+ |
463 |
+ |
464 | dollyStart.set( event.clientX, event.clientY );
+ |
465 |
+ |
466 | }
+ |
467 |
+ |
468 | function handleMouseDownPan( event ) {
+ |
469 |
+ |
470 | panStart.set( event.clientX, event.clientY );
+ |
471 |
+ |
472 | }
+ |
473 |
+ |
474 | function handleMouseMoveRotate( event ) {
+ |
475 |
+ |
476 | rotateEnd.set( event.clientX, event.clientY );
+ |
477 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
+ |
478 | const element = scope.domElement;
+ |
479 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
+ |
480 |
+ |
481 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
+ |
482 | rotateStart.copy( rotateEnd );
+ |
483 | scope.update();
+ |
484 |
+ |
485 | }
+ |
486 |
+ |
487 | function handleMouseMoveDolly( event ) {
+ |
488 |
+ |
489 | dollyEnd.set( event.clientX, event.clientY );
+ |
490 | dollyDelta.subVectors( dollyEnd, dollyStart );
+ |
491 |
+ |
492 | if ( dollyDelta.y > 0 ) {
+ |
493 |
+ |
494 | dollyOut( getZoomScale() );
+ |
495 |
+ |
496 | } else if ( dollyDelta.y < 0 ) {
+ |
497 |
+ |
498 | dollyIn( getZoomScale() );
+ |
499 |
+ |
500 | }
+ |
501 |
+ |
502 | dollyStart.copy( dollyEnd );
+ |
503 | scope.update();
+ |
504 |
+ |
505 | }
+ |
506 |
+ |
507 | function handleMouseMovePan( event ) {
+ |
508 |
+ |
509 | panEnd.set( event.clientX, event.clientY );
+ |
510 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
+ |
511 | pan( panDelta.x, panDelta.y );
+ |
512 | panStart.copy( panEnd );
+ |
513 | scope.update();
+ |
514 |
+ |
515 | }
+ |
516 |
+ |
517 | function handleMouseUp() { // no-op
+ |
518 | }
+ |
519 |
+ |
520 | function handleMouseWheel( event ) {
+ |
521 |
+ |
522 | if ( event.deltaY < 0 ) {
+ |
523 |
+ |
524 | dollyIn( getZoomScale() );
+ |
525 |
+ |
526 | } else if ( event.deltaY > 0 ) {
+ |
527 |
+ |
528 | dollyOut( getZoomScale() );
+ |
529 |
+ |
530 | }
+ |
531 |
+ |
532 | scope.update();
+ |
533 |
+ |
534 | }
+ |
535 |
+ |
536 | function handleKeyDown( event ) {
+ |
537 |
+ |
538 | let needsUpdate = false;
+ |
539 |
+ |
540 | switch ( event.code ) {
+ |
541 |
+ |
542 | case scope.keys.UP:
+ |
543 | pan( 0, scope.keyPanSpeed );
+ |
544 | needsUpdate = true;
+ |
545 | break;
+ |
546 |
+ |
547 | case scope.keys.BOTTOM:
+ |
548 | pan( 0, - scope.keyPanSpeed );
+ |
549 | needsUpdate = true;
+ |
550 | break;
+ |
551 |
+ |
552 | case scope.keys.LEFT:
+ |
553 | pan( scope.keyPanSpeed, 0 );
+ |
554 | needsUpdate = true;
+ |
555 | break;
+ |
556 |
+ |
557 | case scope.keys.RIGHT:
+ |
558 | pan( - scope.keyPanSpeed, 0 );
+ |
559 | needsUpdate = true;
+ |
560 | break;
+ |
561 |
+ |
562 | }
+ |
563 |
+ |
564 | if ( needsUpdate ) {
+ |
565 |
+ |
566 | // prevent the browser from scrolling on cursor keys
+ |
567 | event.preventDefault();
+ |
568 | scope.update();
+ |
569 |
+ |
570 | }
+ |
571 |
+ |
572 | }
+ |
573 |
+ |
574 | function handleTouchStartRotate() {
+ |
575 |
+ |
576 | if ( pointers.length === 1 ) {
+ |
577 |
+ |
578 | rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );
+ |
579 |
+ |
580 | } else {
+ |
581 |
+ |
582 | const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
+ |
583 | const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
+ |
584 | rotateStart.set( x, y );
+ |
585 |
+ |
586 | }
+ |
587 |
+ |
588 | }
+ |
589 |
+ |
590 | function handleTouchStartPan() {
+ |
591 |
+ |
592 | if ( pointers.length === 1 ) {
+ |
593 |
+ |
594 | panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );
+ |
595 |
+ |
596 | } else {
+ |
597 |
+ |
598 | const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
+ |
599 | const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
+ |
600 | panStart.set( x, y );
+ |
601 |
+ |
602 | }
+ |
603 |
+ |
604 | }
+ |
605 |
+ |
606 | function handleTouchStartDolly() {
+ |
607 |
+ |
608 | const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX;
+ |
609 | const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY;
+ |
610 | const distance = Math.sqrt( dx * dx + dy * dy );
+ |
611 | dollyStart.set( 0, distance );
+ |
612 |
+ |
613 | }
+ |
614 |
+ |
615 | function handleTouchStartDollyPan() {
+ |
616 |
+ |
617 | if ( scope.enableZoom ) handleTouchStartDolly();
+ |
618 | if ( scope.enablePan ) handleTouchStartPan();
+ |
619 |
+ |
620 | }
+ |
621 |
+ |
622 | function handleTouchStartDollyRotate() {
+ |
623 |
+ |
624 | if ( scope.enableZoom ) handleTouchStartDolly();
+ |
625 | if ( scope.enableRotate ) handleTouchStartRotate();
+ |
626 |
+ |
627 | }
+ |
628 |
+ |
629 | function handleTouchMoveRotate( event ) {
+ |
630 |
+ |
631 | if ( pointers.length == 1 ) {
+ |
632 |
+ |
633 | rotateEnd.set( event.pageX, event.pageY );
+ |
634 |
+ |
635 | } else {
+ |
636 |
+ |
637 | const position = getSecondPointerPosition( event );
+ |
638 | const x = 0.5 * ( event.pageX + position.x );
+ |
639 | const y = 0.5 * ( event.pageY + position.y );
+ |
640 | rotateEnd.set( x, y );
+ |
641 |
+ |
642 | }
+ |
643 |
+ |
644 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
+ |
645 | const element = scope.domElement;
+ |
646 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
+ |
647 |
+ |
648 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
+ |
649 | rotateStart.copy( rotateEnd );
+ |
650 |
+ |
651 | }
+ |
652 |
+ |
653 | function handleTouchMovePan( event ) {
+ |
654 |
+ |
655 | if ( pointers.length === 1 ) {
+ |
656 |
+ |
657 | panEnd.set( event.pageX, event.pageY );
+ |
658 |
+ |
659 | } else {
+ |
660 |
+ |
661 | const position = getSecondPointerPosition( event );
+ |
662 | const x = 0.5 * ( event.pageX + position.x );
+ |
663 | const y = 0.5 * ( event.pageY + position.y );
+ |
664 | panEnd.set( x, y );
+ |
665 |
+ |
666 | }
+ |
667 |
+ |
668 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
+ |
669 | pan( panDelta.x, panDelta.y );
+ |
670 | panStart.copy( panEnd );
+ |
671 |
+ |
672 | }
+ |
673 |
+ |
674 | function handleTouchMoveDolly( event ) {
+ |
675 |
+ |
676 | const position = getSecondPointerPosition( event );
+ |
677 | const dx = event.pageX - position.x;
+ |
678 | const dy = event.pageY - position.y;
+ |
679 | const distance = Math.sqrt( dx * dx + dy * dy );
+ |
680 | dollyEnd.set( 0, distance );
+ |
681 | dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
+ |
682 | dollyOut( dollyDelta.y );
+ |
683 | dollyStart.copy( dollyEnd );
+ |
684 |
+ |
685 | }
+ |
686 |
+ |
687 | function handleTouchMoveDollyPan( event ) {
+ |
688 |
+ |
689 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
+ |
690 | if ( scope.enablePan ) handleTouchMovePan( event );
+ |
691 |
+ |
692 | }
+ |
693 |
+ |
694 | function handleTouchMoveDollyRotate( event ) {
+ |
695 |
+ |
696 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
+ |
697 | if ( scope.enableRotate ) handleTouchMoveRotate( event );
+ |
698 |
+ |
699 | }
+ |
700 |
+ |
701 | function handleTouchEnd() { // no-op
+ |
702 | } //
+ |
703 | // event handlers - FSM: listen for events and reset state
+ |
704 | //
+ |
705 |
+ |
706 |
+ |
707 | function onPointerDown( event ) {
+ |
708 |
+ |
709 | if ( scope.enabled === false ) return;
+ |
710 |
+ |
711 | if ( pointers.length === 0 ) {
+ |
712 |
+ |
713 | scope.domElement.setPointerCapture( event.pointerId );
+ |
714 | scope.domElement.addEventListener( 'pointermove', onPointerMove );
+ |
715 | scope.domElement.addEventListener( 'pointerup', onPointerUp );
+ |
716 |
+ |
717 | } //
+ |
718 |
+ |
719 |
+ |
720 | addPointer( event );
+ |
721 |
+ |
722 | if ( event.pointerType === 'touch' ) {
+ |
723 |
+ |
724 | onTouchStart( event );
+ |
725 |
+ |
726 | } else {
+ |
727 |
+ |
728 | onMouseDown( event );
+ |
729 |
+ |
730 | }
+ |
731 |
+ |
732 | }
+ |
733 |
+ |
734 | function onPointerMove( event ) {
+ |
735 |
+ |
736 | if ( scope.enabled === false ) return;
+ |
737 |
+ |
738 | if ( event.pointerType === 'touch' ) {
+ |
739 |
+ |
740 | onTouchMove( event );
+ |
741 |
+ |
742 | } else {
+ |
743 |
+ |
744 | onMouseMove( event );
+ |
745 |
+ |
746 | }
+ |
747 |
+ |
748 | }
+ |
749 |
+ |
750 | function onPointerUp( event ) {
+ |
751 |
+ |
752 | if ( scope.enabled === false ) return;
+ |
753 |
+ |
754 | if ( event.pointerType === 'touch' ) {
+ |
755 |
+ |
756 | onTouchEnd();
+ |
757 |
+ |
758 | } else {
+ |
759 |
+ |
760 | onMouseUp( event );
+ |
761 |
+ |
762 | }
+ |
763 |
+ |
764 | removePointer( event ); //
+ |
765 |
+ |
766 | if ( pointers.length === 0 ) {
+ |
767 |
+ |
768 | scope.domElement.releasePointerCapture( event.pointerId );
+ |
769 | scope.domElement.removeEventListener( 'pointermove', onPointerMove );
+ |
770 | scope.domElement.removeEventListener( 'pointerup', onPointerUp );
+ |
771 |
+ |
772 | }
+ |
773 |
+ |
774 | }
+ |
775 |
+ |
776 | function onPointerCancel( event ) {
+ |
777 |
+ |
778 | removePointer( event );
+ |
779 |
+ |
780 | }
+ |
781 |
+ |
782 | function onMouseDown( event ) {
+ |
783 |
+ |
784 | let mouseAction;
+ |
785 |
+ |
786 | switch ( event.button ) {
+ |
787 |
+ |
788 | case 0:
+ |
789 | mouseAction = scope.mouseButtons.LEFT;
+ |
790 | break;
+ |
791 |
+ |
792 | case 1:
+ |
793 | mouseAction = scope.mouseButtons.MIDDLE;
+ |
794 | break;
+ |
795 |
+ |
796 | case 2:
+ |
797 | mouseAction = scope.mouseButtons.RIGHT;
+ |
798 | break;
+ |
799 |
+ |
800 | default:
+ |
801 | mouseAction = - 1;
+ |
802 |
+ |
803 | }
+ |
804 |
+ |
805 | switch ( mouseAction ) {
+ |
806 |
+ |
807 | case THREE.MOUSE.DOLLY:
+ |
808 | if ( scope.enableZoom === false ) return;
+ |
809 | handleMouseDownDolly( event );
+ |
810 | state = STATE.DOLLY;
+ |
811 | break;
+ |
812 |
+ |
813 | case THREE.MOUSE.ROTATE:
+ |
814 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
+ |
815 |
+ |
816 | if ( scope.enablePan === false ) return;
+ |
817 | handleMouseDownPan( event );
+ |
818 | state = STATE.PAN;
+ |
819 |
+ |
820 | } else {
+ |
821 |
+ |
822 | if ( scope.enableRotate === false ) return;
+ |
823 | handleMouseDownRotate( event );
+ |
824 | state = STATE.ROTATE;
+ |
825 |
+ |
826 | }
+ |
827 |
+ |
828 | break;
+ |
829 |
+ |
830 | case THREE.MOUSE.PAN:
+ |
831 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
+ |
832 |
+ |
833 | if ( scope.enableRotate === false ) return;
+ |
834 | handleMouseDownRotate( event );
+ |
835 | state = STATE.ROTATE;
+ |
836 |
+ |
837 | } else {
+ |
838 |
+ |
839 | if ( scope.enablePan === false ) return;
+ |
840 | handleMouseDownPan( event );
+ |
841 | state = STATE.PAN;
+ |
842 |
+ |
843 | }
+ |
844 |
+ |
845 | break;
+ |
846 |
+ |
847 | default:
+ |
848 | state = STATE.NONE;
+ |
849 |
+ |
850 | }
+ |
851 |
+ |
852 | if ( state !== STATE.NONE ) {
+ |
853 |
+ |
854 | scope.dispatchEvent( _startEvent );
+ |
855 |
+ |
856 | }
+ |
857 |
+ |
858 | }
+ |
859 |
+ |
860 | function onMouseMove( event ) {
+ |
861 |
+ |
862 | if ( scope.enabled === false ) return;
+ |
863 |
+ |
864 | switch ( state ) {
+ |
865 |
+ |
866 | case STATE.ROTATE:
+ |
867 | if ( scope.enableRotate === false ) return;
+ |
868 | handleMouseMoveRotate( event );
+ |
869 | break;
+ |
870 |
+ |
871 | case STATE.DOLLY:
+ |
872 | if ( scope.enableZoom === false ) return;
+ |
873 | handleMouseMoveDolly( event );
+ |
874 | break;
+ |
875 |
+ |
876 | case STATE.PAN:
+ |
877 | if ( scope.enablePan === false ) return;
+ |
878 | handleMouseMovePan( event );
+ |
879 | break;
+ |
880 |
+ |
881 | }
+ |
882 |
+ |
883 | }
+ |
884 |
+ |
885 | function onMouseUp( event ) {
+ |
886 |
+ |
887 | handleMouseUp( event );
+ |
888 | scope.dispatchEvent( _endEvent );
+ |
889 | state = STATE.NONE;
+ |
890 |
+ |
891 | }
+ |
892 |
+ |
893 | function onMouseWheel( event ) {
+ |
894 |
+ |
895 | if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE ) return;
+ |
896 | event.preventDefault();
+ |
897 | scope.dispatchEvent( _startEvent );
+ |
898 | handleMouseWheel( event );
+ |
899 | scope.dispatchEvent( _endEvent );
+ |
900 |
+ |
901 | }
+ |
902 |
+ |
903 | function onKeyDown( event ) {
+ |
904 |
+ |
905 | if ( scope.enabled === false || scope.enablePan === false ) return;
+ |
906 | handleKeyDown( event );
+ |
907 |
+ |
908 | }
+ |
909 |
+ |
910 | function onTouchStart( event ) {
+ |
911 |
+ |
912 | trackPointer( event );
+ |
913 |
+ |
914 | switch ( pointers.length ) {
+ |
915 |
+ |
916 | case 1:
+ |
917 | switch ( scope.touches.ONE ) {
+ |
918 |
+ |
919 | case THREE.TOUCH.ROTATE:
+ |
920 | if ( scope.enableRotate === false ) return;
+ |
921 | handleTouchStartRotate();
+ |
922 | state = STATE.TOUCH_ROTATE;
+ |
923 | break;
+ |
924 |
+ |
925 | case THREE.TOUCH.PAN:
+ |
926 | if ( scope.enablePan === false ) return;
+ |
927 | handleTouchStartPan();
+ |
928 | state = STATE.TOUCH_PAN;
+ |
929 | break;
+ |
930 |
+ |
931 | default:
+ |
932 | state = STATE.NONE;
+ |
933 |
+ |
934 | }
+ |
935 |
+ |
936 | break;
+ |
937 |
+ |
938 | case 2:
+ |
939 | switch ( scope.touches.TWO ) {
+ |
940 |
+ |
941 | case THREE.TOUCH.DOLLY_PAN:
+ |
942 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
+ |
943 | handleTouchStartDollyPan();
+ |
944 | state = STATE.TOUCH_DOLLY_PAN;
+ |
945 | break;
+ |
946 |
+ |
947 | case THREE.TOUCH.DOLLY_ROTATE:
+ |
948 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
+ |
949 | handleTouchStartDollyRotate();
+ |
950 | state = STATE.TOUCH_DOLLY_ROTATE;
+ |
951 | break;
+ |
952 |
+ |
953 | default:
+ |
954 | state = STATE.NONE;
+ |
955 |
+ |
956 | }
+ |
957 |
+ |
958 | break;
+ |
959 |
+ |
960 | default:
+ |
961 | state = STATE.NONE;
+ |
962 |
+ |
963 | }
+ |
964 |
+ |
965 | if ( state !== STATE.NONE ) {
+ |
966 |
+ |
967 | scope.dispatchEvent( _startEvent );
+ |
968 |
+ |
969 | }
+ |
970 |
+ |
971 | }
+ |
972 |
+ |
973 | function onTouchMove( event ) {
+ |
974 |
+ |
975 | trackPointer( event );
+ |
976 |
+ |
977 | switch ( state ) {
+ |
978 |
+ |
979 | case STATE.TOUCH_ROTATE:
+ |
980 | if ( scope.enableRotate === false ) return;
+ |
981 | handleTouchMoveRotate( event );
+ |
982 | scope.update();
+ |
983 | break;
+ |
984 |
+ |
985 | case STATE.TOUCH_PAN:
+ |
986 | if ( scope.enablePan === false ) return;
+ |
987 | handleTouchMovePan( event );
+ |
988 | scope.update();
+ |
989 | break;
+ |
990 |
+ |
991 | case STATE.TOUCH_DOLLY_PAN:
+ |
992 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
+ |
993 | handleTouchMoveDollyPan( event );
+ |
994 | scope.update();
+ |
995 | break;
+ |
996 |
+ |
997 | case STATE.TOUCH_DOLLY_ROTATE:
+ |
998 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
+ |
999 | handleTouchMoveDollyRotate( event );
+ |
1000 | scope.update();
+ |
1001 | break;
+ |
1002 |
+ |
1003 | default:
+ |
1004 | state = STATE.NONE;
+ |
1005 |
+ |
1006 | }
+ |
1007 |
+ |
1008 | }
+ |
1009 |
+ |
1010 | function onTouchEnd( event ) {
+ |
1011 |
+ |
1012 | handleTouchEnd( event );
+ |
1013 | scope.dispatchEvent( _endEvent );
+ |
1014 | state = STATE.NONE;
+ |
1015 |
+ |
1016 | }
+ |
1017 |
+ |
1018 | function onContextMenu( event ) {
+ |
1019 |
+ |
1020 | if ( scope.enabled === false ) return;
+ |
1021 | event.preventDefault();
+ |
1022 |
+ |
1023 | }
+ |
1024 |
+ |
1025 | function addPointer( event ) {
+ |
1026 |
+ |
1027 | pointers.push( event );
+ |
1028 |
+ |
1029 | }
+ |
1030 |
+ |
1031 | function removePointer( event ) {
+ |
1032 |
+ |
1033 | delete pointerPositions[ event.pointerId ];
+ |
1034 |
+ |
1035 | for ( let i = 0; i < pointers.length; i ++ ) {
+ |
1036 |
+ |
1037 | if ( pointers[ i ].pointerId == event.pointerId ) {
+ |
1038 |
+ |
1039 | pointers.splice( i, 1 );
+ |
1040 | return;
+ |
1041 |
+ |
1042 | }
+ |
1043 |
+ |
1044 | }
+ |
1045 |
+ |
1046 | }
+ |
1047 |
+ |
1048 | function trackPointer( event ) {
+ |
1049 |
+ |
1050 | let position = pointerPositions[ event.pointerId ];
+ |
1051 |
+ |
1052 | if ( position === undefined ) {
+ |
1053 |
+ |
1054 | position = new THREE.Vector2();
+ |
1055 | pointerPositions[ event.pointerId ] = position;
+ |
1056 |
+ |
1057 | }
+ |
1058 |
+ |
1059 | position.set( event.pageX, event.pageY );
+ |
1060 |
+ |
1061 | }
+ |
1062 |
+ |
1063 | function getSecondPointerPosition( event ) {
+ |
1064 |
+ |
1065 | const pointer = event.pointerId === pointers[ 0 ].pointerId ? pointers[ 1 ] : pointers[ 0 ];
+ |
1066 | return pointerPositions[ pointer.pointerId ];
+ |
1067 |
+ |
1068 | } //
+ |
1069 |
+ |
1070 |
+ |
1071 | scope.domElement.addEventListener( 'contextmenu', onContextMenu );
+ |
1072 | scope.domElement.addEventListener( 'pointerdown', onPointerDown );
+ |
1073 | scope.domElement.addEventListener( 'pointercancel', onPointerCancel );
+ |
1074 | scope.domElement.addEventListener( 'wheel', onMouseWheel, {
+ |
1075 | passive: false
+ |
1076 | } ); // force an update at start
+ |
1077 |
+ |
1078 | this.update();
+ |
1079 |
+ |
1080 | }
+ |
1081 |
+ |
1082 | } // This set of controls performs orbiting, dollying (zooming), and panning.
+ |
1083 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
+ |
1084 | // This is very similar to OrbitControls, another set of touch behavior
+ |
1085 | //
+ |
1086 | // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
+ |
1087 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
+ |
1088 | // Pan - left mouse, or arrow keys / touch: one-finger move
+ |
1089 |
+ |
1090 |
+ |
1091 | class MapControls extends OrbitControls {
+ |
1092 |
+ |
1093 | constructor( object, domElement ) {
+ |
1094 |
+ |
1095 | super( object, domElement );
+ |
1096 | this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up
+ |
1097 |
+ |
1098 | this.mouseButtons.LEFT = THREE.MOUSE.PAN;
+ |
1099 | this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE;
+ |
1100 | this.touches.ONE = THREE.TOUCH.PAN;
+ |
1101 | this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;
+ |
1102 |
+ |
1103 | }
+ |
1104 |
+ |
1105 | }
+ |
1106 |
+ |
1107 | THREE.MapControls = MapControls;
+ |
1108 | THREE.OrbitControls = OrbitControls;
+ |
1109 |
+ |
1110 | } )();
+ |
+ + diff --git a/diy.php b/diy.php index 6a75020..6de3449 100644 --- a/diy.php +++ b/diy.php @@ -32,7 +32,8 @@
a gitea instance
+ +a gitea instance
+ + + diff --git a/index.css b/index.css index fd8593d..086e5ef 100644 --- a/index.css +++ b/index.css @@ -44,7 +44,7 @@ footer{ .linkContainer { display: grid; - grid-template-columns: auto auto auto; + grid-template-columns: auto auto auto auto; width: 100%; } @@ -71,14 +71,67 @@ footer{ @-webkit-keyframes glow { from { - text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #e60073, 0 0 40px #e60073, 0 0 50px #e60073, 0 0 60px #e60073, 0 0 70px #e60073; + text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #e60073, 0 0 40px #e60073; } to { - text-shadow: 0 0 20px #fff, 0 0 30px #ff4da6, 0 0 40px #ff4da6, 0 0 50px #ff4da6, 0 0 60px #ff4da6, 0 0 70px #ff4da6, 0 0 80px #ff4da6; + text-shadow: 0 0 20px #fff, 0 0 30px #ff4da6, 0 0 40px #ff4da6, 0 0 50px #ff4da6; } } +@media only screen and (max-width: 500px) { + [class*="bannerHeader"] { + font-size: 7vh; + color: #fff; + } + .bannerSubtext { + font-size: 4vh; + color: #fff; + } + [class*="infoImgDiv"] { + grid-row-start: 1; + grid-row-end: 1; + justify-content: center; + justify-self: center; + display: flex; + } + [class*="infoDiv"] { + grid-row-start: 2; + grid-row-end: 2; + } + [class*="infoContainer"] { + display: grid; + grid-template-columns: auto; + } + [class*="infoImg"] { + width: 60vw; + grid-row-start: 1; + } + .linkContainer { + grid-template-columns: auto auto; + } + .info { + font-size: 6vw; + } + .infoHeader { + font-size: 9vw; + } + .grid-container { + display: grid; + grid-template-columns: auto; + } + [class*="model"] { + height: 40vh; + width: 90vw; + } + [class*="model1"] { + height: 40vh; + width: 90vw; + } +} + +.infoImg { + width: 30vw; .infoContainer { margin-left: 10vw; @@ -111,3 +164,17 @@ footer{ margin-bottom: 0vw; color: deeppink; } + +.model0 { + width: 50vw; + height: 100vh; +} +.model1 { + width: 50vw; + height: 100vh; +} + +.grid_container { + display: grid; + grid-template-columns: auto auto; +} diff --git a/index.php b/index.php index 0c289c1..d92204c 100644 --- a/index.php +++ b/index.php @@ -51,7 +51,8 @@- + + @@ -71,7 +72,7 @@