GeotiefExplore/src/js/main.js
Arno Kaimbacher f654582403 - add linear background for map in page.css
- set ClearColor of WebGlRenderer to transparent (main.js)
2021-01-19 11:13:45 +01:00

461 lines
18 KiB
JavaScript

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 { Vector3 } from 'three/src/math/Vector3';
import { TinLayer } from './layer/TinLayer';
import { DemLayer } from './layer/DemLayer';
import { Map } from './core/Map';
import * as domEvent from './core/domEvent';
import { Coordinates } from './controls/Coordinates';
import { NortArrow } from './controls/NorthArrow';
import { LayerControl } from './controls/LayerControl';
import { BasemapControl } from './controls/BasemapControl';
import { SliderControl } from './controls/SliderControl';
import { Mesh } from 'three/src/objects/Mesh';
import { SphereGeometry } from 'three/src/geometries/SphereGeometry';
import { MeshLambertMaterial } from 'three/src/materials/MeshLambertMaterial';
import * as util from './core/utilities';
import * as browser from './core/browser';
import * as domUtil from './core/domUtil';
import '../css/page.css'; /* style loader will import it */
class Application {
constructor(container) {
this.container = container;
this.running = false;
this.wireframeMode = false;
this.canvas;
this._canvasImageUrl;
this.downloadButton
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.canvas = document.querySelector('#imgCanvas');
// this.$topTextInput = document.querySelector('#topText');
// this.$bottomTextInput = document.querySelector('#bottomText');
// this.$imageInput = document.querySelector('#image');
this.downloadButton = document.querySelector('#btnDownloadCanvasImage');
this.menuIcon = document.querySelector('#menu-icon');
this.navigation = document.getElementsByClassName('navigation')[0];
// this.addEventListeners();
this.mapIcon = document.querySelector('#menu-map-icon');
this.createScene();
this.addEventListeners();
}
createScene() {
var dirNode = document.getElementsByTagName("body")[0];
if (browser.touch == true) {
//dirNode.setAttribute("dir", "ltr");
domUtil.addClass(dirNode, "touch");
} else {
domUtil.addClass(dirNode, "notouch");
}
// let opt = { r: 200, c: 0x38eeff, o: 0.8 };
var opt = { r: 5, c: 0xffff00, o: 1 };
this.queryMarker = new Mesh(new SphereGeometry(opt.r),
new MeshLambertMaterial({ color: opt.c, opacity: opt.o, transparent: (opt.o < 1) }));
this.queryMarker.visible = true;
// this.queryMarker.position.set(4282010, 2302070, -13616.3);
/* Renderer */
// var bgcolor = 0xfdfdfd;
let bgcolor = 0xfdfdfd;
this.renderer = new WebGLRenderer({ alpha: true, antialias: true, preserveDrawingBuffer: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
// 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.setClearColor(0x000000, 0.0);
// let Empty = Object.freeze([]);
// this.renderer.clippingPlanes = Empty; // GUI sets it to globalPlanes
// this.renderer.localClippingEnabled = true;
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));
// const ambient = new AmbientLight( 0xffffff, 0.5 );
// this.scene.add(ambient);
this._buildDefaultLights(this.scene);
//app.scene.autoUpdate = false;
//// show axes in the screen
//app.scene.add(new THREE.AxisHelper(100));
this.scene.add(this.queryMarker);
/* 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.set(0, -0.1, 150);
// this.camera.lookAt(new Vector3(0, 0, 0));
this.camera = new PerspectiveCamera(30, this.width / this.height, 100, 100000);
// const dirLight = new DirectionalLight(0xffffff, 1);
// dirLight.position.set(585000 + 10000, 6135000 + 10000, -500 + 5000);
// this.camera.add(dirLight);
let x = { min: 3955850, max: 4527300, avg: 4282010 };
let y = { min: 2183600, max: 2502700, avg: 2302070 };
let z = { min: -60066, max: 3574.94, avg: -13616.3 };
const center = new Vector3((x.min + x.max) / 2, (y.min + y.max) / 2, z.avg);
// const center = new Vector3(x.avg, y.avg, z.avg);
const size = Math.max(x.max - x.min, y.max - y.min, z.max - z.min);
const camDirection = new Vector3(-0.5, -Math.SQRT1_2, 0.5);
const camOffset = camDirection.multiplyScalar(size * 2);
this.camera.position.copy(center);
this.camera.position.add(camOffset);
// this.camera.position.set(0, 0, 1500);
this.camera.near = size * 0.1;
this.camera.far = size * 25;
this.camera.updateProjectionMatrix();
/* Camera */
// // const center = new Vector3();
// 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.set(0, -0.1, 150);
// this.camera.lookAt(new Vector3(0, 0, 0));
// create map
this.map = new Map(size, center, this.camera, this.scene, this.renderer.domElement, this.container);
// this.map.minDistance = size*0.75;
// this.map.maxDistance = size*15;
// let boxLayer = new BoxLayer({
// width: 10000, height: 10000, depth: 10000, name: 'test-box', color: 800080
// });
// this.map.addLayer(boxLayer);
//add map controls:
if (util.hasTouch() == false) {
let coordinates = new Coordinates({ camera: this.camera, crs: "EPSG:3034" }).addTo(this.map);
// coordinates.addListener('onPoint', (args) => {
// let vector = args[0];
// this.queryMarker.position.set(vector.x, vector.y, vector.z);
// // this.queryMarker.updateMatrixWorld();
// this.animate();
// }, this);
}
this.northArrow = new NortArrow({ headLength: 1, headWidth: 1 }).addTo(this.map);
// this.dialog = new MobileDialog("Help", { klass: "fm_about", parentDiv: 'basemap-control-parent' }).addTo(this.map);
let demLayer = new DemLayer({
q: 0, shading: true, type: 'dem', name: 'DEM Layer', color: 16382457,
"materialParameter": [{
"i": 0,
"materialtypee": 0,
"ds": 1,
"bottomZ": 3000, //-18.70583629319634
}]
});
demLayer.addBlock({
"width": 226,
"plane": {
"width": x.max - x.min, //100.0,
// "offsetX": 0,
// "offsetY": 0,
// "offsetX" : x.avg,
// "offsetY" : y.avg,
"offsetX": center.x,
"offsetY": center.y,
"height": y.max - y.min, //78.59618717504333
},
"dem_values": [],
"height": 178
});
this.map.addLayer(demLayer);
this.map.currentBasemap = demLayer;
let dxf134Layer = new TinLayer({
geomId: 134, q: true, type: "3dface", name: "South Alpine Superunit", description: "test", color: "907A5C"
});
this.map.addLayer(dxf134Layer);
let dxf135Layer = new TinLayer({
geomId: 135, q: true, type: "3dface", name: "Adriatic Plate", description: "test2", color: "A0512D"
});
this.map.addLayer(dxf135Layer);
let dxf136Layer = new TinLayer({
geomId: 136, q: true, type: "3dface", name: "Austroalpine Superunit", description: "test2", color: "CC4D00"
});
this.map.addLayer(dxf136Layer);
let dxf137Layer = new TinLayer({
geomId: 137, q: true, type: "3dface", name: "Penninic Superunit", description: "test2", color: "80CCFF"
});
this.map.addLayer(dxf137Layer);
let dxf139Layer = new TinLayer({
geomId: 139, q: true, type: "3dface", name: "Sub-Penninic Superunit, Helvetic Superunit & Allochthonous Molasse", description: "test2", color: "FF80CC"
});
this.map.addLayer(dxf139Layer);
let dxf140Layer = new TinLayer({
geomId: 140, q: true, type: "3dface", name: "Eurasian Plate, including autochtomous sedimentary cover", description: "test2", color: "FFB3B3"
});
this.map.addLayer(dxf140Layer);
new LayerControl(this.map.layers, {
collapsed: true,
parentDiv: 'layer-control-parent-id'
}).addTo(this.map);
this.basemapControl = new BasemapControl('Baselayer', {
parentDiv: 'basemap-control-parent'
}).addTo(this.map);
//slider for scaling z value
this.slider = new SliderControl({ layers: this.map.layers }).addTo(this.map);
// domEvent.on(window, 'resize', this.onWindowResize, this);
// domEvent.on(window, 'keydown', this.keydown, this);
this.start();
}
keydown(e) {
if (e.ctrlKey || e.altKey) return;
let keyPressed = e.which;
if (!e.shiftKey) {
//if (keyPressed == 27) app.closePopup(); // ESC
if (keyPressed === 87) {
this.setWireframeMode(); // W
}
}
}
setWireframeMode() {
let wireframe = !this.wireframeMode;
if (wireframe === this.wireframeMode) return;
for (var key in this.map._layers) {
let layer = this.map._layers[key];
layer.setWireframeMode(wireframe);
}
this.wireframeMode = wireframe;
this.animate();
}
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) {
let deg2rad = Math.PI / 180;
// ambient light
scene.add(new AmbientLight(0x999999));
//scene.add(new THREE.AmbientLight(0xeeeeee));
// directional lights
let opt = {
azimuth: 220, // note: default light azimuth of gdaldem hillshade is 315.
altitude: 45 // altitude angle
};
//appSettings.Options.light.directional;
let lambda = (90 - opt.azimuth) * deg2rad;
let phi = opt.altitude * deg2rad;
let x = Math.cos(phi) * Math.cos(lambda),
y = Math.cos(phi) * Math.sin(lambda),
z = Math.sin(phi);
let light1 = new DirectionalLight(0xffffff, 0.5);
light1.position.set(x, y, z);
scene.add(light1);
// thin light from the opposite direction
let 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() {
this.renderer.render(this.scene, this.camera);
this.northArrow.animate();
}
addEventListeners() {
domEvent.on(this.mapIcon, 'click', () => {
this.basemapControl.show();
}, this);
domEvent.on(window, 'resize', this.onWindowResize, this);
domEvent.on(window, 'keydown', this.keydown, this);
// let inputNodes = [this.$topTextInput, this.$bottomTextInput, this.$imageInput];
// inputNodes.forEach(element => domEvent.on(element, 'keyup', this.createMeme, this));
// //if image is changed
// inputNodes.forEach(element => domEvent.on(element, 'change', this.createMeme, this));
domEvent.on(this.downloadButton, 'click', this.downloadMapImage, this);
domEvent.on(this.menuIcon, 'click', function (e) {
e.preventDefault();
this.navigation.classList.toggle("active");
}, this);
var tabButtons = [].slice.call(document.querySelectorAll('ul.tab-nav li span.button'));
tabButtons.map(function (button) {
button.addEventListener('click', function () {
document.querySelector('li span.active.button').classList.remove('active');
button.classList.add('active');
document.querySelector('.tab-pane.active').classList.remove('active');
document.querySelector(button.getAttribute('name')).classList.add('active');
})
})
}
downloadMapImage() {
// if(!this.$imageInput.files[0]) {
// this.$imageInput.parentElement.classList.add('has-error');
// return;
// }
// if(this.$bottomTextInput.value === '') {
// this.$imageInput.parentElement.classList.remove('has-error');
// this.$bottomTextInput.parentElement.classList.add('has-error');
// return;
// }
// this.$imageInput.parentElement.classList.remove('has-error');
// this.$bottomTextInput.parentElement.classList.remove('has-error');
// const imageSource = this.renderer.domElement.toDataURL('image/png');
// const att = document.createAttribute('href');
// att.value = imageSource.replace(/^data:image\/[^;]/, 'data:application/octet-stream');
// this.downloadButton.setAttributeNode(att);
// this.renderer.preserveDrawingBuffer = true;
// this.renderer.render(this.scene, this.camera);
this.saveCanvasImage(this.renderer.domElement);
}
saveCanvasImage(canvas) {
// !HTMLCanvasElement.prototype.toBlob
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement.toBlob
// decode the String
var binStr = atob(canvas.toDataURL("image/png").split(',')[1]);
var len = binStr.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
this.saveBlob(new Blob([arr], { type: "image/png" }));
}
saveBlob(blob) {
// ie
if (window.navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, filename);
//app.popup.hide();
}
else {
// create object url
if (this._canvasImageUrl) {
URL.revokeObjectURL(this._canvasImageUrl);
}
this._canvasImageUrl = URL.createObjectURL(blob);
// display a link to save the image
var e = this.downloadButton;//document.createElement("a");
e.href = this._canvasImageUrl;
}
}
createMeme() {
let context = this.$canvas.getContext('2d');
// font size of top and bottom text
let fontSize = ((this.canvas.width + this.canvas.height) / 2) * 4 / 100;
context.font = `${fontSize}pt sans-serif`;
context.textAlign = 'center';
context.textBaseline = 'top';
/**
* Stroke Text Style
*/
context.lineWidth = fontSize / 5;
context.strokeStyle = 'black';
/**
* Fill Text Style
*/
context.fillStyle = 'white';
// Fix lines over M
context.lineJoin = 'round';
// get he value of the top text an dbottom text from the input fields
let topText = this.$topTextInput.value.toUpperCase();
let bottomText = this.$bottomTextInput.value.toUpperCase();
// Top Text: first parameter text, second and thir parameters contain location where the text should start rendering
context.strokeText(topText, this.canvas.width / 2, this.canvas.height * (5 / 100));
context.fillText(topText, this.canvas.width / 2, this.canvas.height * (5 / 100));
// Bottom Text
context.strokeText(bottomText, this.canvas.width / 2, this.canvas.height * (90 / 100));
context.fillText(bottomText, this.canvas.width / 2, this.canvas.height * (90 / 100));
}
}
var container = document.getElementById("webgl");
new Application(container);