first commit

This commit is contained in:
Arno Kaimbacher 2020-11-12 13:44:48 +01:00
commit 731ebe85b5
29 changed files with 15276 additions and 0 deletions

5
.babelrc Normal file
View File

@ -0,0 +1,5 @@
{
"plugins": [
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}

2
.env.example Normal file
View File

@ -0,0 +1,2 @@
NODE_ENV=
CONSTANT_VALUE=

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
/node_modules
/dist
/.vs/lms/v15
/lms.user
/lms.sln
/lms.phpproj.user
/lms.phpproj
# Composer
/composer.lock
/composer.phar
/vendor
# Linux
*~
*.swp
# Windows
Thumbs.db
desktop.ini
/.idea
/.vscode
/.vs
/.vagrant
/npm-debug.log
/yarn-error.log
/notes.txt
/.env

View File

@ -0,0 +1,36 @@
{
"folders": [
{
"path": "."
}
],
"settings": {},
"launch": {
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
// "port": 9222,
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}",
"breakOnLoad": true,
// "sourceMapPathOverrides": {
// "webpack:///./~/*": "${workspaceFolder}/node_modules/*",
// "webpack:///./*": "${workspaceFolder}/*",
// "webpack:///*": "*",
// "webpack:///src/*": "${workspaceFolder}/*",
// },
// "sourceMapPathOverrides": {
// // "webpack:///src/*": "${workspaceFolder}/*",
// "webpack:///./*": "${workspaceFolder}/*"
// },
"sourceMaps": true,
"timeout": 15000
}
]
}
}

BIN
images/map/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

40
index.html Normal file
View File

@ -0,0 +1,40 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>3D Viewer</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="mobile-web-app-capable" content="yes">
<!-- <link href="content/img/favicon.ico" rel="shortcut icon" type="image/x-icon" /> -->
<meta name="description" content="3D viewer Geological Survey of Austria">
<meta name="author" content="Arno Kaimbacher">
<!-- <link rel="stylesheet" href="src/css/styles.css?v=1.0"> -->
<link rel="stylesheet" type="text/css" href="dist/main.css" />
<!-- <style>
.mapDesktop {
width: 1174px;
height: 1001px;
}
</style> -->
</head>
<body>
<div id="webgl" class="mapDesktop">
<div id="inset"></div>
<div id="progressArea">
<img id="loadingImg" alt="" src="images/map/loading.gif" style="display:none;" />
</div>
</div>
<script src="dist/main.js"></script>
</body>
</html>

6011
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
package.json Normal file
View File

@ -0,0 +1,30 @@
{
"dependencies": {
"three": "^0.119.1"
},
"devDependencies": {
"@babel/core": "^7.11.1",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"babel-loader": "^8.1.0",
"concurrently": "^5.2.0",
"css-loader": "^4.2.0",
"dotenv": "^8.2.0",
"file-loader": "^6.0.0",
"img-loader": "^3.0.1",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^4.0.0",
"url-loader": "^4.1.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-merge": "^4.2.2"
},
"scripts": {
"babel": "babel --presets es2015 js/main.js -o build/main.bundle.js",
"serve": "http-server",
"prod": "rm -rf dist && webpack",
"watch": "concurrently \"npm run serve\" \"npx webpack --source-maps --watch\" "
}
}

93
src/css/page.css Normal file
View File

@ -0,0 +1,93 @@
/*@charset "UTF-8";*/
.mapDesktop {
overflow: hidden;
position: absolute;
bottom: 30px;
top: 30px;
left: 30px;
right: 30px;
}
#inset {
position: absolute;
bottom: 0;
left: 0;
border: none;
width: 120px;
height: 120px;
/*background-color:lightcyan;*/
}
/* control positioning */
.gba-control {
position: relative;
z-index: 7;
pointer-events: auto;
float: left;
clear: both;
}
.gba-top,
.gba-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.gba-top {
top: 0;
}
.gba-right {
right: 0;
/*right: 5px;*/
}
.gba-bottom {
bottom: 0;
}
.gba-left {
left: 0;
}
.gba-right .gba-control {
float: right;
}
.gba-top .gba-control:not(:first-child) {
margin-top: 10px;
}
.gba-bottom .gba-control {
margin-bottom: 10px;
}
.gba-left .gba-control {
margin-left: 0px;
}
.gba-control-home span {
/*padding: 2px;*/
width: 30px;
height: 30px;
/*background-color: rgba(102,102,102,0.80);*/
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
border-radius: 5px;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAABDlBMVEWZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmXl5f///+VlZWZmZmWlpaUlJSYmJiSkpKampqzs7O3t7fMzMyTk5O2trarq6uysrLR0dHY2Njb29v8/PyMjIy4uLi5ubm6urq1tbSbm5uhoaGmpqanp6eoqKi7u7u+vr7BwcHFxcXGxsbHx8fIyMjJycmpqanNzc3Ozs7Pz8/Q0NCNjY3S0tLT09PV1dXW1tavr6/Z2dmxsbHc3Nzd3d3i4uLn5+fv7+/w8PD39/f5+fn7+/uPj4/9/f3+/v6QkJA5Pja9AAAAGnRSTlMABUdVVmxucX6MtLvHycrN2Nzi4+vs7e/3+OshyJcAAAECSURBVHherdLFcsQwEEXRDjLDJOkWGYcnzMzM/P8/Eo8V18i4yl091alSaSGAgclSdnMTPQB9vKBumCriYZg3j0qKGI9DyVRxVPVNHjVZyTN6u/VzGFmNiN4di3NmWWiw1itq9+Faoux5WxhjFNeka660grkkTUZxQ1Ff7glR2WTEO+rUfI0zqgbFM1moB0rm+BEL+5FS1XzUjOvPlFHdViELx3tKa8M7xr/LW7tpvr/A6Gn+HlHGy/+Xv8Ny+XCzUtmo5/LyD2Ofp7m8LYN9nuZ9gy/1djssd17CVlmwD/Susjbrj2yvhdnJPQbTPEjpeHKPwCAvqBe6hmYXs1uY6YdfRkdtRcSvwdgAAAAASUVORK5CYII=') /*img/home.png*/;
/*opacity : 0.8;*/
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}

View File

@ -0,0 +1,66 @@
// import { Class } from '../core/Class';
import * as util from '../core/utilities';
// import * as dom from '../core/domUtil';
// export var Control = Class.extend({
class Control {
// @section
// @aka Control options
options = {
position: 'topright'
};
constructor(defaults) {
if (!(this instanceof Control)) {
throw new TypeError("Control constructor cannot be called as a function.");
}
// properties
util.setOptions(this, defaults);
}
getPosition() {
return this.options.position;
}
getContainer() {
return this._container;
}
addTo(map) {
this._map = map;
var container = this._container = this.onAdd(map);
var pos = this.getPosition();//"topright"
var corner = map._controlCorners[pos];
if (container) {
// $(container).addClass('gba-control');
container.classList.add("gba-control");
if (pos.indexOf('bottom') !== -1) {
corner.insertBefore(container, corner.firstChild);
}
else {
corner.appendChild(container);
}
}
return this;
}
removeFrom(map) {
var pos = this.getPosition(),
corner = map._controlCorners[pos];
corner.removeChild(this._container);
this._map = null;
if (this.onRemove) {
this.onRemove(map);
}
return this;
}
}
export { Control };

