Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
266a770c8e | ||
|
|
a5f94e0a5f | ||
|
|
fff7a4f685 | ||
|
|
d0ae8893cc | ||
|
|
1b4eee6498 | ||
|
|
ac779af339 | ||
|
|
1316a727f3 | ||
|
|
be950ec8c1 | ||
|
|
ca5a39d661 | ||
|
|
fa0256d782 | ||
|
|
114c217ffa | ||
|
|
28cfdc180c | ||
|
|
116058ba77 | ||
|
|
4211548b8b | ||
|
|
12b17fd7af | ||
|
|
47b178fbc1 | ||
|
|
6ab63eb32c | ||
|
|
6445ab3f57 | ||
|
|
129672eb0f | ||
|
|
70031d3bfa | ||
|
|
9db5723746 | ||
|
|
d4ab5c7e9c | ||
|
|
b068fd176f | ||
|
|
f70968fe01 | ||
|
|
1c70433b86 | ||
|
|
54b685ab42 | ||
|
|
e6f6f6b185 | ||
|
|
7bb3b696f7 | ||
|
|
6cdf5310ba | ||
|
|
1967b791e0 | ||
|
|
ebb4b9154e | ||
|
|
b32132c71f | ||
|
|
f398fe4824 | ||
|
|
d5b87f23cf | ||
|
|
7f2fc93fa3 | ||
|
|
32e913c629 | ||
|
|
87c966062c | ||
|
|
d7f867f1a6 | ||
|
|
e188f3474f | ||
|
|
1e80845aa6 | ||
|
|
a85569e54d | ||
|
|
65fac2f406 | ||
|
|
60e28f8fe5 | ||
|
|
792892cb82 | ||
|
|
9159073483 |
@@ -80,3 +80,9 @@ typings/
|
|||||||
*.code-workspace
|
*.code-workspace
|
||||||
.history/
|
.history/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
|
||||||
|
# ignore generated contents-
|
||||||
|
/doc/out/*
|
||||||
|
**/thumbnails
|
||||||
|
**/thumbnail.png
|
||||||
|
After Width: | Height: | Size: 8.0 KiB |
@@ -1,15 +1,47 @@
|
|||||||
|
:root {
|
||||||
|
--white: rgb(250, 250, 250);
|
||||||
|
--light-gray: rgb(219, 219, 219);
|
||||||
|
--gray: rgb(66, 66, 66);
|
||||||
|
--black: rgb(20, 20, 20);
|
||||||
|
--dark-background: rgb(50, 50, 50);
|
||||||
|
|
||||||
|
--border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
background: white;
|
background: var(--white);
|
||||||
color: #000;
|
color: var(--black);
|
||||||
font-family: 'Open Sans', Arial, sans-serif;
|
font-family: 'Open Sans', Arial, sans-serif;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark-mode nav{
|
||||||
|
border-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
margin-top: 50px;
|
||||||
|
min-width: 30%;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px 30px;
|
||||||
|
/* background-color: var(--light-gray); */
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav > h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav > ol a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
html.dark-mode {
|
html.dark-mode {
|
||||||
background: rgb(51, 51, 51);
|
background: var(--dark-background);
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,16 +54,102 @@ html.dark-mode {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-mode a{
|
a {
|
||||||
color: #569CD6;
|
color: #569cd6;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-mode a:hover{
|
.dark-mode a:hover {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
a{
|
.dark-mode button {
|
||||||
|
border: 1px solid rgb(211, 211, 211);
|
||||||
|
color: rgb(211, 211, 211);
|
||||||
|
background: linear-gradient(to top, rgb(53, 53, 53), rgb(73, 73, 73));
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: var(--white);
|
||||||
|
border: 1px solid var(--gray);
|
||||||
|
color: var(--gray);
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
input[type='checkbox'] + .checkbox {
|
||||||
|
position: relative;
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls > * {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-mode .checkbox {
|
||||||
|
background-color: var(--gray);
|
||||||
|
border: 1px solid var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox']:checked + .checkbox {
|
||||||
|
background-color: rgb(174, 238, 78);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox']:checked + .checkbox:after {
|
||||||
|
left: 11px;
|
||||||
|
top: 6px;
|
||||||
|
width: 5px;
|
||||||
|
height: 12px;
|
||||||
|
border: solid var(--white);
|
||||||
|
border-width: 0 4px 4px 0;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-ms-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
filter: brightness(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
box-shadow: 0 0 3px 1px #569cd6;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +171,8 @@ a{
|
|||||||
|
|
||||||
.doctest {
|
.doctest {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-top: 50px;
|
padding-top: 20px;
|
||||||
padding-bottom: 50px;
|
padding-bottom: 20px;
|
||||||
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.5);
|
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
.collapsed .doctest {
|
.collapsed .doctest {
|
||||||
@@ -71,7 +189,7 @@ a{
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.doctest-collapsible-toggle {
|
.doctest-titlebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
|||||||
@@ -239,18 +239,29 @@
|
|||||||
let container = document.createElement('div');
|
let container = document.createElement('div');
|
||||||
container.className = 'doctest-wrapper';
|
container.className = 'doctest-wrapper';
|
||||||
|
|
||||||
let titleParent = container;
|
if (doctest.hasAttribute('data-title') || doctest.hasAttribute('data-collapsible')) {
|
||||||
if (doctest.hasAttribute('data-collapsible')) {
|
let titlebar = document.createElement('div');
|
||||||
let collapsibleToggle = document.createElement('div');
|
titlebar.className = 'doctest-titlebar';
|
||||||
|
titlebar.style = 'min-height: 10px;';
|
||||||
|
container.appendChild(titlebar);
|
||||||
|
|
||||||
|
if (doctest.hasAttribute('data-title')) {
|
||||||
|
let title = document.createElement('h6');
|
||||||
|
title.innerText = doctest.getAttribute('data-title');
|
||||||
|
title.className = 'doctest-section-title';
|
||||||
|
titlebar.appendChild(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doctest.hasAttribute('data-collapsible')) {
|
||||||
let icon = document.createElement('i');
|
let icon = document.createElement('i');
|
||||||
icon.className = 'material-icons';
|
icon.className = 'material-icons';
|
||||||
collapsibleToggle.appendChild(icon);
|
titlebar.classList.add('doctest-collapsible-toggle');
|
||||||
|
|
||||||
collapsibleToggle.className = 'doctest-collapsible-toggle';
|
if (titlebar.childNodes.length > 0) {
|
||||||
collapsibleToggle.style = 'min-height: 10px;';
|
titlebar.insertBefore(icon, titlebar.childNodes[0]);
|
||||||
titleParent = collapsibleToggle;
|
} else {
|
||||||
container.appendChild(collapsibleToggle);
|
titlebar.appendChild(icon);
|
||||||
|
}
|
||||||
|
|
||||||
const collapsedClass = 'collapsed';
|
const collapsedClass = 'collapsed';
|
||||||
|
|
||||||
@@ -269,13 +280,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
setToggleMode(doctest.hasAttribute('data-collapsed'));
|
setToggleMode(doctest.hasAttribute('data-collapsed'));
|
||||||
collapsibleToggle.addEventListener('click', determineToggleMode);
|
titlebar.addEventListener('click', determineToggleMode);
|
||||||
}
|
}
|
||||||
if (doctest.hasAttribute('data-title')) {
|
|
||||||
let title = document.createElement('h6');
|
|
||||||
title.innerText = doctest.getAttribute('data-title');
|
|
||||||
title.className = 'doctest-section-title';
|
|
||||||
titleParent.appendChild(title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let pre = document.createElement('pre');
|
let pre = document.createElement('pre');
|
||||||
@@ -423,9 +429,12 @@
|
|||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'error',
|
'error',
|
||||||
event => {
|
event => {
|
||||||
// if (typeof(event.error) == 'undefined') {
|
if (typeof event.error == 'undefined') {
|
||||||
// console.info("Catched undefined error", event)
|
// This sometimes happens in Edge. Since we have no error
|
||||||
// }
|
// position, we cannot do much beside an info log.
|
||||||
|
console.info('Catched undefined error', event);
|
||||||
|
return
|
||||||
|
}
|
||||||
this.appendError(event.error, event.filename);
|
this.appendError(event.error, event.filename);
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
@@ -455,7 +464,10 @@
|
|||||||
class Events {
|
class Events {
|
||||||
static stop(event) {
|
static stop(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
// I removed this, as it destroys all the Hammer.js events.
|
||||||
|
// And also the click event.
|
||||||
|
// It seems to have no (apparent) negative impact. -SO
|
||||||
|
// event.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
static extractPoint(event) {
|
static extractPoint(event) {
|
||||||
@@ -608,19 +620,6 @@
|
|||||||
|
|
||||||
static toLine(event) {
|
static toLine(event) {
|
||||||
return `${event.type} #${event.target.id} ${event.clientX} ${event.clientY}`
|
return `${event.type} #${event.target.id} ${event.clientX} ${event.clientY}`
|
||||||
let result = event.type;
|
|
||||||
let selector = this.selector(event.target);
|
|
||||||
result += ' selector: ' + selector;
|
|
||||||
if (event.target != document.querySelector(selector)) console.log('Cannot resolve', selector);
|
|
||||||
let keys = ['layerX', 'layerY', 'pageX', 'pageY', 'clientX', 'clientY'];
|
|
||||||
for (let key of keys) {
|
|
||||||
try {
|
|
||||||
result += ' ' + key + ':' + event[key];
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Invalid key: ' + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static compareExtractedWithSimulated() {
|
static compareExtractedWithSimulated() {
|
||||||
@@ -1086,9 +1085,18 @@
|
|||||||
|
|
||||||
// Distance == 0.0 indicates an inside relation.
|
// Distance == 0.0 indicates an inside relation.
|
||||||
static distanceToRect(p, r) {
|
static distanceToRect(p, r) {
|
||||||
let cx = Math.max(Math.min(p.x, r.x + r.width), r.x);
|
let dx = 0;
|
||||||
let cy = Math.max(Math.min(p.y, r.y + r.height), r.y);
|
let dy = 0;
|
||||||
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
if (p.x < r.x) dx = p.x - r.x;
|
||||||
|
else if (p.x > r.x + r.width) dx = p.x - (r.x + r.width);
|
||||||
|
if (p.y < r.y) dy = p.y - r.y;
|
||||||
|
else if (p.y > r.y + r.height) dy = p.y - (r.y + r.height);
|
||||||
|
return Math.sqrt(dx * dx + dy * dy)
|
||||||
|
/* let cx = Math.max(Math.min(p.x, r.x + r.width), r.x)
|
||||||
|
let cy = Math.max(Math.min(p.y, r.y + r.height), r.y)
|
||||||
|
let result = Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
||||||
|
console.log("distanceToRect", p, r, result)
|
||||||
|
return result */
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPageToNode(element, p) {
|
static fromPageToNode(element, p) {
|
||||||
@@ -1716,7 +1724,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ipc = require('electron').ipcRenderer;
|
ipc = window.ipcRenderer || require('electron').ipcRenderer;
|
||||||
logHandlers.log = message => ipc.send('log', message);
|
logHandlers.log = message => ipc.send('log', message);
|
||||||
logHandlers.warn = message => ipc.send('warn', message);
|
logHandlers.warn = message => ipc.send('warn', message);
|
||||||
logHandlers.error = message => ipc.send('error', message);
|
logHandlers.error = message => ipc.send('error', message);
|
||||||
@@ -2614,8 +2622,8 @@
|
|||||||
if (Events.isCaptured(event)) {
|
if (Events.isCaptured(event)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let captured = this.target.capture(event);
|
|
||||||
return captured
|
return this.target.capture ? this.target.capture(event) : false
|
||||||
}
|
}
|
||||||
|
|
||||||
getPosition(event) {
|
getPosition(event) {
|
||||||
@@ -2640,25 +2648,6 @@
|
|||||||
result[id] = this.getPosition(event);
|
result[id] = this.getPosition(event);
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// case 'TouchEvent':
|
|
||||||
// // Needs to be observed: Perhaps changedTouches are all we need. If so
|
|
||||||
// // we can remove the touchEventKey default parameter
|
|
||||||
// if (touchEventKey == 'all') {
|
|
||||||
// for(let t of event.targetTouches) {
|
|
||||||
// result[t.identifier.toString()] = this.getPosition(t)
|
|
||||||
// }
|
|
||||||
// for(let t of event.changedTouches) {
|
|
||||||
// result[t.identifier.toString()] = this.getPosition(t)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// for(let t of event.changedTouches) {
|
|
||||||
// result[t.identifier.toString()] = this.getPosition(t)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -3232,6 +3221,9 @@
|
|||||||
let t = performance.now();
|
let t = performance.now();
|
||||||
let dt = t - this.lastframe;
|
let dt = t - this.lastframe;
|
||||||
this.lastframe = t;
|
this.lastframe = t;
|
||||||
|
|
||||||
|
// When number is not set or is zero. Use one instead.
|
||||||
|
let number = delta.number ? delta.number : 1;
|
||||||
if (dt > 0) {
|
if (dt > 0) {
|
||||||
// Avoid division by zero errors later on
|
// Avoid division by zero errors later on
|
||||||
// and consider the number of involved pointers sind addVelocity will be called by the
|
// and consider the number of involved pointers sind addVelocity will be called by the
|
||||||
@@ -3239,13 +3231,14 @@
|
|||||||
let velocity = {
|
let velocity = {
|
||||||
t: t,
|
t: t,
|
||||||
dt: dt,
|
dt: dt,
|
||||||
dx: delta.x / delta.number,
|
dx: delta.x / number,
|
||||||
dy: delta.y / delta.number
|
dy: delta.y / number
|
||||||
};
|
};
|
||||||
this.velocities.push(velocity);
|
this.velocities.push(velocity);
|
||||||
while (this.velocities.length > buffer) {
|
while (this.velocities.length > buffer) {
|
||||||
this.velocities.shift();
|
this.velocities.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3493,7 +3486,7 @@
|
|||||||
let delta = interaction.delta();
|
let delta = interaction.delta();
|
||||||
|
|
||||||
if (delta != null) {
|
if (delta != null) {
|
||||||
this.addVelocity(delta);
|
this.addVelocity(delta); // uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
let rotate = delta.rotate;
|
let rotate = delta.rotate;
|
||||||
let zoom = delta.zoom;
|
let zoom = delta.zoom;
|
||||||
if (this.maxRotation != null) {
|
if (this.maxRotation != null) {
|
||||||
@@ -3693,6 +3686,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
_move(delta) {
|
_move(delta) {
|
||||||
|
// this.addVelocity(delta) uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
this.x += this.movableX ? delta.x : 0;
|
this.x += this.movableX ? delta.x : 0;
|
||||||
this.y += this.movableX ? delta.y : 0;
|
this.y += this.movableX ? delta.y : 0;
|
||||||
}
|
}
|
||||||
@@ -3730,14 +3724,14 @@
|
|||||||
|
|
||||||
let newOrigin = Points$1.arc(anchor, beta + rotate, distance * thresholdedZoom);
|
let newOrigin = Points$1.arc(anchor, beta + rotate, distance * thresholdedZoom);
|
||||||
let extra = Points$1.subtract(newOrigin, origin);
|
let extra = Points$1.subtract(newOrigin, origin);
|
||||||
let offset = Points$1.subtract(anchor, origin);
|
const anchorOffset = Points$1.subtract(anchor, origin);
|
||||||
this._move(offset);
|
// this._move(offset)
|
||||||
this.scale = newScale;
|
this.scale = newScale;
|
||||||
this.rotation += rotate;
|
this.rotation += rotate;
|
||||||
offset = Points$1.negate(offset);
|
let offset = Points$1.negate(anchorOffset);
|
||||||
offset = Points$1.add(offset, extra);
|
offset = Points$1.add(offset, extra);
|
||||||
offset = Points$1.add(offset, translate);
|
offset = Points$1.add(offset, translate);
|
||||||
this._move(offset);
|
this._move(Points$1.add(anchorOffset, offset));
|
||||||
|
|
||||||
delta.x += extra.x;
|
delta.x += extra.x;
|
||||||
delta.y += extra.y;
|
delta.y += extra.y;
|
||||||
@@ -4507,7 +4501,8 @@
|
|||||||
}
|
}
|
||||||
this._x = x;
|
this._x = x;
|
||||||
this._y = y;
|
this._y = y;
|
||||||
TweenLite.set(this.element, { x: x, y: y });
|
// this.addVelocity({ x: delta.x, y: delta.y }) uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
|
TweenLite.set(this.element, { x, y });
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeAfterTransform(zoom) {
|
resizeAfterTransform(zoom) {
|
||||||
@@ -4714,16 +4709,24 @@
|
|||||||
|
|
||||||
let clickRects = activeNodes.map(link => {
|
let clickRects = activeNodes.map(link => {
|
||||||
let rect = link.getBoundingClientRect();
|
let rect = link.getBoundingClientRect();
|
||||||
|
// Since the getBoundingClientRect is untransformed we cannot rely on it's size
|
||||||
|
// We need a transformed bottom right to calculate local width and height
|
||||||
|
let bottomRight = Points$1.fromPageToNode(element, {
|
||||||
|
x: rect.x + rect.width,
|
||||||
|
y: rect.y + rect.height
|
||||||
|
});
|
||||||
let topLeft = Points$1.fromPageToNode(element, rect);
|
let topLeft = Points$1.fromPageToNode(element, rect);
|
||||||
|
let width = Math.abs(bottomRight.x - topLeft.x);
|
||||||
|
let height = Math.abs(bottomRight.y - topLeft.y);
|
||||||
let center = Points$1.fromPageToNode(element, {
|
let center = Points$1.fromPageToNode(element, {
|
||||||
x: rect.x + rect.width / 2,
|
x: rect.x + width / 2,
|
||||||
y: rect.y + rect.height / 2
|
y: rect.y + height / 2
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
x: topLeft.x,
|
x: topLeft.x,
|
||||||
y: topLeft.y,
|
y: topLeft.y,
|
||||||
width: rect.width,
|
width,
|
||||||
height: rect.height,
|
height,
|
||||||
center,
|
center,
|
||||||
link
|
link
|
||||||
}
|
}
|
||||||
@@ -4751,15 +4754,20 @@
|
|||||||
/* https://stackoverflow.com/questions/49564905/is-it-possible-to-use-click-function-on-svg-tags-i-tried-element-click-on-a
|
/* https://stackoverflow.com/questions/49564905/is-it-possible-to-use-click-function-on-svg-tags-i-tried-element-click-on-a
|
||||||
proposes the dispatchEvent solution. But this leads to problems in flippable.html hiding the back page.
|
proposes the dispatchEvent solution. But this leads to problems in flippable.html hiding the back page.
|
||||||
Therefore we use the original click event (see constructor). */
|
Therefore we use the original click event (see constructor). */
|
||||||
if (this.isSVGNode(node)) {
|
// if (this.isSVGNode(node)) {
|
||||||
if (this.triggerSVGClicks) {
|
// if (this.triggerSVGClicks) {
|
||||||
|
// let click = new Event('click')
|
||||||
|
// node.dispatchEvent(click)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// node.click()
|
||||||
|
|
||||||
let click = new Event('click');
|
let click = new Event('click');
|
||||||
|
click.clientX = event.clientX;
|
||||||
|
click.clientY = event.clientY;
|
||||||
node.dispatchEvent(click);
|
node.dispatchEvent(click);
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
node.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeTapped(node, event) {
|
nodeTapped(node, event) {
|
||||||
console.log('nodeTapped', node, this.isClickable(node));
|
console.log('nodeTapped', node, this.isClickable(node));
|
||||||
@@ -4946,13 +4954,15 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', this.src, false);
|
xhr.open('GET', this.src, false);
|
||||||
xhr.onload = e => {
|
xhr.onreadystatechange = e => {
|
||||||
|
if (xhr.readyState == 4) {
|
||||||
domNode.innerHTML = this.prepare(xhr.response);
|
domNode.innerHTML = this.prepare(xhr.response);
|
||||||
this.addedNode = domNode.firstElementChild;
|
this.addedNode = domNode.firstElementChild;
|
||||||
let { width, height } = this.size(this.addedNode);
|
let { width, height } = this.size(this.addedNode);
|
||||||
if (width) this.wantedWidth = width || this.wantedWidth;
|
if (width) this.wantedWidth = width || this.wantedWidth;
|
||||||
if (height) this.wantedHeight = height || this.wantedHeight;
|
if (height) this.wantedHeight = height || this.wantedHeight;
|
||||||
resolve(this);
|
resolve(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
xhr.onerror = e => {
|
xhr.onerror = e => {
|
||||||
reject(this);
|
reject(this);
|
||||||
@@ -5753,8 +5763,6 @@
|
|||||||
let bottom = parseFloat(this.element.style.bottom);
|
let bottom = parseFloat(this.element.style.bottom);
|
||||||
this.element.style.bottom = bottom - delta.y + 'px';
|
this.element.style.bottom = bottom - delta.y + 'px';
|
||||||
break
|
break
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
//console.log("onResize", this.onResize)
|
//console.log("onResize", this.onResize)
|
||||||
if (this.onResize) {
|
if (this.onResize) {
|
||||||
@@ -6177,8 +6185,6 @@
|
|||||||
x = bbRight;
|
x = bbRight;
|
||||||
if (!this.useEventPosWithBoundingBox) y = (bbTop + bbBottom) / 2;
|
if (!this.useEventPosWithBoundingBox) y = (bbTop + bbBottom) / 2;
|
||||||
break
|
break
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6234,8 +6240,6 @@
|
|||||||
x += this.notchSize * 2;
|
x += this.notchSize * 2;
|
||||||
x += this.posOffset;
|
x += this.posOffset;
|
||||||
break
|
break
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
this.placeOrigin(x, y);
|
this.placeOrigin(x, y);
|
||||||
}
|
}
|
||||||
@@ -6626,10 +6630,10 @@
|
|||||||
Elements$1.addClass(item, 'popupMenuItem');
|
Elements$1.addClass(item, 'popupMenuItem');
|
||||||
this.items[key] = item;
|
this.items[key] = item;
|
||||||
item.onclick = event => {
|
item.onclick = event => {
|
||||||
this.perform(key);
|
this.perform(event, key);
|
||||||
};
|
};
|
||||||
item.ontap = event => {
|
item.ontap = event => {
|
||||||
this.perform(key);
|
this.perform(event, key);
|
||||||
};
|
};
|
||||||
item.onmouseover = event => {
|
item.onmouseover = event => {
|
||||||
this.over(event, key);
|
this.over(event, key);
|
||||||
@@ -6648,16 +6652,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Execute a menu command.
|
/** Execute a menu command.
|
||||||
|
* @param {object} event - The trigger event.
|
||||||
* @param {string} key - The selected key.
|
* @param {string} key - The selected key.
|
||||||
*/
|
*/
|
||||||
perform(key) {
|
perform(event, key) {
|
||||||
let func = this.commands[key];
|
let func = this.commands[key];
|
||||||
if (this.autoClose) {
|
if (this.autoClose) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(
|
||||||
func.call();
|
(event, key) => {
|
||||||
}, 20);
|
func(event, key);
|
||||||
|
},
|
||||||
|
20,
|
||||||
|
event,
|
||||||
|
key
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update the menu item denoted by key.
|
/** Update the menu item denoted by key.
|
||||||
@@ -7983,10 +7993,13 @@
|
|||||||
* @class Highlight
|
* @class Highlight
|
||||||
* @extends {Object}
|
* @extends {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const SCALE = 1.5;
|
||||||
|
|
||||||
class Highlight extends Object {
|
class Highlight extends Object {
|
||||||
static disableAnimations() {
|
static disableAnimations() {
|
||||||
_HighlightEnabled = false;
|
_HighlightEnabled = false;
|
||||||
let expanded = document.querySelectorAll('.' + Highlight.expandedClass);
|
let expanded = document.querySelectorAll('.' + this.expandedClass);
|
||||||
for (let obj of expanded) {
|
for (let obj of expanded) {
|
||||||
this.shrink(obj);
|
this.shrink(obj);
|
||||||
}
|
}
|
||||||
@@ -7997,11 +8010,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
static removeAnimations(svgRoot) {
|
static removeAnimations(svgRoot) {
|
||||||
let expanded = svgRoot.querySelectorAll('.' + Highlight.expandedClass);
|
let expanded = svgRoot.querySelectorAll('.' + this.expandedClass);
|
||||||
for (let obj of expanded) {
|
for (let obj of expanded) {
|
||||||
TweenLite.set(obj, { scale: 1 });
|
TweenLite.set(obj, { scale: 1 });
|
||||||
obj.classList.remove('zooming');
|
obj.classList.remove('zooming');
|
||||||
obj.classList.remove(Highlight.expandedClass);
|
obj.classList.remove(this.expandedClass);
|
||||||
}
|
}
|
||||||
let defs = svgRoot.querySelector('defs');
|
let defs = svgRoot.querySelector('defs');
|
||||||
while (defs.firstChild) {
|
while (defs.firstChild) {
|
||||||
@@ -8031,12 +8044,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static expand(obj, { scale = 2, duration = 3, stroke = 2, onComplete = null } = {}) {
|
static expand(obj, { scale = SCALE, duration = 3, stroke = 2, onComplete = null } = {}) {
|
||||||
if (obj == null) return
|
if (obj == null) return
|
||||||
//console.log("expand")
|
//console.log("expand")
|
||||||
obj.classList.add('zooming');
|
obj.classList.add('zooming');
|
||||||
TweenLite.to(obj, duration, {
|
TweenLite.to(obj, duration, {
|
||||||
scale: scale,
|
scale,
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
let scale = obj._gsTransform.scaleX;
|
let scale = obj._gsTransform.scaleX;
|
||||||
obj.setAttribute('stroke-width', stroke / scale);
|
obj.setAttribute('stroke-width', stroke / scale);
|
||||||
@@ -8044,7 +8057,7 @@
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
console.log('expand complete');
|
console.log('expand complete');
|
||||||
obj.classList.remove('zooming');
|
obj.classList.remove('zooming');
|
||||||
obj.classList.add(Highlight.expandedClass);
|
obj.classList.add(this.expandedClass);
|
||||||
obj.setAttribute('stroke-width', stroke / scale);
|
obj.setAttribute('stroke-width', stroke / scale);
|
||||||
if (onComplete) onComplete();
|
if (onComplete) onComplete();
|
||||||
}
|
}
|
||||||
@@ -8064,7 +8077,7 @@
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
//console.log("shrink complete")
|
//console.log("shrink complete")
|
||||||
obj.classList.remove('zooming');
|
obj.classList.remove('zooming');
|
||||||
obj.classList.remove(Highlight.expandedClass);
|
obj.classList.remove(this.expandedClass);
|
||||||
obj.setAttribute('stroke-width', stroke);
|
obj.setAttribute('stroke-width', stroke);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -8103,7 +8116,7 @@
|
|||||||
let maskImageId = 'maskImage' + id;
|
let maskImageId = 'maskImage' + id;
|
||||||
let maskImage = svgRoot.getElementById(maskImageId);
|
let maskImage = svgRoot.getElementById(maskImageId);
|
||||||
|
|
||||||
if (circle.classList.contains(Highlight.expandedClass)) {
|
if (circle.classList.contains(this.expandedClass)) {
|
||||||
if (!circle.classList.contains('zooming')) {
|
if (!circle.classList.contains('zooming')) {
|
||||||
this.shrink(circle, { stroke });
|
this.shrink(circle, { stroke });
|
||||||
this.shrink(maskImage, { stroke });
|
this.shrink(maskImage, { stroke });
|
||||||
@@ -8126,7 +8139,7 @@
|
|||||||
this.shrink(m, { stroke });
|
this.shrink(m, { stroke });
|
||||||
}
|
}
|
||||||
|
|
||||||
Highlight._createSVGMask(svgRoot, image, id);
|
this._createSVGMask(svgRoot, image, id);
|
||||||
|
|
||||||
// TweenLite.set(maskImage, { transformOrigin: `${tx}% ${ty}%` })
|
// TweenLite.set(maskImage, { transformOrigin: `${tx}% ${ty}%` })
|
||||||
|
|
||||||
@@ -8136,8 +8149,8 @@
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
static openHighlight(target, { animation = 0.5, scale = 2, onExpanded = null } = {}) {
|
static openHighlight(target, { animation = 0.5, scale = SCALE, onExpanded = null } = {}) {
|
||||||
if (Highlight._isExpanded(target)) {
|
if (this._isExpanded(target)) {
|
||||||
console.log('Target is already expanded!');
|
console.log('Target is already expanded!');
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -8161,11 +8174,11 @@
|
|||||||
let image = svgRoot.querySelector('image');
|
let image = svgRoot.querySelector('image');
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [mask, maskImage] = Highlight._getSVGMask(target, {
|
let [mask, maskImage] = this._getSVGMask(target, {
|
||||||
svgRoot,
|
svgRoot,
|
||||||
image
|
image
|
||||||
});
|
});
|
||||||
let center = Highlight._calculateCenterRelativeTo(target, image);
|
let center = this._calculateCenterRelativeTo(target, image);
|
||||||
console.log('_calculateCenterRelativeTo', center);
|
console.log('_calculateCenterRelativeTo', center);
|
||||||
TweenLite.set(maskImage, {
|
TweenLite.set(maskImage, {
|
||||||
transformOrigin: `${center.x} ${center.y}`
|
transformOrigin: `${center.x} ${center.y}`
|
||||||
@@ -8177,16 +8190,16 @@
|
|||||||
onComplete: onExpanded
|
onComplete: onExpanded
|
||||||
});
|
});
|
||||||
|
|
||||||
target.classList.add(Highlight.expandedClass);
|
target.classList.add(this.expandedClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static toggleHighlight(node) {
|
static toggleHighlight(node, options = {}) {
|
||||||
console.log('toggleHighlight', Highlight._isExpanded(node));
|
console.log('toggleHighlight', this._isExpanded(node));
|
||||||
if (Highlight._isExpanded(node)) {
|
if (this._isExpanded(node)) {
|
||||||
Highlight.closeHighlight(node);
|
this.closeHighlight(node, options);
|
||||||
} else {
|
} else {
|
||||||
Highlight.openHighlight(node);
|
this.openHighlight(node, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8209,7 +8222,7 @@
|
|||||||
let maskImage = svgRoot.getElementById(maskImageId);
|
let maskImage = svgRoot.getElementById(maskImageId);
|
||||||
|
|
||||||
if (!mask || !maskImage)
|
if (!mask || !maskImage)
|
||||||
[mask, maskImage] = Highlight._createSVGMask(circle, {
|
[mask, maskImage] = this._createSVGMask(circle, {
|
||||||
svgRoot,
|
svgRoot,
|
||||||
image,
|
image,
|
||||||
id
|
id
|
||||||
@@ -8275,12 +8288,11 @@
|
|||||||
maskImage.setAttribute('width', width);
|
maskImage.setAttribute('width', width);
|
||||||
maskImage.setAttribute('height', height);
|
maskImage.setAttribute('height', height);
|
||||||
maskImage.setAttribute('class', 'addedImage');
|
maskImage.setAttribute('class', 'addedImage');
|
||||||
svgGroup.insertBefore(maskImage, element); // image.nextSibling)
|
|
||||||
TweenLite.set(maskImage, { scale: 1 });
|
TweenLite.set(maskImage, { scale: 1 });
|
||||||
maskImage.style.mask = 'url(#' + maskId + ')';
|
maskImage.style.mask = 'url(#' + maskId + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
svgGroup.appendChild(maskImage);
|
element.insertAdjacentElement('beforebegin', maskImage); // image.nextSibling)
|
||||||
// svgGroup.appendChild(element)
|
// svgGroup.appendChild(element)
|
||||||
|
|
||||||
return [mask, maskImage]
|
return [mask, maskImage]
|
||||||
@@ -8298,14 +8310,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
static _isExpanded(target) {
|
static _isExpanded(target) {
|
||||||
return target.classList.contains(Highlight.expandedClass)
|
return target.classList.contains(this.expandedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static closeHighlight(target, { animation = 0.5 } = {}) {
|
static closeHighlight(target, { animation = 0.5 } = {}) {
|
||||||
target.classList.remove(Highlight.expandedClass);
|
target.classList.remove(this.expandedClass);
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [mask, maskImage] = Highlight._getSVGMask(target);
|
let [mask, maskImage] = this._getSVGMask(target);
|
||||||
console.log('Close Highlight', maskImage);
|
// console.log('Close Highlight', maskImage)
|
||||||
TweenLite.to([target, maskImage], animation, {
|
TweenLite.to([target, maskImage], animation, {
|
||||||
scale: 1
|
scale: 1
|
||||||
});
|
});
|
||||||
@@ -8315,7 +8327,7 @@
|
|||||||
if (!_HighlightEnabled) return
|
if (!_HighlightEnabled) return
|
||||||
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
Highlight.animateCircle(event.target);
|
this.animateCircle(event.target);
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -8481,7 +8493,7 @@
|
|||||||
*/
|
*/
|
||||||
static _replaceCallback(context, element, attributeVal) {
|
static _replaceCallback(context, element, attributeVal) {
|
||||||
if (element.tagName == 'A') {
|
if (element.tagName == 'A') {
|
||||||
element.addEventListener('click', event => {
|
element.addEventListener('pointerdown', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,21 @@
|
|||||||
"./lib/pixi/switch.js",
|
"./lib/pixi/switch.js",
|
||||||
"./lib/pixi/theme.js",
|
"./lib/pixi/theme.js",
|
||||||
"./lib/pixi/tooltip.js",
|
"./lib/pixi/tooltip.js",
|
||||||
"./lib/pixi/volatile.js"
|
"./lib/pixi/volatile.js",
|
||||||
|
"./lib/pixi/maps/mapapp.js",
|
||||||
|
"./lib/pixi/maps/mapviewport.js",
|
||||||
|
"./lib/pixi/maps/geographics.js",
|
||||||
|
"./lib/pixi/maps/geojson.js",
|
||||||
|
"./lib/pixi/maps/geolayer.js",
|
||||||
|
"./lib/pixi/maps/mapprojection.js",
|
||||||
|
"./lib/pixi/maps/maplist.js",
|
||||||
|
"./lib/pixi/maps/overlay.js",
|
||||||
|
"./lib/pixi/maps/scatter.js",
|
||||||
|
"./lib/pixi/maps/utils.js",
|
||||||
|
"./lib/pixi/maps/map.js",
|
||||||
|
"./lib/pixi/maps/projections/projection.js",
|
||||||
|
"./lib/pixi/maps/projections/mercator.js",
|
||||||
|
"./lib/pixi/maps/projections/robinson.js"
|
||||||
],
|
],
|
||||||
"exclude": [],
|
"exclude": [],
|
||||||
"includePattern": ".+\\.js(doc|x)?$",
|
"includePattern": ".+\\.js(doc|x)?$",
|
||||||
@@ -45,7 +59,10 @@
|
|||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"tags": {
|
"tags": {
|
||||||
"allowUnknownTags": true,
|
"allowUnknownTags": true,
|
||||||
"dictionaries": ["jsdoc", "closure"]
|
"dictionaries": [
|
||||||
|
"jsdoc",
|
||||||
|
"closure"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
"applicationName": "iwmlib",
|
"applicationName": "iwmlib",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
(function(){var e=0;var a;var t=document.getElementById("source-code");if(t){var n=config.linenums;if(n){t=t.getElementsByTagName("ol")[0];a=Array.prototype.slice.apply(t.children);a=a.map(function(a){e++;a.id="line"+e})}else{t=t.getElementsByTagName("code")[0];a=t.innerHTML.split("\n");a=a.map(function(a){e++;return'<span id="line'+e+'"></span>'+a});t.innerHTML=a.join("\n")}}})();$(function(){var e=$(".navigation");var a=e.find(".list");var t=$(".search");$("#search").on("keyup",function(t){var n=this.value.trim();if(n){var s=new RegExp(n,"i");e.addClass("searching").removeClass("not-searching").find("li, .itemMembers").removeClass("match");e.find("li").each(function(e,a){var t=$(a);if(t.data("name")&&s.test(t.data("name"))){t.addClass("match");t.closest(".itemMembers").addClass("match");t.closest(".item").addClass("match")}})}else{e.removeClass("searching").addClass("not-searching").find(".item, .itemMembers").removeClass("match")}a.scrollTop(0)});$("#menuToggle").click(function(){a.toggleClass("show");t.toggleClass("show")});e.addClass("not-searching");var n=$(".page-title").data("filename").replace(/\.[a-z]+$/,"");var s=e.find('.item[data-name*="'+n+'"]:eq(0)');if(s.length){s.remove().prependTo(a).addClass("current")}if(config.disqus){$(window).on("load",function(){var e=config.disqus;var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+e+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a);var t=document.createElement("script");t.async=true;t.type="text/javascript";t.src="http://"+e+".disqus.com/count.js";document.getElementsByTagName("BODY")[0].appendChild(t)})}});
|
(function(){var e=0;var a;var t=document.getElementById("source-code");if(t){var n=config.linenums;if(n){t=t.getElementsByTagName("ol")[0];a=Array.prototype.slice.apply(t.children);a=a.map(function(a){e++;a.id="line"+e})}else{t=t.getElementsByTagName("code")[0];a=t.innerHTML.split("\n");a=a.map(function(a){e++;return'<span id="line'+e+'"></span>'+a});t.innerHTML=a.join("\n")}}})();$(function(){var e=$(".navigation");var a=e.find(".list");var t=$(".search");$("#search").on("keyup",function(t){var n=this.value.trim();if(n){var s=new RegExp(n,"i");e.addClass("searching").removeClass("not-searching").find("li, .itemMembers").removeClass("match");e.find("li").each(function(e,a){var t=$(a);if(t.data("name")&&s.test(t.data("name"))){t.addClass("match");t.closest(".itemMembers").addClass("match");t.closest(".item").addClass("match")}})}else{e.removeClass("searching").addClass("not-searching").find(".item, .itemMembers").removeClass("match")}a.scrollTop(0)});$("#menuToggle").click(function(){a.toggleClass("show");t.toggleClass("show")});e.addClass("not-searching");var n=$(".page-title").data("filename").replace(/\.[a-z]+$/,"");var s=e.find('a[href*="'+n+'"]:eq(0)').closest(".item");if(s.length){if(s.parents(".children").length){s.addClass("current");s.find("li.item").addClass("notCurrent");s=s.parents("ul.list>li.item")}s.remove().prependTo(a).addClass("current")}if(config.disqus){$(window).on("load",function(){var e=config.disqus;var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+e+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a);var t=document.createElement("script");t.async=true;t.type="text/javascript";t.src="http://"+e+".disqus.com/count.js";document.getElementsByTagName("BODY")[0].appendChild(t)})}});
|
||||||
@@ -176,7 +176,7 @@ export default class Card {
|
|||||||
*/
|
*/
|
||||||
static _replaceCallback(context, element, attributeVal) {
|
static _replaceCallback(context, element, attributeVal) {
|
||||||
if (element.tagName == 'A') {
|
if (element.tagName == 'A') {
|
||||||
element.addEventListener('click', event => {
|
element.addEventListener('pointerdown', event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,13 @@ function round(value) {
|
|||||||
* @class Highlight
|
* @class Highlight
|
||||||
* @extends {Object}
|
* @extends {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const SCALE = 1.5
|
||||||
|
|
||||||
export default class Highlight extends Object {
|
export default class Highlight extends Object {
|
||||||
static disableAnimations() {
|
static disableAnimations() {
|
||||||
_HighlightEnabled = false
|
_HighlightEnabled = false
|
||||||
let expanded = document.querySelectorAll('.' + Highlight.expandedClass)
|
let expanded = document.querySelectorAll('.' + this.expandedClass)
|
||||||
for (let obj of expanded) {
|
for (let obj of expanded) {
|
||||||
this.shrink(obj)
|
this.shrink(obj)
|
||||||
}
|
}
|
||||||
@@ -41,11 +44,11 @@ export default class Highlight extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static removeAnimations(svgRoot) {
|
static removeAnimations(svgRoot) {
|
||||||
let expanded = svgRoot.querySelectorAll('.' + Highlight.expandedClass)
|
let expanded = svgRoot.querySelectorAll('.' + this.expandedClass)
|
||||||
for (let obj of expanded) {
|
for (let obj of expanded) {
|
||||||
TweenLite.set(obj, { scale: 1 })
|
TweenLite.set(obj, { scale: 1 })
|
||||||
obj.classList.remove('zooming')
|
obj.classList.remove('zooming')
|
||||||
obj.classList.remove(Highlight.expandedClass)
|
obj.classList.remove(this.expandedClass)
|
||||||
}
|
}
|
||||||
let defs = svgRoot.querySelector('defs')
|
let defs = svgRoot.querySelector('defs')
|
||||||
while (defs.firstChild) {
|
while (defs.firstChild) {
|
||||||
@@ -75,12 +78,12 @@ export default class Highlight extends Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static expand(obj, { scale = 2, duration = 3, stroke = 2, onComplete = null } = {}) {
|
static expand(obj, { scale = SCALE, duration = 3, stroke = 2, onComplete = null } = {}) {
|
||||||
if (obj == null) return
|
if (obj == null) return
|
||||||
//console.log("expand")
|
//console.log("expand")
|
||||||
obj.classList.add('zooming')
|
obj.classList.add('zooming')
|
||||||
TweenLite.to(obj, duration, {
|
TweenLite.to(obj, duration, {
|
||||||
scale: scale,
|
scale,
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
let scale = obj._gsTransform.scaleX
|
let scale = obj._gsTransform.scaleX
|
||||||
obj.setAttribute('stroke-width', stroke / scale)
|
obj.setAttribute('stroke-width', stroke / scale)
|
||||||
@@ -88,7 +91,7 @@ export default class Highlight extends Object {
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
console.log('expand complete')
|
console.log('expand complete')
|
||||||
obj.classList.remove('zooming')
|
obj.classList.remove('zooming')
|
||||||
obj.classList.add(Highlight.expandedClass)
|
obj.classList.add(this.expandedClass)
|
||||||
obj.setAttribute('stroke-width', stroke / scale)
|
obj.setAttribute('stroke-width', stroke / scale)
|
||||||
if (onComplete) onComplete()
|
if (onComplete) onComplete()
|
||||||
}
|
}
|
||||||
@@ -108,7 +111,7 @@ export default class Highlight extends Object {
|
|||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
//console.log("shrink complete")
|
//console.log("shrink complete")
|
||||||
obj.classList.remove('zooming')
|
obj.classList.remove('zooming')
|
||||||
obj.classList.remove(Highlight.expandedClass)
|
obj.classList.remove(this.expandedClass)
|
||||||
obj.setAttribute('stroke-width', stroke)
|
obj.setAttribute('stroke-width', stroke)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -147,7 +150,7 @@ export default class Highlight extends Object {
|
|||||||
let maskImageId = 'maskImage' + id
|
let maskImageId = 'maskImage' + id
|
||||||
let maskImage = svgRoot.getElementById(maskImageId)
|
let maskImage = svgRoot.getElementById(maskImageId)
|
||||||
|
|
||||||
if (circle.classList.contains(Highlight.expandedClass)) {
|
if (circle.classList.contains(this.expandedClass)) {
|
||||||
if (!circle.classList.contains('zooming')) {
|
if (!circle.classList.contains('zooming')) {
|
||||||
this.shrink(circle, { stroke })
|
this.shrink(circle, { stroke })
|
||||||
this.shrink(maskImage, { stroke })
|
this.shrink(maskImage, { stroke })
|
||||||
@@ -170,7 +173,7 @@ export default class Highlight extends Object {
|
|||||||
this.shrink(m, { stroke })
|
this.shrink(m, { stroke })
|
||||||
}
|
}
|
||||||
|
|
||||||
Highlight._createSVGMask(svgRoot, image, id)
|
this._createSVGMask(svgRoot, image, id)
|
||||||
|
|
||||||
// TweenLite.set(maskImage, { transformOrigin: `${tx}% ${ty}%` })
|
// TweenLite.set(maskImage, { transformOrigin: `${tx}% ${ty}%` })
|
||||||
|
|
||||||
@@ -180,8 +183,8 @@ export default class Highlight extends Object {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
static openHighlight(target, { animation = 0.5, scale = 2, onExpanded = null } = {}) {
|
static openHighlight(target, { animation = 0.5, scale = SCALE, onExpanded = null } = {}) {
|
||||||
if (Highlight._isExpanded(target)) {
|
if (this._isExpanded(target)) {
|
||||||
console.log('Target is already expanded!')
|
console.log('Target is already expanded!')
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -205,11 +208,11 @@ export default class Highlight extends Object {
|
|||||||
let image = svgRoot.querySelector('image')
|
let image = svgRoot.querySelector('image')
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [mask, maskImage] = Highlight._getSVGMask(target, {
|
let [mask, maskImage] = this._getSVGMask(target, {
|
||||||
svgRoot,
|
svgRoot,
|
||||||
image
|
image
|
||||||
})
|
})
|
||||||
let center = Highlight._calculateCenterRelativeTo(target, image)
|
let center = this._calculateCenterRelativeTo(target, image)
|
||||||
console.log('_calculateCenterRelativeTo', center)
|
console.log('_calculateCenterRelativeTo', center)
|
||||||
TweenLite.set(maskImage, {
|
TweenLite.set(maskImage, {
|
||||||
transformOrigin: `${center.x} ${center.y}`
|
transformOrigin: `${center.x} ${center.y}`
|
||||||
@@ -221,16 +224,16 @@ export default class Highlight extends Object {
|
|||||||
onComplete: onExpanded
|
onComplete: onExpanded
|
||||||
})
|
})
|
||||||
|
|
||||||
target.classList.add(Highlight.expandedClass)
|
target.classList.add(this.expandedClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static toggleHighlight(node) {
|
static toggleHighlight(node, options = {}) {
|
||||||
console.log('toggleHighlight', Highlight._isExpanded(node))
|
console.log('toggleHighlight', this._isExpanded(node))
|
||||||
if (Highlight._isExpanded(node)) {
|
if (this._isExpanded(node)) {
|
||||||
Highlight.closeHighlight(node)
|
this.closeHighlight(node, options)
|
||||||
} else {
|
} else {
|
||||||
Highlight.openHighlight(node)
|
this.openHighlight(node, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +256,7 @@ export default class Highlight extends Object {
|
|||||||
let maskImage = svgRoot.getElementById(maskImageId)
|
let maskImage = svgRoot.getElementById(maskImageId)
|
||||||
|
|
||||||
if (!mask || !maskImage)
|
if (!mask || !maskImage)
|
||||||
[mask, maskImage] = Highlight._createSVGMask(circle, {
|
[mask, maskImage] = this._createSVGMask(circle, {
|
||||||
svgRoot,
|
svgRoot,
|
||||||
image,
|
image,
|
||||||
id
|
id
|
||||||
@@ -319,12 +322,11 @@ export default class Highlight extends Object {
|
|||||||
maskImage.setAttribute('width', width)
|
maskImage.setAttribute('width', width)
|
||||||
maskImage.setAttribute('height', height)
|
maskImage.setAttribute('height', height)
|
||||||
maskImage.setAttribute('class', 'addedImage')
|
maskImage.setAttribute('class', 'addedImage')
|
||||||
svgGroup.insertBefore(maskImage, element) // image.nextSibling)
|
|
||||||
TweenLite.set(maskImage, { scale: 1 })
|
TweenLite.set(maskImage, { scale: 1 })
|
||||||
maskImage.style.mask = 'url(#' + maskId + ')'
|
maskImage.style.mask = 'url(#' + maskId + ')'
|
||||||
}
|
}
|
||||||
|
|
||||||
svgGroup.appendChild(maskImage)
|
element.insertAdjacentElement('beforebegin', maskImage) // image.nextSibling)
|
||||||
// svgGroup.appendChild(element)
|
// svgGroup.appendChild(element)
|
||||||
|
|
||||||
return [mask, maskImage]
|
return [mask, maskImage]
|
||||||
@@ -342,14 +344,14 @@ export default class Highlight extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static _isExpanded(target) {
|
static _isExpanded(target) {
|
||||||
return target.classList.contains(Highlight.expandedClass)
|
return target.classList.contains(this.expandedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static closeHighlight(target, { animation = 0.5 } = {}) {
|
static closeHighlight(target, { animation = 0.5 } = {}) {
|
||||||
target.classList.remove(Highlight.expandedClass)
|
target.classList.remove(this.expandedClass)
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [mask, maskImage] = Highlight._getSVGMask(target)
|
let [mask, maskImage] = this._getSVGMask(target)
|
||||||
console.log('Close Highlight', maskImage)
|
// console.log('Close Highlight', maskImage)
|
||||||
TweenLite.to([target, maskImage], animation, {
|
TweenLite.to([target, maskImage], animation, {
|
||||||
scale: 1
|
scale: 1
|
||||||
})
|
})
|
||||||
@@ -359,7 +361,7 @@ export default class Highlight extends Object {
|
|||||||
if (!_HighlightEnabled) return
|
if (!_HighlightEnabled) return
|
||||||
|
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
Highlight.animateCircle(event.target)
|
this.animateCircle(event.target)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
<link rel="stylesheet" href="../../css/highlight.css">
|
<link rel="stylesheet" href="../../css/highlight.css">
|
||||||
<link rel="stylesheet" href="../../css/popup.css">
|
<link rel="stylesheet" href="../../css/popup.css">
|
||||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||||
<script src="../../dist/iwmlib.js"></script>
|
|
||||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||||
|
<script src="../../dist/iwmlib.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="Doctest.run();">
|
<body onload="Doctest.run();">
|
||||||
|
|||||||
@@ -101,16 +101,24 @@ export default class CardWrapper extends Object {
|
|||||||
|
|
||||||
let clickRects = activeNodes.map(link => {
|
let clickRects = activeNodes.map(link => {
|
||||||
let rect = link.getBoundingClientRect()
|
let rect = link.getBoundingClientRect()
|
||||||
|
// Since the getBoundingClientRect is untransformed we cannot rely on it's size
|
||||||
|
// We need a transformed bottom right to calculate local width and height
|
||||||
|
let bottomRight = Points.fromPageToNode(element, {
|
||||||
|
x: rect.x + rect.width,
|
||||||
|
y: rect.y + rect.height
|
||||||
|
})
|
||||||
let topLeft = Points.fromPageToNode(element, rect)
|
let topLeft = Points.fromPageToNode(element, rect)
|
||||||
|
let width = Math.abs(bottomRight.x - topLeft.x)
|
||||||
|
let height = Math.abs(bottomRight.y - topLeft.y)
|
||||||
let center = Points.fromPageToNode(element, {
|
let center = Points.fromPageToNode(element, {
|
||||||
x: rect.x + rect.width / 2,
|
x: rect.x + width / 2,
|
||||||
y: rect.y + rect.height / 2
|
y: rect.y + height / 2
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
x: topLeft.x,
|
x: topLeft.x,
|
||||||
y: topLeft.y,
|
y: topLeft.y,
|
||||||
width: rect.width,
|
width,
|
||||||
height: rect.height,
|
height,
|
||||||
center,
|
center,
|
||||||
link
|
link
|
||||||
}
|
}
|
||||||
@@ -138,15 +146,20 @@ export default class CardWrapper extends Object {
|
|||||||
/* https://stackoverflow.com/questions/49564905/is-it-possible-to-use-click-function-on-svg-tags-i-tried-element-click-on-a
|
/* https://stackoverflow.com/questions/49564905/is-it-possible-to-use-click-function-on-svg-tags-i-tried-element-click-on-a
|
||||||
proposes the dispatchEvent solution. But this leads to problems in flippable.html hiding the back page.
|
proposes the dispatchEvent solution. But this leads to problems in flippable.html hiding the back page.
|
||||||
Therefore we use the original click event (see constructor). */
|
Therefore we use the original click event (see constructor). */
|
||||||
if (this.isSVGNode(node)) {
|
// if (this.isSVGNode(node)) {
|
||||||
if (this.triggerSVGClicks) {
|
// if (this.triggerSVGClicks) {
|
||||||
|
// let click = new Event('click')
|
||||||
|
// node.dispatchEvent(click)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// node.click()
|
||||||
|
|
||||||
let click = new Event('click')
|
let click = new Event('click')
|
||||||
|
click.clientX = event.clientX
|
||||||
|
click.clientY = event.clientY
|
||||||
node.dispatchEvent(click)
|
node.dispatchEvent(click)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
node.click()
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeTapped(node, event) {
|
nodeTapped(node, event) {
|
||||||
console.log('nodeTapped', node, this.isClickable(node))
|
console.log('nodeTapped', node, this.isClickable(node))
|
||||||
|
|||||||
@@ -145,18 +145,29 @@ export default class Doctest {
|
|||||||
let container = document.createElement('div')
|
let container = document.createElement('div')
|
||||||
container.className = 'doctest-wrapper'
|
container.className = 'doctest-wrapper'
|
||||||
|
|
||||||
let titleParent = container
|
if (doctest.hasAttribute('data-title') || doctest.hasAttribute('data-collapsible')) {
|
||||||
if (doctest.hasAttribute('data-collapsible')) {
|
let titlebar = document.createElement('div')
|
||||||
let collapsibleToggle = document.createElement('div')
|
titlebar.className = 'doctest-titlebar'
|
||||||
|
titlebar.style = 'min-height: 10px;'
|
||||||
|
container.appendChild(titlebar)
|
||||||
|
|
||||||
|
if (doctest.hasAttribute('data-title')) {
|
||||||
|
let title = document.createElement('h6')
|
||||||
|
title.innerText = doctest.getAttribute('data-title')
|
||||||
|
title.className = 'doctest-section-title'
|
||||||
|
titlebar.appendChild(title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doctest.hasAttribute('data-collapsible')) {
|
||||||
let icon = document.createElement('i')
|
let icon = document.createElement('i')
|
||||||
icon.className = 'material-icons'
|
icon.className = 'material-icons'
|
||||||
collapsibleToggle.appendChild(icon)
|
titlebar.classList.add('doctest-collapsible-toggle')
|
||||||
|
|
||||||
collapsibleToggle.className = 'doctest-collapsible-toggle'
|
if (titlebar.childNodes.length > 0) {
|
||||||
collapsibleToggle.style = 'min-height: 10px;'
|
titlebar.insertBefore(icon, titlebar.childNodes[0])
|
||||||
titleParent = collapsibleToggle
|
} else {
|
||||||
container.appendChild(collapsibleToggle)
|
titlebar.appendChild(icon)
|
||||||
|
}
|
||||||
|
|
||||||
const collapsedClass = 'collapsed'
|
const collapsedClass = 'collapsed'
|
||||||
|
|
||||||
@@ -175,13 +186,8 @@ export default class Doctest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setToggleMode(doctest.hasAttribute('data-collapsed'))
|
setToggleMode(doctest.hasAttribute('data-collapsed'))
|
||||||
collapsibleToggle.addEventListener('click', determineToggleMode)
|
titlebar.addEventListener('click', determineToggleMode)
|
||||||
}
|
}
|
||||||
if (doctest.hasAttribute('data-title')) {
|
|
||||||
let title = document.createElement('h6')
|
|
||||||
title.innerText = doctest.getAttribute('data-title')
|
|
||||||
title.className = 'doctest-section-title'
|
|
||||||
titleParent.appendChild(title)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let pre = document.createElement('pre')
|
let pre = document.createElement('pre')
|
||||||
|
|||||||
@@ -117,9 +117,12 @@ export default class Errors {
|
|||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'error',
|
'error',
|
||||||
event => {
|
event => {
|
||||||
// if (typeof(event.error) == 'undefined') {
|
if (typeof event.error == 'undefined') {
|
||||||
// console.info("Catched undefined error", event)
|
// This sometimes happens in Edge. Since we have no error
|
||||||
// }
|
// position, we cannot do much beside an info log.
|
||||||
|
console.info('Catched undefined error', event)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.appendError(event.error, event.filename)
|
this.appendError(event.error, event.filename)
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
export default class Events {
|
export default class Events {
|
||||||
static stop(event) {
|
static stop(event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
// I removed this, as it destroys all the Hammer.js events.
|
||||||
|
// And also the click event.
|
||||||
|
// It seems to have no (apparent) negative impact. -SO
|
||||||
|
// event.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
static extractPoint(event) {
|
static extractPoint(event) {
|
||||||
|
|||||||
@@ -141,7 +141,8 @@ export class HTMLLoader extends CardLoader {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let xhr = new XMLHttpRequest()
|
let xhr = new XMLHttpRequest()
|
||||||
xhr.open('GET', this.src, false)
|
xhr.open('GET', this.src, false)
|
||||||
xhr.onload = e => {
|
xhr.onreadystatechange = e => {
|
||||||
|
if (xhr.readyState == 4) {
|
||||||
domNode.innerHTML = this.prepare(xhr.response)
|
domNode.innerHTML = this.prepare(xhr.response)
|
||||||
this.addedNode = domNode.firstElementChild
|
this.addedNode = domNode.firstElementChild
|
||||||
let { width, height } = this.size(this.addedNode)
|
let { width, height } = this.size(this.addedNode)
|
||||||
@@ -149,6 +150,7 @@ export class HTMLLoader extends CardLoader {
|
|||||||
if (height) this.wantedHeight = height || this.wantedHeight
|
if (height) this.wantedHeight = height || this.wantedHeight
|
||||||
resolve(this)
|
resolve(this)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
xhr.onerror = e => {
|
xhr.onerror = e => {
|
||||||
reject(this)
|
reject(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -849,8 +849,8 @@ export class InteractionDelegate {
|
|||||||
if (Events.isCaptured(event)) {
|
if (Events.isCaptured(event)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let captured = this.target.capture(event)
|
|
||||||
return captured
|
return this.target.capture ? this.target.capture(event) : false
|
||||||
}
|
}
|
||||||
|
|
||||||
getPosition(event) {
|
getPosition(event) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ let logHandlers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ipc = require('electron').ipcRenderer
|
ipc = window.ipcRenderer || require('electron').ipcRenderer
|
||||||
logHandlers.log = message => ipc.send('log', message)
|
logHandlers.log = message => ipc.send('log', message)
|
||||||
logHandlers.warn = message => ipc.send('warn', message)
|
logHandlers.warn = message => ipc.send('warn', message)
|
||||||
logHandlers.error = message => ipc.send('error', message)
|
logHandlers.error = message => ipc.send('error', message)
|
||||||
|
|||||||
@@ -62,12 +62,11 @@ window.FontInfo = FontInfo
|
|||||||
window.Text = Text
|
window.Text = Text
|
||||||
|
|
||||||
//Maps
|
//Maps
|
||||||
import MapView from './maps/mapview.js'
|
|
||||||
import { GeoMap, ImageMap, DeepZoomMap } from './maps/map.js'
|
import { GeoMap, ImageMap, DeepZoomMap } from './maps/map.js'
|
||||||
import { MapData, DeepZoomMapData } from './maps/mapdata.js'
|
import { MapProjection, DeepZoomMapProjection } from './maps/mapprojection'
|
||||||
|
|
||||||
window.MapData = MapData
|
window.MapProjection = MapProjection
|
||||||
window.DeepZoomMapData = DeepZoomMapData
|
window.DeepZoomMapProjection = DeepZoomMapProjection
|
||||||
|
|
||||||
window.GeoMap = GeoMap
|
window.GeoMap = GeoMap
|
||||||
window.ImageMap = ImageMap
|
window.ImageMap = ImageMap
|
||||||
@@ -80,7 +79,8 @@ window.Projection = {
|
|||||||
Robinson
|
Robinson
|
||||||
}
|
}
|
||||||
|
|
||||||
window.MapView = MapView
|
import MapViewport from './maps/mapviewport.js'
|
||||||
|
window.MapViewport = MapViewport
|
||||||
|
|
||||||
import MapApp from './maps/mapapp.js'
|
import MapApp from './maps/mapapp.js'
|
||||||
|
|
||||||
@@ -100,7 +100,6 @@ window.CompactScatter = CompactScatter
|
|||||||
window.CoverScatter = CoverScatter
|
window.CoverScatter = CoverScatter
|
||||||
window.MapObjectScatter = MapObjectScatter
|
window.MapObjectScatter = MapObjectScatter
|
||||||
|
|
||||||
|
|
||||||
import { GeoLayer, MapLayer } from './maps/geolayer.js'
|
import { GeoLayer, MapLayer } from './maps/geolayer.js'
|
||||||
window.GeoLayer = GeoLayer
|
window.GeoLayer = GeoLayer
|
||||||
window.MapLayer = MapLayer
|
window.MapLayer = MapLayer
|
||||||
@@ -118,5 +117,8 @@ import Overlay from './maps/overlay.js'
|
|||||||
window.Overlay = Overlay
|
window.Overlay = Overlay
|
||||||
|
|
||||||
import { MapList } from './maps/maplist.js'
|
import { MapList } from './maps/maplist.js'
|
||||||
|
import GeoJson, { GeoUtils } from './maps/geojson.js'
|
||||||
window.MapList = MapList
|
window.MapList = MapList
|
||||||
|
|
||||||
|
window.GeoJson = GeoJson
|
||||||
|
window.GeoUtils = GeoUtils
|
||||||
|
|||||||
@@ -248,7 +248,10 @@ const button20 = new Button({
|
|||||||
y: 310,
|
y: 310,
|
||||||
label: 'Link Button',
|
label: 'Link Button',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
style: 'link'
|
style: 'link',
|
||||||
|
action: event => {
|
||||||
|
console.log('Link button clicked')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const button21 = new Button({
|
const button21 = new Button({
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ export default class Button extends PIXI.Container {
|
|||||||
const theme = Theme.fromString(opts.theme)
|
const theme = Theme.fromString(opts.theme)
|
||||||
this.theme = theme
|
this.theme = theme
|
||||||
|
|
||||||
|
this.HIDDEN_ALPHA = 0.000000001 // WORKAROUND: See https://github.com/pixijs/pixi.js/wiki/v5-Migration-Guide#graphics-interaction
|
||||||
|
|
||||||
this.opts = Object.assign(
|
this.opts = Object.assign(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -172,10 +174,10 @@ export default class Button extends PIXI.Container {
|
|||||||
|
|
||||||
if (this.opts.style === 'link') {
|
if (this.opts.style === 'link') {
|
||||||
Object.assign(this.opts, {
|
Object.assign(this.opts, {
|
||||||
strokeAlpha: 0,
|
strokeAlpha: this.HIDDEN_ALPHA,
|
||||||
strokeActiveAlpha: 0,
|
strokeActiveAlpha: this.HIDDEN_ALPHA,
|
||||||
fillAlpha: 0,
|
fillAlpha: this.HIDDEN_ALPHA,
|
||||||
fillActiveAlpha: 0
|
fillActiveAlpha: this.HIDDEN_ALPHA
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,10 +288,6 @@ export default class Button extends PIXI.Container {
|
|||||||
this.opts.beforeAction.call(this, e, this)
|
this.opts.beforeAction.call(this, e, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.opts.action) {
|
|
||||||
this.opts.action.call(this, e, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||||
alpha: 0.83,
|
alpha: 0.83,
|
||||||
overwrite: 'none'
|
overwrite: 'none'
|
||||||
@@ -299,6 +297,10 @@ export default class Button extends PIXI.Container {
|
|||||||
this.active = !this.active
|
this.active = !this.active
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.opts.action) {
|
||||||
|
this.opts.action.call(this, e, this)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.opts.afterAction) {
|
if (this.opts.afterAction) {
|
||||||
this.opts.afterAction.call(this, e, this)
|
this.opts.afterAction.call(this, e, this)
|
||||||
}
|
}
|
||||||
@@ -640,8 +642,8 @@ export default class Button extends PIXI.Container {
|
|||||||
hide() {
|
hide() {
|
||||||
this.opts.strokeAlpha = 0.0
|
this.opts.strokeAlpha = 0.0
|
||||||
this.opts.strokeActiveAlpha = 0.0
|
this.opts.strokeActiveAlpha = 0.0
|
||||||
this.opts.fillAlpha = 0.0000000001 // WORKAROUND: See https://github.com/pixijs/pixi.js/wiki/v5-Migration-Guide#graphics-interaction
|
this.opts.fillAlpha = this.HIDDEN_ALPHA
|
||||||
this.opts.fillActiveAlpha = 0.0000000001
|
this.opts.fillActiveAlpha = this.HIDDEN_ALPHA
|
||||||
|
|
||||||
this.layout()
|
this.layout()
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 44 KiB |
@@ -37,6 +37,7 @@ const index = new Index(itemTemplate, [
|
|||||||
['Flippable', 'flippable.html'],
|
['Flippable', 'flippable.html'],
|
||||||
['LabeledGraphics', 'labeledgraphics.html'],
|
['LabeledGraphics', 'labeledgraphics.html'],
|
||||||
['List', 'list.html'],
|
['List', 'list.html'],
|
||||||
|
['Maps', 'maps/index.html'],
|
||||||
['Message', 'message.html'],
|
['Message', 'message.html'],
|
||||||
['Modal', 'modal.html'],
|
['Modal', 'modal.html'],
|
||||||
['Tooltip', 'tooltip.html'],
|
['Tooltip', 'tooltip.html'],
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import { Points } from '../../utils.js'
|
|||||||
import { EventHandler } from './utils.js'
|
import { EventHandler } from './utils.js'
|
||||||
import { FlagPolygon } from '../graphics/label.js'
|
import { FlagPolygon } from '../graphics/label.js'
|
||||||
import { DeepZoomMap } from './map.js'
|
import { DeepZoomMap } from './map.js'
|
||||||
|
import { PIXIUtils } from './utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GeoGraphics are graphical objects, that does not store the graphics information
|
* * GeoGraphics are graphical objects, that does not store the graphics information
|
||||||
* in screen space, but in geographical coordinates. Therefore GeoGraphics must be
|
* in screen space, but in geographical coordinates. Therefore GeoGraphics must be
|
||||||
* placed on GeoLayers to work properly.
|
* placed on GeoLayers to work properly.
|
||||||
*
|
*
|
||||||
@@ -14,11 +15,12 @@ import { DeepZoomMap } from './map.js'
|
|||||||
* The geolayers forward this 'adaptTo' to all children that are GeoGraphics.
|
* The geolayers forward this 'adaptTo' to all children that are GeoGraphics.
|
||||||
* Which adjust their so called 'point' data to the new map.
|
* Which adjust their so called 'point' data to the new map.
|
||||||
*
|
*
|
||||||
* @abstract
|
* @export
|
||||||
|
* @class GeoGraphics
|
||||||
*/
|
*/
|
||||||
export class GeoGraphics {
|
export class GeoGraphics {
|
||||||
constructor(coordinates, { scale = 1, onDraw = null, onDrawEnd = null, debug = false } = {}) {
|
constructor(coordinates, { scale = 1, onDraw = null, onDrawEnd = null, debug = false } = {}) {
|
||||||
this.coordinates = coordinates
|
this._coordinates = coordinates
|
||||||
this.debug = debug
|
this.debug = debug
|
||||||
this.graphics = new PIXI.Graphics()
|
this.graphics = new PIXI.Graphics()
|
||||||
this.scale = scale
|
this.scale = scale
|
||||||
@@ -28,6 +30,17 @@ export class GeoGraphics {
|
|||||||
this._position = null
|
this._position = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The coordinates of the geographics.
|
||||||
|
*
|
||||||
|
* @member {array}
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoGraphics
|
||||||
|
*/
|
||||||
|
get coordinates() {
|
||||||
|
return this._coordinates
|
||||||
|
}
|
||||||
|
|
||||||
clone() {
|
clone() {
|
||||||
console.error(`Call of abstract method clone(). Overwrite in subclass.`, this)
|
console.error(`Call of abstract method clone(). Overwrite in subclass.`, this)
|
||||||
}
|
}
|
||||||
@@ -133,6 +146,12 @@ export class GeoGraphics {
|
|||||||
this._layer = layer
|
this._layer = layer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of the containing layer. Null if on no layer.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoGraphics
|
||||||
|
*/
|
||||||
get map() {
|
get map() {
|
||||||
let map = null
|
let map = null
|
||||||
if (this.mapLayer) {
|
if (this.mapLayer) {
|
||||||
@@ -141,6 +160,13 @@ export class GeoGraphics {
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapLayer of the containing layer. Null if on no layer.
|
||||||
|
*
|
||||||
|
* @member {MapLayer}
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoGraphics
|
||||||
|
*/
|
||||||
get mapLayer() {
|
get mapLayer() {
|
||||||
let mapLayer = null
|
let mapLayer = null
|
||||||
if (this.layer) {
|
if (this.layer) {
|
||||||
@@ -199,6 +225,10 @@ export class GeoGraphics {
|
|||||||
*
|
*
|
||||||
* This GeoGraphics does not provide any visual representation.
|
* This GeoGraphics does not provide any visual representation.
|
||||||
* Draw the desired shape in the onDraw callback.
|
* Draw the desired shape in the onDraw callback.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoPoint
|
||||||
|
* @extends {GeoGraphics}
|
||||||
*/
|
*/
|
||||||
export class GeoPoint extends GeoGraphics {
|
export class GeoPoint extends GeoGraphics {
|
||||||
clone() {
|
clone() {
|
||||||
@@ -228,6 +258,13 @@ export class GeoPoint extends GeoGraphics {
|
|||||||
_draw() {}
|
_draw() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represensts a line between two locations.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoLine
|
||||||
|
* @extends {GeoGraphics}
|
||||||
|
*/
|
||||||
export class GeoLine extends GeoGraphics {
|
export class GeoLine extends GeoGraphics {
|
||||||
/**
|
/**
|
||||||
* @param {object} opts - Optional values
|
* @param {object} opts - Optional values
|
||||||
@@ -330,6 +367,13 @@ export class GeoLine extends GeoGraphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a shape on a map.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoShape
|
||||||
|
* @extends {GeoGraphics}
|
||||||
|
*/
|
||||||
export class GeoShape extends GeoGraphics {
|
export class GeoShape extends GeoGraphics {
|
||||||
clone() {
|
clone() {
|
||||||
return new GeoShape(this.coordinates, this._cloneOptions)
|
return new GeoShape(this.coordinates, this._cloneOptions)
|
||||||
@@ -441,15 +485,12 @@ export class GeoShape extends GeoGraphics {
|
|||||||
*/
|
*/
|
||||||
_drawShape(polygon, hole = []) {
|
_drawShape(polygon, hole = []) {
|
||||||
// We save the fill specified in the onDraw event handler.
|
// We save the fill specified in the onDraw event handler.
|
||||||
//
|
|
||||||
// Consider: Maybe it would be a good idea to add a 'onHoleDraw'
|
|
||||||
// callback to make the hole customizable. Maybe you want
|
|
||||||
// to fill it with a different color or an mediocre alpha value.
|
|
||||||
// then feel free to implement it.
|
|
||||||
let { fill, alpha } = PIXIUtils.saveFill(this.graphics)
|
let { fill, alpha } = PIXIUtils.saveFill(this.graphics)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This may seem redundant, but it's required
|
* a) Draw the hole with a polygon.
|
||||||
|
*
|
||||||
|
* This may seem redundant to (c), but it's required (in this order(!))
|
||||||
* to make the hole clickable.
|
* to make the hole clickable.
|
||||||
*
|
*
|
||||||
* It was a bit confusing, so I made a CodePen
|
* It was a bit confusing, so I made a CodePen
|
||||||
@@ -460,9 +501,15 @@ export class GeoShape extends GeoGraphics {
|
|||||||
this.graphics.drawPolygon(hole)
|
this.graphics.drawPolygon(hole)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* b) Draw the shape.
|
||||||
|
*/
|
||||||
this.graphics.beginFill(fill, alpha)
|
this.graphics.beginFill(fill, alpha)
|
||||||
this.graphics.drawPolygon(polygon)
|
this.graphics.drawPolygon(polygon)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* c) Add the hole.
|
||||||
|
*/
|
||||||
if (hole.length > 0) {
|
if (hole.length > 0) {
|
||||||
this.graphics.beginHole()
|
this.graphics.beginHole()
|
||||||
this.graphics.drawPolygon(hole)
|
this.graphics.drawPolygon(hole)
|
||||||
@@ -475,6 +522,9 @@ export class GeoShape extends GeoGraphics {
|
|||||||
* The MultiGraphics makes use of the other GeoGraphics to
|
* The MultiGraphics makes use of the other GeoGraphics to
|
||||||
* create a single graphics element out of multiple different
|
* create a single graphics element out of multiple different
|
||||||
* GeoGraphics.
|
* GeoGraphics.
|
||||||
|
*
|
||||||
|
* @class GeoMultiGraphics
|
||||||
|
* @extends {GeoGraphics}
|
||||||
*/
|
*/
|
||||||
class GeoMultiGraphics extends GeoGraphics {
|
class GeoMultiGraphics extends GeoGraphics {
|
||||||
/**
|
/**
|
||||||
@@ -524,6 +574,13 @@ class GeoMultiGraphics extends GeoGraphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text that is attatched to a GeoPoint.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoText
|
||||||
|
* @extends {GeoPoint}
|
||||||
|
*/
|
||||||
export class GeoText extends GeoPoint {
|
export class GeoText extends GeoPoint {
|
||||||
constructor(coordinates, text, opts) {
|
constructor(coordinates, text, opts) {
|
||||||
super(coordinates, opts)
|
super(coordinates, opts)
|
||||||
@@ -531,14 +588,6 @@ export class GeoText extends GeoPoint {
|
|||||||
this.textStyle = Object.assign(new PIXI.TextStyle(), opts.textStyle)
|
this.textStyle = Object.assign(new PIXI.TextStyle(), opts.textStyle)
|
||||||
this._text = new PIXI.Text(text, this.textStyle)
|
this._text = new PIXI.Text(text, this.textStyle)
|
||||||
|
|
||||||
//TODO: Make this more generic:
|
|
||||||
// We have 8 layers (12-20) for each map so this temporarily works fine.
|
|
||||||
// Outsource it to the map class.
|
|
||||||
//let textScale = Math.pow(2, 7)
|
|
||||||
|
|
||||||
// let textScale = 5
|
|
||||||
// this.text.scale.set(1 / textScale, 1 / textScale)
|
|
||||||
|
|
||||||
switch (this.align) {
|
switch (this.align) {
|
||||||
case 'left':
|
case 'left':
|
||||||
break
|
break
|
||||||
@@ -570,6 +619,8 @@ export class GeoText extends GeoPoint {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A geotext with a notch at a certain Position.
|
* A geotext with a notch at a certain Position.
|
||||||
|
*
|
||||||
|
* TODO: This is a specialization for the Tüsch. This should be inside the Tüsch project.
|
||||||
*/
|
*/
|
||||||
export class GeoFlagLabel extends GeoText {
|
export class GeoFlagLabel extends GeoText {
|
||||||
constructor(coordinates, text, opts) {
|
constructor(coordinates, text, opts) {
|
||||||
@@ -675,6 +726,13 @@ export class GeoFlagLabel extends GeoText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GeoMultiShape displays multiple forms.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoMultiShape
|
||||||
|
* @extends {GeoShape}
|
||||||
|
*/
|
||||||
export class GeoMultiShape extends GeoShape {
|
export class GeoMultiShape extends GeoShape {
|
||||||
static _manipulatePoints(points, func) {
|
static _manipulatePoints(points, func) {
|
||||||
points.forEach(shape => {
|
points.forEach(shape => {
|
||||||
@@ -714,28 +772,3 @@ export class GeoMultiShape extends GeoShape {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PIXIUtils {
|
|
||||||
/*
|
|
||||||
* Transform a pixi text to it's actual screensize,
|
|
||||||
* ignoring it's local transforms
|
|
||||||
*/
|
|
||||||
static toScreenFontSize(pixiText, fontSize = null) {
|
|
||||||
pixiText._recursivePostUpdateTransform()
|
|
||||||
|
|
||||||
let normalizedScale = {
|
|
||||||
x: pixiText.scale.x / pixiText.transform.worldTransform.a,
|
|
||||||
y: pixiText.scale.x / pixiText.transform.worldTransform.d
|
|
||||||
}
|
|
||||||
|
|
||||||
pixiText.scale = { x: normalizedScale.x, y: normalizedScale.y }
|
|
||||||
if (fontSize) pixiText.style.fontSize = fontSize
|
|
||||||
}
|
|
||||||
|
|
||||||
static saveFill(graphics) {
|
|
||||||
return {
|
|
||||||
fill: graphics.fill.color,
|
|
||||||
alpha: graphics.fill.alpha
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@
|
|||||||
|
|
||||||
// As map an image of europe is used.
|
// As map an image of europe is used.
|
||||||
let europe = "../../../../var/examples/maps/europe/europe.jpg"
|
let europe = "../../../../var/examples/maps/europe/europe.jpg"
|
||||||
let europeData = new MapData(MERCATOR, {
|
let europeMapProjection = new MapProjection(MERCATOR, {
|
||||||
clip: {
|
clip: {
|
||||||
min: { x: 32.863294, y: -18.58 },
|
min: { x: 32.863294, y: -18.58 },
|
||||||
max: { x: 57.467973, y: 44.277158 }
|
max: { x: 57.467973, y: 44.277158 }
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
window.readyHandler = new EventHandler("onReady")
|
window.readyHandler = new EventHandler("onReady")
|
||||||
|
|
||||||
function ready(textures) {
|
function ready(textures) {
|
||||||
let europeMap = new ImageMap(new PIXI.Sprite(textures.get(europe)), europeData)
|
let europeMap = new ImageMap(new PIXI.Sprite(textures.get(europe)), europeMapProjection)
|
||||||
app.setMap("germany", europeMap)
|
app.setMap("germany", europeMap)
|
||||||
app.setup().run()
|
app.setup().run()
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import { GeoGraphics, GeoShape, GeoMultiShape, GeoLine, GeoPoint } from './geogr
|
|||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @export
|
* @export
|
||||||
* @class GeoJsonGraphics
|
* @class
|
||||||
* @extends {GeoGraphics}
|
|
||||||
*/
|
*/
|
||||||
export default class GeoJson {
|
export default class GeoJson {
|
||||||
static isLineType(type) {
|
static isLineType(type) {
|
||||||
@@ -40,6 +39,15 @@ export default class GeoJson {
|
|||||||
return ['Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon']
|
return ['Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a JSON object that contains a FeatureCollection and returns an array
|
||||||
|
* of GeoJson objects.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @param {array} featureCollection - Array of GeoJSON objects that were contained in the feature collection.
|
||||||
|
* @returns {array} Returns an array of geo json objects.
|
||||||
|
* @memberof GeoJson
|
||||||
|
*/
|
||||||
static unwrapFeatureCollection(featureCollection) {
|
static unwrapFeatureCollection(featureCollection) {
|
||||||
if (featureCollection.features == null) {
|
if (featureCollection.features == null) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -59,18 +67,27 @@ export default class GeoJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
list.push({ type, coordinates })
|
list.push({ type, coordinates })
|
||||||
// console.log({type, coordinates})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates and converts one set of coordinates of a specific type.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @param {string} type - Type of the GeoJson.
|
||||||
|
* @param {array} coordinates - array of points.
|
||||||
|
* @returns {array}
|
||||||
|
* @memberof GeoJson
|
||||||
|
*/
|
||||||
static validateAndConvert(type, coordinates) {
|
static validateAndConvert(type, coordinates) {
|
||||||
|
let converted = null
|
||||||
|
|
||||||
if (!GeoJson.validateType(type)) throw new GeoJson.InvalidTypeError(type)
|
if (!GeoJson.validateType(type)) throw new GeoJson.InvalidTypeError(type)
|
||||||
else {
|
else {
|
||||||
if (GeoJson.validateCoordinates(type, coordinates)) {
|
if (GeoJson.validateCoordinates(type, coordinates)) {
|
||||||
let converted = GeoJson.convert(type, coordinates)
|
converted = GeoJson.convert(type, coordinates)
|
||||||
return converted
|
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
`Coordinates are invalid. They must be in format of type '${type} - ${GeoJson._getFormatStringOfType(
|
`Coordinates are invalid. They must be in format of type '${type} - ${GeoJson._getFormatStringOfType(
|
||||||
@@ -79,6 +96,8 @@ export default class GeoJson {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return converted
|
||||||
}
|
}
|
||||||
|
|
||||||
static validateType(type) {
|
static validateType(type) {
|
||||||
@@ -123,7 +142,7 @@ export default class GeoJson {
|
|||||||
* considered valid. A complete list is provided in the GeoUtils.
|
* considered valid. A complete list is provided in the GeoUtils.
|
||||||
*
|
*
|
||||||
* @param {object} point - The point that is tested for validity.
|
* @param {object} point - The point that is tested for validity.
|
||||||
* @returns
|
* @returns {boolean}
|
||||||
* @memberof GeoJson
|
* @memberof GeoJson
|
||||||
*/
|
*/
|
||||||
static validateAndConvertPoint(point) {
|
static validateAndConvertPoint(point) {
|
||||||
@@ -302,7 +321,7 @@ export class GeoUtils {
|
|||||||
* {latitude: lat, longitude: lng}
|
* {latitude: lat, longitude: lng}
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @param {object / array} coordinate - Coordinate to be tested, if it is an valid coordinate.
|
* @param {object|array} coordinate - Coordinate to be tested, if it is an valid coordinate.
|
||||||
* @returns - Returns the coordinate properly transformed. If transformation was not possible, it returns null.
|
* @returns - Returns the coordinate properly transformed. If transformation was not possible, it returns null.
|
||||||
* @memberof GeoGraphics
|
* @memberof GeoGraphics
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import { GeoMap } from './map.js'
|
import { GeoMap } from './map.js'
|
||||||
import MapView from './mapview.js'
|
|
||||||
import { EventHandler } from './utils.js'
|
import { EventHandler } from './utils.js'
|
||||||
import { GeoGraphics } from './geographics.js'
|
import { GeoGraphics } from './geographics.js'
|
||||||
import { MapList } from './maplist.js'
|
import { MapList } from './maplist.js'
|
||||||
//import { GeoGraphics } from "../pixi/geographics.js"
|
import MapViewport from './mapviewport.js'
|
||||||
|
import { ScatterContainer } from '../scatter.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GeoLayer is a special PIXILayer, that recognizes other GeoLayers and
|
* The GeoLayer is a special PIXILayer, that recognizes other GeoLayers and
|
||||||
* GeoGraphics. The layer can be adapted to a map and notifies all Geo-Children
|
* GeoGraphics. The layer can be adapted to a map and notifies all Geo-Children
|
||||||
* of the Adaption.
|
* of the Adaption.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class GeoLayer
|
||||||
*/
|
*/
|
||||||
export class GeoLayer {
|
export class GeoLayer {
|
||||||
constructor(displayObject, opts = {}) {
|
constructor(displayObject, opts = {}) {
|
||||||
@@ -93,6 +96,13 @@ export class GeoLayer {
|
|||||||
return this._visibility
|
return this._visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for geoLayer.displayObject.addChild.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {GeoGraphics | PIXI.DisplayObject} element - Element to add to the displayObject.
|
||||||
|
* @memberof GeoLayer
|
||||||
|
*/
|
||||||
addChild(element) {
|
addChild(element) {
|
||||||
this.displayObject.addChild(element)
|
this.displayObject.addChild(element)
|
||||||
}
|
}
|
||||||
@@ -117,15 +127,6 @@ export class GeoLayer {
|
|||||||
} else console.error('There was no map specified.', this)
|
} else console.error('There was no map specified.', this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// place(geographic) {
|
|
||||||
// if (geographic.constructor.name.startsWith('Geo') && geographic.graphics) {
|
|
||||||
// // Fix to remove the rollupjs circular dependency
|
|
||||||
// //if (geographic instanceof GeoGraphics) {
|
|
||||||
// this.geographics.push(geographic)
|
|
||||||
// super.place(geographic.graphics)
|
|
||||||
// } else super.place(geographic)
|
|
||||||
// }
|
|
||||||
|
|
||||||
removeFromParent() {
|
removeFromParent() {
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
this.parent.removeLayer(this)
|
this.parent.removeLayer(this)
|
||||||
@@ -165,8 +166,15 @@ export class GeoLayer {
|
|||||||
return this._parent
|
return this._parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a GeoLayer as child to the GeoLayer.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {GeoLayer} layer - GeoLayer to add.
|
||||||
|
* @memberof GeoLayer
|
||||||
|
*/
|
||||||
addLayer(layer) {
|
addLayer(layer) {
|
||||||
if (layer instanceof GeoLayer || layer instanceof MapLayer) {
|
if (layer instanceof GeoLayer) {
|
||||||
layer.removeFromParent()
|
layer.removeFromParent()
|
||||||
|
|
||||||
this.layers.push(layer)
|
this.layers.push(layer)
|
||||||
@@ -218,6 +226,18 @@ export class GeoLayer {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map layer is responsible for showing certain maps, at a specific position It contains
|
||||||
|
* a list of available maps and can switch between them seamlessly. GeoGraphics placed on the MapLayer itself
|
||||||
|
* or child Geolayers will be adapted to maps and adjusted on map change automatically.
|
||||||
|
*
|
||||||
|
* The map layer is the 'king' of the geo layers. Every geolayer
|
||||||
|
* needs a map layer at it's root. Otherwise they won't work-
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class MapLayer
|
||||||
|
* @extends {GeoLayer}
|
||||||
|
*/
|
||||||
export class MapLayer extends GeoLayer {
|
export class MapLayer extends GeoLayer {
|
||||||
constructor(
|
constructor(
|
||||||
mapList,
|
mapList,
|
||||||
@@ -247,7 +267,7 @@ export class MapLayer extends GeoLayer {
|
|||||||
listeners: onChange
|
listeners: onChange
|
||||||
})
|
})
|
||||||
|
|
||||||
this.mapview = new MapView({
|
this._mapview = new MapViewport({
|
||||||
zoom,
|
zoom,
|
||||||
focus,
|
focus,
|
||||||
viewport
|
viewport
|
||||||
@@ -267,6 +287,18 @@ export class MapLayer extends GeoLayer {
|
|||||||
this.changeMap(mapList.active)
|
this.changeMap(mapList.active)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Todo: rename to mapviewport.
|
||||||
|
/**
|
||||||
|
* Returns the MapViewport of this map layer.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @member {MapViewport}
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
|
get mapview() {
|
||||||
|
return this._mapview
|
||||||
|
}
|
||||||
|
|
||||||
get mapChangeLocked() {
|
get mapChangeLocked() {
|
||||||
return this._mapChangeLocked
|
return this._mapChangeLocked
|
||||||
}
|
}
|
||||||
@@ -279,22 +311,34 @@ export class MapLayer extends GeoLayer {
|
|||||||
this._mapChangeLocked = false
|
this._mapChangeLocked = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts all child layers and their GeoGraphics.
|
||||||
|
*
|
||||||
|
* This is called primarily on a map change.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
adapt() {
|
adapt() {
|
||||||
this.layers.forEach(layer => {
|
this.layers.forEach(layer => {
|
||||||
if (layer.adapt) layer.adapt(this.map)
|
if (layer.adapt) layer.adapt(this.map)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(coordinates, zoom) {
|
|
||||||
this.mapview.updateFocusPoint(this.map)
|
|
||||||
}
|
|
||||||
|
|
||||||
transformed(e) {
|
transformed(e) {
|
||||||
this.mapview.transformed(this.map)
|
this.mapview.update(this.map)
|
||||||
this.layers.forEach(layer => layer.parentMapLayerTransformed(this))
|
this.layers.forEach(layer => layer.parentMapLayerTransformed(this))
|
||||||
this.transformHandler.call(this)
|
this.transformHandler.call(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the map layer-
|
||||||
|
*
|
||||||
|
* @param {ScatterContainer} scatterContainer - ScatterContainer of the app.
|
||||||
|
* @param {PIXI.DisplayObject} [container=null] - Container of the newly created MapLayer. If null, an empty PIXI.Container will be created.
|
||||||
|
* @returns {MapLayer} - Returns the cloned MapLayer.
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
clone(scatterContainer, container = null) {
|
clone(scatterContainer, container = null) {
|
||||||
let mapList = this.mapList.clone()
|
let mapList = this.mapList.clone()
|
||||||
container = container == null ? new PIXI.Container() : container
|
container = container == null ? new PIXI.Container() : container
|
||||||
@@ -369,23 +413,46 @@ export class MapLayer extends GeoLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the mapviews focus to the map.
|
||||||
|
* This may be useful, if the container was modified.
|
||||||
|
*
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
refocus() {
|
refocus() {
|
||||||
this.mapview.apply(this.map)
|
this.mapview.apply(this.map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @returns {GeoMap} - Returns the active map.
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
get map() {
|
get map() {
|
||||||
return this.mapList.map
|
return this.mapList.map
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is required for the consistency of georelated layers.
|
*
|
||||||
* The request traverses up to the mapLayer where it then returns
|
* This is required for the geo layers.
|
||||||
* the responsible map layer.
|
* MapLayer requests from the geoLayers traverse up to the next MapLayer.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @returns {MapLayer} - Returns this MapLayer.
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapLayer
|
||||||
*/
|
*/
|
||||||
get mapLayer() {
|
get mapLayer() {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the MapLayer.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof MapLayer
|
||||||
|
*/
|
||||||
cleanup() {
|
cleanup() {
|
||||||
this.mapList.cleanup()
|
this.mapList.cleanup()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>PIXI Maps Doctests</title>
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="../../../css/index.css">
|
||||||
|
|
||||||
|
<script src="../../../dist/iwmlib.js"></script>
|
||||||
|
|
||||||
|
<template id="itemTemplate">
|
||||||
|
<a class="wrapper" href="">
|
||||||
|
<div class="preview">
|
||||||
|
<div class="thumbnail-container">
|
||||||
|
<div class="thumbnail">
|
||||||
|
<img class="icon" src="thumbnails/notfound.png">
|
||||||
|
<!-- <iframe src="" frameborder="0"></iframe> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="title"></div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo>img {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header>h1 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
word-spacing: 0.25em;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header>p {
|
||||||
|
max-width: 720px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
color: rgb(207, 207, 207);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
background-color: #4c4f4f;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
padding: 68px 50px 10px 150px;
|
||||||
|
|
||||||
|
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
height: auto;
|
||||||
|
min-height: auto;
|
||||||
|
width: auto;
|
||||||
|
min-width: auto;
|
||||||
|
|
||||||
|
margin: 0 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<a id="logo" target="_blank" href="http://www.iwm-tuebingen.de">
|
||||||
|
<img src="../../../assets/logos/iwm_logo_2015_twitter.png">
|
||||||
|
</a>
|
||||||
|
<h1>Maps Module</h1>
|
||||||
|
<p>The maps module provides a handy toolkit to easily integrate maps in an application. Create a full screen map
|
||||||
|
application by using the mapapp. Utilize the GeoLayer-system to integrate maps in an existing application.
|
||||||
|
Draw graphics onto the map using geographical positions instead of pixel positions with the GeoGraphics.
|
||||||
|
Or just use an Overlay to quickly draw icons for each point on a map.
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<div id="container" class="container">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const index = new Index(itemTemplate, [
|
||||||
|
["GeoGraphics", "geographics.html"],
|
||||||
|
["GeoJson", "geojson.html"],
|
||||||
|
["GeoMap", "map.html"],
|
||||||
|
["MapApp", "mapapp.html"],
|
||||||
|
["MapProjection", "mapprojection.html"],
|
||||||
|
["MapViewport", "mapviewport.html"],
|
||||||
|
["Overlay", "overlay.html"],
|
||||||
|
["Scatter", "scatter.html"]
|
||||||
|
],
|
||||||
|
null)
|
||||||
|
index.load()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -71,10 +71,10 @@
|
|||||||
const projection = new Projection.Mercator()
|
const projection = new Projection.Mercator()
|
||||||
|
|
||||||
// Create a map data object.
|
// Create a map data object.
|
||||||
const osmDeepZoomMapData = new DeepZoomMapData(projection, tilesConfig, { app })
|
const osmDeepZoomMapProjection = new DeepZoomMapProjection(projection, tilesConfig, { app })
|
||||||
|
|
||||||
// Create the map
|
// Create the map
|
||||||
const osmMap = new DeepZoomMap(osmDeepZoomMapData, tilesConfig)
|
const osmMap = new DeepZoomMap(osmDeepZoomMapProjection, tilesConfig)
|
||||||
|
|
||||||
// Add the map to the app.
|
// Add the map to the app.
|
||||||
app.addMap("osm", osmMap)
|
app.addMap("osm", osmMap)
|
||||||
@@ -122,10 +122,10 @@
|
|||||||
const projection = new Projection.Robinson(10)
|
const projection = new Projection.Robinson(10)
|
||||||
|
|
||||||
// Create a map data object.
|
// Create a map data object.
|
||||||
let mapData = new MapData(projection)
|
let mapProjection = new MapProjection(projection)
|
||||||
|
|
||||||
// Create the map
|
// Create the map
|
||||||
let imageMap = new ImageMap(sprites.get(mapTexture), mapData)
|
let imageMap = new ImageMap(sprites.get(mapTexture), mapProjection)
|
||||||
|
|
||||||
|
|
||||||
// Add the map to the app.
|
// Add the map to the app.
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { MapObjectScatter } from './scatter.js'
|
import { MapObjectScatter } from './scatter.js'
|
||||||
import { DeepZoomImage, DeepZoomInfo } from '../deepzoom/image.js'
|
import { DeepZoomImage, DeepZoomInfo } from '../deepzoom/image.js'
|
||||||
import { MapData, DeepZoomMapData } from './mapdata.js'
|
import { MapProjection, DeepZoomMapProjection } from './mapprojection.js'
|
||||||
import { Points } from '../../utils.js'
|
import { Points } from '../../utils.js'
|
||||||
import { EventHandler } from './utils.js'
|
import { EventHandler } from './utils.js'
|
||||||
import Mercator from './projections/mercator.js'
|
import Mercator from './projections/mercator.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GeoMap class displays a map, that it gets from MapData object.
|
* The GeoMap class displays a map, that it gets from MapProjection object.
|
||||||
* It handles the current location on the map, the zoom factor, interactions and
|
* It handles the current location on the map, the zoom factor, interactions and
|
||||||
* the viewport, the area of the map, the user can see and navigate to.
|
* the viewport, the area of the map, the user can see and navigate to.
|
||||||
*
|
*
|
||||||
@@ -26,12 +26,12 @@ export class GeoMap {
|
|||||||
* Creates instance of GeoMap
|
* Creates instance of GeoMap
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {MapData}[mapdata={}] - The mapdata describes how the map has to be interpreted by the Map class. E.g. what are the boundaries of the map?
|
* @param {MapProjection}[mapProjection={}] - The map projection describes how the map has to be interpreted by the Map class. E.g. what are the boundaries of the map?
|
||||||
* @param {object}[opts={}] - With the opts, the created MapObjectScatter can be adjusted.
|
* @param {object}[opts={}] - With the opts, the created MapObjectScatter can be adjusted.
|
||||||
* @param {boolean}[opts.cover=false] - Enables covering behaviour of a map object. Normally maps should cover the whole app.
|
* @param {boolean}[opts.cover=false] - Enables covering behaviour of a map object. Normally maps should cover the whole app.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
mapdata = {},
|
mapProjection = {},
|
||||||
{
|
{
|
||||||
debug = true,
|
debug = true,
|
||||||
cover = true,
|
cover = true,
|
||||||
@@ -43,7 +43,7 @@ export class GeoMap {
|
|||||||
translatable = true,
|
translatable = true,
|
||||||
scalable = true,
|
scalable = true,
|
||||||
rotatable = false, // Many functionalities are not supported when rotating the map. Mainly the cover mechanism.
|
rotatable = false, // Many functionalities are not supported when rotating the map. Mainly the cover mechanism.
|
||||||
viewport = mapdata.maxViewport,
|
viewport = mapProjection.maxViewport,
|
||||||
// Events
|
// Events
|
||||||
onLoad = null,
|
onLoad = null,
|
||||||
onTransform = null
|
onTransform = null
|
||||||
@@ -54,7 +54,7 @@ export class GeoMap {
|
|||||||
this.onTransform = new EventHandler('transform', { listeners: onTransform })
|
this.onTransform = new EventHandler('transform', { listeners: onTransform })
|
||||||
|
|
||||||
this._alpha = alpha
|
this._alpha = alpha
|
||||||
this.cover = cover
|
this._cover = cover
|
||||||
this.debug = debug
|
this.debug = debug
|
||||||
|
|
||||||
//TODO discuss if this is required here.
|
//TODO discuss if this is required here.
|
||||||
@@ -68,15 +68,15 @@ export class GeoMap {
|
|||||||
this.scalable = scalable
|
this.scalable = scalable
|
||||||
this.viewport = viewport
|
this.viewport = viewport
|
||||||
|
|
||||||
this.mapdata = mapdata
|
this._mapProjection = mapProjection
|
||||||
this.overlays = {}
|
this.overlays = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust the viewport depending on the mapdata clipping.
|
* Adjust the viewport depending on the mapProjection clipping.
|
||||||
*/
|
*/
|
||||||
if (this.mapdata.clip) {
|
if (this.mapProjection.clip) {
|
||||||
const vp = this.viewport
|
const vp = this.viewport
|
||||||
const cp = this.mapdata.clip
|
const cp = this.mapProjection.clip
|
||||||
let bounds = {
|
let bounds = {
|
||||||
min: {
|
min: {
|
||||||
x: vp.min.x > cp.min.x ? vp.min.x : cp.min.x,
|
x: vp.min.x > cp.min.x ? vp.min.x : cp.min.x,
|
||||||
@@ -92,29 +92,64 @@ export class GeoMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the scatter covers the container.
|
||||||
|
* @member {boolean}
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
|
get cover() {
|
||||||
|
// For cloning we want to store the cover inside the map.
|
||||||
|
// But the scatter is responsible for the cover state.
|
||||||
|
// So we update the app's cover state every time
|
||||||
|
// we get the value.
|
||||||
|
if (this.image && this.image.scatter && this.image.scatter.cover != null) {
|
||||||
|
this._cover = this.image.scatter.cover
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._cover
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the image object used by the GeoMap.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
|
get image() {
|
||||||
|
return this._image
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapProjection of the map.
|
||||||
|
*
|
||||||
|
* @member {MapProjection}
|
||||||
|
* @readonly
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
|
get mapProjection() {
|
||||||
|
return this._mapProjection
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all EventHandlers.
|
||||||
|
*
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
flushHandlers() {
|
flushHandlers() {
|
||||||
// this.onLoaded
|
this.onLoad.empty()
|
||||||
this.onTransform.empty()
|
this.onTransform.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks all transformations on the map.
|
||||||
|
* Single parameters can be set if necessary. False means the value is locked, true means they can be modified.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {object} [{ rotatable = false, translatable = false, movableX = false, movableY = false, scalable = false }={}]
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
lock({ rotatable = false, translatable = false, movableX = false, movableY = false, scalable = false } = {}) {
|
lock({ rotatable = false, translatable = false, movableX = false, movableY = false, scalable = false } = {}) {
|
||||||
if (this.image && this.image.scatter) {
|
|
||||||
this.image.scatter.translatable = rotatable
|
|
||||||
this.image.scatter.movableX = translatable
|
|
||||||
this.image.scatter.movableY = movableX
|
|
||||||
this.image.scatter.rotatable = movableY
|
|
||||||
this.image.scatter.scalable = scalable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue #001: This causes the map to not be displayed at the correct position on
|
|
||||||
// map change.
|
|
||||||
// // Rotation does not yet work with the cover mechanism.
|
|
||||||
// //this.rotatable = false
|
|
||||||
// this.translatable = false
|
|
||||||
// this.scalable = false
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock({ rotatable = true, translatable = true, movableX = true, movableY = true, scalable = true } = {}) {
|
|
||||||
if (this.image && this.image.scatter) {
|
if (this.image && this.image.scatter) {
|
||||||
this.image.scatter.translatable = translatable
|
this.image.scatter.translatable = translatable
|
||||||
this.image.scatter.movableX = movableX
|
this.image.scatter.movableX = movableX
|
||||||
@@ -122,13 +157,26 @@ export class GeoMap {
|
|||||||
this.image.scatter.rotatable = rotatable
|
this.image.scatter.rotatable = rotatable
|
||||||
this.image.scatter.scalable = scalable
|
this.image.scatter.scalable = scalable
|
||||||
}
|
}
|
||||||
// Issue #001
|
|
||||||
// // Rotation does not yet work with the cover mechanism.
|
|
||||||
// //this.rotatable = true
|
|
||||||
// this.translatable = true
|
|
||||||
// this.scalable = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks all transformations on the map.
|
||||||
|
* Single parameters can be set if necessary. False means the value is locked, true means they can be modified.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {object} [{ rotatable = false, translatable = false, movableX = false, movableY = false, scalable = false }={}]
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
|
unlock({ rotatable = true, translatable = true, movableX = true, movableY = true, scalable = true } = {}) {
|
||||||
|
this.lock({ rotatable, translatable, movableX, movableY, scalable })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unloads the image of the map.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
unload() {
|
unload() {
|
||||||
if (this.image) {
|
if (this.image) {
|
||||||
if (this.image.parent) {
|
if (this.image.parent) {
|
||||||
@@ -142,6 +190,12 @@ export class GeoMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the map, freeing all memory ba flushing handlers and removing the image.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
remove() {
|
remove() {
|
||||||
if (this.image) this.image.mask = null
|
if (this.image) this.image.mask = null
|
||||||
|
|
||||||
@@ -164,6 +218,7 @@ export class GeoMap {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapps the display object around a scatter object.
|
* Wrapps the display object around a scatter object.
|
||||||
|
* creates the image.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {DisplayObject} displayObject - Defines the display object that will be wrapped inside the scatter object.
|
* @param {DisplayObject} displayObject - Defines the display object that will be wrapped inside the scatter object.
|
||||||
@@ -172,11 +227,9 @@ export class GeoMap {
|
|||||||
load(image, renderer, frame = null, scatter = null) {
|
load(image, renderer, frame = null, scatter = null) {
|
||||||
if (this.debug) console.log('Load image: ', image, frame)
|
if (this.debug) console.log('Load image: ', image, frame)
|
||||||
|
|
||||||
this.image = image
|
this._image = image
|
||||||
if (frame) this.setFrame(frame)
|
if (frame) this.setFrame(frame)
|
||||||
|
|
||||||
let boundaries = this.mapdata.getBoundaries()
|
|
||||||
|
|
||||||
let scatterOpts = Object.assign({
|
let scatterOpts = Object.assign({
|
||||||
cover: this.cover,
|
cover: this.cover,
|
||||||
scaleable: this.scaleable,
|
scaleable: this.scaleable,
|
||||||
@@ -186,7 +239,6 @@ export class GeoMap {
|
|||||||
startScale: this.startScale,
|
startScale: this.startScale,
|
||||||
minScale: this.minScale,
|
minScale: this.minScale,
|
||||||
maxScale: this.maxScale,
|
maxScale: this.maxScale,
|
||||||
boundaries,
|
|
||||||
onTransform: this.transformed.bind(this)
|
onTransform: this.transformed.bind(this)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -242,11 +294,11 @@ export class GeoMap {
|
|||||||
* to a coordinate with latitude and longitude.
|
* to a coordinate with latitude and longitude.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param {object} point - Point in form of {x: x_val, y: y_val}.
|
* @param {object} point - Point in form of {x, y}.
|
||||||
* @returns {object} - Coordinates on the map in form of {x: latitude, y: longitude}.
|
* @returns {object} - Coordinates on the map in form of {x: latitude, y: longitude}.
|
||||||
*/
|
*/
|
||||||
coordinatesFromPoint(point) {
|
coordinatesFromPoint(point) {
|
||||||
let coords = this.mapdata.toCoordinates(this.toRelativePosition(point))
|
let coords = this.mapProjection.toCoordinates(this.toRelativePosition(point))
|
||||||
return coords
|
return coords
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,10 +306,10 @@ export class GeoMap {
|
|||||||
* Transform coordinates in the map into pixel positions on the deep zoom image.
|
* Transform coordinates in the map into pixel positions on the deep zoom image.
|
||||||
*
|
*
|
||||||
* @param {object} coords - Coordinates of a map position in form {x: latitude, y: longitude}.
|
* @param {object} coords - Coordinates of a map position in form {x: latitude, y: longitude}.
|
||||||
* @return - Returns a image position in form of {x: x_val, y: y_val}.
|
* @return {Point} - Returns a image position in form of {x: x, y: y}.
|
||||||
*/
|
*/
|
||||||
coordinatesToPoint(coordinates) {
|
coordinatesToPoint(coordinates) {
|
||||||
return this.toAbsolutePixelCoordinates(this.mapdata.toPixel(coordinates))
|
return this.toAbsolutePixelCoordinates(this.mapProjection.toPixel(coordinates))
|
||||||
}
|
}
|
||||||
|
|
||||||
toRelativePosition(point) {
|
toRelativePosition(point) {
|
||||||
@@ -324,15 +376,41 @@ export class GeoMap {
|
|||||||
this.frame = null
|
this.frame = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The complete Triforce, or one or more components of the Triforce.
|
||||||
|
* @typedef {Object} Frame
|
||||||
|
* @property {number} x - X position of the frame.
|
||||||
|
* @property {number} y - Y position of the frame.
|
||||||
|
* @property {number} width - Width of the frame.
|
||||||
|
* @property {number} height - Height od the frame.
|
||||||
|
* @property {Point} localCenter - Local center of the map.
|
||||||
|
* @property {Point} center - Global center of the map.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the frame if the map.
|
||||||
|
*
|
||||||
|
* Frame is the display in which the map is shown.
|
||||||
|
* Normally it's the app, but it can be another element,
|
||||||
|
* for example when in a submap.
|
||||||
|
*
|
||||||
|
* @param {Frame} frame
|
||||||
|
* @memberof GeoMap
|
||||||
|
*/
|
||||||
setFrame(frame) {
|
setFrame(frame) {
|
||||||
if (this.debug) console.log('Set Frame: ', frame)
|
|
||||||
this.frame = frame
|
this.frame = frame
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets the frame if the map.
|
||||||
|
*
|
||||||
* Frame is the display in which the map is shown.
|
* Frame is the display in which the map is shown.
|
||||||
* Normally it's the app, but it can be another element,
|
* Normally it's the app, but it can be another element,
|
||||||
* for example when in a submap.
|
* for example when in a submap.
|
||||||
|
*
|
||||||
|
* @returns {Frame} - Returns the frame of the map.
|
||||||
|
* @memberof GeoMap
|
||||||
*/
|
*/
|
||||||
getFrame() {
|
getFrame() {
|
||||||
let frame = {
|
let frame = {
|
||||||
@@ -418,6 +496,7 @@ export class GeoMap {
|
|||||||
* for creating the maps.
|
* for creating the maps.
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
|
* @private
|
||||||
* @param {object} json - The object containing multiple map data sets.
|
* @param {object} json - The object containing multiple map data sets.
|
||||||
* @param {error-object} error - An object that contains an parameter message: {message = ""}. This is faking a call by reference.
|
* @param {error-object} error - An object that contains an parameter message: {message = ""}. This is faking a call by reference.
|
||||||
* @returns {boolean} - True if all sets were valid. False otherwise.
|
* @returns {boolean} - True if all sets were valid. False otherwise.
|
||||||
@@ -453,6 +532,7 @@ export class GeoMap {
|
|||||||
*Validates of a single data set contains the valid data for creating a map.
|
*Validates of a single data set contains the valid data for creating a map.
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
|
* @private
|
||||||
* @param {object} json - The object containing a single set of map data.
|
* @param {object} json - The object containing a single set of map data.
|
||||||
* @returns {boolean} - True if valid, otherwise false.
|
* @returns {boolean} - True if valid, otherwise false.
|
||||||
* @memberof GeoMap
|
* @memberof GeoMap
|
||||||
@@ -488,8 +568,8 @@ export class GeoMap {
|
|||||||
const tilesConfig = data.tiles
|
const tilesConfig = data.tiles
|
||||||
const options = data.options
|
const options = data.options
|
||||||
|
|
||||||
const mapdata = new DeepZoomMapData(projection, tilesConfig)
|
const mapProjection = new DeepZoomMapProjection(projection, tilesConfig)
|
||||||
return new DeepZoomMap(mapdata, tilesConfig, options)
|
return new DeepZoomMap(mapProjection, tilesConfig, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
static _getProjectionByName(projection) {
|
static _getProjectionByName(projection) {
|
||||||
@@ -509,40 +589,39 @@ GeoMap.counter = 0
|
|||||||
* The DeepZoomMap class extends the GeoMap to create
|
* The DeepZoomMap class extends the GeoMap to create
|
||||||
* maps as deepzoom images from maptiles.
|
* maps as deepzoom images from maptiles.
|
||||||
*
|
*
|
||||||
* @extends GeoMap
|
* @export
|
||||||
* @class
|
* @class DeepZoomMap
|
||||||
* @see {@link maps.html}
|
* @extends {GeoMap}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class DeepZoomMap extends GeoMap {
|
export class DeepZoomMap extends GeoMap {
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object} tilesConfig - The tiles config object, that defines at what path and in which format the tiles are.
|
* @param {object} tilesConfig - The tiles config object, that defines at what path and in which format the tiles are.
|
||||||
* @param {MapData} mapdata - A MapData object, that contains informations of how the given map has to be interpreted.
|
* @param {MapProjection} mapProjection - A MapProjection object, that contains informations of how the given map has to be interpreted.
|
||||||
* @param {object} opts - Additional options to specify the behaviour of the deep zoom image.
|
* @param {object} opts - Additional options to specify the behaviour of the deep zoom image.
|
||||||
*/
|
*/
|
||||||
constructor(mapdata, tilesConfig, opts = {}) {
|
constructor(mapProjection, tilesConfig, opts = {}) {
|
||||||
opts = Object.assign(
|
opts = Object.assign(
|
||||||
{
|
{
|
||||||
maxScale: Math.min(tilesConfig.width, tilesConfig.height) / tilesConfig.tileSize,
|
maxScale: Math.min(tilesConfig.width, tilesConfig.height) / tilesConfig.tileSize,
|
||||||
minScale: mapdata.getMinScale,
|
minScale: mapProjection.getMinScale,
|
||||||
highResolution: true,
|
highResolution: true,
|
||||||
debug: false
|
debug: false
|
||||||
},
|
},
|
||||||
opts
|
opts
|
||||||
)
|
)
|
||||||
super(mapdata, opts)
|
super(mapProjection, opts)
|
||||||
|
|
||||||
this.tilesConfig = tilesConfig
|
this.tilesConfig = tilesConfig
|
||||||
this._verifyMapdata()
|
this._verifyMapProjection()
|
||||||
}
|
}
|
||||||
|
|
||||||
_verifyMapdata() {
|
_verifyMapProjection() {
|
||||||
if (!(this.mapdata instanceof MapData)) {
|
if (!(this.mapProjection instanceof MapProjection)) {
|
||||||
console.error('Use the MapData object for creating maps!')
|
console.error('Use the MapProjection object for creating maps!')
|
||||||
} else {
|
} else {
|
||||||
if (!(this.mapdata instanceof DeepZoomMapData)) {
|
if (!(this.mapProjection instanceof DeepZoomMapProjection)) {
|
||||||
console.error('Use the DeepZoomMapData object.')
|
console.error('Use the DeepZoomMapProjection object.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,10 +632,10 @@ export class DeepZoomMap extends GeoMap {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
load(container = null, scatter = null) {
|
load(container = null, scatter = null) {
|
||||||
if (!this.mapdata.app) console.error('App was not set in the mapdata.')
|
if (!this.mapProjection.app) console.error('App was not set in the mapProjection.')
|
||||||
this.info = new DeepZoomInfo(this.tilesConfig)
|
this.info = new DeepZoomInfo(this.tilesConfig)
|
||||||
let image = new DeepZoomImage(this.info, {
|
let image = new DeepZoomImage(this.info, {
|
||||||
app: this.mapdata.app,
|
app: this.mapProjection.app,
|
||||||
alpha: this.alpha,
|
alpha: this.alpha,
|
||||||
debug: this.debug,
|
debug: this.debug,
|
||||||
world: scatter == null ? scatter : scatter.getWorldScatter()
|
world: scatter == null ? scatter : scatter.getWorldScatter()
|
||||||
@@ -674,7 +753,7 @@ export class DeepZoomMap extends GeoMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clone(container, scatter = null) {
|
clone(container, scatter = null) {
|
||||||
const map = new DeepZoomMap(this.mapdata, this.tilesConfig, {
|
const map = new DeepZoomMap(this.mapProjection, this.tilesConfig, {
|
||||||
alpha: this.alpha,
|
alpha: this.alpha,
|
||||||
cover: this.cover,
|
cover: this.cover,
|
||||||
debug: this.debug,
|
debug: this.debug,
|
||||||
@@ -734,15 +813,17 @@ DeepZoomMap.tintcolors = [0xff0000, 0xff00ff, 0xffff00, 0x00ff00, 0x00ffff, 0x00
|
|||||||
DeepZoomMap.tintcolor = 0
|
DeepZoomMap.tintcolor = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* ImageMap extends GeoMap to display simple images
|
* ImageMap extends GeoMap to display simple images
|
||||||
* as maps.
|
* as maps.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class ImageMap
|
||||||
|
* @extends {GeoMap}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class ImageMap extends GeoMap {
|
export class ImageMap extends GeoMap {
|
||||||
constructor(sprite, mapdata, opts = {}) {
|
constructor(sprite, mapProjection, opts = {}) {
|
||||||
super(mapdata, opts)
|
super(mapProjection, opts)
|
||||||
if (this.debug) console.log('Construct Image Map', sprite, mapdata, opts)
|
if (this.debug) console.log('Construct Image Map', sprite, mapProjection, opts)
|
||||||
|
|
||||||
this.sprite = sprite
|
this.sprite = sprite
|
||||||
|
|
||||||
@@ -756,7 +837,7 @@ export class ImageMap extends GeoMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clone(container = null, scatter = null) {
|
clone(container = null, scatter = null) {
|
||||||
const map = new ImageMap(new PIXI.Sprite(this.sprite.texture), this.mapdata, {
|
const map = new ImageMap(new PIXI.Sprite(this.sprite.texture), this.mapProjection, {
|
||||||
alpha: this.alpha,
|
alpha: this.alpha,
|
||||||
cover: this.cover,
|
cover: this.cover,
|
||||||
debug: this.debug,
|
debug: this.debug,
|
||||||
|
|||||||
@@ -98,11 +98,11 @@
|
|||||||
resolutionDependent: false
|
resolutionDependent: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// The mapdata object contains informations,
|
// The map projection object contains informations,
|
||||||
// how the displayed map has to be interpreted.
|
// how the displayed map has to be interpreted.
|
||||||
// e.g. which projection is used or how the
|
// e.g. which projection is used or how the
|
||||||
// image is clipped.
|
// image is clipped.
|
||||||
let europeData = new MapData(new Projection.Mercator(), {
|
let europeData = new MapProjection(new Projection.Mercator(), {
|
||||||
clip: {
|
clip: {
|
||||||
min: { x: 32.863294, y: -18.58 },
|
min: { x: 32.863294, y: -18.58 },
|
||||||
max: { x: 57.467973, y: 44.277158 }
|
max: { x: 57.467973, y: 44.277158 }
|
||||||
@@ -120,16 +120,16 @@
|
|||||||
cover
|
cover
|
||||||
})
|
})
|
||||||
|
|
||||||
let testMapData = new DeepZoomMapData(new Projection.Mercator(), testConfig.tiles, {
|
let testMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), testConfig.tiles, {
|
||||||
app
|
app
|
||||||
})
|
})
|
||||||
let testMap = new DeepZoomMap(testMapData, Object.assign({}, testConfig.tiles, { app }), { cover })
|
let testMap = new DeepZoomMap(testMapProjection, Object.assign({}, testConfig.tiles, { app }), { cover })
|
||||||
app.addMap("test", testMap)
|
app.addMap("test", testMap)
|
||||||
|
|
||||||
let osmMapData = new DeepZoomMapData(new Projection.Mercator(), osmConfig.tiles, {
|
let osmMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), osmConfig.tiles, {
|
||||||
app
|
app
|
||||||
})
|
})
|
||||||
let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, osmConfig.tiles, { app }), { cover })
|
let deepZoomMap = new DeepZoomMap(osmMapProjection, Object.assign({}, osmConfig.tiles, { app }), { cover })
|
||||||
app.addMap("osm", deepZoomMap)
|
app.addMap("osm", deepZoomMap)
|
||||||
|
|
||||||
// Finally apply the map to the MapApp
|
// Finally apply the map to the MapApp
|
||||||
|
|||||||
@@ -7,12 +7,35 @@ import { Points } from '../../utils.js'
|
|||||||
import Logging from '../../logging.js'
|
import Logging from '../../logging.js'
|
||||||
import { MapList } from './maplist.js'
|
import { MapList } from './maplist.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A PIXI.Point or object in form {x,y}.
|
||||||
|
*
|
||||||
|
* @typedef {Object} Point
|
||||||
|
* @property {number} x - Indicates whether the Courage component is present.
|
||||||
|
* @property {number} y - Indicates whether the Power component is present.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A coordinate point is a PIXI.Point or object in form {x,y} that contains map coordinates
|
||||||
|
* instead of pixel values, where x represents the latitude and y the longitude.
|
||||||
|
* @typedef {Object} CoordinatePoint
|
||||||
|
* @property {number} x - Indicates whether the Courage component is present.
|
||||||
|
* @property {number} y - Indicates whether the Power component is present.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MapApp is responsible for showing fullscreen
|
* MapApp is responsible for showing fullscreen
|
||||||
* map applications.
|
* map applications.
|
||||||
*
|
*
|
||||||
|
* @export
|
||||||
|
* @class MapApp
|
||||||
|
* @extends {PIXIApp}
|
||||||
*/
|
*/
|
||||||
export default class MapApp extends PIXIApp {
|
export default class MapApp extends PIXIApp {
|
||||||
|
/**
|
||||||
|
*Creates an instance of MapApp.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
constructor(opts = {}) {
|
constructor(opts = {}) {
|
||||||
super(opts)
|
super(opts)
|
||||||
|
|
||||||
@@ -27,7 +50,6 @@ export default class MapApp extends PIXIApp {
|
|||||||
coordsLogging: false,
|
coordsLogging: false,
|
||||||
overlays: {},
|
overlays: {},
|
||||||
keycodes: {},
|
keycodes: {},
|
||||||
showHotkeys: false,
|
|
||||||
imageMapZoomHeight: 256, //Defines the zoomvalue 1 for all image maps inside the mapapp.
|
imageMapZoomHeight: 256, //Defines the zoomvalue 1 for all image maps inside the mapapp.
|
||||||
focus: null,
|
focus: null,
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
@@ -44,7 +66,6 @@ export default class MapApp extends PIXIApp {
|
|||||||
this.overlayElements = new Map()
|
this.overlayElements = new Map()
|
||||||
this.debug = opts.debug
|
this.debug = opts.debug
|
||||||
this.fpsLogging = opts.fpsLogging
|
this.fpsLogging = opts.fpsLogging
|
||||||
this.showHotkeys = opts.showHotkeys
|
|
||||||
this.keycodes = this._extractKeyCodes(opts.keycodes)
|
this.keycodes = this._extractKeyCodes(opts.keycodes)
|
||||||
this.coordsLogging = opts.coordsLogging
|
this.coordsLogging = opts.coordsLogging
|
||||||
this.overlays = opts.overlays
|
this.overlays = opts.overlays
|
||||||
@@ -106,9 +127,15 @@ export default class MapApp extends PIXIApp {
|
|||||||
console.log(JSON.stringify(boundaries))
|
console.log(JSON.stringify(boundaries))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the MapLayer.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
_setupMapLayer() {
|
_setupMapLayer() {
|
||||||
this.mapContainer = new PIXI.Container()
|
this.mapContainer = new PIXI.Container()
|
||||||
this.mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, {
|
this._mapLayer = new MapLayer(this.mapList, this.scene, this.mapContainer, {
|
||||||
name: 'Root Map Layer',
|
name: 'Root Map Layer',
|
||||||
focus: this.focus,
|
focus: this.focus,
|
||||||
zoom: this.zoom,
|
zoom: this.zoom,
|
||||||
@@ -174,26 +201,49 @@ export default class MapApp extends PIXIApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relayouts the app. E.g. called when the window is resized.
|
||||||
|
*
|
||||||
|
* @param {number} width - Desired width of the app.
|
||||||
|
* @param {number} height - Desired height of the app.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
layout(width, height) {
|
layout(width, height) {
|
||||||
this.scene.resize(width, height)
|
this.scene.resize(width, height)
|
||||||
this.mapLayer.mapview.update()
|
this.mapLayer.mapview.update()
|
||||||
this.onSizeChanged.call(this)
|
this.onSizeChanged.call(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the sceneFactory of the PIXIApp to create a RigidScatterContainer instead of
|
||||||
|
* a regular PIXI.Container()
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {RigidScatterContainer} - Returns the newly created RigidScatterContainer.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
sceneFactory() {
|
sceneFactory() {
|
||||||
return new RigidScatterContainer(this.width, this.height, this.renderer, {
|
return new RigidScatterContainer(this.width, this.height, this.renderer, {
|
||||||
app: this,
|
app: this,
|
||||||
showBounds: true,
|
showBounds: false,
|
||||||
showTouches: true,
|
showTouches: false,
|
||||||
showPolygon: true,
|
showPolygon: false,
|
||||||
container: this
|
container: this,
|
||||||
|
stopEvents: false,
|
||||||
|
claimEvents: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the map to the given key.
|
||||||
|
*
|
||||||
|
* @param {string} key - Identifier of the map to change to.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
selectMap(key) {
|
selectMap(key) {
|
||||||
|
if (this.debug) console.log('Select map', key, result)
|
||||||
let result = this.mapList.select(key)
|
let result = this.mapList.select(key)
|
||||||
|
|
||||||
console.log('Select map', key, result)
|
|
||||||
if (result && this.mapLayer) {
|
if (result && this.mapLayer) {
|
||||||
this.mapLayer.changeMap(this.mapList.map)
|
this.mapLayer.changeMap(this.mapList.map)
|
||||||
}
|
}
|
||||||
@@ -211,14 +261,30 @@ export default class MapApp extends PIXIApp {
|
|||||||
this.selectMap(key)
|
this.selectMap(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a map to the maplist.
|
||||||
|
* If no map is set, the added map will be set as default.
|
||||||
|
*
|
||||||
|
* @param {string} key - Identifier for the map.
|
||||||
|
* @param {GeoMap} map - Map object to add.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
addMap(key, map) {
|
addMap(key, map) {
|
||||||
if (this.mapList) this.mapList.add(key, map)
|
if (this.mapList) this.mapList.add(key, map)
|
||||||
else console.error('Cannot access mapLayer. It was not initialized yet.')
|
else console.error('Cannot access mapLayer. It was not initialized yet.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds multiple maps at once.
|
||||||
|
*
|
||||||
|
* @param {object} mapObject
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
addMaps(mapObject) {
|
addMaps(mapObject) {
|
||||||
for (let [key, val] of Object.entries(mapObject)) {
|
for (let [key, val] of Object.entries(mapObject)) {
|
||||||
|
if (val instanceof GeoMap) {
|
||||||
this.addMap(key, val)
|
this.addMap(key, val)
|
||||||
|
} else console.warn('Tried adding maps that are not og Type GeoMap.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +292,14 @@ export default class MapApp extends PIXIApp {
|
|||||||
this.onTransform.call(this, event)
|
this.onTransform.call(this, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Called when the mapLayer changed the map.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {*} lastMap
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
_mapChanged(lastMap) {
|
_mapChanged(lastMap) {
|
||||||
if (lastMap) {
|
if (lastMap) {
|
||||||
lastMap.flushHandlers()
|
lastMap.flushHandlers()
|
||||||
@@ -243,6 +317,16 @@ export default class MapApp extends PIXIApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mapLayer of the map.
|
||||||
|
*
|
||||||
|
* @member {MapLayer}
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
|
get mapLayer() {
|
||||||
|
return this._mapLayer
|
||||||
|
}
|
||||||
|
|
||||||
_doesOverlayElementExist(layer, type, name) {
|
_doesOverlayElementExist(layer, type, name) {
|
||||||
let layerElements = this.overlayElements.get(layer)
|
let layerElements = this.overlayElements.get(layer)
|
||||||
return layerElements != undefined && layerElements[type] != null && layerElements[type][name] != null
|
return layerElements != undefined && layerElements[type] != null && layerElements[type][name] != null
|
||||||
@@ -265,7 +349,9 @@ export default class MapApp extends PIXIApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the current coordinates to the clipboard.
|
* Copies the current location to the clipboard.
|
||||||
|
*
|
||||||
|
* @memberof MapApp
|
||||||
*/
|
*/
|
||||||
locationToClipboard() {
|
locationToClipboard() {
|
||||||
let hidden = document.createElement('input')
|
let hidden = document.createElement('input')
|
||||||
@@ -278,6 +364,15 @@ export default class MapApp extends PIXIApp {
|
|||||||
document.body.removeChild(hidden)
|
document.body.removeChild(hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to copy polygons to the clipboard.
|
||||||
|
*
|
||||||
|
* Useful for debugging or to roughly trace a shape in the map.
|
||||||
|
* The generated pointarray can be used as geometry of a geographic
|
||||||
|
* or inside an overlay to draw that shape onto the map.
|
||||||
|
*
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
pathToClipboard() {
|
pathToClipboard() {
|
||||||
let hidden = document.createElement('input')
|
let hidden = document.createElement('input')
|
||||||
document.body.appendChild(hidden)
|
document.body.appendChild(hidden)
|
||||||
@@ -301,25 +396,27 @@ export default class MapApp extends PIXIApp {
|
|||||||
document.body.removeChild(hidden)
|
document.body.removeChild(hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the active map.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
get map() {
|
get map() {
|
||||||
return this.mapList.map
|
return this.mapList.map
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeMapKey() {
|
|
||||||
return this.mapLayer.active
|
|
||||||
}
|
|
||||||
|
|
||||||
getRelativePosition(x, y) {
|
|
||||||
return {
|
|
||||||
x: x * app.width,
|
|
||||||
y: y * app.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearDrawData() {
|
clearDrawData() {
|
||||||
this.drawData = []
|
this.drawData = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a text field on the map.
|
||||||
|
* The text element is a DOMElement.
|
||||||
|
*
|
||||||
|
* @param {string} msg - Message to log.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
showNotification(msg) {
|
showNotification(msg) {
|
||||||
let notification = document.createElement('div')
|
let notification = document.createElement('div')
|
||||||
notification.classList.add('notification')
|
notification.classList.add('notification')
|
||||||
@@ -362,8 +459,25 @@ export default class MapApp extends PIXIApp {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentLocationToString() {}
|
/**
|
||||||
|
* @typedef KeyCode
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} key - an ID.
|
||||||
|
* @property {boolean} altKey - Defines if KeyCode requires the alt key to be pressed.
|
||||||
|
* @property {boolean} shiftKey - Defines if KeyCode requires the shift key to be pressed.
|
||||||
|
* @property {boolean} ctrlKey - Defines if KeyCode requires the ctrl key to be pressed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check's if a key event matches a defined KeyCode.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {KeyboardEvent} event - Event that is fired on keydown, -pressed or -up.
|
||||||
|
* @param {KeyCode} keyCode - KeyCode is an object in the form of : {key:number, altKey:boolean,shiftKey:boolean,ctrlKey:boolean }
|
||||||
|
* @returns {boolean} - True, when the event matches the keycode, false otherwise.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
_matchKeyCode(event, keyCode) {
|
_matchKeyCode(event, keyCode) {
|
||||||
// If keycode does not exist or is invalid - return.
|
// If keycode does not exist or is invalid - return.
|
||||||
if (!keyCode || keyCode.key == null) return false
|
if (!keyCode || keyCode.key == null) return false
|
||||||
@@ -385,6 +499,13 @@ export default class MapApp extends PIXIApp {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks on every key down if it matches a keycode.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {KeyboardEvent} event
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
_checkForKeyCode(event) {
|
_checkForKeyCode(event) {
|
||||||
if (this._matchKeyCode(event, this.keycodes.copyCoordinate)) {
|
if (this._matchKeyCode(event, this.keycodes.copyCoordinate)) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@@ -443,10 +564,28 @@ export default class MapApp extends PIXIApp {
|
|||||||
this.drawMode = this.DRAW_MODES.PIXI_POINT
|
this.drawMode = this.DRAW_MODES.PIXI_POINT
|
||||||
}
|
}
|
||||||
|
|
||||||
_extractKeyCodes(keycodeText) {
|
/**
|
||||||
|
* @typedef KeyCodePairs
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} name - Name of the KeyCode.
|
||||||
|
* @property {KeyCode} keyCode - KeyCode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts keycodes from a string.
|
||||||
|
*
|
||||||
|
* KeycodeStrings may look like this 'ctrl+shift+b'
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {KeyCodePairs} nameKeyCodePairs
|
||||||
|
* @returns {array} - Returns an array of KeyCode objects.
|
||||||
|
* @memberof MapApp
|
||||||
|
*/
|
||||||
|
_extractKeyCodes(nameKeyCodePairs) {
|
||||||
let out = {}
|
let out = {}
|
||||||
|
|
||||||
for (let [name, combinationString] of Object.entries(keycodeText)) {
|
for (let [name, combinationString] of Object.entries(nameKeyCodePairs)) {
|
||||||
let keys = combinationString.split('+')
|
let keys = combinationString.split('+')
|
||||||
out[name] = {
|
out[name] = {
|
||||||
key: null,
|
key: null,
|
||||||
@@ -517,35 +656,8 @@ export default class MapApp extends PIXIApp {
|
|||||||
const center = submap.center
|
const center = submap.center
|
||||||
const radius = submap.container.width / 2
|
const radius = submap.container.width / 2
|
||||||
const distance = Points.distance(center, event.data.global) / submap.scatter.scale
|
const distance = Points.distance(center, event.data.global) / submap.scatter.scale
|
||||||
if (distance > radius) {
|
|
||||||
//submap.resize((distance) * 2, .2)
|
|
||||||
//submap.centerAt(myevent.center)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (const submap of this.submaps) {
|
|
||||||
// const center = submap.center
|
|
||||||
// const radius = submap.container.width / 2
|
|
||||||
// const distance = Points.distance(center, event.data.global) / submap.scatter.scale
|
|
||||||
// const inside = distance < radius + 10
|
|
||||||
|
|
||||||
// console.log(distance, radius)
|
|
||||||
|
|
||||||
// if (inside) {
|
|
||||||
// // (this.width + 80) / 2 * this.scatter.scale
|
|
||||||
// //const width = (submap.width + 80) / 2 * submap.scatter.scale
|
|
||||||
// //console.log(width)
|
|
||||||
|
|
||||||
// if (distance > radius) {
|
|
||||||
// submap.resize((distance) * 2, .2)
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if (distance < radius + 20) {
|
|
||||||
// //submap.resize((distance - 30) * 2, .2)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__onEnd(event) {
|
__onEnd(event) {
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* MapList is a list of maps with one active index.
|
||||||
|
* It contains some utility functions to change the map.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class MapList
|
||||||
|
*/
|
||||||
export class MapList {
|
export class MapList {
|
||||||
constructor(active = null, maps = {}) {
|
constructor(active = null, maps = {}) {
|
||||||
this.maps = maps
|
this._maps = maps
|
||||||
this.active = active
|
this._active = active
|
||||||
|
|
||||||
if (Object.keys(maps).length > 0) this.select(active)
|
if (Object.keys(maps).length > 0) this.select(active)
|
||||||
}
|
}
|
||||||
@@ -9,8 +16,9 @@ export class MapList {
|
|||||||
/**
|
/**
|
||||||
* Selects a map from the map list.
|
* Selects a map from the map list.
|
||||||
*
|
*
|
||||||
|
* @public
|
||||||
* @param {string} active - Name of the map to select.
|
* @param {string} active - Name of the map to select.
|
||||||
* @returns
|
* @returns {Map} - Returns the active map. Returns null if no map was added to the MapList.
|
||||||
* @memberof MapList
|
* @memberof MapList
|
||||||
*/
|
*/
|
||||||
select(active) {
|
select(active) {
|
||||||
@@ -29,7 +37,7 @@ export class MapList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.active !== active) {
|
if (this.active !== active) {
|
||||||
this.active = active
|
this._active = active
|
||||||
map = this.maps[active]
|
map = this.maps[active]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -40,6 +48,13 @@ export class MapList {
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the entire maplist.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @returns {MapList} - Returns a cloned instance of this map list.
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
clone() {
|
clone() {
|
||||||
let maps = {}
|
let maps = {}
|
||||||
|
|
||||||
@@ -50,17 +65,63 @@ export class MapList {
|
|||||||
return new MapList(this.active, maps)
|
return new MapList(this.active, maps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new map to the map list.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {string} key - Key to identify the map.
|
||||||
|
* @param {GeoMap} map - The GeoMap to add.
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
add(key, map) {
|
add(key, map) {
|
||||||
if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.')
|
if (this.maps[key] != null) consol.warn('Key already in mapList. The existing key was overwritten.')
|
||||||
if (this.active == null) this.active = key
|
if (this.active == null) this._active = key
|
||||||
map.name = key
|
map.name = key
|
||||||
this.maps[key] = map
|
this.maps[key] = map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the the active map.
|
||||||
|
* If none is set, it returns null.
|
||||||
|
*
|
||||||
|
*@public
|
||||||
|
* @readonly
|
||||||
|
* @member {GeoMap}
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
get map() {
|
get map() {
|
||||||
return this.maps && this.maps[this.active] ? this.maps[this.active] : null
|
return this.maps && this.maps[this.active] ? this.maps[this.active] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of addedd cards.
|
||||||
|
*
|
||||||
|
* @member {object}
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
|
get maps() {
|
||||||
|
return this._maps
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the active key.
|
||||||
|
*
|
||||||
|
* @member {string}
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
|
get active() {
|
||||||
|
return this._active
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the next map in the map array.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @returns {GeoMap} - Returns the next map in the list.
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
next() {
|
next() {
|
||||||
let keys = Object.keys(this.maps)
|
let keys = Object.keys(this.maps)
|
||||||
let idx = keys.indexOf(this.active)
|
let idx = keys.indexOf(this.active)
|
||||||
@@ -69,6 +130,13 @@ export class MapList {
|
|||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all maps from the maplist.
|
||||||
|
* And cleans up all maps.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof MapList
|
||||||
|
*/
|
||||||
cleanup() {
|
cleanup() {
|
||||||
for (let key in this.maps) {
|
for (let key in this.maps) {
|
||||||
let map = this.maps[key]
|
let map = this.maps[key]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset='UTF-8'>
|
<meta charset='UTF-8'>
|
||||||
<title>MapData</title>
|
<title>MapProjection</title>
|
||||||
|
|
||||||
|
|
||||||
<link rel='stylesheet' href='../../3rdparty/highlight/styles/default.css'>
|
<link rel='stylesheet' href='../../3rdparty/highlight/styles/default.css'>
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload='Doctest.run()'>
|
<body onload='Doctest.run()'>
|
||||||
<h1>MapData</h1>
|
<h1>MapProjection</h1>
|
||||||
<p>Mapdata calculates is responsible for transforming map coordinates to pixel coordinates and backwards.</p>
|
<p>The map projection calculates is responsible for transforming map coordinates to pixel coordinates and backwards.</p>
|
||||||
|
|
||||||
<h2>Static Squared World Map</h2>
|
<h2>Static Squared World Map</h2>
|
||||||
<p>The most simple example is a squared world map, thats projected with mercator transformation. Ranging from
|
<p>The most simple example is a squared world map, thats projected with mercator transformation. Ranging from
|
||||||
@@ -73,9 +73,9 @@
|
|||||||
|
|
||||||
|
|
||||||
//Helper function to print the coordinates to a dom element.
|
//Helper function to print the coordinates to a dom element.
|
||||||
function printCoordinates(element, mapdata, out_dom) {
|
function printCoordinates(element, mapProjection, out_dom) {
|
||||||
element.addEventListener("mousemove", (event) => {
|
element.addEventListener("mousemove", (event) => {
|
||||||
let coords = mapdata.toCoordinates({ x: event.offsetX / event.target.width, y: event.offsetY / event.target.height })
|
let coords = mapProjection.toCoordinates({ x: event.offsetX / event.target.width, y: event.offsetY / event.target.height })
|
||||||
out_dom.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4)
|
out_dom.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,8 @@
|
|||||||
</script>
|
</script>
|
||||||
<script class="doctest">
|
<script class="doctest">
|
||||||
|
|
||||||
// Instantiate our mapdata.
|
// Instantiate our map projection.
|
||||||
let squared_world = new MapData(new Projection.Mercator());
|
let squared_world = new MapProjection(new Projection.Mercator());
|
||||||
|
|
||||||
// Define a position, we are interested in in {x: latitude, y: longitude}
|
// Define a position, we are interested in in {x: latitude, y: longitude}
|
||||||
let iceland = { x: 64.514979, y: -19.020796 }
|
let iceland = { x: 64.514979, y: -19.020796 }
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
printCoordinates(map_image_0, squared_world, map_coords_0)
|
printCoordinates(map_image_0, squared_world, map_coords_0)
|
||||||
</script>
|
</script>
|
||||||
<h2 id="germany">Clipped Map</h2>
|
<h2 id="germany">Clipped Map</h2>
|
||||||
<p>Often we don't use the whole map, or our map is a subsection of the world. MapData can clip those cases, using
|
<p>Often we don't use the whole map, or our map is a subsection of the world. MapProjection can clip those cases, using
|
||||||
the a
|
the a
|
||||||
bounding box of min and max coordinates.</p>
|
bounding box of min and max coordinates.</p>
|
||||||
<p>Coordinates:
|
<p>Coordinates:
|
||||||
@@ -127,8 +127,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<script class="doctest">
|
<script class="doctest">
|
||||||
|
|
||||||
//Same procedure as above, just add a clipping parameter to the MapData object.
|
//Same procedure as above, just add a clipping parameter to the MapProjection object.
|
||||||
let europe = new MapData(new Projection.Mercator(), {
|
let europe = new MapProjection(new Projection.Mercator(), {
|
||||||
clip: {
|
clip: {
|
||||||
min: { x: 32.863294, y: -18.58 },
|
min: { x: 32.863294, y: -18.58 },
|
||||||
max: { x: 57.467973, y: 44.277158 }
|
max: { x: 57.467973, y: 44.277158 }
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
const size = 256
|
const size = 256
|
||||||
|
|
||||||
|
|
||||||
// Fake offset by using the old mapdata.
|
// Fake offset by using the old map projection.
|
||||||
let translation = squared_world.toPixel({ x: 90-10, y: -140 })
|
let translation = squared_world.toPixel({ x: 90-10, y: -140 })
|
||||||
console.log(translation)
|
console.log(translation)
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
//This map is clipped at the bottom
|
//This map is clipped at the bottom
|
||||||
// And also translated in hoizontal direction.
|
// And also translated in hoizontal direction.
|
||||||
// The translate option corrects that.
|
// The translate option corrects that.
|
||||||
let translated_world = new MapData(new Projection.Mercator(), {
|
let translated_world = new MapProjection(new Projection.Mercator(), {
|
||||||
translate: { x: -10, y: 40 },
|
translate: { x: -10, y: 40 },
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
/**
|
/**
|
||||||
* MapData contains the informations about how
|
* MapProjection contains the informations about how
|
||||||
* a Map has to be interpreted. What are the bounds of the
|
* a Map has to be interpreted. What are the bounds of the
|
||||||
* map and how to translate coordinates into
|
* map and how to translate coordinates into
|
||||||
* image positions.
|
* image positions.
|
||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
* @see {@link mapdata.html}
|
* @see {@link mapprojection.html}
|
||||||
*/
|
*/
|
||||||
export class MapData {
|
export class MapProjection {
|
||||||
/**
|
/**
|
||||||
* Creates instance of MapData
|
* Creates instance of MapProjection
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Projection}[projection] - Specifies the projection of the map (e.g. Mercator Projection).
|
* @param {Projection}[projection] - Specifies the projection of the map (e.g. Mercator Projection).
|
||||||
* @param {object}[opts] - Addiditonal options.
|
* @param {object}[opts] - Addiditonal options.
|
||||||
* @param {[[minLat, minLng],[maxLat, maxLng]]}[opts.bounds] - Describes the minimum and maximum coordinates on the map
|
* @param {array}[opts.bounds] - Describes the minimum and maximum coordinates on the map in the form of {[[minLat, minLng],[maxLat, maxLng]]}.
|
||||||
* @param {Point}[opts.translate] - Defines a translation, when clipping is not an option (e.g. when the whole world is shown, but translated.)
|
* @param {Point}[opts.translate] - Defines a translation, when clipping is not an option (e.g. when the whole world is shown, but translated.)
|
||||||
*/
|
*/
|
||||||
constructor(projection, opts = {}) {
|
constructor(projection, opts = {}) {
|
||||||
@@ -25,7 +25,7 @@ export class MapData {
|
|||||||
opts
|
opts
|
||||||
)
|
)
|
||||||
|
|
||||||
this.projection = projection
|
this._projection = projection
|
||||||
|
|
||||||
if (this.opts.clip) {
|
if (this.opts.clip) {
|
||||||
let _cmin = this.projection.forward(this.opts.clip.min)
|
let _cmin = this.projection.forward(this.opts.clip.min)
|
||||||
@@ -49,12 +49,24 @@ export class MapData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The projection used by the map projection.
|
||||||
|
*
|
||||||
|
* @member {Projection}
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapProjection
|
||||||
|
*/
|
||||||
|
get projection() {
|
||||||
|
return this._projection
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a pixel point on the map to a geographical coordinate.
|
* Transforms a pixel point on the map to a geographical coordinate.
|
||||||
*
|
*
|
||||||
* @param {{x,y} | PIXI.Point} point - A pixel position on the map.
|
* @public
|
||||||
* @returns {{x,y} | PIXI.Point} - A geographical coordinate.
|
* @param {Point} point - A pixel position on the map.
|
||||||
* @memberof MapData
|
* @returns {CoordinatePoint} A geographical coordinate.
|
||||||
|
* @memberof MapProjection
|
||||||
*/
|
*/
|
||||||
toCoordinates(point) {
|
toCoordinates(point) {
|
||||||
if (this.opts.clip) {
|
if (this.opts.clip) {
|
||||||
@@ -84,9 +96,10 @@ export class MapData {
|
|||||||
/**
|
/**
|
||||||
* Transform a geographical coordinate to a pixel point on the map.
|
* Transform a geographical coordinate to a pixel point on the map.
|
||||||
*
|
*
|
||||||
* @param {{x,y} | PIXI.Point} coordinates - A point in the form of {x:lat,y:lng}.
|
* @public
|
||||||
* @returns {{x,y} | PIXI.Point} point - A pixel position on the map.
|
* @param {CoordinatePoint} coordinates - A point in the form of {x:lat,y:lng}.
|
||||||
* @memberof MapData
|
* @returns {Point} A pixel position on the map.
|
||||||
|
* @memberof MapProjection
|
||||||
*/
|
*/
|
||||||
toPixel(coordinates) {
|
toPixel(coordinates) {
|
||||||
let coords = { x: coordinates.x, y: coordinates.y }
|
let coords = { x: coordinates.x, y: coordinates.y }
|
||||||
@@ -116,6 +129,19 @@ export class MapData {
|
|||||||
return point
|
return point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clipping describes the
|
||||||
|
* piece of the map that is shown. The returned object contains a min and max value of the clipping in form of: {min: {x,y}, max:{x,y}}. Where x and y are in between 0 and 1.
|
||||||
|
*
|
||||||
|
* E.g. if we just show a map of
|
||||||
|
* europe, then we have to set the clipping properly, otherwise
|
||||||
|
* the preojection would produce the wrong results when transforming
|
||||||
|
* from a point to coordinates or the other way around.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @member {object}
|
||||||
|
* @memberof MapProjection
|
||||||
|
*/
|
||||||
get clip() {
|
get clip() {
|
||||||
let unclipped = {
|
let unclipped = {
|
||||||
min: { x: 0, y: 0 },
|
min: { x: 0, y: 0 },
|
||||||
@@ -126,30 +152,28 @@ export class MapData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bounds to pixel transforms some bounds in form of {min:{x:minLat, y:minLng},max:{x:maxLat, y:maxLng}}
|
* Returns the biggest viewport the map projection allows.
|
||||||
* to pixel coordinates.
|
* This is determined by the projecton or the clipping on the mapapp.
|
||||||
*
|
*
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapProjection
|
||||||
*/
|
*/
|
||||||
getBoundaries() {
|
|
||||||
// let min = this.toPixel(bounds.min)
|
|
||||||
// let max = this.toPixel(bounds.max)
|
|
||||||
|
|
||||||
// Y values needs to be swapped, as PIXI has it's origin
|
|
||||||
// in the top-left corner and a regular map in the bottom-left corner.
|
|
||||||
let boundaries = {
|
|
||||||
min: { x: 0, y: 0 },
|
|
||||||
max: { x: 1, y: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
return boundaries
|
|
||||||
}
|
|
||||||
|
|
||||||
get maxViewport() {
|
get maxViewport() {
|
||||||
return this.opts.clip ? this.opts.clip : this.projection.maxViewport
|
return this.opts.clip ? this.opts.clip : this.projection.maxViewport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DeepZoomMapData extends MapData {
|
/**
|
||||||
|
* Special map projection for DeepZoomMap objects.
|
||||||
|
*
|
||||||
|
* Note: It just transform the clipping parameter of the tiles config
|
||||||
|
* to the clipping of the mapapp.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class DeepZoomMapProjection
|
||||||
|
* @extends {MapProjection}
|
||||||
|
*/
|
||||||
|
export class DeepZoomMapProjection extends MapProjection {
|
||||||
constructor(projection, tilesConfig, opts = {}) {
|
constructor(projection, tilesConfig, opts = {}) {
|
||||||
if (tilesConfig.clip) {
|
if (tilesConfig.clip) {
|
||||||
opts.clip = {
|
opts.clip = {
|
||||||
@@ -81,11 +81,11 @@
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let osmMapData = new DeepZoomMapData(new Projection.Mercator(), osmConfig.tiles, {
|
let osmMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), osmConfig.tiles, {
|
||||||
app: app
|
app: app
|
||||||
})
|
})
|
||||||
|
|
||||||
let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, osmConfig.tiles, { app: app }), { cover: true })
|
let deepZoomMap = new DeepZoomMap(osmMapProjection, Object.assign({}, osmConfig.tiles, { app: app }), { cover: true })
|
||||||
|
|
||||||
app.setMap("deepzoom", deepZoomMap)
|
app.setMap("deepzoom", deepZoomMap)
|
||||||
|
|
||||||
@@ -127,11 +127,11 @@
|
|||||||
|
|
||||||
const app = new MapApp(opts)
|
const app = new MapApp(opts)
|
||||||
|
|
||||||
let osmMapData = new DeepZoomMapData(new Projection.Mercator(), osmConfig.tiles, {
|
let osmMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), osmConfig.tiles, {
|
||||||
app: app
|
app: app
|
||||||
})
|
})
|
||||||
|
|
||||||
let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, osmConfig.tiles, { app: app }), Object.assign({ cover: false }, mapOptipns))
|
let deepZoomMap = new DeepZoomMap(osmMapProjection, Object.assign({}, osmConfig.tiles, { app: app }), Object.assign({ cover: false }, mapOptipns))
|
||||||
|
|
||||||
app.setMap("deepzoom", deepZoomMap)
|
app.setMap("deepzoom", deepZoomMap)
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@
|
|||||||
// Called when all textures are loaded.
|
// Called when all textures are loaded.
|
||||||
let ready = (sprites) => {
|
let ready = (sprites) => {
|
||||||
|
|
||||||
// Define the mapdata for the map.
|
// Define the map projection for the map.
|
||||||
let europeData = new MapData(new Projection.Mercator(), {
|
let europeData = new MapProjection(new Projection.Mercator(), {
|
||||||
clip: {
|
clip: {
|
||||||
min: { x: 32.863294, y: -18.58 },
|
min: { x: 32.863294, y: -18.58 },
|
||||||
max: { x: 57.467973, y: 44.277158 }
|
max: { x: 57.467973, y: 44.277158 }
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Create the map using the texture and the mapdata.
|
// Create the map using the texture and the map projection.
|
||||||
// Optionally customize the map by supplying secific options.
|
// Optionally customize the map by supplying secific options.
|
||||||
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||||
cover: false
|
cover: false
|
||||||
@@ -270,12 +270,12 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create the deepzoomdata.
|
// Create the deepzoomdata.
|
||||||
let osmMapData = new DeepZoomMapData(new Projection.Mercator(), mapConfig.tiles, {
|
let osmMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), mapConfig.tiles, {
|
||||||
app
|
app
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create the app.
|
// Create the app.
|
||||||
let deepZoomMap = new DeepZoomMap(osmMapData, Object.assign({}, mapConfig.tiles, { app }), { cover: false })
|
let deepZoomMap = new DeepZoomMap(osmMapProjection, Object.assign({}, mapConfig.tiles, { app }), { cover: false })
|
||||||
|
|
||||||
// Set the map in the app.
|
// Set the map in the app.
|
||||||
app.setMap("deepzoom", deepZoomMap)
|
app.setMap("deepzoom", deepZoomMap)
|
||||||
|
|||||||
|
After Width: | Height: | Size: 148 KiB |
@@ -0,0 +1,163 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="dark-mode">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>MapViewport</title>
|
||||||
|
|
||||||
|
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../../fonts/material-icon-font/material-icons.css">
|
||||||
|
<link rel='stylesheet' href='../../3rdparty/highlight/styles/vs2015.css'>
|
||||||
|
<link rel='stylesheet' href='../../../css/doctest.css'>
|
||||||
|
|
||||||
|
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||||
|
<script src="../../../dist/iwmlib.js"></script>
|
||||||
|
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="Doctest.run()">
|
||||||
|
<h1>MapViewport</h1>
|
||||||
|
<p>
|
||||||
|
The MapViewport works under the hood of a map layer to track the informations about the current focus point and
|
||||||
|
zoom position.
|
||||||
|
This is important to maintain the same view when maps are changed.
|
||||||
|
</p>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<div id="mapControl"></div>
|
||||||
|
<div id="cityControl" class="controls"></div>
|
||||||
|
<p><strong>WHAT TO SEE:</strong> The map should focus Paris.</p>
|
||||||
|
<script>
|
||||||
|
let osmConfig = {
|
||||||
|
"projection": "mercator",
|
||||||
|
"type": "deepzoom",
|
||||||
|
"tiles": {
|
||||||
|
"tileSize": 256,
|
||||||
|
"format": "png",
|
||||||
|
"overlap": 0,
|
||||||
|
"type": "map",
|
||||||
|
"height": 1024,
|
||||||
|
"width": 1024,
|
||||||
|
"path": "../assets/maps/osm",
|
||||||
|
"urlTileTemplate": "{path}/{level}/{row}/{column}.{format}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let testConfig = {
|
||||||
|
"projection": "mercator",
|
||||||
|
"type": "deepzoom",
|
||||||
|
"tiles": {
|
||||||
|
"tileSize": 128,
|
||||||
|
"format": "jpg",
|
||||||
|
"overlap": 0,
|
||||||
|
"type": "map",
|
||||||
|
"height": 4096,
|
||||||
|
"width": 4096,
|
||||||
|
"path": "../assets/maps/test",
|
||||||
|
"urlTileTemplate": "{path}/{level}/{row}/{column}.{format}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script class="doctest">
|
||||||
|
let capitals = {
|
||||||
|
london: { x: 51.5, y: -0.083333 },
|
||||||
|
rome: { x: 41.9, y: 12.483333 },
|
||||||
|
madrid: { x: 40.4, y: -3.683333 },
|
||||||
|
paris: { x: 48.833986, y: 2.346989 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// You may define a focus point ...
|
||||||
|
let focus = capitals.paris
|
||||||
|
|
||||||
|
// ... and a zoom level.
|
||||||
|
let zoom = 1
|
||||||
|
|
||||||
|
// Name has to be app (like all other PIXIApps).
|
||||||
|
const app = (window.app = new MapApp({
|
||||||
|
focus,
|
||||||
|
zoom,
|
||||||
|
view: canvas,
|
||||||
|
coordsLogging: true,
|
||||||
|
width: 512,
|
||||||
|
height: 512
|
||||||
|
}))
|
||||||
|
|
||||||
|
// As map an image of europe is used.
|
||||||
|
let europe = '../assets/maps/pixabay/europe.jpg'
|
||||||
|
|
||||||
|
//Preload all required sprites for the image map.
|
||||||
|
app.loadSprites([europe], sprites => ready(sprites), {
|
||||||
|
resolutionDependent: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// The map projection object contains informations,
|
||||||
|
// how the displayed map has to be interpreted.
|
||||||
|
// e.g. which projection is used or how the
|
||||||
|
// image is clipped.
|
||||||
|
let europeData = new MapProjection(new Projection.Mercator(), {
|
||||||
|
clip: {
|
||||||
|
min: { x: 32.863294, y: -18.58 },
|
||||||
|
max: { x: 57.467973, y: 44.277158 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function ready(sprites) {
|
||||||
|
|
||||||
|
const cover = true
|
||||||
|
|
||||||
|
// When resources are loaded, the ImageMap can be instantiated.
|
||||||
|
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||||
|
coordsLogging: true,
|
||||||
|
maxScale: 1,
|
||||||
|
cover
|
||||||
|
})
|
||||||
|
|
||||||
|
let testMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), testConfig.tiles, {
|
||||||
|
app
|
||||||
|
})
|
||||||
|
let testMap = new DeepZoomMap(testMapProjection, Object.assign({}, testConfig.tiles, { app }), { cover })
|
||||||
|
app.addMap("test", testMap)
|
||||||
|
|
||||||
|
let osmMapProjection = new DeepZoomMapProjection(new Projection.Mercator(), osmConfig.tiles, {
|
||||||
|
app
|
||||||
|
})
|
||||||
|
let deepZoomMap = new DeepZoomMap(osmMapProjection, Object.assign({}, osmConfig.tiles, { app }), { cover })
|
||||||
|
app.addMap("osm", deepZoomMap)
|
||||||
|
|
||||||
|
// Finally apply the map to the MapApp
|
||||||
|
app.setMap('europe', imageMap)
|
||||||
|
|
||||||
|
// The app requires a map before beeing able to run.
|
||||||
|
// So start the app here.
|
||||||
|
app.setup().run()
|
||||||
|
|
||||||
|
for (let [key, val] of Object.entries(app.mapList.maps)) {
|
||||||
|
let mapBtn = document.createElement("button")
|
||||||
|
mapBtn.innerText = key
|
||||||
|
mapBtn.addEventListener("click", () => {
|
||||||
|
app.mapLayer.changeMap(val)
|
||||||
|
})
|
||||||
|
mapControl.appendChild(mapBtn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [key, val] of Object.entries(capitals)) {
|
||||||
|
let cityBtn = document.createElement("button")
|
||||||
|
cityBtn.innerText = key
|
||||||
|
cityBtn.addEventListener("click", () => {
|
||||||
|
app.mapLayer.map.moveTo(val)
|
||||||
|
})
|
||||||
|
cityControl.appendChild(cityBtn)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import { DeepZoomMap } from './map.js'
|
import { DeepZoomMap } from './map.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MapView class is responsible for a consistent map view.
|
* The MapViewport class is responsible for a consistent map view.
|
||||||
* It is aware of the current viewposition, the scale and viewport.
|
* It is aware of the current viewposition, the scale and viewport.
|
||||||
* It ensures, that maps can be changed, without the user noticing it.
|
* It ensures, that maps can be changed, without the user noticing it.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default class MapView {
|
export default class MapViewport {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} [focus = {x:0, y:0}] - Defines the startup focuspoint of the app.
|
* @param {object} [focus = {x:0, y:0}] - Defines the startup focuspoint of the app.
|
||||||
* @param {number} [zoom = 0] - Defines the startup zoom of the app. Note that this is just a request.
|
* @param {number} [zoom = 0] - Defines the startup zoom of the app. Note that this is just a request.
|
||||||
* The MapView will prioritize a full scale app, than displaying the demanded zoom factor
|
* The MapViewport will prioritize a full scale app, than displaying the demanded zoom factor
|
||||||
*/
|
*/
|
||||||
constructor({ focus = null, zoom = null, viewport = { min: { x: -85, y: -180 }, max: { x: 85, y: 180 } } } = {}) {
|
constructor({ focus = null, zoom = null, viewport = { min: { x: -85, y: -180 }, max: { x: 85, y: 180 } } } = {}) {
|
||||||
this.viewport = viewport
|
this.viewport = viewport
|
||||||
@@ -20,32 +20,71 @@ export default class MapView {
|
|||||||
this.referenceHeight = 256
|
this.referenceHeight = 256
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current focus point as map coordinates.
|
||||||
|
*
|
||||||
|
* @member {CoordinatePoint}
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
get focus() {
|
get focus() {
|
||||||
return this._focus
|
return this._focus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current zoom distance.
|
||||||
|
* On DeepZoomMaps this is equal to the zoom level.
|
||||||
|
*
|
||||||
|
* @member {number}
|
||||||
|
* @readonly
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
get zoom() {
|
get zoom() {
|
||||||
return this._zoom
|
return this._zoom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the current view to a map.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {GeoMap} map - Map the viewport should be applied to.
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
apply(map) {
|
apply(map) {
|
||||||
map.moveTo(this._focus, this._zoom)
|
map.moveTo(this._focus, this._zoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
transformed(map) {
|
/**
|
||||||
|
* Update the focus point and zoom according to the map.
|
||||||
|
* This is commonly called when the map is transformed.
|
||||||
|
*
|
||||||
|
* @param {GeoMap} map - Map to update.
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
|
update(map) {
|
||||||
this.updateZoom(map)
|
this.updateZoom(map)
|
||||||
this.updateFocusPoint(map)
|
this.updateFocusPoint(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition(map) {
|
/**
|
||||||
this.updateFocusPoint(map)
|
* Updates the focus point.
|
||||||
this.updateZoom(map)
|
* This is automatically called when calling update.
|
||||||
}
|
*
|
||||||
|
* @param {GeoMap} map
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
updateFocusPoint(map) {
|
updateFocusPoint(map) {
|
||||||
const frame = map.getFrame()
|
const frame = map.getFrame()
|
||||||
this._focus = this.coordinatesFromWindowPoint(map, frame.localCenter)
|
this._focus = this.coordinatesFromWindowPoint(map, frame.localCenter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the zoom.
|
||||||
|
* This is automatically called when calling update.
|
||||||
|
*
|
||||||
|
* @param {GeoMap} map
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
updateZoom(map) {
|
updateZoom(map) {
|
||||||
/**
|
/**
|
||||||
* TODO: This relies on the fact, that all maps have the same tileSize,
|
* TODO: This relies on the fact, that all maps have the same tileSize,
|
||||||
@@ -57,6 +96,16 @@ export default class MapView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a position on the map to a position in the window.
|
||||||
|
*
|
||||||
|
* Inverse of windowPointToMapPoint.
|
||||||
|
*
|
||||||
|
* @param {GeoMap} map - Map to calculate the position on.
|
||||||
|
* @param {Point} point - Position on the map in pixels.
|
||||||
|
* @returns {Point} - Pixel position in the window.
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
mapPointToWindowPoint(map, point) {
|
mapPointToWindowPoint(map, point) {
|
||||||
let windowPoint = { x: 0, y: 0 }
|
let windowPoint = { x: 0, y: 0 }
|
||||||
|
|
||||||
@@ -76,6 +125,16 @@ export default class MapView {
|
|||||||
return windowPoint
|
return windowPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms in the window to a position on the map.
|
||||||
|
*
|
||||||
|
* Inverse of mapPointToWindowPoint(map, point) {.
|
||||||
|
*
|
||||||
|
* @param {GeoMap} map - Map to calculate the position on.
|
||||||
|
* @param {Point} point -Pixel position in the window.
|
||||||
|
* @returns {Point} - Position on the map in pixels.
|
||||||
|
* @memberof MapViewport
|
||||||
|
*/
|
||||||
windowPointToMapPoint(map, point) {
|
windowPointToMapPoint(map, point) {
|
||||||
let pointOnMap = { x: 0, y: 0 }
|
let pointOnMap = { x: 0, y: 0 }
|
||||||
if (map['image'] && map.image['parent']) {
|
if (map['image'] && map.image['parent']) {
|
||||||
@@ -111,7 +170,7 @@ export default class MapView {
|
|||||||
y: position.y / (map.height * map.scatter.scale)
|
y: position.y / (map.height * map.scatter.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinates = map.mapdata.toCoordinates(normalized)
|
let coordinates = map.mapProjection.toCoordinates(normalized)
|
||||||
|
|
||||||
return coordinates
|
return coordinates
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" class="dark-mode">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
<script src="../../../dist/iwmlib.js"></script>
|
<script src="../../../dist/iwmlib.js"></script>
|
||||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||||
|
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="../../../assets/icons/map.png">
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.inline-showcase {
|
.inline-showcase {
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
|
|
||||||
<body onload="Doctest.run()">
|
<body onload="Doctest.run()">
|
||||||
<h1 class="title">Overlay</h1>
|
<h1 class="title">Overlay</h1>
|
||||||
|
<!-- <a href="../../../" class="Documentation"></a> -->
|
||||||
<p class="description">
|
<p class="description">
|
||||||
The overlayclass creates a convenient way to create and design
|
The overlayclass creates a convenient way to create and design
|
||||||
complex map overlays.
|
complex map overlays.
|
||||||
@@ -46,7 +49,7 @@
|
|||||||
coordsLogging: true
|
coordsLogging: true
|
||||||
})
|
})
|
||||||
var osmworld = '../assets/maps/osm/0/0/0.png'
|
var osmworld = '../assets/maps/osm/0/0/0.png'
|
||||||
let worlOSMData = new MapData(new Projection.Mercator())
|
let worlOSMData = new MapProjection(new Projection.Mercator())
|
||||||
|
|
||||||
|
|
||||||
function setupMap(textures) {
|
function setupMap(textures) {
|
||||||
@@ -108,17 +111,22 @@
|
|||||||
|
|
||||||
let exampleOverlayJSON = {
|
let exampleOverlayJSON = {
|
||||||
icon: '../../../assets/icons/place.png',
|
icon: '../../../assets/icons/place.png',
|
||||||
iconColor: '0x000000',
|
iconColor: "0x35aaea",
|
||||||
iconAnchor: { x: 0.5, y: 1 },
|
iconAnchor: { x: 0.5, y: 1 },
|
||||||
|
size: 5,
|
||||||
scale: 0.2,
|
scale: 0.2,
|
||||||
color: '0xFF00FF',
|
disabledColor: 0x000000,
|
||||||
fillAlpha: 0,
|
disabledIconColor: 0xCCCCCC,
|
||||||
|
disabledScale: 0.5,
|
||||||
|
color: '0x3FA7EE',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
name: 'Abidjan',
|
name: 'Custom Icon',
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
icon: '../../../assets/icons//beenhere.png',
|
icon: '../../../assets/icons/beenhere.png',
|
||||||
iconColor: 0x00ff00,
|
iconColor: 0x00ff00,
|
||||||
|
iconAlpha: 0.5,
|
||||||
|
size: 0,
|
||||||
labelVerticalAlignment: "underneath",
|
labelVerticalAlignment: "underneath",
|
||||||
label: 'Abidjan',
|
label: 'Abidjan',
|
||||||
location: {
|
location: {
|
||||||
@@ -126,17 +134,19 @@
|
|||||||
y: -4.006472
|
y: -4.006472
|
||||||
},
|
},
|
||||||
information:
|
information:
|
||||||
'... der größte städtische Ballungsraum der Elfenbeinküste.'
|
'Here a custom icon is used. It overrides the icon setting in the global section.'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Berlin',
|
name: 'Berlin',
|
||||||
|
label: "enabled",
|
||||||
|
disabledLabel: "disabled",
|
||||||
location: {
|
location: {
|
||||||
x: 52.52543,
|
x: 52.52543,
|
||||||
y: 13.385291
|
y: 13.385291
|
||||||
},
|
},
|
||||||
information:
|
information:
|
||||||
'... ist die Bundeshauptstadt der Bundesrepublik Deutschland.'
|
'... ist die Bundeshauptstadt der Bundesrepublik Deutschland.',
|
||||||
|
enabled: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Canberra',
|
name: 'Canberra',
|
||||||
@@ -156,7 +166,7 @@
|
|||||||
y: 18.416962
|
y: 18.416962
|
||||||
},
|
},
|
||||||
information:
|
information:
|
||||||
'... ist eine Hafenstadt an der Südwestküste Südafrikas auf einer Halbinsel, die vom beeindruckenden Tafelberg dominiert wird.'
|
`This item adjusts it's size according to the map.`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Moskau',
|
name: 'Moskau',
|
||||||
@@ -190,7 +200,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Tokio',
|
name: 'Tokio',
|
||||||
|
type: "factory",
|
||||||
|
label: "factory",
|
||||||
location: {
|
location: {
|
||||||
x: 35.696278,
|
x: 35.696278,
|
||||||
y: 139.731366
|
y: 139.731366
|
||||||
@@ -220,6 +231,7 @@
|
|||||||
|
|
||||||
function texturesLoaded(textures) {
|
function texturesLoaded(textures) {
|
||||||
|
|
||||||
|
|
||||||
/** When all textures are loaded .... */
|
/** When all textures are loaded .... */
|
||||||
setupMap(textures)
|
setupMap(textures)
|
||||||
|
|
||||||
@@ -231,6 +243,27 @@
|
|||||||
let cleaner = null
|
let cleaner = null
|
||||||
const vanishingTime = 1000
|
const vanishingTime = 1000
|
||||||
|
|
||||||
|
// Factories must return a geographics object.
|
||||||
|
Overlay.createFactory("factory", (item) => {
|
||||||
|
|
||||||
|
// This is applied to every item in the overlay that has
|
||||||
|
// the type factory'
|
||||||
|
|
||||||
|
|
||||||
|
let geographics = new GeoPoint(item.location)
|
||||||
|
|
||||||
|
geographics.drawHandler.add((graphics) => {
|
||||||
|
graphics.beginFill(item.color, item.fillAlpha)
|
||||||
|
graphics.drawRect(0, 0, 10, 10)
|
||||||
|
})
|
||||||
|
|
||||||
|
let text = new PIXI.Text(item.name, {fontSize: 5})
|
||||||
|
geographics.graphics.addChild(text)
|
||||||
|
|
||||||
|
|
||||||
|
return geographics
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* The actual PIXI elements are created when the overlay.create() is called.
|
* The actual PIXI elements are created when the overlay.create() is called.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GeoLayer } from './geolayer.js'
|
import { GeoLayer } from './geolayer.js'
|
||||||
import { GeoPoint, GeoMultiShape } from './geographics.js'
|
import { GeoPoint, GeoMultiShape, GeoGraphics } from './geographics.js'
|
||||||
import GeoJson from './geojson.js'
|
import GeoJson from './geojson.js'
|
||||||
|
|
||||||
import Popup from '../popup.js'
|
import Popup from '../popup.js'
|
||||||
@@ -11,46 +11,83 @@ import Popup from '../popup.js'
|
|||||||
*
|
*
|
||||||
* It's highly configurable and adaptable to a variety of scenarios.
|
* It's highly configurable and adaptable to a variety of scenarios.
|
||||||
*
|
*
|
||||||
*/
|
* @export
|
||||||
|
* @class Overlay
|
||||||
export default class Overlay {
|
|
||||||
/**
|
|
||||||
*Creates an instance of Overlay.
|
|
||||||
* @param {*} [{
|
|
||||||
* name = "unnamed", {string}
|
|
||||||
* connector = false,
|
|
||||||
* connectorType = "line",
|
|
||||||
* location = null,
|
|
||||||
* label = false,
|
|
||||||
* labelType = null,
|
|
||||||
* labelLocation = null,
|
|
||||||
* labelAlignment = "center",
|
|
||||||
* labelVerticalAlign = "underneath",
|
|
||||||
* labelTarget = null,
|
|
||||||
* shape = "geometry", {string} - Defines the shape to be used: geometry, circle, rectangle
|
|
||||||
* geometry = null,
|
|
||||||
* geometryType = "point",
|
|
||||||
* geometryFallback = "circle",
|
|
||||||
* informationPopup = "infocard",
|
|
||||||
*
|
*
|
||||||
* }={}]
|
*
|
||||||
* @memberof Overlay
|
* @param {object} options
|
||||||
|
* @param {object} options.name Name of the item.
|
||||||
|
* @param {object} options.borderColor
|
||||||
|
* @param {object} options.borderThickness
|
||||||
|
* @param {object} options.enabled Determines if enabled, disabled when false.
|
||||||
|
* @param {object} options.labelScale
|
||||||
|
* @param {object} options.location
|
||||||
|
* @param {object} options.label
|
||||||
|
* @param {object} options.labelType
|
||||||
|
* @param {object} options.labelLocation
|
||||||
|
* @param {object} options.labelAlignment
|
||||||
|
* @param {object} options.labelVerticalAlignment
|
||||||
|
* @param {object} options.labelSpacing
|
||||||
|
* @param {object} options.labelTarget
|
||||||
|
* @param {object} options.geometry
|
||||||
|
* @param {object} options.information
|
||||||
|
* @param {object} options.informationPath
|
||||||
|
* @param {object} options.informationType
|
||||||
|
* @param {object} options.icon
|
||||||
|
* @param {object} options.iconAlpha
|
||||||
|
* @param {object} options.iconAnchor
|
||||||
|
* @param {object} options.iconColor
|
||||||
|
* @param {object} options.iconScale
|
||||||
|
* @param {object} options.iconOffset
|
||||||
|
* @param {object} options.items
|
||||||
|
* @param {object} options.color Color of te point.
|
||||||
|
* @param {object} options.fillAlpha FillAlpha of the point.
|
||||||
|
* @param {object} options.size Size of the point.
|
||||||
|
* @param {object} options.scale Determines the scale of the graphics.
|
||||||
|
* @param {object} options.rescale Rescales the graphics relative to the map, that they keep their original scale. Only works for the entire overlay atm. Therefore must be set in the global param eters and not inside the children.
|
||||||
|
* @param {object} options.popoverOffset
|
||||||
|
* @param {object} options.zoomVisibility
|
||||||
|
* @param {object} options.labelMultiLineAlign
|
||||||
|
* @param {object} options.labelBreakWords
|
||||||
|
* @param {object} options.labelDropShadow
|
||||||
|
* @param {object} options.labelDropShadowAlpha
|
||||||
|
* @param {object} options.labelDropShadowAngle
|
||||||
|
* @param {object} options.labelDropShadowBlur
|
||||||
|
* @param {object} options.labelDropShadowColor
|
||||||
|
* @param {object} options.labelDropShadowDistance
|
||||||
|
* @param {object} options.fontColor
|
||||||
|
* @param {object} options.fontFamily
|
||||||
|
* @param {object} options.fontSize
|
||||||
|
* @param {object} options.fontStyle
|
||||||
|
* @param {object} options.fontWeight
|
||||||
|
* @param {object} options.labelStroke
|
||||||
|
* @param {object} options.labelStrokeThickness
|
||||||
|
* @param {object} options.wordWrap
|
||||||
|
* @param {object} options.wordWrapWidth
|
||||||
|
* @param {object} options.labelFill
|
||||||
|
* @param {object} options.labelFillGradientType
|
||||||
|
* @param {object} options.labelFillGradientStops
|
||||||
|
* @param {object} options.fontVariant
|
||||||
|
* @param {object} options.labelLeading
|
||||||
|
* @param {object} options.letterSpacing
|
||||||
|
* @param {object} options.labelLineHeight
|
||||||
|
* @param {object} options.labelLineJoin
|
||||||
|
* @param {object} options.labelMiterLimit
|
||||||
|
* @param {object} options.labelPadding
|
||||||
|
* @param {object} options.labelTrim
|
||||||
|
* @param {object} options.textBaseline
|
||||||
|
* @param {object} options.labelWhiteSpace
|
||||||
*/
|
*/
|
||||||
constructor(opts = {}) {
|
export default class Overlay {
|
||||||
|
constructor(options = {}) {
|
||||||
let defaultTextStyle = new PIXI.TextStyle()
|
let defaultTextStyle = new PIXI.TextStyle()
|
||||||
|
|
||||||
Object.assign(
|
let defaultOptions = {
|
||||||
this,
|
|
||||||
{
|
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
name: 'unnamed',
|
name: 'unnamed',
|
||||||
|
|
||||||
borderColor: 0x000000,
|
borderColor: 0x000000,
|
||||||
borderThickness: 5,
|
borderThickness: 5,
|
||||||
|
|
||||||
disabledAlpha: 1,
|
|
||||||
disabledColor: 0xaa1111,
|
|
||||||
disabledBorderColor: 0x000000,
|
|
||||||
enabled: true,
|
enabled: true,
|
||||||
labelScale: 1,
|
labelScale: 1,
|
||||||
location: null,
|
location: null,
|
||||||
@@ -58,7 +95,7 @@ export default class Overlay {
|
|||||||
labelType: null,
|
labelType: null,
|
||||||
labelLocation: null,
|
labelLocation: null,
|
||||||
labelAlignment: 'center',
|
labelAlignment: 'center',
|
||||||
labelVerticalAlign: 'underneath',
|
labelVerticalAlignment: 'underneath',
|
||||||
labelSpacing: 10,
|
labelSpacing: 10,
|
||||||
labelTarget: null,
|
labelTarget: null,
|
||||||
geometry: null,
|
geometry: null,
|
||||||
@@ -114,15 +151,76 @@ export default class Overlay {
|
|||||||
labelTrim: defaultTextStyle.trim,
|
labelTrim: defaultTextStyle.trim,
|
||||||
textBaseline: defaultTextStyle.textBaseline,
|
textBaseline: defaultTextStyle.textBaseline,
|
||||||
labelWhiteSpace: defaultTextStyle.whiteSpace
|
labelWhiteSpace: defaultTextStyle.whiteSpace
|
||||||
},
|
|
||||||
opts
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultOptions = this.addDisabled(defaultOptions)
|
||||||
|
|
||||||
|
console.log('DISABLED VERTICALA.', defaultOptions.disabledLabelVerticalAlignment)
|
||||||
|
|
||||||
|
options = this.addDisabled(options)
|
||||||
|
|
||||||
|
options = Object.assign({}, defaultOptions, options)
|
||||||
|
|
||||||
|
Object.assign(this, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some parameters shall not have a disabled option.
|
||||||
|
* These are defined here.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
|
get excludedDisableParameters() {
|
||||||
|
return ['items', 'rescale', 'name', 'type', 'enabled']
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the normal properties to the disabled version of the property,
|
||||||
|
* while conserving already set disabled properties.
|
||||||
|
*
|
||||||
|
* @param {*} options
|
||||||
|
* @returns {object} - Returns the modified options object.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
|
addDisabled(options) {
|
||||||
|
for (let [key, value] of Object.entries(options)) {
|
||||||
|
if (this.excludedDisableParameters.indexOf(key) == -1) {
|
||||||
|
let disabledProperty = this.toDisabledPropertyString(key)
|
||||||
|
if (options[disabledProperty] == undefined) {
|
||||||
|
options[disabledProperty] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Textures need to be loaded by the app. Texture parameters return all parameters that need to be evaluated for textures.
|
||||||
|
* @readonly
|
||||||
|
* @member {array}
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
get textureParameters() {
|
get textureParameters() {
|
||||||
return ['icon']
|
const textureParameters = ['icon']
|
||||||
|
|
||||||
|
textureParameters.forEach(textureParameter => {
|
||||||
|
textureParameters.push(this.toDisabledPropertyString(textureParameter))
|
||||||
|
})
|
||||||
|
|
||||||
|
return textureParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The required textures are saved inside the single items.
|
||||||
|
* Their texture string gets replaced by a texture object
|
||||||
|
* containing the path and the texture.
|
||||||
|
*
|
||||||
|
* @param {*} parameter
|
||||||
|
* @param {*} key
|
||||||
|
* @param {*} path
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
setTexture(parameter, key, path) {
|
setTexture(parameter, key, path) {
|
||||||
let obj = (this[parameter] = {})
|
let obj = (this[parameter] = {})
|
||||||
obj._key = key
|
obj._key = key
|
||||||
@@ -150,6 +248,14 @@ export default class Overlay {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively calls a function on child items.
|
||||||
|
*
|
||||||
|
* @param {*} parameter
|
||||||
|
* @param {*} func
|
||||||
|
* @param {*} [obj=null]
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
apply(parameter, func, obj = null) {
|
apply(parameter, func, obj = null) {
|
||||||
if (obj == null) return
|
if (obj == null) return
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
@@ -187,13 +293,21 @@ export default class Overlay {
|
|||||||
adjustItems = null,
|
adjustItems = null,
|
||||||
cleanupItems = null
|
cleanupItems = null
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'
|
console.log(this)
|
||||||
|
|
||||||
|
const name = this.name
|
||||||
|
? this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'
|
||||||
|
: 'Unnamed Overlay'
|
||||||
|
|
||||||
let geoLayer = new GeoLayer(new PIXI.Container(), { name })
|
let geoLayer = new GeoLayer(new PIXI.Container(), { name })
|
||||||
geoLayer.visibility = this.zoomVisibility
|
geoLayer.visibility = this.zoomVisibility
|
||||||
|
|
||||||
if (this.rescale) geoLayer.rescale = this.rescale
|
if (this.rescale) geoLayer.rescale = this.rescale
|
||||||
this.items.forEach(item => {
|
this.items.forEach(item => {
|
||||||
if (!excludeItems(item)) {
|
if (!excludeItems(item)) {
|
||||||
|
//Copies all values to a disabled state.
|
||||||
|
item = this.addDisabled(item)
|
||||||
|
|
||||||
if (adjustItems) {
|
if (adjustItems) {
|
||||||
adjustItems(item)
|
adjustItems(item)
|
||||||
}
|
}
|
||||||
@@ -208,11 +322,60 @@ export default class Overlay {
|
|||||||
})
|
})
|
||||||
return geoLayer
|
return geoLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to pick a property or disabled property using an enabled parameter.
|
||||||
|
*
|
||||||
|
* @param {*} item
|
||||||
|
* @param {*} property
|
||||||
|
* @param {boolean} [enabled=true]
|
||||||
|
* @returns {any} - Returns the picked item property.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
|
pickItemProperty(item, property, enabled = true) {
|
||||||
|
return enabled ? this.getItemProperty(item, property) : this.getDisabledItemProperty(item, property)
|
||||||
|
}
|
||||||
|
|
||||||
|
toDisabledPropertyString(propertyName) {
|
||||||
|
const prefix = 'disabled'
|
||||||
|
return prefix + propertyName[0].toUpperCase() + propertyName.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get's the disabled version of the property as long as it is not excluded.
|
||||||
|
*
|
||||||
|
* @param {*} item
|
||||||
|
* @param {*} property
|
||||||
|
* @returns {any} - Returns the picked item property.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
|
getDisabledItemProperty(item, property) {
|
||||||
|
if (this.excludedDisableParameters.indexOf(property) === -1) {
|
||||||
|
property = this.toDisabledPropertyString(property)
|
||||||
|
}
|
||||||
|
const propertyValue = this.getItemProperty(item, property)
|
||||||
|
return propertyValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to get the infromation from an overlay item.
|
||||||
|
* If the item does not contain the property, the overlay definition will be used.
|
||||||
|
* When the overlay definition is not set, the default value is used.
|
||||||
|
*
|
||||||
|
* @param {OverlayItem} item - Item to get the informations from.
|
||||||
|
* @param {string} property - Name of the property.
|
||||||
|
* @returns {any} - Returns the picked item property.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
getItemProperty(item, property) {
|
getItemProperty(item, property) {
|
||||||
let propertyValue = null
|
let propertyValue = null
|
||||||
const propertyExistsOnItem = item[property] !== undefined
|
const propertyExistsOnItem = item[property] !== undefined
|
||||||
const propertyExistsOnOverlay = this[property] !== undefined
|
const propertyExistsOnOverlay = this[property] !== undefined
|
||||||
|
|
||||||
|
if (property == 'disabledLabelVerticalAlignment') {
|
||||||
|
console.log(this)
|
||||||
|
console.log(this['disabledLabelVerticalAlignment'], propertyExistsOnItem, propertyExistsOnOverlay)
|
||||||
|
}
|
||||||
if (propertyExistsOnItem) propertyValue = item[property]
|
if (propertyExistsOnItem) propertyValue = item[property]
|
||||||
else if (propertyExistsOnOverlay) propertyValue = this[property]
|
else if (propertyExistsOnOverlay) propertyValue = this[property]
|
||||||
else {
|
else {
|
||||||
@@ -229,6 +392,15 @@ export default class Overlay {
|
|||||||
else return false
|
else return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An overlay can have a reference to another file.
|
||||||
|
* That single overlays are more easy to maintain.
|
||||||
|
*
|
||||||
|
* @param {*} item
|
||||||
|
* @param {*} property
|
||||||
|
* @returns {any} - Returns the reference as object or the property.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
_resolveReference(item, property) {
|
_resolveReference(item, property) {
|
||||||
if (this._isReference(property)) {
|
if (this._isReference(property)) {
|
||||||
let referencedProperty = property['@property']
|
let referencedProperty = property['@property']
|
||||||
@@ -281,18 +453,30 @@ export default class Overlay {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a geographic for each item.
|
||||||
|
* By default it uses the regular routine but you may
|
||||||
|
* specify a factory for the defined type.
|
||||||
|
*
|
||||||
|
* @param {*} item
|
||||||
|
* @param {*} [informationCallback=null]
|
||||||
|
* @returns {GeoGraphics} - Returns the created geographics.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
createItem(item, informationCallback = null) {
|
createItem(item, informationCallback = null) {
|
||||||
let geographics
|
let geographics
|
||||||
|
|
||||||
|
let type = this.getItemProperty(item, 'type')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use a factory to draw the items, if a type is specified.
|
* Use a factory to draw the items, if a type is specified.
|
||||||
*/
|
*/
|
||||||
if (this.type != 'auto') {
|
if (type != 'auto') {
|
||||||
let geographicsFactory = Overlay.requestFactory(this.type)
|
let geographicsFactory = Overlay.requestFactory(type)
|
||||||
if (!geographicsFactory)
|
if (!geographicsFactory)
|
||||||
console.error(
|
console.error(
|
||||||
'Invalid Overlay Mode: ' +
|
'Invalid Overlay Mode: ' +
|
||||||
this.type +
|
type +
|
||||||
'. Fallback to auto mode. Overlaymodes must be registeres beforehand. Valid modes are: ' +
|
'. Fallback to auto mode. Overlaymodes must be registeres beforehand. Valid modes are: ' +
|
||||||
Overlay.listFactories().join(',') +
|
Overlay.listFactories().join(',') +
|
||||||
'.'
|
'.'
|
||||||
@@ -318,84 +502,100 @@ export default class Overlay {
|
|||||||
this._drawRoutine(geographics, item, informationCallback)
|
this._drawRoutine(geographics, item, informationCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._drawLabel(item, geographics)
|
let label = this._createLabel(item, geographics)
|
||||||
|
if (label != null && geographics != null) {
|
||||||
|
console.log(geographics)
|
||||||
|
|
||||||
|
geographics.graphics.addChild(label)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return geographics
|
return geographics
|
||||||
}
|
}
|
||||||
|
|
||||||
_drawLabel(item, geographics) {
|
/**
|
||||||
let label = this.getItemProperty(item, 'label')
|
*
|
||||||
if (label) {
|
* Draws a label that is shown next to the item on the map.
|
||||||
let textStyle = this._gatherFontStyle(item)
|
*
|
||||||
let text = new PIXI.Text(label, textStyle)
|
* @param {*} item
|
||||||
|
* @returns {PIXI.Text} - Returns the created label or null.
|
||||||
|
* @memberof Overlay
|
||||||
|
*/
|
||||||
|
_createLabel(item) {
|
||||||
|
let enabled = this.getItemProperty(item, 'enabled')
|
||||||
|
let labelText = this.pickItemProperty(item, 'label', enabled)
|
||||||
|
let label = null
|
||||||
|
|
||||||
let labelScale = this.getItemProperty(item, 'labelScale')
|
if (labelText) {
|
||||||
text.scale.set(labelScale, labelScale)
|
let textStyle = this._gatherFontStyle(item)
|
||||||
|
label = new PIXI.Text(labelText, textStyle)
|
||||||
|
|
||||||
|
let labelScale = this.pickItemProperty(item, 'labelScale', enabled)
|
||||||
|
label.scale.set(labelScale, labelScale)
|
||||||
|
|
||||||
let position = new PIXI.Point()
|
let position = new PIXI.Point()
|
||||||
|
|
||||||
let align = this.getItemProperty(item, 'labelAlignment')
|
let align = this.pickItemProperty(item, 'labelAlignment', enabled)
|
||||||
if (align == 'left');
|
if (align == 'left');
|
||||||
else if (align == 'center') position.set(text.position.x - text.width / 2, text.position.y)
|
else if (align == 'center') position.set(label.position.x - label.width / 2, label.position.y)
|
||||||
else if (align == 'right') position.set(text.position.x - text.width, text.position.y)
|
else if (align == 'right') position.set(label.position.x - label.width, label.position.y)
|
||||||
else this._logPropertyNotImplemented('labelAlignment', align)
|
else this._logPropertyNotImplemented('labelAlignment', align)
|
||||||
|
|
||||||
let verticalAlign = this.getItemProperty(item, 'labelVerticalAlignment')
|
let verticalAlign = this.pickItemProperty(item, 'labelVerticalAlignment', enabled)
|
||||||
if (verticalAlign == 'underneath') {
|
if (verticalAlign == 'underneath') {
|
||||||
let size = this.getItemProperty(item, 'size')
|
let size = this.pickItemProperty(item, 'size', enabled)
|
||||||
let scale = this.getItemProperty(item, 'scale')
|
let scale = this.pickItemProperty(item, 'scale', enabled)
|
||||||
|
|
||||||
let labelSpacing = this.getItemProperty(item, 'labelSpacing')
|
let labelSpacing = this.pickItemProperty(item, 'labelSpacing', enabled)
|
||||||
|
|
||||||
position.y += size * scale + labelSpacing
|
position.y += size * scale + labelSpacing
|
||||||
} else if (verticalAlign == 'above') {
|
} else if (verticalAlign == 'above') {
|
||||||
let size = this.getItemProperty(item, 'size')
|
let size = this.pickItemProperty(item, 'size', enabled)
|
||||||
let scale = this.getItemProperty(item, 'scale')
|
let scale = this.pickItemProperty(item, 'scale', enabled)
|
||||||
|
|
||||||
let labelSpacing = this.getItemProperty(item, 'labelSpacing')
|
let labelSpacing = this.pickItemProperty(item, 'labelSpacing', enabled)
|
||||||
|
|
||||||
position.y -= size * scale + text.height + labelSpacing
|
position.y -= size * scale + label.height + labelSpacing
|
||||||
} else this._logPropertyNotImplemented('labelVerticalAlignment', verticalAlign)
|
} else this._logPropertyNotImplemented('labelVerticalAlignment', verticalAlign)
|
||||||
|
|
||||||
text.position.set(position.x, position.y)
|
label.position.set(position.x, position.y)
|
||||||
|
|
||||||
geographics.graphics.addChild(text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
_gatherFontStyle(item) {
|
_gatherFontStyle(item) {
|
||||||
|
const enabled = this.getItemProperty(item, 'enabled')
|
||||||
return {
|
return {
|
||||||
align: this.getItemProperty(item, 'labelMultiLineAlign'),
|
align: this.pickItemProperty(item, 'labelMultiLineAlign', enabled),
|
||||||
breakWords: this.getItemProperty(item, 'labelBreakWords'),
|
breakWords: this.pickItemProperty(item, 'labelBreakWords', enabled),
|
||||||
dropShadow: this.getItemProperty(item, 'labelDropShadow'),
|
dropShadow: this.pickItemProperty(item, 'labelDropShadow', enabled),
|
||||||
dropShadowAlpha: this.getItemProperty(item, 'labelDropShadowAlpha'),
|
dropShadowAlpha: this.pickItemProperty(item, 'labelDropShadowAlpha', enabled),
|
||||||
dropShadowAngle: this.getItemProperty(item, 'labelDropShadowAngle'),
|
dropShadowAngle: this.pickItemProperty(item, 'labelDropShadowAngle', enabled),
|
||||||
dropShadowBlur: this.getItemProperty(item, 'labelDropShadowBlur'),
|
dropShadowBlur: this.pickItemProperty(item, 'labelDropShadowBlur', enabled),
|
||||||
dropShadowColor: this.getItemProperty(item, 'labelDropShadowColor'),
|
dropShadowColor: this.pickItemProperty(item, 'labelDropShadowColor', enabled),
|
||||||
dropShadowDistance: this.getItemProperty(item, 'labelDropShadowDistance'),
|
dropShadowDistance: this.pickItemProperty(item, 'labelDropShadowDistance', enabled),
|
||||||
fontFamily: this.getItemProperty(item, 'fontFamily'),
|
fontFamily: this.pickItemProperty(item, 'fontFamily', enabled),
|
||||||
fontSize: this.getItemProperty(item, 'fontSize'),
|
fontSize: this.pickItemProperty(item, 'fontSize', enabled),
|
||||||
fontStyle: this.getItemProperty(item, 'fontStyle'),
|
fontStyle: this.pickItemProperty(item, 'fontStyle', enabled),
|
||||||
fontWeight: this.getItemProperty(item, 'fontWeight'),
|
fontWeight: this.pickItemProperty(item, 'fontWeight', enabled),
|
||||||
stroke: this.getItemProperty(item, 'labelStroke'),
|
stroke: this.pickItemProperty(item, 'labelStroke', enabled),
|
||||||
strokeThickness: this.getItemProperty(item, 'labelStrokeThickness'),
|
strokeThickness: this.pickItemProperty(item, 'labelStrokeThickness', enabled),
|
||||||
wordWrap: this.getItemProperty(item, 'wordWrap'),
|
wordWrap: this.pickItemProperty(item, 'wordWrap', enabled),
|
||||||
wordWrapWidth: this.getItemProperty(item, 'wordWrapWidth'),
|
wordWrapWidth: this.pickItemProperty(item, 'wordWrapWidth', enabled),
|
||||||
|
fill: this.pickItemProperty(item, 'labelFill', enabled),
|
||||||
fill: this.getItemProperty(item, 'labelFill'),
|
fillGradientType: this.pickItemProperty(item, 'labelFillGradientType', enabled),
|
||||||
fillGradientType: this.getItemProperty(item, 'labelFillGradientType'),
|
fillGradientStops: this.pickItemProperty(item, 'labelFillGradientStops', enabled),
|
||||||
fillGradientStops: this.getItemProperty(item, 'labelFillGradientStops'),
|
fontVariant: this.pickItemProperty(item, 'fontVariant', enabled),
|
||||||
fontVariant: this.getItemProperty(item, 'fontVariant'),
|
leading: this.pickItemProperty(item, 'labelLeading', enabled),
|
||||||
leading: this.getItemProperty(item, 'labelLeading'),
|
letterSpacing: this.pickItemProperty(item, 'letterSpacing', enabled),
|
||||||
letterSpacing: this.getItemProperty(item, 'letterSpacing'),
|
lineHeight: this.pickItemProperty(item, 'labelLineHeight', enabled),
|
||||||
lineHeight: this.getItemProperty(item, 'labelLineHeight'),
|
lineJoin: this.pickItemProperty(item, 'labelLineJoin', enabled),
|
||||||
lineJoin: this.getItemProperty(item, 'labelLineJoin'),
|
miterLimit: this.pickItemProperty(item, 'labelMiterLimit', enabled),
|
||||||
miterLimit: this.getItemProperty(item, 'labelMiterLimit'),
|
padding: this.pickItemProperty(item, 'labelPadding', enabled),
|
||||||
padding: this.getItemProperty(item, 'labelPadding'),
|
trim: this.pickItemProperty(item, 'labelTrim', enabled),
|
||||||
trim: this.getItemProperty(item, 'labelTrim'),
|
textBaseline: this.pickItemProperty(item, 'textBaseline', enabled),
|
||||||
textBaseline: this.getItemProperty(item, 'textBaseline'),
|
whiteSpace: this.pickItemProperty(item, 'labelWhiteSpace', enabled)
|
||||||
whiteSpace: this.getItemProperty(item, 'labelWhiteSpace')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,25 +640,27 @@ export default class Overlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_createIcon(geographics, item) {
|
_createIcon(geographics, item) {
|
||||||
let icon = this.getItemProperty(item, 'icon')
|
let enabled = this.getItemProperty(item, 'enabled')
|
||||||
|
let icon = this.pickItemProperty(item, 'icon', enabled)
|
||||||
|
|
||||||
if (icon) {
|
if (icon) {
|
||||||
if (icon.texture) {
|
if (icon.texture) {
|
||||||
let sprite = new PIXI.Sprite(icon.texture)
|
let sprite = new PIXI.Sprite(icon.texture)
|
||||||
|
|
||||||
const iconAnchor = this.getItemProperty(item, 'iconAnchor')
|
const iconAnchor = this.pickItemProperty(item, 'iconAnchor', enabled)
|
||||||
sprite.anchor.set(iconAnchor.x, iconAnchor.y)
|
sprite.anchor.set(iconAnchor.x, iconAnchor.y)
|
||||||
|
|
||||||
const iconScale = this.getItemProperty(item, 'iconScale')
|
const iconScale = this.pickItemProperty(item, 'iconScale', enabled)
|
||||||
if (iconScale) sprite.scale.set(iconScale, iconScale)
|
if (iconScale) sprite.scale.set(iconScale, iconScale)
|
||||||
|
|
||||||
const iconOffset = this.getItemProperty(item, 'iconOffset')
|
const iconOffset = this.pickItemProperty(item, 'iconOffset', enabled)
|
||||||
if (iconOffset && iconOffset.x != null && iconOffset.y != null)
|
if (iconOffset && iconOffset.x != null && iconOffset.y != null)
|
||||||
sprite.position.set(iconOffset.x, iconOffset.y)
|
sprite.position.set(iconOffset.x, iconOffset.y)
|
||||||
|
|
||||||
const iconColor = this.getItemProperty(item, 'iconColor')
|
const iconColor = this.pickItemProperty(item, 'iconColor', enabled)
|
||||||
if (iconColor) sprite.tint = iconColor
|
if (iconColor) sprite.tint = iconColor
|
||||||
|
|
||||||
const iconAlpha = this.getItemProperty(item, 'iconAlpha')
|
const iconAlpha = this.pickItemProperty(item, 'iconAlpha', enabled)
|
||||||
if (iconAlpha) sprite.alpha = iconAlpha
|
if (iconAlpha) sprite.alpha = iconAlpha
|
||||||
|
|
||||||
geographics.graphics.addChild(sprite)
|
geographics.graphics.addChild(sprite)
|
||||||
@@ -468,28 +670,6 @@ export default class Overlay {
|
|||||||
|
|
||||||
_createInformation(geographics, item, callback = null) {
|
_createInformation(geographics, item, callback = null) {
|
||||||
if (item.information) {
|
if (item.information) {
|
||||||
/**
|
|
||||||
* SO: The overlay class is quite convenient.
|
|
||||||
* But managing the information creation solely inside this
|
|
||||||
* class restricts us massively.
|
|
||||||
*
|
|
||||||
* Maybe a restructuring would be good, that we can handle
|
|
||||||
* the creation of information with a callback and can adapt
|
|
||||||
* to any occuring situation.
|
|
||||||
*
|
|
||||||
* e.g.
|
|
||||||
*
|
|
||||||
* overlay.informationHandler((geo, type, item)=>{
|
|
||||||
* switch(type){
|
|
||||||
* case "popup":
|
|
||||||
* createPopup(item.information)
|
|
||||||
* break;
|
|
||||||
*
|
|
||||||
* ....
|
|
||||||
* }
|
|
||||||
* })
|
|
||||||
*/
|
|
||||||
|
|
||||||
geographics.graphics.interactive = true
|
geographics.graphics.interactive = true
|
||||||
const informationType = this.getItemProperty(item, 'informationType')
|
const informationType = this.getItemProperty(item, 'informationType')
|
||||||
|
|
||||||
@@ -538,17 +718,21 @@ export default class Overlay {
|
|||||||
|
|
||||||
_fill(geographics, item) {
|
_fill(geographics, item) {
|
||||||
const enabled = this.getItemProperty(item, 'enabled')
|
const enabled = this.getItemProperty(item, 'enabled')
|
||||||
const color = enabled ? this.getItemProperty(item, 'color') : this.getItemProperty(item, 'disabledColor')
|
const color = this.pickItemProperty(item, 'color', enabled)
|
||||||
let alpha = enabled ? this.getItemProperty(item, 'fillAlpha') : this.getItemProperty(item, 'disabledAlpha')
|
const alpha = this.pickItemProperty(item, 'fillAlpha', enabled)
|
||||||
geographics.graphics.beginFill(color, alpha)
|
geographics.graphics.beginFill(color, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
_drawPoint(item, informationCallback = null) {
|
_drawPoint(item, informationCallback = null) {
|
||||||
const overlay = this
|
const overlay = this
|
||||||
|
|
||||||
|
const enabled = this.getItemProperty(item, 'enabled')
|
||||||
|
|
||||||
|
let that = this
|
||||||
let geographic = new GeoPoint(item.location, {
|
let geographic = new GeoPoint(item.location, {
|
||||||
onDraw: function() {
|
onDraw: function() {
|
||||||
overlay._fill.call(overlay, this, item)
|
overlay._fill.call(overlay, this, item)
|
||||||
const size = overlay.getItemProperty(item, 'size') ? overlay.getItemProperty(item, 'size') : 0
|
const size = that.pickItemProperty(item, 'size', enabled)
|
||||||
this.graphics.drawCircle(0, 0, size)
|
this.graphics.drawCircle(0, 0, size)
|
||||||
overlay._drawRoutine.call(overlay, this, item, informationCallback)
|
overlay._drawRoutine.call(overlay, this, item, informationCallback)
|
||||||
}
|
}
|
||||||
@@ -563,10 +747,19 @@ export default class Overlay {
|
|||||||
|
|
||||||
Overlay.Modes = { auto: null }
|
Overlay.Modes = { auto: null }
|
||||||
|
|
||||||
Overlay.createFactory = function(name, geographicsFactory) {
|
/**
|
||||||
if (Overlay.Modes.hasOwnProperty(name))
|
* Creates a factory for a specific type.
|
||||||
console.warn(`The mode ${name} was already implemented and was overwritten!`)
|
*
|
||||||
Overlay.Modes[name] = geographicsFactory
|
* @param {string} type - Name of the factory. When overlay items match the type, the factory is applied.
|
||||||
|
* @param {function} geographicsFactory - A function that is called with every item. Can be used to draw the geographics individually.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberof {Overlay}
|
||||||
|
*/
|
||||||
|
Overlay.createFactory = function(type, geographicsFactory) {
|
||||||
|
if (Overlay.Modes.hasOwnProperty(type))
|
||||||
|
console.warn(`The mode ${type} was already implemented and was overwritten!`)
|
||||||
|
Overlay.Modes[type] = geographicsFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay.requestFactory = function(name) {
|
Overlay.requestFactory = function(name) {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
<body onload="Doctest.run()">
|
<body onload="Doctest.run()">
|
||||||
<h1>Projections</h1>
|
<h1>Projections</h1>
|
||||||
<p>
|
<p>
|
||||||
Projections are used on the mapdata to translate coordinates to pixelpositions. There are various
|
Projections are used on the map projection to translate coordinates to pixelpositions. There are various
|
||||||
projections that can be used. All implemented ones are showcased here.
|
projections that can be used. All implemented ones are showcased here.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -258,6 +258,31 @@ export class Vector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PIXIUtils {
|
||||||
|
/*
|
||||||
|
* Transform a pixi text to it's actual screensize,
|
||||||
|
* ignoring it's local transforms
|
||||||
|
*/
|
||||||
|
static toScreenFontSize(pixiText, fontSize = null) {
|
||||||
|
pixiText._recursivePostUpdateTransform();
|
||||||
|
|
||||||
|
let normalizedScale = {
|
||||||
|
x: pixiText.scale.x / pixiText.transform.worldTransform.a,
|
||||||
|
y: pixiText.scale.x / pixiText.transform.worldTransform.d
|
||||||
|
};
|
||||||
|
|
||||||
|
pixiText.scale = { x: normalizedScale.x, y: normalizedScale.y };
|
||||||
|
if (fontSize) pixiText.style.fontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static saveFill(graphics) {
|
||||||
|
return {
|
||||||
|
fill: graphics.fill.color,
|
||||||
|
alpha: graphics.fill.alpha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The EventHandler class is used to take care of a event based design
|
* The EventHandler class is used to take care of a event based design
|
||||||
* pattern. Callbacks can subscribe to an event and these unknown sources
|
* pattern. Callbacks can subscribe to an event and these unknown sources
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class InteractivePopup extends AbstractPopup {
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @param {object} [opts] - An options object to specify to style and behaviour of the popup.
|
* @param {object} [opts] - An options object to specify to style and behaviour of the popup.
|
||||||
* @param {boolean} [opts.closeOnPopup=false] - Should the popup be closed when the user clicks on the popup?
|
* @param {boolean} [opts.closeOnPopup=false] - Should the popup be closed when the user clicks on the popup?
|
||||||
* @param {boolean} [opts.closeButton=true] - Should a close button be displayed on the upper right corner?
|
* @param {boolean|string} [opts.closeButton=true] - Should a close button be displayed on the upper right corner? Alternatively, a URL to the image can be specified.
|
||||||
* @param {object} [opts.button] - A Button object to be display on the lower right corner.
|
* @param {object} [opts.button] - A Button object to be display on the lower right corner.
|
||||||
* @param {object} [opts.buttonGroup] - A ButtonGroup object to be displayed on the lower right corner.
|
* @param {object} [opts.buttonGroup] - A ButtonGroup object to be displayed on the lower right corner.
|
||||||
*/
|
*/
|
||||||
@@ -73,7 +73,16 @@ export class InteractivePopup extends AbstractPopup {
|
|||||||
// closeButton
|
// closeButton
|
||||||
//-----------------
|
//-----------------
|
||||||
if (this.opts.closeButton) {
|
if (this.opts.closeButton) {
|
||||||
let closeButton = PIXI.Sprite.from('../../assets/icons/close.png')
|
let url = null
|
||||||
|
if (typeof this.opts.closeButton === 'string' || this.opts.closeButton instanceof String) {
|
||||||
|
url = InteractivePopup.iconIsUrl(this.opts.closeButton)
|
||||||
|
? this.opts.closeButton
|
||||||
|
: `../../assets/icons/${this.opts.closeButton}.png`
|
||||||
|
} else {
|
||||||
|
url = '../../assets/icons/close.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
let closeButton = PIXI.Sprite.from(url)
|
||||||
closeButton.width = this.headerStyle.fontSize
|
closeButton.width = this.headerStyle.fontSize
|
||||||
closeButton.height = closeButton.width
|
closeButton.height = closeButton.width
|
||||||
closeButton.tint = this.theme.color2
|
closeButton.tint = this.theme.color2
|
||||||
@@ -172,6 +181,18 @@ export class InteractivePopup extends AbstractPopup {
|
|||||||
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if an icon string is an url.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @static
|
||||||
|
* @param {string} url - The url to test.
|
||||||
|
* @return {boolean} true if the url is an url to an image.
|
||||||
|
*/
|
||||||
|
static iconIsUrl(url) {
|
||||||
|
return /\.(png|svg|gif|jpg|jpeg|tif|tiff)$/i.test(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,7 +218,7 @@ export default class Popup extends InteractivePopup {
|
|||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {object} [opts] - An options object to specify to style and behaviour of the popup.
|
* @param {object} [opts] - An options object to specify to style and behaviour of the popup.
|
||||||
* @param {boolean} [opts.closeButton=false] - Should a close button be displayed on the upper right corner?
|
* @param {boolean|string} [opts.closeButton=false] - Should a close button be displayed on the upper right corner? Alternatively, a URL to the image can be specified.
|
||||||
* @param {number} [opts.minWidth=0] - The minimum width of the popup.
|
* @param {number} [opts.minWidth=0] - The minimum width of the popup.
|
||||||
* @param {number} [opts.minHeight=0] - The minimum height of the popup.
|
* @param {number} [opts.minHeight=0] - The minimum height of the popup.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -315,7 +315,6 @@ export class DisplayObjectScatter extends AbstractScatter {
|
|||||||
if (y != null) this.y = y
|
if (y != null) this.y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getWorldScatter() {
|
getWorldScatter() {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
backgroundFill = 0xffffff,
|
backgroundFill = 0xffffff,
|
||||||
colorAlpha = 1,
|
colorAlpha = 1,
|
||||||
captureEvents = true,
|
captureEvents = true,
|
||||||
acceptMouseEvents = true
|
acceptMouseEvents = true,
|
||||||
|
lineWidth = 16,
|
||||||
|
minStrokeLength = 4
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super()
|
super()
|
||||||
this.activePointers = 0
|
this.activePointers = 0
|
||||||
@@ -99,7 +101,8 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
this.undoCommandStack = []
|
this.undoCommandStack = []
|
||||||
this.strokes = []
|
this.strokes = []
|
||||||
this.stroke = []
|
this.stroke = []
|
||||||
this.minStrokeLength = 4
|
this.lineWidth = lineWidth
|
||||||
|
this.minStrokeLength = minStrokeLength
|
||||||
if (captureEvents) this.registerEventHandler(acceptMouseEvents)
|
if (captureEvents) this.registerEventHandler(acceptMouseEvents)
|
||||||
this.drawBackground()
|
this.drawBackground()
|
||||||
}
|
}
|
||||||
@@ -273,7 +276,8 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
pressure: event.pressure || null,
|
pressure: event.pressure || null,
|
||||||
tiltX: this.tiltX,
|
tiltX: this.tiltX,
|
||||||
tiltY: this.tiltY,
|
tiltY: this.tiltY,
|
||||||
color: this.color
|
color: this.color,
|
||||||
|
lineWidth: this.tiltToLineWidth(this.tiltY)
|
||||||
}
|
}
|
||||||
return desc
|
return desc
|
||||||
}
|
}
|
||||||
@@ -297,7 +301,7 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tiltToLineWidth(value) {
|
tiltToLineWidth(value) {
|
||||||
return 16 //Math.round(Math.abs(value / 10) + 1)
|
return this.lineWidth * Math.round(Math.abs(value / 10) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
drawStroke(stroke) {
|
drawStroke(stroke) {
|
||||||
@@ -305,11 +309,11 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
let start = stroke[0]
|
let start = stroke[0]
|
||||||
this.beginFill(0, 0)
|
this.beginFill(0, 0)
|
||||||
this.moveTo(start.x, start.y)
|
this.moveTo(start.x, start.y)
|
||||||
let lineWidth = this.tiltToLineWidth(start.tiltY)
|
let lineWidth = start.lineWidth
|
||||||
this.lineStyle(lineWidth, start.color, this.colorAlpha)
|
this.lineStyle(lineWidth, start.color, this.colorAlpha)
|
||||||
for (let i = 1; i < stroke.length; i++) {
|
for (let i = 1; i < stroke.length; i++) {
|
||||||
let info = stroke[i]
|
let info = stroke[i]
|
||||||
let lw = this.tiltToLineWidth(info.tiltY)
|
let lw = info.lineWidth
|
||||||
if (lw != lineWidth) {
|
if (lw != lineWidth) {
|
||||||
lineWidth = lw
|
lineWidth = lw
|
||||||
this.lineStyle(lineWidth, info.color, this.colorAlpha)
|
this.lineStyle(lineWidth, info.color, this.colorAlpha)
|
||||||
@@ -328,7 +332,7 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
|
|
||||||
drawStrokes() {
|
drawStrokes() {
|
||||||
this.drawBackground()
|
this.drawBackground()
|
||||||
this.lineStyle(1.0, 0xff0000, 1)
|
this.lineStyle(this.lineWidth, 0xff0000, 1)
|
||||||
for (let stroke of this.iterStrokes()) {
|
for (let stroke of this.iterStrokes()) {
|
||||||
this.drawStroke(stroke)
|
this.drawStroke(stroke)
|
||||||
}
|
}
|
||||||
@@ -356,17 +360,17 @@ export default class Stylus extends PIXI.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
normalizeInfo(info) {
|
normalizeInfo(info) {
|
||||||
let { x, y, pressure, tiltX, tiltY, color } = info
|
let { x, y, pressure, tiltX, tiltY, color, lineWidth } = info
|
||||||
x /= this.wantedWidth
|
x /= this.wantedWidth
|
||||||
y /= this.wantedHeight
|
y /= this.wantedHeight
|
||||||
return { x, y, pressure, tiltX, tiltY, color }
|
return { x, y, pressure, tiltX, tiltY, color, lineWidth }
|
||||||
}
|
}
|
||||||
|
|
||||||
denormalizeInfo(info) {
|
denormalizeInfo(info) {
|
||||||
let { x, y, pressure, tiltX, tiltY, color } = info
|
let { x, y, pressure, tiltX, tiltY, color, lineWidth } = info
|
||||||
x = x * this.wantedWidth
|
x = x * this.wantedWidth
|
||||||
y = y * this.wantedHeight
|
y = y * this.wantedHeight
|
||||||
return { x, y, pressure, tiltX, tiltY, color }
|
return { x, y, pressure, tiltX, tiltY, color, lineWidth }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert strokes into an object that can be stored in an Indexed DB.
|
// Convert strokes into an object that can be stored in an Indexed DB.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 33 KiB |
@@ -34,8 +34,8 @@ oncontextmenu="PopupMenu.open(cmds,
|
|||||||
oncontextmenu="PopupMenu.open(cmds, {x: event.offsetX, y: event.offsetY}, { parent: example, keepWithin: example}); return false;"></div>
|
oncontextmenu="PopupMenu.open(cmds, {x: event.offsetX, y: event.offsetY}, { parent: example, keepWithin: example}); return false;"></div>
|
||||||
<script class="doctest">
|
<script class="doctest">
|
||||||
let cmds = {
|
let cmds = {
|
||||||
"Start": () => alert("Start"),
|
"Start": (event, key) => {console.log("start", event, key); alert(key) },
|
||||||
"Stop": () => alert("Stop")
|
"Stop": (event, key) => alert(key)
|
||||||
}
|
}
|
||||||
let app = new App()
|
let app = new App()
|
||||||
let popup = new PopupMenu({ parent: example, fontSize: "2em", autoClose: false })
|
let popup = new PopupMenu({ parent: example, fontSize: "2em", autoClose: false })
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ export default class PopupMenu extends Popup {
|
|||||||
Elements.addClass(item, 'popupMenuItem')
|
Elements.addClass(item, 'popupMenuItem')
|
||||||
this.items[key] = item
|
this.items[key] = item
|
||||||
item.onclick = event => {
|
item.onclick = event => {
|
||||||
this.perform(key)
|
this.perform(event, key)
|
||||||
}
|
}
|
||||||
item.ontap = event => {
|
item.ontap = event => {
|
||||||
this.perform(key)
|
this.perform(event, key)
|
||||||
}
|
}
|
||||||
item.onmouseover = event => {
|
item.onmouseover = event => {
|
||||||
this.over(event, key)
|
this.over(event, key)
|
||||||
@@ -105,16 +105,22 @@ export default class PopupMenu extends Popup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Execute a menu command.
|
/** Execute a menu command.
|
||||||
|
* @param {object} event - The trigger event.
|
||||||
* @param {string} key - The selected key.
|
* @param {string} key - The selected key.
|
||||||
*/
|
*/
|
||||||
perform(key) {
|
perform(event, key) {
|
||||||
let func = this.commands[key]
|
let func = this.commands[key]
|
||||||
if (this.autoClose) {
|
if (this.autoClose) {
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(
|
||||||
func.call()
|
(event, key) => {
|
||||||
}, 20)
|
func(event, key)
|
||||||
|
},
|
||||||
|
20,
|
||||||
|
event,
|
||||||
|
key
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update the menu item denoted by key.
|
/** Update the menu item denoted by key.
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ class Throwable {
|
|||||||
let t = performance.now()
|
let t = performance.now()
|
||||||
let dt = t - this.lastframe
|
let dt = t - this.lastframe
|
||||||
this.lastframe = t
|
this.lastframe = t
|
||||||
|
|
||||||
|
// When number is not set or is zero. Use one instead.
|
||||||
|
let number = delta.number ? delta.number : 1
|
||||||
if (dt > 0) {
|
if (dt > 0) {
|
||||||
// Avoid division by zero errors later on
|
// Avoid division by zero errors later on
|
||||||
// and consider the number of involved pointers sind addVelocity will be called by the
|
// and consider the number of involved pointers sind addVelocity will be called by the
|
||||||
@@ -124,13 +127,14 @@ class Throwable {
|
|||||||
let velocity = {
|
let velocity = {
|
||||||
t: t,
|
t: t,
|
||||||
dt: dt,
|
dt: dt,
|
||||||
dx: delta.x / delta.number,
|
dx: delta.x / number,
|
||||||
dy: delta.y / delta.number
|
dy: delta.y / number
|
||||||
}
|
}
|
||||||
this.velocities.push(velocity)
|
this.velocities.push(velocity)
|
||||||
while (this.velocities.length > buffer) {
|
while (this.velocities.length > buffer) {
|
||||||
this.velocities.shift()
|
this.velocities.shift()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +382,7 @@ export class AbstractScatter extends Throwable {
|
|||||||
let delta = interaction.delta()
|
let delta = interaction.delta()
|
||||||
|
|
||||||
if (delta != null) {
|
if (delta != null) {
|
||||||
this.addVelocity(delta)
|
this.addVelocity(delta) // uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
let rotate = delta.rotate
|
let rotate = delta.rotate
|
||||||
let zoom = delta.zoom
|
let zoom = delta.zoom
|
||||||
if (this.maxRotation != null) {
|
if (this.maxRotation != null) {
|
||||||
@@ -578,6 +582,7 @@ export class AbstractScatter extends Throwable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_move(delta) {
|
_move(delta) {
|
||||||
|
// this.addVelocity(delta) uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
this.x += this.movableX ? delta.x : 0
|
this.x += this.movableX ? delta.x : 0
|
||||||
this.y += this.movableX ? delta.y : 0
|
this.y += this.movableX ? delta.y : 0
|
||||||
}
|
}
|
||||||
@@ -615,14 +620,14 @@ export class AbstractScatter extends Throwable {
|
|||||||
|
|
||||||
let newOrigin = Points.arc(anchor, beta + rotate, distance * thresholdedZoom)
|
let newOrigin = Points.arc(anchor, beta + rotate, distance * thresholdedZoom)
|
||||||
let extra = Points.subtract(newOrigin, origin)
|
let extra = Points.subtract(newOrigin, origin)
|
||||||
let offset = Points.subtract(anchor, origin)
|
const anchorOffset = Points.subtract(anchor, origin)
|
||||||
this._move(offset)
|
// this._move(offset)
|
||||||
this.scale = newScale
|
this.scale = newScale
|
||||||
this.rotation += rotate
|
this.rotation += rotate
|
||||||
offset = Points.negate(offset)
|
let offset = Points.negate(anchorOffset)
|
||||||
offset = Points.add(offset, extra)
|
offset = Points.add(offset, extra)
|
||||||
offset = Points.add(offset, translate)
|
offset = Points.add(offset, translate)
|
||||||
this._move(offset)
|
this._move(Points.add(anchorOffset, offset))
|
||||||
|
|
||||||
delta.x += extra.x
|
delta.x += extra.x
|
||||||
delta.y += extra.y
|
delta.y += extra.y
|
||||||
@@ -1392,7 +1397,8 @@ export class DOMScatter extends AbstractScatter {
|
|||||||
}
|
}
|
||||||
this._x = x
|
this._x = x
|
||||||
this._y = y
|
this._y = y
|
||||||
TweenLite.set(this.element, { x: x, y: y })
|
// this.addVelocity({ x: delta.x, y: delta.y }) uo: reverted commit fa0256d782dd498c6d3e51321260ca375ca9f855
|
||||||
|
TweenLite.set(this.element, { x, y })
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeAfterTransform(zoom) {
|
resizeAfterTransform(zoom) {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 55 KiB |
@@ -396,9 +396,18 @@ export class Points {
|
|||||||
|
|
||||||
// Distance == 0.0 indicates an inside relation.
|
// Distance == 0.0 indicates an inside relation.
|
||||||
static distanceToRect(p, r) {
|
static distanceToRect(p, r) {
|
||||||
let cx = Math.max(Math.min(p.x, r.x + r.width), r.x)
|
let dx = 0
|
||||||
|
let dy = 0
|
||||||
|
if (p.x < r.x) dx = p.x - r.x
|
||||||
|
else if (p.x > r.x + r.width) dx = p.x - (r.x + r.width)
|
||||||
|
if (p.y < r.y) dy = p.y - r.y
|
||||||
|
else if (p.y > r.y + r.height) dy = p.y - (r.y + r.height)
|
||||||
|
return Math.sqrt(dx * dx + dy * dy)
|
||||||
|
/* let cx = Math.max(Math.min(p.x, r.x + r.width), r.x)
|
||||||
let cy = Math.max(Math.min(p.y, r.y + r.height), r.y)
|
let cy = Math.max(Math.min(p.y, r.y + r.height), r.y)
|
||||||
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
let result = Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
||||||
|
console.log("distanceToRect", p, r, result)
|
||||||
|
return result */
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPageToNode(element, p) {
|
static fromPageToNode(element, p) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "iwmlib",
|
"name": "iwmlib",
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"description": "An Open Source library for multi-touch, WebGL powered applications.",
|
"description": "An Open Source library for multi-touch, WebGL powered applications.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -27,10 +27,10 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "LGPL-3.0-or-later",
|
"license": "LGPL-3.0-or-later",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@pixi/jsdoc-template": "^2.4.3",
|
"@pixi/jsdoc-template": "^2.5.1",
|
||||||
"eslint": "^6.6.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-prettier": "^6.5.0",
|
"eslint-config-prettier": "^6.9.0",
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
"fs-extra": "^8.0.1",
|
"fs-extra": "^8.0.1",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
@@ -48,13 +48,13 @@
|
|||||||
"gsap": "^2.1.3",
|
"gsap": "^2.1.3",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"optimal-select": "^4.0.1",
|
"optimal-select": "^4.0.1",
|
||||||
"pixi-compressed-textures": "^2.0.3",
|
"pixi-compressed-textures": "^2.0.5",
|
||||||
"pixi-ease": "^2.4.2",
|
"pixi-ease": "^2.4.2",
|
||||||
"pixi-filters": "^3.0.3",
|
"pixi-filters": "^3.0.3",
|
||||||
"pixi-particles": "^4.2.0",
|
"pixi-particles": "^4.2.0",
|
||||||
"pixi-projection": "^0.3.5",
|
"pixi-projection": "^0.3.7",
|
||||||
"pixi-viewport": "^4.3.3",
|
"pixi-viewport": "^4.8.0",
|
||||||
"pixi.js": "^5.2.0",
|
"pixi.js": "^5.2.1",
|
||||||
"propagating-hammerjs": "^1.4.7"
|
"propagating-hammerjs": "^1.4.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||