View File

@ -0,0 +1,102 @@
import { Control } from "./Control";
import * as dom from '../core/domUtil';
import * as domEvent from '../core/domEvent';
class HomeButton extends Control {
options = {
position: 'topright',
homeText: '+',
//homeTitle: 'Home Extent',
visible: true
};
constructor(defaults) {
super(defaults);
// properties
this.map = {};
this.visible = this.options.visible;
this.home = this.options.home;
}
onAdd(map) {
if (!this.map) {
//self.destroy();
logger.warning('HomeButton::map required', true);
return;
}
this.map = map;
//this.options.home.initialZoom = map.options.zoom;
//this.options.home.initialCenter = map.options.center;
var b = this._nls = "test"; //util.mixin({}, N.widgets.home);
var className = 'gba-control-home';
// Create sidebar container
//var container = this._container = L.DomUtil.create('div', className);
var container = this._container = dom.createDom("div", { "class": className });
//if (this.options.home) {
this._homeButton = this._createButton(
//this.options.zoomInText, this.options.zoomInTitle,
"", "b.title",
className + '-do', container, this._goHome, this);
this._init();
//}
//this._updateDisabled();
//map.on('zoomend zoomlevelschange', this._updateDisabled, this);
return container;
}
_init() {
// show or hide widget
this._visible();
////// if no extent set, set extent to map extent
//if (!this.home) {
// this.home = this.map.getBounds();
//}
//// widget is now loaded
this.loaded = true;
}
_visible() {
if (this.visible === true) {
//domStyle.set(self.domNode, 'display', 'block');
// $(this._container).css('display', 'block');
this._container.style.display = 'block';
} else {
//domStyle.set(self.domNode, 'display', 'none');
// $(this._container).css('display', 'none');
this._container.style.display = 'none';
}
}
_goHome() {
//this._map.zoomIn(e.shiftKey ? 3 : 1);
this._exitFired = false;
//var bounds = L.latLngBounds(this.options.home._southWest, this.options.home._northEast);
//this.map.fitBounds(bounds);
this.map.reset();
}
_createButton(html, title, className, container, fn, context) {
//var link = L.DomUtil.create('a', className, container);
let link = dom.createDom("span", { "class": className, innerHTML: html, title: title }, container);
// let stop = domEvent.stopPropagation();
domEvent.on(link, 'click', fn, context);
// .on(link, 'click', stop)
// .on(link, 'mousedown', stop)
// .on(link, 'dblclick', stop)
// .on(link, 'click', domEvent.preventDefault())
// //.on(link, 'click', fn.bind(this));
// .on(link, 'click', fn, context);
return link;
}
}
export { HomeButton };

49
src/js/core/Class.js Normal file
View File

@ -0,0 +1,49 @@
import * as util from './utilities';
export function Class() { }
// @function extend(props: Object): Function
// [Extends the current class](#class-inheritance) given the properties to be included.
Class.extend = function (props) {
var NewClass = function () {
// call the constructor
if (this.init) {
this.init.apply(this, arguments);
}
//// call all constructor hooks
//if (this._initHooks) {
// this.callInitHooks();
//}
};
// instantiate class without calling constructor
var F = function () { };
F.prototype = this.prototype;
var proto = new F();
proto.constructor = NewClass;
NewClass.prototype = proto;
//inherit parent's statics
for (var i in this) {
if (this.hasOwnProperty(i) && i !== 'prototype') {
NewClass[i] = this[i];
}
}
// mix given properties into the prototype
util.extend(proto, props);
return NewClass;
};
// @function include(properties: Object): this
// [Includes a mixin](#class-includes) into the current class.
Class.include = function (props) {
util.extend(this.prototype, props);
return this;
};

206
src/js/core/EventEmitter.js Normal file
View File

@ -0,0 +1,206 @@
import * as util from './utilities';
var eventsKey = '_events';
class EventEmitter {
constructor() {
var test = "test";
}
_getEvents() {
return this._events || (this._events = {});
}
getListeners(evt) {
var events = this._getEvents();
var response;
var key;
// Return a concatenated array of all matching events if
// the selector is a regular expression.
if (evt instanceof RegExp) {
response = {};
for (key in events) {
if (events.hasOwnProperty(key) && evt.test(key)) {
response[key] = events[key];
}
}
}
else {
response = events[evt] || (events[evt] = []);
}
return response;
}
getListenersAsObject(evt) {
var listeners = this.getListeners(evt);
var response;
if (listeners instanceof Array) {
response = {};
response[evt] = listeners;
}
return response || listeners;
}
addListener(evt, fn, context) { // (String, Function[, Object]) or (Object[, Object])
// types can be a map of types/handlers
//if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; }
//var events = this.getListenersAsObject(evt);
var events = this[eventsKey] = this[eventsKey] || {};
var contextId = context && context !== this && util.stamp(context);
var i, len, event, type, indexKey, indexLenKey, typeIndex;
//// types can be a string of space-separated words
//types = util.splitWords(types);
//for (i = 0, len = types.length; i < len; i++) {
event = {
action: fn,
context: context || this
};
type = evt;// types[i];
if (contextId) {
// store listeners of a particular context in a separate hash (if it has an id)
// gives a major performance boost when removing thousands of map layers
indexKey = type + '_idx';
indexLenKey = indexKey + '_len';
typeIndex = events[indexKey] = events[indexKey] || {};
if (!typeIndex[contextId]) {
typeIndex[contextId] = [];
// keep track of the number of keys in the index to quickly check if it's empty
events[indexLenKey] = (events[indexLenKey] || 0) + 1;
}
typeIndex[contextId].push(event);
}
else {
events[type] = events[type] || [];
events[type].push(event);
}
//}
return this;
}
removeListener(evt, fn, context) { // ([String, Function, Object]) or (Object[, Object])
if (!this[eventsKey]) {
return this;
}
//if (!types) {
// return this.clearAllEventListeners();
//}
//if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; }
var events = this[eventsKey],
contextId = context && context !== this && util.stamp(context),
i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
//types = L.Util.splitWords(types);
//for (i = 0, len = types.length; i < len; i++) {
type = evt;//types[i];
indexKey = type + '_idx';
indexLenKey = indexKey + '_len';
typeIndex = events[indexKey];
if (!fn) {
// clear all listeners for a type if function isn't specified
delete events[type];
delete events[indexKey];
delete events[indexLenKey];
}
else {
listeners = contextId && typeIndex ? typeIndex[contextId] : events[type];
if (listeners) {
for (j = listeners.length - 1; j >= 0; j--) {
if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) {
removed = listeners.splice(j, 1);
// set the old action to a no-op, because it is possible
// that the listener is being iterated over as part of a dispatch
//removed[0].action = util.falseFn;
}
}
if (context && typeIndex && (listeners.length === 0)) {
delete typeIndex[contextId];
events[indexLenKey]--;
}
}
}
return this;
}
hasEventListeners(type) { // (String) -> Boolean
var events = this[eventsKey];
return !!events && ((type in events && events[type].length > 0) ||
(type + '_idx' in events && events[type + '_idx_len'] > 0));
}
// (String[, Object])
emit(type, data) {
if (!this.hasEventListeners(type)) {
return this;
}
var event = util.extend({}, data, { type: type, target: this });
var events = this[eventsKey],
listeners, i, len, typeIndex, contextId;
if (events[type]) {
// make sure adding/removing listeners inside other listeners won't cause infinite loop
listeners = events[type].slice();
for (i = 0, len = listeners.length; i < len; i++) {
listeners[i].action.call(listeners[i].context, event);
}
}
// fire event for the context-indexed listeners as well
typeIndex = events[type + '_idx'];
for (contextId in typeIndex) {
listeners = typeIndex[contextId].slice();
if (listeners) {
for (i = 0, len = listeners.length; i < len; i++) {
listeners[i].action.call(listeners[i].context, event);
}
}
}
return this;
}
}
// aliases; we should ditch those eventually
// @method on(…): this
// Alias to [`on(…)`](#evented-on)
EventEmitter.on = EventEmitter.addListener;
// @method off(…): this
EventEmitter.off = EventEmitter.removeListener;
export { EventEmitter };

82
src/js/core/Map.js Normal file
View File

@ -0,0 +1,82 @@
import { OrbitControls } from '../lib/OrbitControls';
import * as dom from './domUtil';
import { HomeButton } from '../controls/HomeButton';
import * as util from './utilities';
class Map extends OrbitControls {
container;
_layers;
_controlCorners;
_controlContainer;
_controls;
constructor(camera, scene, domElement, container) {
// call parent constructor of OrbitControls
super(camera, scene, domElement);
this.container = container;
//init the control corners
if (this._initControlPos) {
this._initControlPos();
}
this._layers = {};
this.initControls();
}
_initControlPos() {
//var test = document.getElementById("webgl");
var corners = this._controlCorners = {};
var l = 'gba-';
var container = this._controlContainer =
//util.create('div', l + 'control-container', this.domElement);
dom.createDom("div", { "class": l + 'control-container' }, this.container);
function createCorner(vSide, hSide) {
var className = l + vSide + ' ' + l + hSide;
//corners[vSide + hSide] = util.create('div', className, container);
corners[vSide + hSide] = dom.createDom("div", { "class": className }, container);
}
createCorner('top', 'left');
createCorner('top', 'right');
createCorner('bottom', 'left');
createCorner('bottom', 'right');
}
initControls() {
this._controls = this._controls || {};
// this._controls.homeControl = (new HomeButton()).addTo(this);
let homeControl = this._controls.homeControl = new HomeButton();
homeControl.addTo(this);
}
addLayer(layer) {
var id = util.stamp(layer);
if (this._layers[id]) {
return this;
}
this._layers[id] = layer;
//layer._mapToAdd = this;
layer.index = id;
//if (layer.beforeAdd) {
// layer.beforeAdd(this);
//}
//this.whenReady(layer._layerAdd, layer);
layer._layerAdd(this);
this.emit("change");
return this;
}
hasLayer (layer) {
return !!layer && (util.stamp(layer) in this._layers);
}
}
export { Map };

157
src/js/core/domEvent.js Normal file
View File

@ -0,0 +1,157 @@
//static function
var stampForFn = (function () {
var lastId = 0,
key = '_id';
return function (obj) {
obj[key] = obj[key] || ++lastId;
return obj[key];
};
}());
export function addListener(obj, type, fn, context) { // (HTMLElement, String, Function[, Object])
var id = stampForFn(fn);
var key = '_gba_' + type + id;
var handler, originalHandler, newType;
if (obj[key]) { return this; }
handler = function (e) {
return fn.call(context || obj, e || domEvent._getEvent());
};
//if (L.Browser.pointer && type.indexOf('touch') === 0) {
// return this.addPointerListener(obj, type, handler, id);
//}
//if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) {
// this.addDoubleTapListener(obj, handler, id);
//}
if ('addEventListener' in obj) {
if (type === 'mousewheel') {
obj.addEventListener('DOMMouseScroll', handler, false);
obj.addEventListener(type, handler, false);
}
else if ((type === 'mouseenter') || (type === 'mouseleave')) {
originalHandler = handler;
newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout');
handler = function (e) {
if (!_checkMouse(obj, e)) { return; }
return originalHandler(e);
};
obj.addEventListener(newType, handler, false);
}
//else if (type === 'click' && L.Browser.android) {
// originalHandler = handler;
// handler = function (e) {
// return L.DomEvent._filterClick(e, originalHandler);
// };
// obj.addEventListener(type, handler, false);
//}
else {
obj.addEventListener(type, handler, false);
}
}
else if ('attachEvent' in obj) {
obj.attachEvent('on' + type, handler);
}
obj[key] = handler;
return this;
}
// @function on(…): this
// Alias to [`L.DomEvent.on`](#domevent-on)
export { addListener as on };
export function removeListener(obj, type, fn) { // (HTMLElement, String, Function)
var id = stampForFn(fn);
var key = '_gba_' + type + id;
var handler = obj[key];
if (!handler) { return this; }
//if (L.Browser.pointer && type.indexOf('touch') === 0) {
// this.removePointerListener(obj, type, id);
//} else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
// this.removeDoubleTapListener(obj, id);
//} else if ('removeEventListener' in obj) {
if ('removeEventListener' in obj) {
if (type === 'mousewheel') {
obj.removeEventListener('DOMMouseScroll', handler, false);
obj.removeEventListener(type, handler, false);
} else if ((type === 'mouseenter') || (type === 'mouseleave')) {
obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false);
} else {
obj.removeEventListener(type, handler, false);
}
} else if ('detachEvent' in obj) {
obj.detachEvent('on' + type, handler);
}
obj[key] = null;
return this;
}
// @function removeListener(…): this
// Alias to [`L.DomEvent.off`](#domevent-off)
export { removeListener as off };
// check if element really left/entered the event target (for mouseenter/mouseleave)
function _checkMouse(el, e) {
var related = e.relatedTarget;
if (!related) { return true; }
try {
while (related && (related !== el)) {
related = related.parentNode;
}
} catch (err) {
return false;
}
return (related !== el);
}
export function stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
skipped(e);
return this;
}
export function preventDefault(e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
return this;
}
var skipEvents = {};
export function skipped(e) {
var skipped = skipEvents[e.type];
// reset when checking, as it's only used in map container and propagates outside of the map
skipEvents[e.type] = false;
return skipped;
}

102
src/js/core/domUtil.js Normal file
View File

@ -0,0 +1,102 @@
import * as util from './utilities';
/*
* @namespace DomUtil
*
* Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
* tree, used by Leaflet internally.
*
* Most functions expecting or returning a `HTMLElement` also work for
* SVG elements. The only difference is that classes refer to CSS classes
* in HTML and SVG classes in SVG.
*/
// @function get(id: String|HTMLElement): HTMLElement
// Returns an element given its DOM id, or returns the element itself
// if it was passed directly.
export function byId(id, doc) {
// inline'd type check.
// be sure to return null per documentation, to match IE branch.
return ((typeof id == "string") ? (doc || document).getElementById(id) : id) || null; // DOMNode
}
// @function empty(el: HTMLElement)
// Removes all of `el`'s children elements from `el`
export function empty(el) {
while (el.firstChild) {
el.removeChild(el.firstChild);
}
}
export function createDom(tagName, opt_attributes, parent_node) {
return _createDom(document, arguments);
}
function _createDom(doc, args) {
var tagName = args[0];
var attributes = args[1];
//var var_args = args[2];
var element = doc.createElement(tagName);
//var element = $(tagName);
if (attributes) {
if (typeof attributes === "string") {
element.className = attributes;
}
//else if ($.isArray(attributes)) {
// //goog.dom.classes.add.apply(null, [element].concat(attributes));
//}
else {
setProperties(element, attributes);
}
}
if (args.length > 2) {
var parent_node = args[2];
parent_node.appendChild(element);
//parent_node.insertBefore(element, parent_node.firstChild)
}
return element;
}
export function setProperties(element, properties) {
//goog.object.forEach(properties, function(val, key) {
// $.each(properties, function (key, val) {
for (let key in properties) {
// object.update();
// });
let val = properties[key];
if (key === 'style') {
element.style.cssText = val;
}
else if (key === 'class') {
element.className = val;
}
else if (key === 'for') {
element.htmlFor = val;
}
else if (key in ATTRIBUTE_MAP) {
element.setAttribute(ATTRIBUTE_MAP[key], val);
}
else {
element[key] = val;
}
}
}
let ATTRIBUTE_MAP = {
'cellpadding': 'cellPadding',
'cellspacing': 'cellSpacing',
'colspan': 'colSpan',
'frameborder': 'frameBorder',
'height': 'height',
'maxlength': 'maxLength',
'role': 'role',
'rowspan': 'rowSpan',
'type': 'type',
'usemap': 'useMap',
'valign': 'vAlign',
'width': 'width'
};

11
src/js/core/index.js Normal file
View File

@ -0,0 +1,11 @@
export { Class } from './Class';
import { EventEmitter } from './Events';
export { EventEmitter };
import * as util from './utilities';
export { util };
export { setLoading, extend, showLoading, hideLoading, setOptions } from './utilities';
import * as dom from './dom';
export { dom };

143
src/js/core/utilities.js Normal file
View File

@ -0,0 +1,143 @@
import * as dom from './domUtil';
/*
* @namespace util
*
* Various utility functions, used by GeptiefExplore internally.
*/
const LOADING_ID_PREFIX = "loading_";
export function setLoading(elemID) {
//debug("setting loading " + elemID);
//// 1) create the jQuery Deferred object that will be used
//var deferred = $.Deferred();
//var ownerDocumentBody = document.getElementById(elemID);
var loadingDivID = LOADING_ID_PREFIX + elemID;
//var loadingDivID = "loading_" + elemID;
var existingDiv = document.getElementById(loadingDivID);
//var existingDiv = dom.byId(loadingDivID);
// if the loading div for given element already exists,
// increment the lock attribute value (or create the attribute,
// if not exists)
if (existingDiv != null) {
//existingDiv.css("display", "inline");
//dom.setProperties(existingDiv, {
// style: "display: block"
//});
if (typeof (existingDiv.attr("lock")) === "undefined") {
existingDiv.attr("lock", 1);
} else {
existingDiv.attr("lock", parseInt(existingDiv.attr("lock")) + 1);
}
}
// otherwise, create the div and append it to body
else {
// construct the div from markup
//var loadingDiv = dom.createDom("div", { id: loadingDivID, "class": "loading" }, ownerDocumentBody);
//var loadingDiv = $("<div id=\"" + loadingDivID + "\" class=\"loading\"></div>");
var loadingDiv = document.createElement('div');
loadingDiv.setAttribute("id", loadingDivID);
loadingDiv.setAttribute("class", "loading");
//var loadingDivContent = dom.createDom("div", { id: loadingDivID, innerHTML: myLabels.viewer.messages.waitMessage, "class": "loading-content" }, loadingDiv);
// var loadingDivContent = $("<div class=\"loading-content\">" + myLabels.viewer.messages.waitMessage + "</div>");
var loadingDivContent = document.createElement("div");
loadingDivContent.innerHTML = "Hi there and greetings!";
loadingDiv.appendChild(loadingDivContent);
// get the element to be covered with the loading div...
//var targetElement = $("#" + elemID);
var targetElement = document.getElementById(elemID);
// ... and get its proportions
// var offset = targetElement.offset();
var width = targetElement.offsetWidth
var height = targetElement.offsetHeight;
// make the div fit the target element
// loadingDiv.css({
// "left": targetElement.offsetLeft + "px",
// "top": targetElement.offsetTop + "px",
// "width": width + "px",
// "height": height + "px"
// });
//dom.setProperties(loadingDiv, {
// style: "width:" + width + "px; height:" + height + "px;"// left:" + offset.left + "px; top:" + offset.top + "px"
//});
loadingDiv.style.left = targetElement.offsetLeft + "px";
loadingDiv.style.top = targetElement.offsetTop + "px";
loadingDiv.style.width = width + "px";
loadingDiv.style.height = height + "px";
// make the text appear in the middle of the loading div
//dom.setProperties(loadingDivContent, {
// style: "line-height:" + height + "px;"
//});
// loadingDivContent.css({
// "line-height": height + "px"
// });
loadingDivContent.style.lineHeight = height + "px";
// $("body").append(loadingDiv);
//loadingDiv.appendTo('body');
document.body.appendChild(loadingDiv);
return loadingDiv;
}
}
// @function extend(dest: Object, src?: Object): Object
// extend an object with properties of one or more other objects
export function extend(dest) {
var i, j, len, src;
for (j = 1, len = arguments.length; j < len; j++) {
src = arguments[j];
for (i in src) {
dest[i] = src[i];
}
}
return dest;
}
export function showLoading () {
var element = dom.byId("loadingImg");
//domUtil.show(_loading);
if (element) {
element.style.display = "block";
}
}
export function hideLoading () {
var element = dom.byId("loadingImg");
if (element) {
element.style.display = "none";
}
}
// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`
export function setOptions (obj, options) {
if (!Object.prototype.hasOwnProperty.call(obj, 'options')) {
obj.options = obj.options ? create(obj.options) : {};
}
for (var i in options) {
obj.options[i] = options[i];
}
return obj.options;
}
export function stamp (){
var lastId = 0,
key = '_gba_id';
return function (obj) {
obj[key] = obj[key] || ++lastId;
return obj[key];
};
}

35
src/js/layer/BoxLayer.js Normal file
View File

@ -0,0 +1,35 @@
import { BoxGeometry } from 'three/src/geometries/BoxGeometry';
import { MeshBasicMaterial } from 'three/src/materials/MeshBasicMaterial';
import { Mesh } from 'three/src/objects/Mesh';
import { Layer } from './Layer'
class BoxLayer extends Layer {
constructor(size) {
super();
this.geometry = new BoxGeometry(size.width, size.height, size.depth);
this.material = new MeshBasicMaterial({
color: 800080
});
this.mesh = new Mesh(this.geometry, this.material);
}
onAdd(map) {
this.build(this.getScene());
//this.update();
this.emit('add');
}
build(app_scene) {
// this.objects.push(layer);
app_scene.add(this.getMesh());
}
getMesh() {
return this.mesh;
}
}
export { BoxLayer };

16
src/js/layer/DxfLayer.js Normal file
View File

@ -0,0 +1,16 @@
import { Group } from 'three/src/objects/Group';
class DxfLayer extends Layer {
constructor() {
super();
this.objectGroup = new Group();
this.queryableObjects = [];
this.borderVisible = false;
this.declaredClass = "DxfLayer";
}
}
export { DxfLayer };

47
src/js/layer/Layer.js Normal file
View File

@ -0,0 +1,47 @@
import { EventEmitter } from '../core/EventEmitter';
class Layer extends EventEmitter {
options = {
pane: 'overlayPane',
nonBubblingEvents: [] // Array of events that should not be bubbled to DOM parents (like the map)
};
constructor(size) {
super();
}
addTo(map) {
map.addLayer(this);
return this;
}
_layerAdd(e) {
var map = e;//.target;
// check in case layer gets added and then removed before the map is ready
if (!map.hasLayer(this)) { return; }
this._map = map;
//this._zoomAnimated = map._zoomAnimated;
//if (this.getEvents) {
// map.on(this.getEvents(), this);
//}
this.onAdd(map);
//if (this.getAttribution && this._map.attributionControl) {
// this._map.attributionControl.addAttribution(this.getAttribution());
//}
//this.fire('add');
//map.fire('layeradd', { layer: this });
}
getScene() {
return this._map.scene;
}
}
export { Layer };

794
src/js/lib/OrbitControls.js Normal file
View File

@ -0,0 +1,794 @@
import { Vector2 } from 'three/src/math/Vector2';
import { Vector3 } from 'three/src/math/Vector3';
import { EventEmitter } from '../core/EventEmitter';
import * as domEvent from '../core/domEvent';
/**
* INTERNALS: Any functions not added to the OrbitControls reference won't be visible, or accessible outside of
* this file (closure); however, these methods and functions don't belong to the OrbitControls class either
* and are static as a result.
*/
var EPS = 0.000001;
var mouseDownPoint = new Vector2();
var mouseUpPoint = new Vector2();
var rotateStart = new Vector2();
var rotateEnd = new Vector2();
var rotateDelta = new Vector2();
var panStart = new Vector2();
var panEnd = new Vector2();
var panDelta = new Vector2();
var panOffset = new Vector3();
var offset = new Vector3();
var dollyStart = new Vector2();
var dollyEnd = new Vector2();
var dollyDelta = new Vector2();
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var pan = new Vector3();
var lastPosition = new Vector3();
var STATE = { NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5, CAMERA_ROTATE: 6 };
var state = STATE.NONE;
class OrbitControls extends EventEmitter {
object;
domElement;
scene;
enabled;
target;
center;
noZoom;
zoomSpeed;
minDistance;
maxDistance;
upsideDown;
noRotate;
rotateSpeed;
keyRotateAngle;
noPan;
keyPanSpeed;
autoRotateSpeed;
minPolarAngle;
maxPolarAngle;
noKeys;
keys;
target0;
position0;
rotateDifference;
constructor(camera, scene, domElement) {
super();
this.object = camera;
this.domElement = (domElement !== undefined) ? domElement : document;
this.scene = scene;
// Set to false to disable this control
this.enabled = true;
// "target" sets the location of focus, where the control orbits around
// and where it pans with respect to.
this.target = new Vector3();
// center is old, deprecated; use "target" instead
this.center = this.target;
// This option actually enables dollying in and out; left as "zoom" for
// backwards compatibility
this.noZoom = false;
this.zoomSpeed = 1.0;
// Limits to how far you can dolly in and out
this.minDistance = 0;
this.maxDistance = Infinity;
// Set to true for upside down
this.upsideDown = false;
this.object.up.set(0, 0, 1);
// Set to true to disable this control
this.noRotate = false;
this.rotateSpeed = 1.0;
this.keyRotateAngle = Math.PI / 90;
// Set to true to disable this control
this.noPan = false;
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
// // Set to true to automatically rotate around the target
// this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
// Set to true to disable use of the keys
this.noKeys = false;
// The four arrow keys and additional keys
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40, AUTOROTATE: 82, UPSIDEDOWN: 85, RESET: 82 };
// for reset
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this._initEvents('on');
}
_initEvents(onOff) {
if (!domEvent) { return; }
onOff = onOff || 'on';
//this.domElement.addEventListener('contextmenu', function (event) { event.preventDefault(); }, false);
domEvent
[onOff](this.domElement, 'contextmenu', domEvent.stopPropagation)
[onOff](this.domElement, 'contextmenu', domEvent.preventDefault);
//this.domElement.addEventListener('mousedown', onMouseDown, false);
domEvent
[onOff](this.domElement, 'mousedown', domEvent.stopPropagation)
[onOff](this.domElement, 'click', domEvent.stopPropagation)
[onOff](this.domElement, 'dblclick', domEvent.stopPropagation)
[onOff](this.domElement, 'mousedown', domEvent.preventDefault)
[onOff](this.domElement, 'mousedown', this.onMouseDown, this);
//this.domElement.addEventListener('mousewheel', onMouseWheel, false);
domEvent
[onOff](this.domElement, 'mousewheel', domEvent.preventDefault)
[onOff](this.domElement, 'mousewheel', domEvent.stopPropagation)
[onOff](this.domElement, 'mousewheel', this.onMouseWheel, this);
//this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
domEvent
[onOff](this.domElement, 'DOMMouseScroll', domEvent.preventDefault)
[onOff](this.domElement, 'DOMMouseScroll', domEvent.stopPropagation)
[onOff](this.domElement, 'DOMMouseScroll', this.onMouseWheel, this);
//window.addEventListener('keydown', onKeyDown, false);
domEvent
[onOff](window, 'keydown', domEvent.stopPropagation)
[onOff](window, 'keydown', domEvent.preventDefault)
[onOff](window, 'keydown', this.onKeyDown, this);
//this.domElement.addEventListener('mousemove', onMouseMove, false);
domEvent[onOff](this.domElement, 'mousemove', this.onMouseMove, this);
//this.domElement.addEventListener('touchstart', touchstart, false);
domEvent[onOff](this.domElement, 'touchstart', this.onTouchStart, this);
//this.domElement.addEventListener('touchend', touchend, false);
domEvent[onOff](this.domElement, 'touchend', this.onTouchEnd, this);
//this.domElement.addEventListener('touchmove', touchmove, false);
domEvent[onOff](this.domElement, 'touchmove', this.onTouchMove, this);
domEvent[onOff](this.domElement, 'mouseleave', this.onMouseLeave, this);
}
_getZoomScale() {
return Math.pow(0.95, this.zoomSpeed);
}
_AutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * this.autoRotateSpeed;
}
rotateLeft(angle) {
if (angle === undefined) {
angle = this._AutoRotationAngle();
}
thetaDelta += angle;
}
rotateUp(angle) {
if (angle === undefined) {
angle = this._AutoRotationAngle();
}
phiDelta -= angle;
}
// pass in distance in world space to move left
panLeft(distance) {
var te = this.object.matrix.elements;
// get X column of matrix
panOffset.set(te[0], te[1], te[2]);
panOffset.multiplyScalar(-distance);
pan.add(panOffset);
}
// pass in distance in world space to move up
panUp(distance) {
var te = this.object.matrix.elements;
// get Y column of matrix
panOffset.set(te[4], te[5], te[6]);
panOffset.multiplyScalar(distance);
pan.add(panOffset);
}
// pass in x,y of change desired in pixel space,
// right and down are positive
pan(deltaX, deltaY) {
var element = this.domElement === document ? this.domElement.body : this.domElement;
if (this.object.fov !== undefined) {
// perspective
var position = this.object.position;
var offset = position.clone().sub(this.target);
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan((this.object.fov / 2) * Math.PI / 180.0);
// we actually don't use screenWidth, since perspective camera is fixed to screen height
this.panLeft(2 * deltaX * targetDistance / element.clientHeight);
this.panUp(2 * deltaY * targetDistance / element.clientHeight);
}
else if (this.object.top !== undefined) {
// orthographic
this.panLeft(deltaX * (this.object.right - this.object.left) / element.clientWidth);
this.panUp(deltaY * (this.object.top - this.object.bottom) / element.clientHeight);
}
else {
// camera neither orthographic or perspective
console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.');
}
}
moveForward(delta) {
var element = this.domElement === document ? this.domElement.body : this.domElement;
panOffset.copy(this.object.position).sub(this.target);
var targetDistance = panOffset.length() * Math.tan((this.object.fov / 2) * Math.PI / 180.0);
panOffset.z = 0;
panOffset.normalize();
panOffset.multiplyScalar(-2 * delta * targetDistance / element.clientHeight);
pan.add(panOffset);
}
dollyIn(dollyScale) {
if (dollyScale === undefined) {
dollyScale = this._getZoomScale();
}
scale /= dollyScale;
this.update();
}
dollyOut(dollyScale) {
if (dollyScale === undefined) {
dollyScale = this._getZoomScale();
}
scale *= dollyScale;
this.update();
}
update() {
var position = this.object.position; //x = 0, y = -100, z = 200;
// move target to panned location
this.target.add(pan);//target ist am Anfang immer x = 0; y = 0; z = 0;
//auch pan ist am Anfang immer x = 0; y = 0; z = 0;
//if (this.autoRotate) { //R
// this.rotateLeft(getAutoRotationAngle());
//}
var theta, phi, radius;
//if rotate:
if (thetaDelta || phiDelta) {
offset.copy(position).sub(this.target);
// angle from y-axis around z-axis
theta = Math.atan2(offset.x, offset.y);
// angle from z-axis
phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
theta += thetaDelta;
phi += phiDelta;
// restrict phi to be between desired limits
phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi));
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));
radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius));
offset.x = radius * Math.sin(phi) * Math.sin(theta);
offset.y = radius * Math.sin(phi) * Math.cos(theta);
offset.z = radius * Math.cos(phi);
position.copy(this.target).add(offset);
}
//else if (cameraThetaDelta || cameraPhiDelta) {
// offset.copy(this.target).sub(position);
// // angle from y-axis around z-axis
// theta = Math.atan2(offset.x, offset.y);
// // angle from z-axis
// phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
// theta += cameraThetaDelta;
// phi += cameraPhiDelta;
// // restrict phi to be between desired limits
// phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi));
// // restrict phi to be betwee EPS and PI-EPS
// phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));
// radius = offset.length() * scale;
// // restrict radius to be between desired limits
// radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius));
// offset.x = radius * Math.sin(phi) * Math.sin(theta);
// offset.y = radius * Math.sin(phi) * Math.cos(theta);
// offset.z = radius * Math.cos(phi);
// this.target.copy(position).add(offset);
//}
else if (scale !== 1) {
offset.copy(position).sub(this.target);
offset.multiplyScalar(scale);
position.copy(this.target).add(offset);
}
//pan
else {
position.add(pan);
}
this.object.lookAt(this.target);
thetaDelta = 0;
phiDelta = 0;
// cameraThetaDelta = 0;
// cameraPhiDelta = 0;
scale = 1;
pan.set(0, 0, 0);
if (lastPosition.distanceTo(this.object.position) > 0) {
//this.dispatchEvent(changeEvent);
//scope.emit("change");
lastPosition.copy(this.object.position);
}
this.emit("change", lastPosition);
}
reset() {
state = STATE.NONE;
this.target.copy(this.target0);//0 0 0
this.object.position.copy(this.position0);
//this.object.position.set(0, 0, 180);
this.update();
}
onMouseDown(event) {
if (this.enabled === false) {
return;
}
this.rotateDifference = 0;
event.preventDefault();
//2d vector:
mouseDownPoint.set(event.clientX, event.clientY);
//linke Maustaste
if (event.button === 0) {
if (this.noRotate === true) {
return;
}
state = STATE.ROTATE;
rotateStart.set(event.clientX, event.clientY);
this.emit("mousedown", event);
}
else if (event.button === 1) {
if (this.noZoom === true) {
return;
}
state = STATE.DOLLY;
//2d vector:
dollyStart.set(event.clientX, event.clientY);
}
//rechte Maustaste
else if (event.button === 2) {
if (this.noPan === true) {
return;
}
state = STATE.PAN;
panStart.set(event.clientX, event.clientY);
}
//this.domElement.addEventListener('mousemove', onMouseDrag, false);
domEvent.on(this.domElement, 'mousemove', this.onMouseDrag, this);
//this.domElement.addEventListener('mouseup', onMouseUp, false);
domEvent.on(this.domElement, 'mouseup', this.onMouseUp, this);
//scope.dispatchEvent(startEvent);
this.emit('movestart', null);
}
onMouseMove(event) {
this.emit('mouse-move', event);
}
onMouseDrag(event) {
if (this.enabled === false) {
return;
}
event.preventDefault();
var element = this.domElement === document ? this.domElement.body : this.domElement;
if (state === STATE.ROTATE) {
if (this.noRotate === true) return;
rotateEnd.set(event.clientX, event.clientY);
rotateDelta.subVectors(rotateEnd, rotateStart);
// rotating across whole screen goes 360 degrees around
this.rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * this.rotateSpeed);
// rotating up and down along whole screen attempts to go 360, but limited to 180
this.rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * this.rotateSpeed);
this.rotateDifference = rotateStart.distanceTo(rotateEnd);
rotateStart.copy(rotateEnd);
this.emit("mouse-pan", event);
}
else if (state === STATE.DOLLY) {
if (this.noZoom === true) return;
dollyEnd.set(event.clientX, event.clientY);
dollyDelta.subVectors(dollyEnd, dollyStart);
if (dollyDelta.y > 0) {
this.dollyIn();
} else {
this.dollyOut();
}
dollyStart.copy(dollyEnd);
}
else if (state === STATE.PAN) {
if (this.noPan === true) return;
panEnd.set(event.clientX, event.clientY);
panDelta.subVectors(panEnd, panStart);
this.pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
this.emit("mouse-pan", event);
}
//scope.emit('mouse-move', event);
this.update();
} //onMouseDrag end
onMouseUp(event) {
if (this.enabled === false) {
return;
}
//this.domElement.removeEventListener('mousemove', onMouseDrag, false);
domEvent.off(this.domElement, 'mousemove', this.onMouseDrag);
//this.domElement.removeEventListener('mouseup', onMouseUp, false);
domEvent.off(this.domElement, 'mouseup', this.onMouseUp);
//scope.dispatchEvent(endEvent);
state = STATE.NONE;
mouseUpPoint.set(event.clientX, event.clientY);
//var distance = mouseDownPoint.distanceTo(mouseUpPoint);
//linke Maustaste
if (event.button === 0 && mouseDownPoint.equals(mouseUpPoint)) {// && Math.abs(this.rotateDifference) === 0 ) {
//if (event.button === 0 && (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) ) {
this.emit("clicked", event);
//Q3D.application.canvasClicked(event);
}
} //onMoseUp end
onMouseWheel(event) {
if (this.enabled === false || this.noZoom === true) return;
event.preventDefault();
var delta = 0;
if (event.wheelDelta !== undefined) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
}
else if (event.detail !== undefined) { // Firefox
delta = - event.detail;
}
if (delta > 0) {
this.dollyOut();
}
else {
this.dollyIn();
}
this.update();
//scope.dispatchEvent(startEvent);
//scope.dispatchEvent(endEvent);
}
onMouseLeave(event) {
domEvent.off(this.domElement, 'mousemove', this.onMouseDrag);
//this.domElement.removeEventListener('mouseup', onMouseUp, false);
domEvent.off(this.domElement, 'mouseup', this.onMouseUp);
}
onKeyDown(event) {
if (this.enabled === false || this.noKeys === true || this.noPan === true) return;
if (event.shiftKey && event.ctrlKey) {
//zoom +
if (event.keyCode === this.keys.UP) this.dollyOut();
else if (event.keyCode === this.keys.BOTTOM) this.dollyIn();
else return;
}
else if (event.shiftKey) {
switch (event.keyCode) {
case this.keys.UP:
this.rotateUp(this.keyRotateAngle);
break;
case this.keys.BOTTOM:
this.rotateUp(-this.keyRotateAngle);
break;
case this.keys.LEFT:
this.rotateLeft(-this.keyRotateAngle);
break;
case this.keys.RIGHT:
this.rotateLeft(this.keyRotateAngle);
break;
//neu
case this.keys.RESET:
this.reset();
break;
default:
return;
}
}
else if (event.ctrlKey) {
switch (event.keyCode) {
case this.keys.UP:
this.rotateUp(this.keyRotateAngle);
break;
case this.keys.BOTTOM:
this.rotateUp(-this.keyRotateAngle);
break;
case this.keys.LEFT:
this.rotateLeft(this.keyRotateAngle);
break;
case this.keys.RIGHT:
this.rotateLeft(-this.keyRotateAngle);
break;
default:
break;
}
}
else {
switch (event.keyCode) {
case this.keys.UP:
this.moveForward(-this.keyPanSpeed);
break;
case this.keys.BOTTOM:
this.moveForward(+this.keyPanSpeed);
break;
case this.keys.LEFT:
this.pan(-this.keyPanSpeed, 0);
break;
case this.keys.RIGHT:
this.pan(+this.keyPanSpeed, 0);
break;
//case scope.keys.AUTOROTATE: //R
// scope.autoRotate = !scope.autoRotate;
// break;
case this.keys.UPSIDEDOWN:
this.upsideDown = !this.upsideDown;
if (this.upsideDown) this.object.up.set(0, 0, -1);
else this.object.up.set(0, 0, 1);
break;
default:
break;
}
}
this.update();
}
onTouchStart(event) {
if (this.enabled === false) return;
switch (event.touches.length) {
case 1: // one-fingered touch: rotate
//if (scope.enableRotate === false) return;
if (this.noRotate === true) return;
state = STATE.TOUCH_ROTATE;
rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
break;
case 2: // two-fingered touch: dolly
//if ( scope.enableZoom === false ) return;
if (this.noZoom === true) {
return;
}
state = STATE.TOUCH_DOLLY;
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
var distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
break;
case 3: // three-fingered touch: pan
//if ( scope.enablePan === false ) return;
if (this.noPan === true) {
return;
}
state = STATE.TOUCH_PAN;
panStart.set(event.touches[0].pageX, event.touches[0].pageY);
break;
default:
state = STATE.NONE;
}
//if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
if (state !== STATE.NONE) {
this.emit('touchstart', null);
}
}
onTouchMove(event) {
if (this.enabled === false) return;
event.preventDefault();
event.stopPropagation();
var element = this.domElement === document ? this.domElement.body : this.domElement;
switch (event.touches.length) {
case 1: // one-fingered touch: rotate
//if (scope.enableRotate === false) return;
if (this.noRotate === true) return;
if (state !== STATE.TOUCH_ROTATE) return;
rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
rotateDelta.subVectors(rotateEnd, rotateStart);
// rotating across whole screen goes 360 degrees around
this.rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * this.rotateSpeed);
// rotating up and down along whole screen attempts to go 360, but limited to 180
this.rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * this.rotateSpeed);
rotateStart.copy(rotateEnd);
this.emit("mouse-pan", event);
this.update();
break;
case 2: // two-fingered touch: dolly
//if (scope.enableZoom === false) return;
if (this.noZoom === true) return;
if (state !== STATE.TOUCH_DOLLY) return;
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
var distance = Math.sqrt(dx * dx + dy * dy);
dollyEnd.set(0, distance);
dollyDelta.subVectors(dollyEnd, dollyStart);
if (dollyDelta.y > 0) {
this.dollyOut(this._getZoomScale());
}
else if (dollyDelta.y < 0) {
this.dollyIn(this._getZoomScale());
}
dollyStart.copy(dollyEnd);
this.emit("mouse-pan", event);
this.update();
break;
case 3: // three-fingered touch: pan
//if (scope.enablePan === false) return;
if (this.noPan === true) return;
if (state !== STATE.TOUCH_PAN) return;
panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
panDelta.subVectors(panEnd, panStart);
this.pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
this.update();
break;
default:
state = STATE.NONE;
}
}
onTouchEnd( /* event */) {
if (this.enabled === false) {
return;
}
//scope.dispatchEvent(endEvent);
this.emit('touchend', null);
state = STATE.NONE;
}
}
export { OrbitControls };

158
src/js/main.js Normal file
View File

@ -0,0 +1,158 @@
// import { DirectionalLight, AmbientLight, WebGLRenderer, PerspectiveCamera, Scene } from 'three';
import { DirectionalLight } from 'three/src/lights/DirectionalLight';
import { AmbientLight } from 'three/src/lights/AmbientLight';
import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer';
import { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera';
import { Scene } from 'three/src/scenes/Scene';
import { BoxLayer } from './layer/BoxLayer';
// import * as util from './core/utilities';
// import { OrbitControls } from './lib/OrbitControls.js'
import { Map } from './core/Map';
import * as domEvent from './core/domEvent';
import '../css/page.css'; /* style loader will import it */
class Application {
constructor(container) {
this.container = container;
this.running = false; // this is public
this.objects = [];
if (container.clientWidth && container.clientHeight) {
this.width = container.clientWidth;
this.height = container.clientHeight;
this._fullWindow = false;
} else {
this.width = window.innerWidth;
this.height = window.innerHeight;
this._fullWindow = true;
}
this.createScene();
}
createScene() {
/* Renderer */
var bgcolor = 0xfdfdfd;
this.renderer = new WebGLRenderer({ alpha: true, antialias: true });
// this.renderer.setSize(window.innerWidth, window.innerHeight);
// document.body.appendChild(this.renderer.domElement);
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColor(bgcolor, 1); // second param is opacity, 0 => transparent
this.renderer.render
this.container.appendChild(this.renderer.domElement);
/* Scene: that will hold all our elements such as objects, cameras and lights. */
this.scene = new Scene();
//app.scene.add(new THREE.AmbientLight(0xeeeeee));
this._buildDefaultLights(this.scene);
//app.scene.autoUpdate = false;
//// show axes in the screen
//app.scene.add(new THREE.AxisHelper(100));
/* Camera */
var angle = 45;
var aspect = this.width / this.height;
var near = 0.1; //This is the distance at which the camera will start rendering scene objects
var far = 2000; //Anything beyond this distance will not be rendered
this.camera = new PerspectiveCamera(angle, aspect, near, far);
//this.camera.position.z = 20;
this.camera.position.set(0, -0.1, 150);
// this.camera.lookAt(new THREE.Vector3(0, 0, 0));
// this.controls = new OrbitControls(this.camera, this.scene, this.renderer.domElement);
this.map = new Map(this.camera, this.scene, this.renderer.domElement, this.container);
let boxLayer = new BoxLayer({ width: 10, height: 10, depth: 10 });
this.map.addLayer(boxLayer);
domEvent.on(window, 'click', this.onWindowResize, this);
// util.setLoading("webgl");
this.start();
}
onWindowResize() {
if (this._fullWindow) {
this._setCanvasSize(window.innerWidth, window.innerHeight);
}
else {
this._setCanvasSize(this.container.clientWidth, this.container.clientHeight);
}
}
_setCanvasSize (width, height) {
this.width = width;
this.height = height;
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(width, height);
this.animate();
}
_buildDefaultLights(scene) {
var deg2rad = Math.PI / 180;
// ambient light
scene.add(new AmbientLight(0x999999));
//scene.add(new THREE.AmbientLight(0xeeeeee));
// directional lights
var opt = {
azimuth: 220, // note: default light azimuth of gdaldem hillshade is 315.
altitude: 45 // altitude angle
};
//appSettings.Options.light.directional;
var lambda = (90 - opt.azimuth) * deg2rad;
var phi = opt.altitude * deg2rad;
var x = Math.cos(phi) * Math.cos(lambda),
y = Math.cos(phi) * Math.sin(lambda),
z = Math.sin(phi);
var light1 = new DirectionalLight(0xffffff, 0.5);
light1.position.set(x, y, z);
scene.add(light1);
// thin light from the opposite direction
var light2 = new DirectionalLight(0xffffff, 0.1);
light2.position.set(-x, -y, -z);
scene.add(light2);
}
start() {
this.running = true;
this.map.addListener('change', this.animate, this); // add this only if there is no animation loop (requestAnimationFrame)
this.animate();
}
animate() {
if (this.running) {
// requestAnimationFrame(() => {
// this.animate();
// }, 1000 / 30);
// this.objects.forEach((object) => {
// object.update();
// });
}
this.renderer.render(this.scene, this.camera);
}
add(layer) {
this.objects.push(layer);
this.scene.add(layer.getMesh());
}
}
var container = document.getElementById("webgl");
let app = new Application(container);
// app.add(new BoxLayer({
// width: 10,
// height: 10,
// depth: 10
// }));

5
typings.json Normal file
View File

@ -0,0 +1,5 @@
{
"globalDevDependencies": {
"three": "registry:dt/three#0.84.0+20170323144537"
}
}

6875
typings/globals/three/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
{
"resolution": "main",
"tree": {
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/ccda793e883ecb20bd396121f1e89df8c1dd00ce/three/index.d.ts",
"raw": "registry:dt/three#0.84.0+20170323144537",
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/ccda793e883ecb20bd396121f1e89df8c1dd00ce/three/index.d.ts"
}
}

1
typings/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference path="globals/three/index.d.ts" />

163
webpack.config.js Normal file
View File

@ -0,0 +1,163 @@
require('dotenv').config();
const path = require('path');
const webpack = require('webpack'); //e.g. for iusing DefinePlugin
// const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// https://www.sitepoint.com/es6-babel-webpack/
/**
* flag Used to check if the environment is production or not
*/
const isProduction = (process.env.NODE_ENV === 'production');
const devMode = (process.env.NODE_ENV !== 'production');
/**
* Include hash to filenames for cache busting - only at production
*/
const fileNamePrefix = isProduction ? '[chunkhash].' : '';
module.exports = {
mode: process.env.NODE_ENV,
context: __dirname,
entry: './src/js/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
//filename: fileNamePrefix + '[name].js',
publicPath: '/dist/',
},
module: {
rules: [
{
test: /\.(svg|eot|ttf|woff|woff2)$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[ext]'
}
},
{
test: /\.(png|jpg|gif)$/,
loaders: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]'
}
},
'img-loader'
],
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.(less|css)$/,
use: [
{
// loader: (isProduction === true) ? MiniCssExtractPlugin.loader : 'style-loader',
// loader: 'style-loader',
loader: MiniCssExtractPlugin.loader,
// loader: MiniCssExtractPlugin.loader,
// options: {
// hmr: process.env.NODE_ENV === 'development',
// },
},
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "less-loader",
options: {
sourceMap: true
}
}
]
},
]
},
stats: {
colors: true
},
// devtool: 'source-map',
optimization: {
minimize: isProduction,
minimizer: [new TerserPlugin({
parallel: true,
sourceMap: true,
terserOptions: {
extractComments: 'all',
compress: {
drop_console: true,
drop_debugger: true,
keep_classnames: false,
keep_fnames: false,
},
}
})],
},
plugins: [
new webpack.DefinePlugin({ // Remove this plugin if you don't plan to define any global constants
ENVIRONMENT: JSON.stringify(process.env.NODE_ENV),
CONSTANT_VALUE: JSON.stringify(process.env.CONSTANT_VALUE),
}),
// extractLess,
new MiniCssExtractPlugin({ // Make sure MiniCssExtractPlugin instance is included in array before the PurifyCSSPlugin
// Options similar to the same options in webpackOptions.output
// both options are optional
// filename: '[name].css',
// chunkFilename: '[id].css',
filename: '[name].css',
chunkFilename: '[id].css',
}),
// new PurifyCSSPlugin({
// paths: glob.sync(__dirname + '/*.html'),
// minimize: true,
// }),
// new webpack.HotModuleReplacementPlugin(),
],
};
/**
* Production only plugins
*/
if (isProduction === true) {
module.exports.plugins.push(
// module.exports.optimization.minimizer.push(
// new UglifyJsPlugin({ sourceMap: true })
// );
function () { // Create a manifest.json file that contain the hashed file names of generated static resources
this.plugin("done", function (status) {
require("fs").writeFileSync(
__dirname + "/dist/manifest.json",
JSON.stringify(status.toJson().assetsByChunkName)
);
});
},
);
//development
} else {
module.exports.plugins.push(
//auto updating on dev server
new webpack.HotModuleReplacementPlugin()// HMR plugin will cause problems with [chunkhash]
);
}

7
webpack.prod.config.js Normal file
View File

@ -0,0 +1,7 @@
const merge = require('webpack-merge');
const common = require('./webpack.config.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
});