Compare commits
No commits in common. "main" and "obersalzberg" have entirely different histories.
main
...
obersalzbe
@ -28,8 +28,5 @@
|
||||
"plugins": [
|
||||
"prettier"
|
||||
],
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||
"rules": {
|
||||
"comma-dangle": ["error", "never"]
|
||||
}
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"]
|
||||
}
|
||||
6
.gitignore
vendored
@ -77,12 +77,12 @@ typings/
|
||||
.fusebox/
|
||||
|
||||
# own
|
||||
*.code-workspace
|
||||
.history/
|
||||
.vscode/
|
||||
|
||||
|
||||
# ignore generated contents-
|
||||
/doc/out/*
|
||||
**/thumbnails
|
||||
**/thumbnail.png
|
||||
/site/dist
|
||||
/site/__pycache__
|
||||
**/thumbnail.png
|
||||
@ -3,6 +3,5 @@
|
||||
"jsxSingleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"printWidth": 120,
|
||||
"trailingComma": "none"
|
||||
"printWidth": 120
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$1" = "dist" ]
|
||||
then
|
||||
if [ -z "$2" ]
|
||||
then
|
||||
npm run package-all
|
||||
else
|
||||
npm run package-app-$2
|
||||
fi
|
||||
else
|
||||
electron . ./lib/index.html
|
||||
fi
|
||||
@ -1,289 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar { display: none; }
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
font-size: 22pt;
|
||||
-webkit-tap-highlight-color: #ccc;
|
||||
background-color: #DDD;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
/* https://davidwalsh.name/font-smoothing */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
header {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
#progressBar {
|
||||
position: absolute;
|
||||
background-color: rgb(165, 165, 196);
|
||||
width: 0%;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
#info {
|
||||
width: 100%;
|
||||
margin: 3px;
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
text-align:center;
|
||||
}
|
||||
</style>
|
||||
<title>
|
||||
Browser
|
||||
</title>
|
||||
</head>
|
||||
|
||||
<body style="width: 100%; height: 100%; -webkit-app-region: no-drag">
|
||||
<header id="header" style="-webkit-app-region: drag">
|
||||
<div id="progressBar"></div>
|
||||
<span id="info">Minimal Header</span>
|
||||
</header>
|
||||
<main></main>
|
||||
</body>
|
||||
<script>
|
||||
const { ipcRenderer } = require("electron")
|
||||
|
||||
let urls = new Set()
|
||||
let favicons = new Set()
|
||||
let progress = 0
|
||||
|
||||
info.innerHTML = window.location.href
|
||||
|
||||
function notify(url) {
|
||||
if (urls.has(url)) return
|
||||
console.log(url)
|
||||
//header.innerHTML += `<p>${url}</p>`
|
||||
urls.add(url)
|
||||
}
|
||||
|
||||
let colorExtractorCanvas = document.createElement('canvas')
|
||||
let colorExtractorContext = colorExtractorCanvas.getContext('2d')
|
||||
let colorExtractorImage = document.createElement('img')
|
||||
|
||||
function getColor(url, callback) {
|
||||
colorExtractorImage.onload = function (e) {
|
||||
let w = colorExtractorImage.width
|
||||
let h = colorExtractorImage.height
|
||||
colorExtractorCanvas.width = w
|
||||
colorExtractorCanvas.height = h
|
||||
let offset = Math.max(1, Math.round(0.00032 * w * h))
|
||||
colorExtractorContext.drawImage(colorExtractorImage, 0, 0, w, h)
|
||||
let data = colorExtractorContext.getImageData(0, 0, w, h).data
|
||||
let pixels = {}
|
||||
let d, add, sum
|
||||
for (let i = 0; i < data.length; i += 4 * offset) {
|
||||
d = Math.round(data[i] / 5) * 5 + ',' + Math.round(data[i + 1] / 5) * 5 + ',' + Math.round(data[i + 2] / 5) * 5
|
||||
add = 1
|
||||
sum = data[i] + data[i + 1] + data[i + 2]
|
||||
// very dark or light pixels shouldn't be counted as heavily
|
||||
if (sum < 310) {
|
||||
add = 0.35
|
||||
}
|
||||
if (sum < 50) {
|
||||
add = 0.01
|
||||
}
|
||||
if (data[i] > 210 || data[i + 1] > 210 || data[i + 2] > 210) {
|
||||
add = 0.5 - (0.0001 * sum)
|
||||
}
|
||||
if (pixels[d]) {
|
||||
pixels[d] = pixels[d] + add
|
||||
} else {
|
||||
pixels[d] = add
|
||||
}
|
||||
}
|
||||
// find the largest pixel set
|
||||
let largestPixelSet = null
|
||||
let ct = 0
|
||||
for (let k in pixels) {
|
||||
if (k === '255,255,255' || k === '0,0,0') {
|
||||
pixels[k] *= 0.05
|
||||
}
|
||||
if (pixels[k] > ct) {
|
||||
largestPixelSet = k
|
||||
ct = pixels[k]
|
||||
}
|
||||
}
|
||||
let res = largestPixelSet.split(',')
|
||||
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = parseInt(res[i])
|
||||
}
|
||||
callback(res)
|
||||
}
|
||||
colorExtractorImage.src = url
|
||||
}
|
||||
|
||||
function getTextColor(bgColor) {
|
||||
let output = runNetwork(bgColor)
|
||||
if (output.black > 0.5) {
|
||||
return 'black'
|
||||
}
|
||||
return 'white'
|
||||
}
|
||||
|
||||
var runNetwork = function anonymous(input) {
|
||||
var net = {
|
||||
'layers': [{
|
||||
'r': {},
|
||||
'g': {},
|
||||
'b': {}
|
||||
}, {
|
||||
'0': {
|
||||
'bias': 14.176907520571566,
|
||||
'weights': {
|
||||
'r': -3.2764240497480652,
|
||||
'g': -16.90247884718719,
|
||||
'b': -2.9976364179397814
|
||||
}
|
||||
},
|
||||
'1': {
|
||||
'bias': 9.086071102351246,
|
||||
'weights': {
|
||||
'r': -4.327474143397604,
|
||||
'g': -15.780660155750773,
|
||||
'b': 2.879230202567851
|
||||
}
|
||||
},
|
||||
'2': {
|
||||
'bias': 22.274487339773476,
|
||||
'weights': {
|
||||
'r': -3.5830205067960965,
|
||||
'g': -25.498384261673618,
|
||||
'b': -6.998329189107962
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'black': {
|
||||
'bias': 17.873962570788997,
|
||||
'weights': {
|
||||
'0': -15.542217788633987,
|
||||
'1': -13.377152708685674,
|
||||
'2': -24.52215186113144
|
||||
}
|
||||
}
|
||||
}],
|
||||
'outputLookup': true,
|
||||
'inputLookup': true
|
||||
}
|
||||
|
||||
for (var i = 1; i < net.layers.length; i++) {
|
||||
var layer = net.layers[i]
|
||||
var output = {}
|
||||
|
||||
for (var id in layer) {
|
||||
var node = layer[id]
|
||||
var sum = node.bias
|
||||
|
||||
for (var iid in node.weights) {
|
||||
sum += node.weights[iid] * input[iid]
|
||||
}
|
||||
output[id] = (1 / (1 + Math.exp(-sum)))
|
||||
}
|
||||
input = output
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function applyColors(backgroundColor, foregroundColor) {
|
||||
console.log("applyColors", backgroundColor, foregroundColor)
|
||||
progressBar.style.backgroundColor = backgroundColor
|
||||
info.style.color = foregroundColor
|
||||
}
|
||||
|
||||
ipcRenderer.on('title', (sender, title) => {
|
||||
info.innerHTML = title
|
||||
})
|
||||
|
||||
ipcRenderer.on('favicons', (sender, urls) => {
|
||||
console.log("favicons event", urls)
|
||||
for (let url of urls) {
|
||||
if (!favicons.has(url)) {
|
||||
getColor(url, c => {
|
||||
let cr = 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')'
|
||||
let obj = {
|
||||
r: c[0] / 255,
|
||||
g: c[1] / 255,
|
||||
b: c[2] / 255
|
||||
}
|
||||
let textclr = getTextColor(obj)
|
||||
applyColors(cr, textclr)
|
||||
})
|
||||
}
|
||||
favicons.add(url)
|
||||
}
|
||||
})
|
||||
|
||||
ipcRenderer.on('progress', (sender, amount) => {
|
||||
console.log("progress event", amount)
|
||||
if (amount > progress) {
|
||||
progress = Math.min(amount, 1)
|
||||
}
|
||||
progressBar.style.width = Math.round(progress * 100) + '%'
|
||||
})
|
||||
|
||||
ipcRenderer.on('did-start-loading', (sender, url) => {
|
||||
console.log('did-start-loading', url)
|
||||
})
|
||||
|
||||
ipcRenderer.on('did-get-response-details', (sender, info) => {
|
||||
let {
|
||||
status, newURL, originalURL,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers,
|
||||
resourceType
|
||||
} = info
|
||||
notify(newURL)
|
||||
notify(originalURL)
|
||||
//console.log('did-get-response-details', info)
|
||||
})
|
||||
ipcRenderer.on('did-get-redirect-request', (sender, info) => {
|
||||
let { oldURL,
|
||||
newURL,
|
||||
isMainFrame,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers
|
||||
} = info
|
||||
notify(newURL)
|
||||
notify(oldURL)
|
||||
//console.log('did-get-response-details', info)
|
||||
})
|
||||
ipcRenderer.on('did-stop-loading', (sender, info) => {
|
||||
//console.log('did-stop-loading', info)
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
||||
@ -1,49 +0,0 @@
|
||||
const carlo = require('carlo');
|
||||
const fse = require('fs-extra');
|
||||
const urlExists = require('url-exists');
|
||||
|
||||
// command line arguments
|
||||
let path = 'index.html'
|
||||
process.argv.forEach((value, index, array) => {
|
||||
if (index === 2) {
|
||||
path = value
|
||||
}
|
||||
});
|
||||
|
||||
(async () => {
|
||||
// Launch the browser.
|
||||
const opts = {}
|
||||
|
||||
// Set path to custom chrome
|
||||
const chrome = `${__dirname}/../chrome/chrome.exe`
|
||||
if (fse.pathExistsSync(chrome)) {
|
||||
opts.executablePath = chrome
|
||||
}
|
||||
|
||||
// Launch app
|
||||
const app = await carlo.launch(opts)
|
||||
|
||||
// Terminate Node.js process on app window closing.
|
||||
app.on('exit', () => process.exit())
|
||||
|
||||
// Tell carlo where your web files are located.
|
||||
app.serveFolder(`${__dirname}/../`)
|
||||
|
||||
// Check if URL exists
|
||||
urlExists('https://localhost:8443', async (error, exists) => {
|
||||
|
||||
if (exists) {
|
||||
console.info('Serve files via server')
|
||||
app.serveOrigin('https://localhost:8443') // Optional
|
||||
} else {
|
||||
console.info('Serve files from file system')
|
||||
}
|
||||
|
||||
// Expose 'env' function in the web environment.
|
||||
await app.exposeFunction('env', _ => process.env)
|
||||
|
||||
// Navigate to the main page of your app.
|
||||
console.info('Starting carlo with', path)
|
||||
await app.load(path)
|
||||
})
|
||||
})()
|
||||
@ -1,24 +0,0 @@
|
||||
const path = require('path')
|
||||
const electron = require('electron')
|
||||
const fs = require('fs')
|
||||
let loadedLanguage
|
||||
let app = electron.app ? electron.app : electron.remote.app
|
||||
|
||||
module.exports = i18n
|
||||
|
||||
function i18n() {
|
||||
if (fs.existsSync(path.join(__dirname, 'i18n', app.getLocale() + '.js'))) {
|
||||
loadedLanguage = JSON.parse(fs.readFileSync(path.join(__dirname, 'i18n', app.getLocale() + '.js'), 'utf8'))
|
||||
}
|
||||
else {
|
||||
loadedLanguage = JSON.parse(fs.readFileSync(path.join(__dirname, 'i18n', 'en.js'), 'utf8'))
|
||||
}
|
||||
}
|
||||
|
||||
i18n.prototype.__ = function(phrase) {
|
||||
let translation = loadedLanguage[phrase]
|
||||
if (translation === undefined) {
|
||||
translation = phrase
|
||||
}
|
||||
return translation
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
{
|
||||
"edit": "Bearbeiten",
|
||||
"undo": "Widerrufen",
|
||||
"redo": "Wiederholen",
|
||||
"cut": "Ausschneiden",
|
||||
"copy": "Kopieren",
|
||||
"paste": "Einsetzen",
|
||||
"pasteandmatchstyle": "Einsetzen und Stil anpassen",
|
||||
"delete": "Löschen",
|
||||
"selectall": "Alles auswählen",
|
||||
"view": "Darstellung",
|
||||
"reload": "Seite neu laden",
|
||||
"forcereload": "Cache löschen und Seite neu laden",
|
||||
"resetzoom": "Originalgröße",
|
||||
"zoomin": "Vergrößern",
|
||||
"zoomout": "Verkleinern",
|
||||
"togglefullscreen": "Vollbildmodus umschalten",
|
||||
"minimalpad": "Minimal-Pad",
|
||||
"multiuserbrowser": "Mehrbenutzer-Browser",
|
||||
"history": "Verlauf",
|
||||
"back": "Zurück",
|
||||
"forward": "Vorwärts",
|
||||
"home": "Startseite",
|
||||
"recentlyvisited": "Kürzlich besucht",
|
||||
"bookmarks": "Lesezeichen",
|
||||
"localfilesystem": "Lokales Dateisystem",
|
||||
"testframes": "Testseiten",
|
||||
"develop": "Entwickler",
|
||||
"toggledevelopertools": "Webinformationen umschalten",
|
||||
"openprocessmonitor": "Prozessmonitor öffnen",
|
||||
"selectfolder": "Datenverzeichnis auswählen...",
|
||||
"selectfolder.noadmin.ok": "OK",
|
||||
"selectfolder.noadmin.message": "Keine ausreichenden Berechtigungen",
|
||||
"selectfolder.noadmin.detail": "Um das Datenverzeichnis zu ändern, muss der IWM Browser mit Administrator-Berechtigungen gestartet werden.",
|
||||
"selectfolder.warning.next": "Weiter",
|
||||
"selectfolder.warning.cancel": "Abbrechen",
|
||||
"selectfolder.warning.message": "Datenverzeichnis vorhanden",
|
||||
"selectfolder.warning.detail": "Ihr IWM Browser besitzt bereits ein (verlinktes) Datenverzeichnis. Wenn Sie fortfahren, wird das alte Verzeichnis gesichert und ein neues wird erstellt.",
|
||||
"selectfolder.select.title": "Datenverzeichnis wählen",
|
||||
"selectfolder.select.buttonLabel": "Auswählen",
|
||||
"selectfolder.samefolder.ok": "OK",
|
||||
"selectfolder.samefolder.message": "Ungültiges Datenverzeichnis",
|
||||
"selectfolder.samefolder.detail.same": "Das alte Datenverzeichnis darf nicht als neues Verzeichnis ausgewählt werden.",
|
||||
"selectfolder.samefolder.detail.within": "Das neue Datenverzeichnis darf sich nicht innerhalb des alten Verzeichnisses befinden.",
|
||||
"selectfolder.info.ok": "OK",
|
||||
"selectfolder.info.message": "Link auf Datenverzeichnis erstellt",
|
||||
"selectfolder.info.detail": "Der IWM Browser verwendet nun den Ordner \"${0}\" als neues Datenverzeichnis.",
|
||||
"startserver": "Starte Server",
|
||||
"stopserver": "Stoppe Server",
|
||||
"runloadtests": "Starte Ladetests",
|
||||
"window": "Fenster",
|
||||
"close": "Fenster schließen",
|
||||
"minimize": "Im Dock ablegen",
|
||||
"zoom": "Zoomen",
|
||||
"front": "Alle nach vorne bringen",
|
||||
"screenshot": "Bildschirmfoto erstellen",
|
||||
"help": "Hilfe",
|
||||
"iwm": "Leibniz-Institut für Wissensmedien",
|
||||
"about": "Über IWM Browser",
|
||||
"quit": "IWM Browser beenden"
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
{
|
||||
"edit": "Edit",
|
||||
"undo": "Undo",
|
||||
"redo": "Redo",
|
||||
"cut": "Cut",
|
||||
"copy": "Copy",
|
||||
"paste": "Paste",
|
||||
"pasteandmatchstyle": "Paste and Match Style",
|
||||
"delete": "Delete",
|
||||
"selectall": "Select all",
|
||||
"view": "View",
|
||||
"reload": "Reload",
|
||||
"forcereload": "Force Reload",
|
||||
"resetzoom": "Actual size",
|
||||
"zoomin": "Zoom in",
|
||||
"zoomout": "Zoom out",
|
||||
"togglefullscreen": "Toggle Full Screen",
|
||||
"minimalpad": "Minimal Pad",
|
||||
"multiuserbrowser": "Multi-User Browser",
|
||||
"history": "History",
|
||||
"back": "Back",
|
||||
"forward": "Forward",
|
||||
"home": "Home",
|
||||
"recentlyvisited": "Recently Visited",
|
||||
"bookmarks": "Bookmarks",
|
||||
"localfilesystem": "Local Filesystem",
|
||||
"testframes": "Test Frames",
|
||||
"develop": "Develop",
|
||||
"toggledevelopertools": "Toggle Developer Tools",
|
||||
"openprocessmonitor": "Open Process Monitor",
|
||||
"selectfolder": "Select data folder...",
|
||||
"selectfolder.noadmin.ok": "OK",
|
||||
"selectfolder.noadmin.message": "Insufficient permissions",
|
||||
"selectfolder.noadmin.detail": "To change the data directory, the IWM Browser must be started with administrator privileges.",
|
||||
"selectfolder.warning.next": "Next",
|
||||
"selectfolder.warning.cancel": "Cancel",
|
||||
"selectfolder.warning.message": "Data folder exists",
|
||||
"selectfolder.warning.detail": "Your IWM Browser already has a (linked) data directory. If you continue, the old directory is backed up and a new one is created.",
|
||||
"selectfolder.select.title": "Select data folder",
|
||||
"selectfolder.select.buttonLabel": "Select",
|
||||
"selectfolder.samefolder.ok": "OK",
|
||||
"selectfolder.samefolder.message": "Invalid data folder",
|
||||
"selectfolder.samefolder.detail.same": "The old data directory cannot be selected as the new directory.",
|
||||
"selectfolder.samefolder.detail.within": "The new data directory cannot be inside the old directory.",
|
||||
"selectfolder.info.ok": "OK",
|
||||
"selectfolder.info.message": "Created link to data folder",
|
||||
"selectfolder.info.detail": "The IWM Browser now uses the folder \"${0}\" as the new data folder.",
|
||||
"startserver": "Start Server",
|
||||
"stopserver": "Stop Server",
|
||||
"runloadtests": "Run Load Tests",
|
||||
"window": "Window",
|
||||
"close": "Close",
|
||||
"minimize": "Minimize",
|
||||
"zoom": "Zoom",
|
||||
"front": "Bring All to Front",
|
||||
"screenshot": "Make Screenshot",
|
||||
"help": "Help",
|
||||
"iwm": "Leibniz-Institut für Wissensmedien",
|
||||
"about": "About IWM Browser",
|
||||
"quit": "Quit IWM Browser"
|
||||
}
|
||||
578
browser/main.js
@ -1,578 +0,0 @@
|
||||
/* globals require, __dirname, process */
|
||||
/*eslint no-console: ["error", { allow: ["log"] }]*/
|
||||
|
||||
const { app, BrowserWindow, BrowserView, ipcMain, dialog, shell } = require('electron')
|
||||
const electronLocalshortcut = require('electron-localshortcut')
|
||||
//const electron = require('electron')
|
||||
const os = require('os')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { URL } = require('url')
|
||||
const Store = require('./store.js')
|
||||
const { prettyPrint } = require('html')
|
||||
|
||||
// Use this constant to start the application in kiosk-mode or in development mode
|
||||
const DEVELOPMENT = true
|
||||
// true: Dev-Tools are open
|
||||
// false (KIOSK-Mode): No application switcher, no menu, no taskbar (or dock on a mac), shortcuts are working
|
||||
|
||||
global.multiUserMode = true
|
||||
global.errorCount = 0
|
||||
global.stopTestsOnError = false
|
||||
global.jsonData = { value: null }
|
||||
// UO: Experimental feature using Native Windows
|
||||
global.useBrowserView = false
|
||||
global.useMinimalPad = true
|
||||
global.menu = null
|
||||
global.observeTraffic = false
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let win
|
||||
let browsers = new Map() // url: BrowserWindow
|
||||
|
||||
const store = new Store({
|
||||
// We'll call our data file 'user-preferences'
|
||||
configName: 'user-preferences',
|
||||
defaults: {
|
||||
url: `file://${__dirname}/index.html`,
|
||||
devTools: DEVELOPMENT,
|
||||
multiUserBrowser: true
|
||||
}
|
||||
})
|
||||
|
||||
function createWindow() {
|
||||
|
||||
if (global.observeTraffic) {
|
||||
const {session} = require('electron')
|
||||
session.defaultSession.webRequest.onCompleted((details) => {
|
||||
console.log("onCompleted", details.url)
|
||||
})
|
||||
}
|
||||
let { screen } = require('electron')
|
||||
|
||||
let bounds = store.get('storedBounds')
|
||||
? store.get('storedBounds')
|
||||
: screen.getPrimaryDisplay().bounds
|
||||
|
||||
// let displays = screen.getAllDisplays()
|
||||
// let externalDisplay = null
|
||||
|
||||
// externalDisplay = displays[displays.length-1]
|
||||
// const {width, height} =displays[displays.length-1].workAreaSize
|
||||
|
||||
// externalDisplay = displays[0]
|
||||
// const {width, height} =displays[0].workAreaSize
|
||||
|
||||
win = new BrowserWindow({
|
||||
x: bounds.x,
|
||||
y: bounds.y,
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
fullscreenable: true,
|
||||
fullscreen: !DEVELOPMENT,
|
||||
title: 'IWM Browser',
|
||||
show: false,
|
||||
kiosk: !DEVELOPMENT,
|
||||
acceptFirstMouse: true,
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
allowRunningInsecureContent: true,
|
||||
nodeIntegration: true,
|
||||
webviewTag: true,
|
||||
nativeWindowOpen: true,
|
||||
devTools: true,
|
||||
preload: path.join(__dirname, './preload.js')
|
||||
},
|
||||
icon: path.join(__dirname, 'assets/icons/png/64x64.png')
|
||||
})
|
||||
|
||||
module.exports.win = win
|
||||
|
||||
let url = store.get('url')
|
||||
if (process.argv.length > 2) {
|
||||
let path = process.argv[2]
|
||||
url = `file://${__dirname}/../${path}`
|
||||
console.log('Using process.argv[2]', url)
|
||||
}
|
||||
console.log('Using', url)
|
||||
win.maximize()
|
||||
|
||||
// BAD: All other methods don't work (like ensureFileSync, fileExists...)
|
||||
try {
|
||||
let settings = require('./settings.json')
|
||||
console.log('Using settings', `file://${__dirname}/${settings.url}`)
|
||||
win.loadURL(`file://${__dirname}/${settings.url}`)
|
||||
} catch (ex) {
|
||||
win.loadURL(url)
|
||||
}
|
||||
|
||||
const { webContents } = win
|
||||
//
|
||||
// if (process.platform === 'win32' && win.isKiosk()) {
|
||||
// webContents.on('did-finish-load', function() {
|
||||
// webContents.executeJavaScript('document.body.style.cursor = "none";')
|
||||
// })
|
||||
// }
|
||||
|
||||
// Add the app menu
|
||||
let menu = require('./menu.js')
|
||||
global.menu = menu
|
||||
|
||||
// Add global shortcuts
|
||||
// Esc quits the app
|
||||
electronLocalshortcut.register('Esc', () => {
|
||||
app.quit()
|
||||
})
|
||||
|
||||
// Command (Mac) or Control (Win) + K toggles the Kiosk mode
|
||||
electronLocalshortcut.register('CommandOrControl+K', () => {
|
||||
if (win) {
|
||||
win.setKiosk(!win.isKiosk())
|
||||
}
|
||||
})
|
||||
|
||||
// Show if its ready.
|
||||
win.once('ready-to-show', () => {
|
||||
webContents.send('preparePads')
|
||||
win.show()
|
||||
})
|
||||
|
||||
// Clear cache
|
||||
webContents.session.clearCache(() => console.log('Cache cleared'))
|
||||
|
||||
// Open dev tools when in development mode
|
||||
if (store.get('devTools')) {
|
||||
webContents.openDevTools({ mode: 'right' })
|
||||
} else {
|
||||
webContents.closeDevTools()
|
||||
}
|
||||
|
||||
webContents.on('devtools-opened', () => {
|
||||
store.set('devTools', true)
|
||||
})
|
||||
|
||||
webContents.on('devtools-closed', () => {
|
||||
store.set('devTools', false)
|
||||
})
|
||||
|
||||
webContents.on('did-navigate', (event, url) => {
|
||||
menu.setHistoryStatus()
|
||||
})
|
||||
|
||||
/* UO: At this point we have no access to the event or link position*/
|
||||
|
||||
webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
|
||||
console.log('new-window', global.multiUserMode)
|
||||
if (global.multiUserMode) {
|
||||
event.preventDefault()
|
||||
webContents.send('newPad', url, options.x, options.y)
|
||||
}
|
||||
})
|
||||
|
||||
// WORKAROUND: On windows, if the app was set to fullscreen, the menubar is not hidden
|
||||
if (win.isKiosk()) {
|
||||
win.setMenuBarVisibility(false)
|
||||
}
|
||||
|
||||
win.on('focus', event => {
|
||||
menu.focus()
|
||||
})
|
||||
|
||||
win.on('blur', event => {
|
||||
menu.blur()
|
||||
})
|
||||
|
||||
win.on('enter-full-screen', () => {
|
||||
win.setMenuBarVisibility(false)
|
||||
})
|
||||
|
||||
win.on('leave-full-screen', () => {
|
||||
win.setMenuBarVisibility(true)
|
||||
})
|
||||
|
||||
win.on('enter-html-full-screen', () => {
|
||||
win.setMenuBarVisibility(false)
|
||||
})
|
||||
|
||||
win.on('leave-html-full-screen', () => {
|
||||
win.setMenuBarVisibility(true)
|
||||
})
|
||||
win.on('close', () => {
|
||||
store.set('storedBounds', win.getBounds())
|
||||
})
|
||||
|
||||
// Emitted when the window is closed.
|
||||
win.on('closed', () => {
|
||||
app.quit()
|
||||
})
|
||||
}
|
||||
|
||||
// When work makes progress, show the progress bar
|
||||
function onProgress(progress) {
|
||||
// Use values 0 to 1, or -1 to hide the progress bar
|
||||
try {
|
||||
win.setProgressBar(progress || -1) // Progress bar works on all platforms
|
||||
} catch (e) {
|
||||
if (DEVELOPMENT) console.log(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
function trySend(target, ...args) {
|
||||
try {
|
||||
target.send(...args)
|
||||
} catch (e) {
|
||||
if (DEVELOPMENT) console.log(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
function openBrowserView(url, x, y) {
|
||||
const useMinBrowser = false // Change this to switch between Min and a custom browser
|
||||
|
||||
const minURL = 'file:///Users/uo/devel/min/index.html'
|
||||
const browserURL = `file://${__dirname}/browser.html`
|
||||
let width = 640
|
||||
let height = 1200
|
||||
let [winWidth, winHeight] = win.getSize()
|
||||
if (x + width > winWidth) {
|
||||
x = winWidth - width
|
||||
}
|
||||
if (y + height > winHeight) {
|
||||
y = winHeight - height
|
||||
}
|
||||
console.log('open browser view')
|
||||
let browser = new BrowserWindow({
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
minWidth: 320,
|
||||
minHeight: 350,
|
||||
titleBarStyle: useMinBrowser ? 'hidden-inset' : 'hidden',
|
||||
frame: process.platform !== 'win32'
|
||||
})
|
||||
let browserContents = browser.webContents
|
||||
browser.setAlwaysOnTop(true)
|
||||
if (useMinBrowser) {
|
||||
browserContents.on('did-finish-load', event => {
|
||||
console.log('did-finish-load', browserContents.getURL())
|
||||
|
||||
browserContents.executeJavaScript(
|
||||
'Object.values(window.webviews.elementMap).map(obj => obj.src)',
|
||||
result => {
|
||||
console.log(
|
||||
'window.webviews',
|
||||
result,
|
||||
url,
|
||||
result.indexOf(url)
|
||||
)
|
||||
if (result.indexOf(url) == -1) {
|
||||
console.log('Adding tab')
|
||||
browserContents.send('addTab', { url })
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
browser.loadURL(minURL)
|
||||
} else {
|
||||
console.log('Loading', browserURL)
|
||||
browser.loadURL(browserURL)
|
||||
let view = new BrowserView({
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
devTools: true
|
||||
}
|
||||
})
|
||||
//browserContents.openDevTools({mode: 'right'})
|
||||
|
||||
browser.setBrowserView(view)
|
||||
view.setBounds({ x: 0, y: 24, width: width, height: height - 24 })
|
||||
view.setAutoResize({ width: true, height: true })
|
||||
|
||||
let viewContents = view.webContents
|
||||
let progress = 0
|
||||
|
||||
viewContents.on('page-title-set', event => {
|
||||
console.log('page-title-set', event)
|
||||
})
|
||||
viewContents.on('page-favicon-updated', (event, favicons) => {
|
||||
//console.log("page-favicon-updated", event, favicons)
|
||||
trySend(browserContents, 'favicons', favicons)
|
||||
})
|
||||
|
||||
viewContents.on('did-start-loading', event => {
|
||||
onProgress(0)
|
||||
trySend(browserContents, 'progress', 0)
|
||||
trySend(browserContents, 'did-start-loading')
|
||||
//let senderURL = event.sender.getURL() || url
|
||||
//console.log('did-start-loading', senderURL)
|
||||
})
|
||||
viewContents.on(
|
||||
'did-get-response-details',
|
||||
(
|
||||
event,
|
||||
status,
|
||||
newURL,
|
||||
originalURL,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers,
|
||||
resourceType
|
||||
) => {
|
||||
trySend(browserContents, 'did-get-response-details', {
|
||||
status,
|
||||
newURL,
|
||||
originalURL,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers,
|
||||
resourceType
|
||||
})
|
||||
progress += 0.01
|
||||
onProgress(progress)
|
||||
trySend(browserContents, 'progress', progress)
|
||||
//console.log('did-get-response-details', newURL)
|
||||
}
|
||||
)
|
||||
viewContents.on(
|
||||
'did-get-redirect-request',
|
||||
(
|
||||
event,
|
||||
oldURL,
|
||||
newURL,
|
||||
isMainFrame,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers
|
||||
) => {
|
||||
trySend(browserContents, 'did-get-redirect-request', {
|
||||
oldURL,
|
||||
newURL,
|
||||
isMainFrame,
|
||||
httpResponseCode,
|
||||
requestMethod,
|
||||
referrer,
|
||||
headers
|
||||
})
|
||||
//console.log('did-get-redirect-request', newURL)
|
||||
}
|
||||
)
|
||||
viewContents.on('did-stop-loading', event => {
|
||||
//console.log('did-stop-loading', event.sender.getURL())
|
||||
trySend(browserContents, 'did-stop-loading')
|
||||
})
|
||||
viewContents.on('did-finish-load', event => {
|
||||
//console.log('did-finish-load', event.sender.getURL())
|
||||
progress = 1
|
||||
onProgress(progress)
|
||||
trySend(browserContents, 'progress', progress)
|
||||
})
|
||||
viewContents.on('dom-ready', event => {
|
||||
if (progress < 0.5) {
|
||||
progress = 0.5
|
||||
onProgress(progress)
|
||||
trySend(browserContents, 'progress', progress)
|
||||
}
|
||||
viewContents.executeJavaScript('document.title', result => {
|
||||
trySend(browserContents, 'title', result)
|
||||
})
|
||||
|
||||
//console.log('dom-ready', event.sender.getURL())
|
||||
})
|
||||
|
||||
viewContents.on('new-window', function (event, url) {
|
||||
event.preventDefault()
|
||||
console.log('new-window')
|
||||
openBrowserView(url, x, y)
|
||||
})
|
||||
|
||||
viewContents.loadURL(url)
|
||||
}
|
||||
browsers.set(url, browser)
|
||||
browser.on('closed', e => {
|
||||
for (let [url, browser] of browsers.entries()) {
|
||||
if (browser == e.sender) {
|
||||
browsers.delete(url)
|
||||
console.log('removed browser view', url)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// UO: Experimental call. Opens a Min Browser window or a limited window with a browser view
|
||||
ipcMain.on('loadBrowserView', (e, opts = {}) => {
|
||||
let { url, x, y } = opts
|
||||
openBrowserView(url, x, y)
|
||||
})
|
||||
|
||||
ipcMain.on('multiUserMode', (e, opts = {}) => {
|
||||
global.multiUserMode = opts
|
||||
})
|
||||
|
||||
ipcMain.on('padContainerLoaded', e => {
|
||||
win.webContents.send('padContainerAvailable')
|
||||
})
|
||||
|
||||
ipcMain.on('createScreenshot', (e, opts = {}) => {
|
||||
opts = Object.assign(
|
||||
{},
|
||||
{
|
||||
name: `iwmbrowser-${new Date()
|
||||
.toISOString()
|
||||
.replace(/:/g, '-')}.png`,
|
||||
path: os.tmpdir()
|
||||
},
|
||||
opts
|
||||
)
|
||||
|
||||
win.webContents.capturePage(image => {
|
||||
if (image) {
|
||||
let file = path.join(opts.path, opts.name)
|
||||
fs.writeFile(file, image.toPNG(), err => {
|
||||
if (err) {
|
||||
//throw err
|
||||
} else {
|
||||
console.log(`Screenshot saved: ${file}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('directoryListing', (e, opts = {}) => {
|
||||
let { directory, files, folders } = opts
|
||||
console.log("directoryListing", opts)
|
||||
try {
|
||||
let listing = fs.readdirSync(directory)
|
||||
let result = { directory, files: [], folders: [] }
|
||||
for (let name of listing) {
|
||||
if (name.startsWith('.'))
|
||||
continue
|
||||
let fullPath = path.join(directory, name)
|
||||
let stat = fs.lstatSync(fullPath)
|
||||
if (files && stat.isFile()) {
|
||||
if (typeof files == 'string' && !files.endsWith(files))
|
||||
continue
|
||||
result.files.push(name)
|
||||
}
|
||||
if (folders && stat.isDirectory())
|
||||
result.folders.push(name)
|
||||
}
|
||||
e.sender.send('directoryListing', result)
|
||||
} catch (err) {
|
||||
let args = { directory, errorMessage: err.message}
|
||||
e.sender.send('directoryListingError', args)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('createTextfile', (e, opts = {}) => {
|
||||
opts = Object.assign(
|
||||
{},
|
||||
{
|
||||
name: `iwmbrowser-${new Date()
|
||||
.toISOString()
|
||||
.replace(/:/g, '-')}.txt`,
|
||||
path: os.tmpdir(),
|
||||
text: ''
|
||||
},
|
||||
opts
|
||||
)
|
||||
let file = path.join(opts.path, opts.name)
|
||||
fs.writeFile(file, opts.text, err => {
|
||||
if (err) {
|
||||
//throw err
|
||||
} else {
|
||||
console.log(`Textfile saved: ${file}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('error', e => {
|
||||
console.log('Received error notification')
|
||||
global.errorCount += 1
|
||||
})
|
||||
|
||||
ipcMain.on('openExternal', (e, url=null) => {
|
||||
console.log('Received openExternal', url)
|
||||
if (url) {
|
||||
shell.openExternal(url)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('save', (e, opts = {}) => {
|
||||
let { url, html, saveAs, action } = opts
|
||||
// url must absolute URL
|
||||
let urlObj = new URL(url)
|
||||
let pathname = urlObj.pathname
|
||||
if (saveAs) {
|
||||
pathname = dialog.showSaveDialog(win, { title: 'Save as:', defaultPath: pathname })
|
||||
if (typeof pathname == 'undefined')
|
||||
return
|
||||
}
|
||||
try {
|
||||
console.log("Saving", pathname, action)
|
||||
html = prettyPrint(html, { indent_size: 4 });
|
||||
fs.writeFileSync(pathname, html, 'utf-8')
|
||||
if (saveAs) {
|
||||
let normalized = pathname.replace(/\\/g, '/')
|
||||
e.sender.send('savedAs', {url: `file://${normalized}`, action})
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.warn('Failed to save the file', pathname)
|
||||
e.sender.send('saveFailed', pathname)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on(
|
||||
'select-client-certificate',
|
||||
(event, webContents, url, list, callback) => {
|
||||
console.log('select-client-certificate', url, list)
|
||||
event.preventDefault()
|
||||
ipc.once('client-certificate-selected', (event, item) => {
|
||||
console.log('selected:', item)
|
||||
callback(item)
|
||||
})
|
||||
mainWindow.webContents.send('select-client-certificate', list)
|
||||
}
|
||||
)
|
||||
|
||||
app.on(
|
||||
'certificate-error',
|
||||
(event, webContents, url, error, certificate, callback) => {
|
||||
console.log('certificate-error', url)
|
||||
event.preventDefault()
|
||||
const result = true // TODO: do real validation here
|
||||
callback(result)
|
||||
}
|
||||
)
|
||||
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (win === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
store: store
|
||||
}
|
||||
629
browser/menu.js
@ -1,629 +0,0 @@
|
||||
/* globals require, process */
|
||||
/*eslint no-console: ["error", { allow: ["log", "error"] }] */
|
||||
|
||||
const { Menu, app, shell, dialog } = require('electron')
|
||||
const fs = require('fs')
|
||||
const fse = require('fs-extra')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const { openProcessManager } = require('electron-process-manager')
|
||||
const main = require('./main.js')
|
||||
|
||||
let { thumbnail } = require('./utils.js')
|
||||
const loadTests = require('./test.js')
|
||||
const i18n = new (require('./i18n.js'))()
|
||||
|
||||
function selectURL(url) {
|
||||
url = url.replace(/\\/g, '/')
|
||||
console.log('selectURL', url)
|
||||
main.win.loadURL(url)
|
||||
main.store.set('url', url)
|
||||
}
|
||||
|
||||
function findItems(key, value) {
|
||||
let items = []
|
||||
|
||||
for (let i = 0; i < menu.items.length; i++) {
|
||||
for (let j = 0; j < menu.items[i].submenu.items.length; j++) {
|
||||
let item = menu.items[i].submenu.items[j]
|
||||
if (item[key] === value) {
|
||||
items.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
function findItem(key, value) {
|
||||
return findItems(key, value)[0]
|
||||
}
|
||||
|
||||
function toggleBookmarks(bookmark) {
|
||||
let items = findItems('class', 'bookmark')
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
items[i].checked = false
|
||||
}
|
||||
|
||||
bookmark.checked = true
|
||||
}
|
||||
|
||||
function checkBookmark(url) {
|
||||
let items = findItems('url', url)
|
||||
if (items.length === 1) {
|
||||
toggleBookmarks(items[0])
|
||||
}
|
||||
}
|
||||
|
||||
function setHistoryStatus() {
|
||||
const historyBack = findItem('id', 'history-back')
|
||||
historyBack.enabled = main.win.webContents.canGoBack()
|
||||
|
||||
const historyForward = findItem('id', 'history-forward')
|
||||
historyForward.enabled = main.win.webContents.canGoForward()
|
||||
}
|
||||
|
||||
function showSelectDataFolderDialog(focusedWindow) {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
title: i18n.__('selectfolder.select.title'),
|
||||
buttonLabel: i18n.__('selectfolder.select.buttonLabel'),
|
||||
properties: ['openDirectory', 'createDirectory', 'noResolveAliases', 'treatPackageAsDirectory']
|
||||
},
|
||||
(filePaths) => {
|
||||
if (filePaths && filePaths.length === 1) {
|
||||
const varPath = path.join(__dirname, '../var')
|
||||
|
||||
// Check if the same folder was used
|
||||
if (filePaths[0].startsWith(varPath)) {
|
||||
const same = filePaths[0] === varPath
|
||||
|
||||
dialog.showMessageBox(
|
||||
{
|
||||
type: 'error',
|
||||
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
|
||||
buttons: [i18n.__('selectfolder.samefolder.ok')],
|
||||
defaultId: 0,
|
||||
message: i18n.__('selectfolder.samefolder.message'),
|
||||
detail: same
|
||||
? i18n.__('selectfolder.samefolder.detail.same')
|
||||
: i18n.__('selectfolder.samefolder.detail.within'),
|
||||
cancelId: 0
|
||||
},
|
||||
(response) => {
|
||||
showSelectDataFolderDialog(focusedWindow)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
// Backup
|
||||
if (fse.pathExistsSync(varPath)) {
|
||||
const varPathBackup = findNextVarFolder()
|
||||
// Rename old var folder or link
|
||||
fse.renameSync(varPath, varPathBackup)
|
||||
} else {
|
||||
// BUG: Workaround because pathExistsSync return false on existing symbolic links with a missing target
|
||||
fse.removeSync(varPath)
|
||||
}
|
||||
|
||||
// Add new symlink
|
||||
main.store.set('dataFolder', filePaths[0])
|
||||
fs.symlinkSync(filePaths[0], varPath, 'dir')
|
||||
|
||||
dialog.showMessageBox(
|
||||
{
|
||||
type: 'info',
|
||||
icon: path.join(__dirname, '../assets/icons/png/link.png'),
|
||||
buttons: [i18n.__('selectfolder.info.ok')],
|
||||
defaultId: 0,
|
||||
message: i18n.__('selectfolder.info.message'),
|
||||
detail: i18n.__('selectfolder.info.detail').replace(/\$\{0\}/, filePaths[0]),
|
||||
cancelId: 0
|
||||
},
|
||||
(response) => {
|
||||
if (focusedWindow) focusedWindow.reload()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function findNextVarFolder() {
|
||||
let exists = true
|
||||
let counter = 0
|
||||
|
||||
while (exists) {
|
||||
counter++
|
||||
exists = fse.pathExistsSync(path.join(__dirname, `../var${counter}`))
|
||||
}
|
||||
|
||||
return path.join(__dirname, `../var${counter}`)
|
||||
}
|
||||
|
||||
function showFolderBrowser(focusedWindow) {
|
||||
const varPath = path.join(__dirname, '../var')
|
||||
const varPathExists = fse.pathExistsSync(varPath)
|
||||
if (varPathExists) {
|
||||
dialog.showMessageBox(
|
||||
{
|
||||
type: 'warning',
|
||||
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
|
||||
buttons: [i18n.__('selectfolder.warning.next'), i18n.__('selectfolder.warning.cancel')],
|
||||
defaultId: 1,
|
||||
message: i18n.__('selectfolder.warning.message'),
|
||||
detail: i18n.__('selectfolder.warning.detail'),
|
||||
cancelId: 1
|
||||
},
|
||||
(response) => {
|
||||
if (response === 0) {
|
||||
showSelectDataFolderDialog(focusedWindow)
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
showSelectDataFolderDialog(focusedWindow)
|
||||
}
|
||||
}
|
||||
|
||||
const template = [
|
||||
{
|
||||
label: i18n.__('edit'),
|
||||
submenu: [
|
||||
{
|
||||
role: 'undo',
|
||||
label: i18n.__('undo')
|
||||
},
|
||||
{
|
||||
role: 'redo',
|
||||
label: i18n.__('redo')
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
role: 'cut',
|
||||
label: i18n.__('cut')
|
||||
},
|
||||
{
|
||||
role: 'copy',
|
||||
label: i18n.__('copy')
|
||||
},
|
||||
{
|
||||
role: 'paste',
|
||||
label: i18n.__('paste')
|
||||
},
|
||||
{
|
||||
role: 'pasteandmatchstyle',
|
||||
label: i18n.__('pasteandmatchstyle')
|
||||
},
|
||||
{
|
||||
role: 'delete',
|
||||
label: i18n.__('delete')
|
||||
},
|
||||
{
|
||||
role: 'selectall',
|
||||
label: i18n.__('selectall')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: i18n.__('view'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('reload'),
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.webContents.setVisualZoomLevelLimits(1, 1)
|
||||
focusedWindow.reload()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'forcereload',
|
||||
label: i18n.__('forcereload'),
|
||||
accelerator: 'CmdOrCtrl+Shift+R',
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.webContents.session.clearCache(() => console.log('Cache cleared'))
|
||||
|
||||
focusedWindow.webContents.setVisualZoomLevelLimits(1, 1)
|
||||
focusedWindow.reload()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
role: 'resetzoom',
|
||||
label: i18n.__('resetzoom')
|
||||
},
|
||||
{
|
||||
role: 'zoomin',
|
||||
label: i18n.__('zoomin')
|
||||
},
|
||||
{
|
||||
role: 'zoomout',
|
||||
label: i18n.__('zoomout')
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
id: 'togglefullscreen',
|
||||
label: i18n.__('togglefullscreen'),
|
||||
accelerator: process.platform === 'darwin' ? 'Cmd+Ctrl+F' : 'F11',
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('multiuserbrowser'),
|
||||
accelerator: 'CmdOrCtrl+M',
|
||||
type: 'checkbox',
|
||||
checked: true,
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
main.store.set('multiUserBrowser', item.checked)
|
||||
global.multiUserMode = item.checked
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: i18n.__('minimalpad'),
|
||||
accelerator: 'CmdOrCtrl+p',
|
||||
type: 'checkbox',
|
||||
checked: true,
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
main.store.set('minimalPad', item.checked)
|
||||
global.useMinimalPad = item.checked
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: i18n.__('history'),
|
||||
submenu: [
|
||||
{
|
||||
id: 'history-back',
|
||||
label: i18n.__('back'),
|
||||
accelerator: 'CmdOrCtrl+Left',
|
||||
click(item, focusedWindow) {
|
||||
main.win.webContents.goBack()
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'history-forward',
|
||||
label: i18n.__('forward'),
|
||||
accelerator: 'CmdOrCtrl+Right',
|
||||
click(item, focusedWindow) {
|
||||
main.win.webContents.goForward()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: i18n.__('home'),
|
||||
accelerator: 'CmdOrCtrl+Up',
|
||||
click(item, focusedWindow) {
|
||||
main.win.webContents.goToIndex(0)
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('recentlyvisited'),
|
||||
enabled: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: i18n.__('bookmarks'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('localfilesystem'),
|
||||
class: 'bookmark',
|
||||
type: 'checkbox',
|
||||
url: `file://${__dirname}/../index.html`,
|
||||
accelerator: 'CmdOrCtrl+L',
|
||||
click(item, focusedWindow) {
|
||||
selectURL(item.url)
|
||||
toggleBookmarks(item)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: i18n.__('testframes'),
|
||||
class: 'bookmark',
|
||||
type: 'checkbox',
|
||||
url: `file://${__dirname}/../index.html?test`,
|
||||
accelerator: 'CmdOrCtrl+T',
|
||||
click(item, focusedWindow) {
|
||||
selectURL(item.url)
|
||||
toggleBookmarks(item)
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
id: 'localhost',
|
||||
label: 'https://localhost:8443',
|
||||
class: 'bookmark',
|
||||
type: 'checkbox',
|
||||
enabled: false,
|
||||
url: 'https://localhost:8443/index.html',
|
||||
click(item, focusedWindow) {
|
||||
selectURL(item.url)
|
||||
toggleBookmarks(item)
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'localhost',
|
||||
label: 'https://localhost:3000',
|
||||
class: 'bookmark',
|
||||
type: 'checkbox',
|
||||
enabled: true,
|
||||
url: 'https://localhost:3000/index.html',
|
||||
click(item, focusedWindow) {
|
||||
selectURL(item.url)
|
||||
toggleBookmarks(item)
|
||||
}
|
||||
},
|
||||
// {
|
||||
// label: 'http://tornado.iwm-kmrc.de:8000',
|
||||
// class: 'bookmark',
|
||||
// type: 'checkbox',
|
||||
// url: 'http://tornado.iwm-kmrc.de:8000/index.html',
|
||||
// click(item, focusedWindow) {
|
||||
// selectURL(item.url)
|
||||
// toggleBookmarks(item)
|
||||
// }
|
||||
// },
|
||||
{
|
||||
label: 'http://rousseau.iwm-kmrc.de/index.html',
|
||||
class: 'bookmark',
|
||||
type: 'checkbox',
|
||||
url: 'http://rousseau.iwm-kmrc.de/index.html',
|
||||
click(item, focusedWindow) {
|
||||
selectURL(item.url)
|
||||
toggleBookmarks(item)
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: i18n.__('develop'),
|
||||
submenu: [
|
||||
{
|
||||
id: 'toggledevelopertools',
|
||||
label: i18n.__('toggledevelopertools'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
click(item, focusedWindow) {
|
||||
if (focusedWindow) focusedWindow.webContents.toggleDevTools()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: i18n.__('openprocessmonitor'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+P' : 'Ctrl+Shift+P',
|
||||
click(item, focusedWindow) {
|
||||
openProcessManager()
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('selectfolder'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+D' : 'Ctrl+Shift+D',
|
||||
click(item, focusedWindow) {
|
||||
if (process.platform === 'win32') {
|
||||
var exec = require('child_process').exec
|
||||
exec('NET SESSION', function (err, so, se) {
|
||||
const admin = se.length === 0 ? true : false
|
||||
|
||||
if (admin) {
|
||||
showFolderBrowser(focusedWindow)
|
||||
} else {
|
||||
dialog.showMessageBox({
|
||||
type: 'error',
|
||||
icon: path.join(__dirname, '../assets/icons/png/512x512-empty.png'),
|
||||
buttons: [i18n.__('selectfolder.noadmin.ok')],
|
||||
message: i18n.__('selectfolder.noadmin.message'),
|
||||
detail: i18n.__('selectfolder.noadmin.detail')
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
showFolderBrowser(focusedWindow)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
id: 'startserver',
|
||||
label: i18n.__('startserver'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+S' : 'Ctrl+Shift+S',
|
||||
click(item, focusedWindow) {
|
||||
const { server } = require('../server/main.js')
|
||||
server.start()
|
||||
item.visible = false
|
||||
findItem('id', 'stopserver').visible = true
|
||||
findItem('id', 'localhost').enabled = true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'stopserver',
|
||||
label: i18n.__('stopserver'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+S' : 'Ctrl+Shift+S',
|
||||
visible: false,
|
||||
click(item, focusedWindow) {
|
||||
const { server } = require('../server/main.js')
|
||||
server.stop()
|
||||
item.visible = false
|
||||
findItem('id', 'startserver').visible = true
|
||||
findItem('id', 'localhost').enabled = false
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('runloadtests'),
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+L' : 'Ctrl+Shift+L',
|
||||
click(item, focusedWindow) {
|
||||
loadTests(focusedWindow)
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Aktualisiere Tüsch POIs',
|
||||
click(item, focusedWindow) {
|
||||
const UpdatePOI = require('../dev/tuesch/bin/menu/update-pois.js')
|
||||
UpdatePOI.update('./dev/tuesch')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'window',
|
||||
label: i18n.__('window'),
|
||||
submenu: [
|
||||
{
|
||||
role: 'close',
|
||||
label: i18n.__('close')
|
||||
},
|
||||
{
|
||||
role: 'minimize',
|
||||
label: i18n.__('minimize')
|
||||
},
|
||||
{
|
||||
role: 'zoom',
|
||||
label: i18n.__('zoom')
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
role: 'front',
|
||||
label: i18n.__('front')
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('screenshot'),
|
||||
accelerator: 'CmdOrCtrl+S',
|
||||
async click(item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
await focusedWindow.webContents.capturePage().then((image) => {
|
||||
let screenshotFile = path.join(os.tmpdir(), 'screenshot.png')
|
||||
|
||||
console.log('image captured', screenshotFile)
|
||||
|
||||
let url = focusedWindow.webContents.getURL()
|
||||
if (url.startsWith('file://')) {
|
||||
let normalized = path.normalize(url).replace('.html', '.png')
|
||||
screenshotFile = normalized.replace('file:', '')
|
||||
let thumbnailFile = screenshotFile.replace('index.png', 'thumbnail.png')
|
||||
if (url.endsWith('index.html')) {
|
||||
thumbnailFile = screenshotFile.replace('index.png', 'thumbnail.png')
|
||||
} else {
|
||||
let folderName = path.dirname(screenshotFile)
|
||||
let baseName = path.basename(screenshotFile)
|
||||
thumbnailFile = path.join(folderName, 'thumbnails', baseName)
|
||||
}
|
||||
fs.writeFile(thumbnailFile, thumbnail(image), (err) => {
|
||||
if (err) {
|
||||
throw err
|
||||
} else {
|
||||
console.log(`Thumbnail written to ${thumbnailFile}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
fs.writeFile(screenshotFile, image.toPNG(), (err) => {
|
||||
if (err) {
|
||||
throw err
|
||||
} else {
|
||||
console.log(`Screenshot written to ${screenshotFile}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
label: i18n.__('help'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('iwm'),
|
||||
click() {
|
||||
shell.openExternal('https://www.iwm-tuebingen.de')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
const name = app.getName()
|
||||
template.unshift({
|
||||
label: name,
|
||||
submenu: [
|
||||
{
|
||||
role: 'about',
|
||||
label: i18n.__('about')
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
role: 'quit',
|
||||
label: i18n.__('quit')
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
checkBookmark(main.store.get('url'))
|
||||
setHistoryStatus()
|
||||
|
||||
function focus() {
|
||||
findItem('id', 'forcereload').enabled = true
|
||||
findItem('id', 'togglefullscreen').enabled = true
|
||||
findItem('id', 'toggledevelopertools').enabled = true
|
||||
}
|
||||
|
||||
function blur() {
|
||||
findItem('id', 'forcereload').enabled = false
|
||||
findItem('id', 'togglefullscreen').enabled = false
|
||||
findItem('id', 'toggledevelopertools').enabled = false
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
menu,
|
||||
setHistoryStatus,
|
||||
focus,
|
||||
blur
|
||||
}
|
||||
@ -1,171 +0,0 @@
|
||||
/* globals require, __dirname, process */
|
||||
/*eslint no-console: ["error", { allow: ["log", "info", "warn", "error"] }]*/
|
||||
|
||||
const fse = require('fs-extra')
|
||||
const path = require('path')
|
||||
const packager = require('electron-packager')
|
||||
const rebuild = require('electron-rebuild')
|
||||
|
||||
// Arguments
|
||||
//----------------------
|
||||
let folder = null
|
||||
|
||||
if (process.argv.length < 3) {
|
||||
console.error('Missing command line parameter "folder"!')
|
||||
process.exit(1)
|
||||
} else {
|
||||
folder = process.argv[2]
|
||||
}
|
||||
|
||||
// Settings
|
||||
//----------------------
|
||||
let settings = null
|
||||
const root = path.join(__dirname, '../')
|
||||
|
||||
try {
|
||||
settings = require(`../${folder}/settings.json`)
|
||||
} catch (e) {
|
||||
console.error('Cannot read settings.json in folder, does it exist?')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Read settings
|
||||
//----------------------
|
||||
const title = `--- Build "${settings.name || settings.id}" ---`
|
||||
const line = Array(title.length + 1).join('-')
|
||||
console.info(line)
|
||||
console.info(title)
|
||||
console.info(line)
|
||||
|
||||
// Using folder
|
||||
//----------------------
|
||||
const tempFolder = path.join(root, 'temp', settings.id)
|
||||
console.log(`Using folder ${tempFolder}`)
|
||||
|
||||
// Delete temp folder (when last run aborted)
|
||||
fse.removeSync(tempFolder)
|
||||
console.log(`Folder ${tempFolder} deleted`)
|
||||
|
||||
// Create folder
|
||||
fse.ensureDirSync(tempFolder)
|
||||
console.log(`Folder ${tempFolder} created`)
|
||||
|
||||
// Create subfolders
|
||||
const defaultFolders = ['assets', 'browser', 'css', 'lib', 'node_modules', 'server']
|
||||
console.log(`The folders ${defaultFolders.join(', ')} are included by default`)
|
||||
const folders = new Set(settings.browser.folders.concat(defaultFolders))
|
||||
for (let folder of folders) {
|
||||
console.log(`Copy folder ${folder}`)
|
||||
const folderOld = path.join(root, folder)
|
||||
const folderNew = path.join(root, 'temp', settings.id, folder)
|
||||
|
||||
fse.copySync(folderOld, folderNew)
|
||||
}
|
||||
|
||||
// Write package.json
|
||||
//----------------------
|
||||
let json = {
|
||||
name: settings.id,
|
||||
productName: settings.name || settings.id,
|
||||
version: settings.version,
|
||||
main: 'browser/main.js',
|
||||
dependencies: {}
|
||||
}
|
||||
|
||||
// Read and write dependencies
|
||||
const packageJson = fse.readJsonSync(path.join(root, 'package.json'))
|
||||
Object.assign(json.dependencies, packageJson.dependencies)
|
||||
|
||||
// Add browser dependencies
|
||||
if (settings.browser.dependencies) {
|
||||
let dependencies = {}
|
||||
for (let dependency of settings.browser.dependencies) {
|
||||
dependencies[dependency] = '*'
|
||||
}
|
||||
Object.assign(json.dependencies, dependencies)
|
||||
}
|
||||
|
||||
console.log('Create package.json')
|
||||
fse.writeJsonSync(path.join(tempFolder, 'package.json'), json, {spaces: 4})
|
||||
|
||||
// Write URL to settings.json
|
||||
//----------------------
|
||||
console.log('Write URL to browser/settings.json')
|
||||
fse.writeJsonSync(path.join(tempFolder, 'browser/settings.json'), {url: `../${folder}/index.html`}, {spaces: 4})
|
||||
|
||||
// Build with electron-packager
|
||||
//----------------------
|
||||
console.log('Start electron-packager')
|
||||
packager({
|
||||
dir: `./temp/${settings.id}`,
|
||||
arch: 'x64',
|
||||
asar: false,
|
||||
overwrite: true,
|
||||
out: './dist/electron',
|
||||
icon: './assets/icons/icon',
|
||||
platform: settings.browser.platform || ['darwin', 'win32'],
|
||||
prune: false,
|
||||
afterCopy: [(buildPath, electronVersion, platform, arch, callback) => {
|
||||
console.log(`Rebuild Node.js modules for ${platform}...`)
|
||||
rebuild.rebuild({buildPath, electronVersion, arch})
|
||||
.then(() => {
|
||||
console.log(`...Node.js modules for ${platform} rebuilded`)
|
||||
callback()
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(`Error: ${error}`)
|
||||
callback(error)
|
||||
});
|
||||
}]
|
||||
})
|
||||
.then(appPaths => {
|
||||
console.log('electron-packager finished')
|
||||
|
||||
// Delete temp folder
|
||||
//----------------------
|
||||
fse.removeSync(tempFolder)
|
||||
console.log(`Folder ${tempFolder} deleted`)
|
||||
|
||||
// Write data folders
|
||||
//----------------------
|
||||
if (settings.browser.data) {
|
||||
console.log('Copy data folders')
|
||||
for (let folder of settings.browser.data) {
|
||||
for (let appPath of appPaths) {
|
||||
console.log(`Copy folder ${folder} to ${appPath}`)
|
||||
const source = path.join(root, folder)
|
||||
const target = path.join(getResourcesPath(root, appPath), folder)
|
||||
fse.copySync(source, target, {
|
||||
dereference: true,
|
||||
filter: item => {
|
||||
if (settings.browser.dataExtensions && fse.lstatSync(item).isFile() && !settings.browser.dataExtensions.includes(path.extname(item).substring(1).toLowerCase())) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finished
|
||||
//----------------------
|
||||
console.info('Finished')
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
function getResourcesPath(root, appPath) {
|
||||
|
||||
let resourcesPath = ""
|
||||
|
||||
if (/darwin/.test(appPath) || /mas/.test(appPath)) {
|
||||
resourcesPath = path.join(root, appPath, `${json.productName}.app/Contents/Resources/app`)
|
||||
} else if (/win32/.test(appPath) || /linux/.test(appPath)) {
|
||||
resourcesPath = path.join(root, appPath, 'resources/app')
|
||||
}
|
||||
|
||||
return resourcesPath
|
||||
}
|
||||
570
browser/pad.js
@ -1,570 +0,0 @@
|
||||
const {fileURL} = require('./utils.js')
|
||||
const path = require('path')
|
||||
|
||||
/* A specialization that ignores webview events and thus allows
|
||||
* webviews to get touch, mouse and wheel events.
|
||||
*/
|
||||
class DOMPadContainer extends DOMScatterContainer {
|
||||
|
||||
capture(event) {
|
||||
if (event.target.tagName === 'WEBVIEW' || event.target.classList.contains('interactiveElement'))
|
||||
return false
|
||||
return super.capture(event)
|
||||
}
|
||||
}
|
||||
|
||||
/* A wrapper for a webview that behaves like a virtual tablet browser.
|
||||
* Uses a DOMScatter to zoom and rotate the virtual browser window.
|
||||
* The position of buttons and the border size remain constant.
|
||||
*/
|
||||
class Pad {
|
||||
|
||||
constructor(scatterContainer, {
|
||||
startScale=1.0, minScale=0.25, maxScale=10.5,
|
||||
autoBringToFront=true,
|
||||
url="https://www.iwm-tuebingen.de/www/index.html",
|
||||
hideOnStart=false,
|
||||
translatable=true, scalable=true, rotatable=true,
|
||||
movableX=true,
|
||||
movableY=true,
|
||||
rotationDegrees=null,
|
||||
rotation=null,
|
||||
onTransform=null,
|
||||
transformOrigin = 'center center',
|
||||
// extras which are in part needed
|
||||
x=0,
|
||||
y=0,
|
||||
width=null,
|
||||
height=null,
|
||||
resizable=false,
|
||||
} ={}) {
|
||||
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.url = url
|
||||
this.hideOnStart = hideOnStart
|
||||
this.width = width
|
||||
this.height = height
|
||||
this.minScale = minScale
|
||||
this.maxScale = maxScale
|
||||
this.scatterContainer = scatterContainer
|
||||
this.startScale = startScale
|
||||
this.scale = startScale
|
||||
this.scalable = scalable
|
||||
this.rotatable = rotatable
|
||||
this.rotationDegrees = this.startRotationDegrees
|
||||
this.transformOrigin = transformOrigin
|
||||
|
||||
this.frame = document.createElement('div')
|
||||
this.frame.classList.add("pad")
|
||||
this.border = 50 / startScale
|
||||
|
||||
Elements.setStyle(this.frame, {
|
||||
backgroundColor: "#333",
|
||||
position: "absolute",
|
||||
display: 'flex',
|
||||
width: this.width+"px",
|
||||
height: this.height+"px",
|
||||
top: 0,
|
||||
left: 0,
|
||||
// boxShadow: `10px 10px 10px rgba(0, 0, 0, 0.5)`,
|
||||
// borderRadius: '10px',
|
||||
overflow: "visible"})
|
||||
|
||||
document.body.appendChild( this.frame)
|
||||
|
||||
this.web=document.createElement("webview")
|
||||
this.webBackground=document.createElement("div")
|
||||
this.webViewSnapshot=document.createElement("img")
|
||||
this.overlay = document.createElement('div')
|
||||
|
||||
this.loadAnim = document.createElement("div")
|
||||
this.loadAnim.style.webkitAnimation= "spin 2s linear infinite"
|
||||
this.loadAnim.style.animation= "spin 2s linear infinite"
|
||||
this.loadAnim.style.position = "absolute"
|
||||
|
||||
document.styleSheets[0].insertRule('\
|
||||
@keyframes spin {\
|
||||
from { transform: rotateZ(0deg); }\
|
||||
to { transform: rotateZ(360deg); }\
|
||||
}'
|
||||
)
|
||||
|
||||
this.overlay.appendChild(this.loadAnim)
|
||||
|
||||
Elements.setStyle(this.web, {
|
||||
position: "absolute",
|
||||
overflow: "auto",
|
||||
border: "1px solid #fff"
|
||||
})
|
||||
// this.web.classList.add("interactiveElement")
|
||||
// this.web.style.pointerEvents="none"
|
||||
|
||||
Elements.setStyle(this.webBackground, {
|
||||
position: "absolute",
|
||||
overflow: "auto",
|
||||
background: "white"
|
||||
})
|
||||
|
||||
Elements.setStyle(this.overlay, {
|
||||
position: "absolute",
|
||||
overflow: "auto",
|
||||
background: "white",
|
||||
opacity: "0.8"
|
||||
})
|
||||
|
||||
Elements.setStyle(this.webViewSnapshot, {
|
||||
position: "absolute",
|
||||
overflow: "auto"
|
||||
})
|
||||
|
||||
let timeTouchStart = 0
|
||||
this.overlayCaptureEvents = document.createElement('div')
|
||||
// overlay.style.background="white"
|
||||
|
||||
this.overlayCaptureEvents.classList.add("interactiveElement")
|
||||
|
||||
this.overlayCaptureEvents.addEventListener('touchmove',(e)=>{
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
this.overlayCaptureEvents.addEventListener('pointerup',(e)=>{
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let p = {x:e.clientX, y:e.clientY}
|
||||
|
||||
let webviewPosition = Points.fromPageToNode(this.web,p)
|
||||
|
||||
let d = new Date()
|
||||
|
||||
if(d.getTime()-timeTouchStart<150)this.web.sendInputEvent({type:'mouseUp', x: webviewPosition.x, y: webviewPosition.y, button:'left', clickCount: 1})
|
||||
})
|
||||
|
||||
this.overlayCaptureEvents.addEventListener('pointerdown',(e)=>{
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.scatter.bringToFront()
|
||||
let p = {x:e.clientX, y:e.clientY}
|
||||
|
||||
let webviewPosition = Points.fromPageToNode(this.web,p)
|
||||
|
||||
let d = new Date()
|
||||
timeTouchStart = d.getTime()
|
||||
|
||||
this.web.sendInputEvent({type:'mouseDown', x: webviewPosition.x, y: webviewPosition.y, button:'left', clickCount: 1})
|
||||
})
|
||||
|
||||
this.overlayCaptureEvents.addEventListener('pointermove',(e)=>{
|
||||
if(e.pointerType!='mouse'){
|
||||
let rotation = Angle.radian2degree(this.scatter.rotation);
|
||||
rotation = (rotation + 360) % 360;
|
||||
|
||||
let r = Math.sqrt(Math.pow(e.movementX, 2) + Math.pow(e.movementY, 2));
|
||||
let phi = Angle.radian2degree(Math.atan2(e.movementX, e.movementY));
|
||||
|
||||
phi = ((phi) + 630) % 360;
|
||||
let rot = ((rotation + 90) + 630) % 360;
|
||||
|
||||
let diffAngle = ((0 + rot) + 360) % 360;
|
||||
let phiCorrected = (phi + diffAngle + 360) % 360;
|
||||
|
||||
let deltaX = r * Math.cos(Angle.degree2radian(phiCorrected));
|
||||
let deltaY = -r * Math.sin(Angle.degree2radian(phiCorrected));
|
||||
|
||||
this.web.executeJavaScript("window.scrollTo(scrollX+"+(-1*deltaX)+", scrollY+"+ (-1*deltaY)+")")
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
this.overlayCaptureEvents.addEventListener('mousewheel',(e)=>{
|
||||
console.log("mousewheel",e.deltaY)
|
||||
// webview.sendInputEvent({type:'mouseWheel', x: 0, y: 0, deltaX: e.deltaX, deltaY: -e.deltaY, canScroll: true })
|
||||
this.web.executeJavaScript("window.scrollTo(scrollX+"+e.deltaX+", scrollY+"+ e.deltaY+")")
|
||||
})
|
||||
|
||||
this.frame.appendChild(this.webBackground)
|
||||
this.frame.appendChild(this.web)
|
||||
this.frame.appendChild(this.webViewSnapshot)
|
||||
this.frame.appendChild(this.overlay)
|
||||
if(remote.getGlobal('multiUserMode'))this.frame.appendChild(this.overlayCaptureEvents)
|
||||
|
||||
this.webViewSnapshot.style.visibility="hidden"
|
||||
|
||||
this.web.src=url
|
||||
this.web.preload= path.join(__dirname, './preloadPad.js')
|
||||
|
||||
this.closeButton = this.addButton("../assets/icons/svg/cross.svg", "close")
|
||||
this.backButton = this.addButton("../assets/icons/svg/left.svg", "go back")
|
||||
this.forwardButton = this.addButton("../assets/icons/svg/right.svg", "go forward")
|
||||
|
||||
this.backButton.style.opacity = 0.5
|
||||
this.forwardButton.style.opacity = 0.5
|
||||
|
||||
/*for (let callback of window.padLoadedHandler) {
|
||||
callback(this, url)
|
||||
}*/
|
||||
|
||||
this.web.addEventListener('new-window', (e) => {
|
||||
|
||||
if(e.url.indexOf("youtube")>-1)return
|
||||
|
||||
if (urlPadMap.has(e.url)) {
|
||||
let childPad = urlPadMap.get(e.url)
|
||||
childPad.scatter.moveTo(x, y)
|
||||
return childPad
|
||||
}
|
||||
let childPad = new Pad(this.scatterContainer, {
|
||||
x: this.scatter.position.x+100,
|
||||
y: this.scatter.position.y+100,
|
||||
url: e.url,
|
||||
width: this.scatter.width,
|
||||
height: this.scatter.height,
|
||||
scalable: true,
|
||||
rotatable: true})
|
||||
urlPadMap.set(e.url, childPad)
|
||||
|
||||
for(let callback of window.padLoadedHandler) {
|
||||
callback(childPad, url)
|
||||
}
|
||||
})
|
||||
|
||||
this.web.addEventListener('did-navigate', (e) => {
|
||||
this.enableButtons()
|
||||
})
|
||||
|
||||
this.web.addEventListener('dom-ready',()=>{
|
||||
//if(this.url.indexOf('local')>-1)this.web.openDevTools()
|
||||
})
|
||||
|
||||
this.web.addEventListener('ipc-message', (e) => {
|
||||
if(e.channel='webviewPointerDown')this.scatter.bringToFront()
|
||||
})
|
||||
|
||||
this.web.addEventListener('did-start-loading', ()=>{
|
||||
this.overlay.style.visibility="visible"
|
||||
|
||||
let w = this.overlay.offsetWidth
|
||||
let h = this.overlay.offsetHeight
|
||||
|
||||
console.log("did start loading",h,w)
|
||||
|
||||
let animationSize = w<h ? w*0.5 : h*0.5
|
||||
let animationRingWidth = animationSize*0.1;
|
||||
|
||||
this.loadAnim.style.border=animationRingWidth+"px solid #f3f3f3"
|
||||
this.loadAnim.style.borderTop=animationRingWidth+"px solid #ffb18c"
|
||||
this.loadAnim.style.borderRadius="50%"
|
||||
this.loadAnim.style.height=animationSize-animationRingWidth*2+"px"
|
||||
this.loadAnim.style.width=animationSize-animationRingWidth*2+"px"
|
||||
this.loadAnim.style.top = h*0.25+"px"
|
||||
this.loadAnim.style.left = w*0.25+"px"
|
||||
w<h ? this.loadAnim.style.top = 0.5*(h-animationSize)+"px" : this.loadAnim.style.left = 0.5*(w-animationSize)+"px"
|
||||
})
|
||||
|
||||
this.web.addEventListener('did-stop-loading', ()=>{
|
||||
this.overlay.style.visibility="hidden"
|
||||
})
|
||||
|
||||
/*this.backButton.addEventListener('click', ()=>{
|
||||
if(this.web.canGoBack())
|
||||
this.web.goBack()
|
||||
})
|
||||
|
||||
this.forwardButton.addEventListener('click', ()=>{
|
||||
if(this.web.canGoForward())
|
||||
this.web.goForward()
|
||||
})
|
||||
|
||||
this.closeButton.addEventListener('click', ()=>{
|
||||
this.close()
|
||||
})*/
|
||||
|
||||
InteractionMapper.on('tap',this.backButton, e => {
|
||||
if(this.web.canGoBack())
|
||||
this.web.goBack()
|
||||
})
|
||||
|
||||
InteractionMapper.on('tap',this.forwardButton, e => {
|
||||
if(this.web.canGoForward())
|
||||
this.web.goForward()
|
||||
})
|
||||
|
||||
InteractionMapper.on('tap',this.closeButton, e => {
|
||||
this.close()
|
||||
})
|
||||
|
||||
this.scatter = new DOMScatter(this.frame, scatterContainer, {
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
startScale: this.startScale,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
minScale: this.minScale,
|
||||
maxScale: this.maxScale,
|
||||
scalable: this.scalable,
|
||||
resizable: true,
|
||||
rotatable: this.rotatable})
|
||||
|
||||
let img=document.createElement("img")
|
||||
img.style.width = "70%"
|
||||
img.style.position = "absolute"
|
||||
img.style.bottom = "20%"
|
||||
img.style.right = "20%"
|
||||
img.style.pointerEvents="none"
|
||||
img.src = "../../assets/icons/png/flat/resize.png"
|
||||
this.scatter.resizeButton.appendChild(img)
|
||||
|
||||
this.scatter.moveTo({x, y})
|
||||
this.scatter.bringToFront()
|
||||
|
||||
this.scatter.addTransformEventCallback((e) => {
|
||||
let newBorder = 50 / e.scale
|
||||
if (newBorder !== this.border) {
|
||||
this.border = newBorder
|
||||
this.layout()
|
||||
}
|
||||
})
|
||||
this.layout()
|
||||
|
||||
}
|
||||
|
||||
rad2degree(alpha){
|
||||
return alpha * 180 / Math.PI;
|
||||
}
|
||||
|
||||
degree2rad(alpha){
|
||||
return alpha * Math.PI / 180;
|
||||
}
|
||||
|
||||
close() {
|
||||
// this.frame.style.display="none"
|
||||
this.frame.parentNode.removeChild(this.frame)
|
||||
urlPadMap.delete(this.url)
|
||||
}
|
||||
|
||||
enableButtons() {
|
||||
this.backButton.style.opacity = (this.web.canGoBack()) ? 1 : 0.5
|
||||
this.forwardButton.style.opacity = (this.web.canGoForward()) ? 1 : 0.5
|
||||
}
|
||||
|
||||
addButton(src, value) {
|
||||
let button = document.createElement("img")
|
||||
button.type = "image"
|
||||
button.className = "frameButton"
|
||||
button.style.position = "absolute"
|
||||
button.src = fileURL(src)
|
||||
button.value="close"
|
||||
button.draggable = false
|
||||
button.classList.add("interactiveElement")
|
||||
this.frame.appendChild(button)
|
||||
return button
|
||||
}
|
||||
|
||||
layout() {
|
||||
let b = this.border
|
||||
let b2 = b * 2
|
||||
let b8 = b / 8
|
||||
let b25 = b / 25
|
||||
let b15 = b / 15
|
||||
|
||||
this.scatter.resizeButton.style.width=b+"px"
|
||||
this.scatter.resizeButton.style.height=b+"px"
|
||||
|
||||
Elements.setStyle(this.frame, {
|
||||
// borderRadius: b8 + "px",
|
||||
// boxShadow: `${b25}px ${b15}px ${b8}px rgba(0, 0, 0, 0.5)`
|
||||
})
|
||||
let size = "calc(100% - " + (2*b+2) +"px)"
|
||||
Elements.setStyle(this.web, {
|
||||
width: size,
|
||||
height: size,
|
||||
margin: b+"px"})
|
||||
Elements.setStyle(this.webViewSnapshot, {
|
||||
width: size,
|
||||
height: size,
|
||||
margin: b+"px"})
|
||||
Elements.setStyle(this.webBackground, {
|
||||
width: size,
|
||||
height: size,
|
||||
margin: b+"px"})
|
||||
|
||||
Elements.setStyle(this.overlay, {
|
||||
width: size,
|
||||
height: size,
|
||||
margin: b+"px"})
|
||||
|
||||
Elements.setStyle(this.overlayCaptureEvents, {
|
||||
width: size,
|
||||
height: size,
|
||||
opacity: 0.0001,
|
||||
background: "white",
|
||||
margin: b+"px"})
|
||||
|
||||
Elements.setStyle(this.closeButton, {
|
||||
right: (b * 1.75) + "px",
|
||||
bottom: "0px",
|
||||
width: b+"px",
|
||||
height: b+"px"})
|
||||
|
||||
Elements.setStyle(this.backButton, {
|
||||
left: (b * 0.8) +"px",
|
||||
bottom: "0px",
|
||||
width: b+"px",
|
||||
height: b+"px"})
|
||||
|
||||
Elements.setStyle(this.forwardButton, {
|
||||
left: (this.border + (b * 0.8)) +"px",
|
||||
bottom: "0px",
|
||||
width: b+"px",
|
||||
height: b+"px"})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PadFromElement {
|
||||
|
||||
constructor(element, scatterContainer, {
|
||||
startScale=1.0, minScale=0.1, maxScale=1.0,
|
||||
autoBringToFront=true,
|
||||
translatable=true, scalable=true, rotatable=true,
|
||||
movableX=true,
|
||||
movableY=true,
|
||||
rotationDegrees=null,
|
||||
rotation=null,
|
||||
onTransform=null,
|
||||
transformOrigin = 'center center',
|
||||
// extras which are in part needed
|
||||
x=0,
|
||||
y=0,
|
||||
width=null,
|
||||
height=null,
|
||||
resizable=false,
|
||||
} ={}) {
|
||||
|
||||
this.element = element
|
||||
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.width = width
|
||||
this.height = height
|
||||
this.minScale = minScale
|
||||
this.maxScale = maxScale
|
||||
this.scatterContainer = scatterContainer
|
||||
this.scale = startScale
|
||||
this.scalable = scalable
|
||||
this.rotatable = rotatable
|
||||
this.rotationDegrees = this.startRotationDegrees
|
||||
this.transformOrigin = transformOrigin
|
||||
|
||||
this.frame = document.createElement('div')
|
||||
Elements.setStyle(this.frame, {
|
||||
width: this.width+"px",
|
||||
height: this.height+"px",
|
||||
backgroundColor: "#333",
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
overflow: "auto"})
|
||||
|
||||
this.closeButton = this.addButton("../assets/icons/svg/cross.svg", "close")
|
||||
|
||||
document.body.appendChild( this.frame)
|
||||
this.border = 50
|
||||
|
||||
this.frame.appendChild(this.element)
|
||||
|
||||
this.title = document.createElement("div")
|
||||
this.title.innerHTML = "Titel"
|
||||
this.title.style.color = "white"
|
||||
this.frame.appendChild(this.title)
|
||||
|
||||
Elements.setStyle(this.title, {
|
||||
position: "absolute"
|
||||
})
|
||||
// this.element.style.overflow = "auto"
|
||||
// this.element.style.position = "absolute"
|
||||
|
||||
this.layout()
|
||||
|
||||
this.closeButton.addEventListener('click', ()=>{
|
||||
this.frame.style.display="none"
|
||||
})
|
||||
|
||||
this.scatter = new DOMScatter(this.frame, scatterContainer, {
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
startScale: this.startScale,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
minScale: this.minScale,
|
||||
maxScale: this.maxScale,
|
||||
scalable: this.scalable,
|
||||
resizable: true,
|
||||
rotatable: this.rotatable})
|
||||
|
||||
this.scatter.bringToFront()
|
||||
this.scatter.addTransformEventCallback((e) => {
|
||||
let newBorder = 50 / e.scale
|
||||
if (newBorder !== this.border) {
|
||||
this.border = newBorder
|
||||
this.layout()
|
||||
}
|
||||
})
|
||||
|
||||
this.element.addEventListener('pointerdown', (e) => {
|
||||
this.scatter.bringToFront()
|
||||
})
|
||||
}
|
||||
|
||||
close() {
|
||||
// this.frame.style.display="none"
|
||||
this.frame.parentNode.removeChild(this.frame)
|
||||
urlPadMap.delete(this.url)
|
||||
}
|
||||
|
||||
addButton(src, value) {
|
||||
let button = document.createElement("img")
|
||||
button.type = "image"
|
||||
button.className = "frameButton"
|
||||
button.style.position = "absolute"
|
||||
button.src = fileURL(src)
|
||||
button.value="close"
|
||||
button.draggable = false
|
||||
this.frame.appendChild(button)
|
||||
return button
|
||||
}
|
||||
|
||||
layout() {
|
||||
let b = this.border
|
||||
let b2 = b * 2
|
||||
let b8 = b / 8
|
||||
let b25 = b / 25
|
||||
let b15 = b / 15
|
||||
|
||||
this.scatter.resizeButton.style.width=b+"px"
|
||||
this.scatter.resizeButton.style.height=b+"px"
|
||||
|
||||
Elements.setStyle(this.frame, {
|
||||
// borderRadius: b8 + "px",
|
||||
// boxShadow: `${b25}px ${b15}px ${b8}px rgba(0, 0, 0, 0.5)`
|
||||
})
|
||||
let size = "calc(100% - " + (2*b+2) +"px)"
|
||||
Elements.setStyle(this.element, {
|
||||
width: size,
|
||||
height: size,
|
||||
top: b+"px",
|
||||
left: b+"px"})
|
||||
Elements.setStyle(this.closeButton, {
|
||||
right: (b * 0.75) + "px",
|
||||
bottom: "0px",
|
||||
width: b+"px",
|
||||
height: b+"px"})
|
||||
Elements.setStyle(this.title, {
|
||||
left: (b * 1.5) + "px",
|
||||
fontSize: (b * 0.8) + "px",
|
||||
top: (0.1)+"0px"})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Pad, DOMPadContainer, PadFromElement }
|
||||
@ -1,231 +0,0 @@
|
||||
const { fileURL, loadScript, hideCursor, showCursor } = require('./utils.js')
|
||||
let { remote } = require('electron')
|
||||
|
||||
const webFrame = require('electron').webFrame
|
||||
|
||||
// UO: Disable unintended zoom of fullscreen page if user wants to zoom
|
||||
// only parts like Eyevisit info cards.
|
||||
console.log('Disable pinch zoom', webFrame)
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
|
||||
let padContainer = null
|
||||
let hideCursorTimeout = null
|
||||
let debug = false
|
||||
let urlPadMap = new Map()
|
||||
|
||||
window.urlPadMap = urlPadMap
|
||||
window.padLoadedHandler = []
|
||||
window.nodeDirname = __dirname
|
||||
|
||||
function pageSize() {
|
||||
var w = window,
|
||||
d = document,
|
||||
e = d.documentElement,
|
||||
g = d.getElementsByTagName('body')[0],
|
||||
width = w.innerWidth || e.clientWidth || g.clientWidth,
|
||||
height = w.innerHeight || e.clientHeight || g.clientHeight
|
||||
|
||||
return [width, height]
|
||||
}
|
||||
|
||||
let size = pageSize()
|
||||
let pageWidth = size[0]
|
||||
let pageHeight = size[1]
|
||||
|
||||
/* Open a new at x, y position. */
|
||||
function openPad(url, x, y) {
|
||||
console.log('openPad')
|
||||
if (remote.getGlobal('useBrowserView')) {
|
||||
return ipcRenderer.send('loadBrowserView', { url, x, y })
|
||||
}
|
||||
const { Pad } = require('./pad.js')
|
||||
const { minimalPad } = require('./padMinimal.js')
|
||||
pad = null
|
||||
if (urlPadMap.has(url)) {
|
||||
let pad = urlPadMap.get(url)
|
||||
pad.scatter.bringToFront()
|
||||
/*TweenMax.to(pad.frame, 0.5, {
|
||||
boxShadow: "0 0 25px 5px white", onComplete: () => {
|
||||
TweenMax.to(pad.frame, 0.5, { boxShadow: "none" })
|
||||
}
|
||||
})*/
|
||||
TweenMax.to(pad.frame, 0.2, {
|
||||
scale: '1.01',
|
||||
onComplete: () => {
|
||||
TweenMax.to(pad.frame, 0.2, { scale: '1' })
|
||||
}
|
||||
})
|
||||
// pad.scatter.moveTo(x, y)
|
||||
return pad
|
||||
}
|
||||
y + 1600 > pageHeight ? (y = pageHeight - 1600) : (y = y)
|
||||
if (remote.getGlobal('useMinimalPad')) {
|
||||
pad = new minimalPad(padContainer, {
|
||||
x: x,
|
||||
y: y,
|
||||
url: url,
|
||||
tabbedView: true,
|
||||
hasTtitleBar: false,
|
||||
hideOnStart: false,
|
||||
startScale: 1,
|
||||
width: 1000,
|
||||
height: 1500,
|
||||
scalable: true,
|
||||
rotatable: true
|
||||
})
|
||||
}
|
||||
if (!remote.getGlobal('useMinimalPad')) {
|
||||
pad = new Pad(padContainer, {
|
||||
x: x,
|
||||
y: y,
|
||||
url: url,
|
||||
hideOnStart: false,
|
||||
startScale: 1,
|
||||
width: 1000,
|
||||
height: 1500,
|
||||
scalable: true,
|
||||
rotatable: true
|
||||
})
|
||||
}
|
||||
urlPadMap.set(url, pad)
|
||||
for (let callback of window.padLoadedHandler) {
|
||||
callback(pad, url)
|
||||
}
|
||||
}
|
||||
|
||||
window.padLoadedHandler.push((pad, url) => {
|
||||
console.log('Add specific behavior')
|
||||
})
|
||||
|
||||
/* According to https://electron.atom.io/docs/faq/
|
||||
"I can not use jQuery/RequireJS/Meteor/AngularJS in Electron" we
|
||||
have to rename the symbols in the page before including other libraries.
|
||||
Remember to use nodeRequire after this point.
|
||||
*/
|
||||
window.nodeRequire = require
|
||||
delete window.require
|
||||
delete window.exports
|
||||
delete window.module
|
||||
|
||||
/* Create a DOMPadContainer, i.e. a special DOMScatterContainer, as a wrapper
|
||||
of the document body.
|
||||
*/
|
||||
window.addEventListener('load', e => {
|
||||
console.log('preloading')
|
||||
// ../iwmlib/dist/iwmlib.3rdparty.js
|
||||
// loadScript('../iwmlib/lib/3rdparty/preload.js', () => {
|
||||
loadScript('../../iwmlib/dist/iwmlib.3rdparty.preload.js', () => {
|
||||
//console.log("../iwmlib/dist/iwmlib.3rdparty.js loaded")
|
||||
console.log('greensock loaded')
|
||||
// loadScript('../iwmlib/dist/iwmlib.js', () => {
|
||||
loadScript('../../iwmlib/dist/iwmlib.js', () => {
|
||||
console.log('../iwmlib/dist/iwmlib.js loaded')
|
||||
|
||||
/* const { Pad, DOMPadContainer } = nodeRequire('./pad.js')
|
||||
padContainer = new DOMPadContainer(document.body)
|
||||
|
||||
window.nodePadContainer = padContainer
|
||||
ipcRenderer.send('padContainerLoaded') */
|
||||
|
||||
/*Register a handler for mousemove events. Hide the cursor a few
|
||||
*seconds after the last move event.
|
||||
*/
|
||||
document.body.addEventListener('mousemove', e => {
|
||||
showCursor()
|
||||
clearTimeout(hideCursorTimeout)
|
||||
hideCursorTimeout = setTimeout(hideCursor, 3000)
|
||||
})
|
||||
})
|
||||
|
||||
if (debug) {
|
||||
loadScript('../iwmlib/dist/iwmlib.pixi.js', () => {
|
||||
console.log('../iwmlib/dist/iwmlib.pixi.js loaded')
|
||||
const DebugApp = require('./debug.js')
|
||||
let debugApp = new DebugApp(document.body)
|
||||
debugApp.setup()
|
||||
debugApp.run()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/* Register a handler for all click events and check whether the link target
|
||||
opens a new window. If the link target is blank, prevent the default behavior
|
||||
and create a Pad scatter object instead.
|
||||
*/
|
||||
window.addEventListener('click', e => {
|
||||
let node = e.target
|
||||
let url = ''
|
||||
let target = ''
|
||||
|
||||
let multiUserMode = false // remote.getGlobal('multiUserMode') // DOMScatter && remote.getGlobal('multiUserMode')
|
||||
|
||||
// console.log("click", multiUserMode, remote.getGlobal('multiUserMode'))
|
||||
if (multiUserMode) {
|
||||
while (node !== null) {
|
||||
if (node.tagName === 'A' || node.tagName === 'a') {
|
||||
if (node.target instanceof SVGAnimatedString) {
|
||||
url = node.href.baseVal
|
||||
target = node.target.baseVal
|
||||
} else {
|
||||
url = node.href
|
||||
target = node.target
|
||||
}
|
||||
if (target === '_blank') {
|
||||
e.preventDefault()
|
||||
openPad(url, e.clientX, e.clientY)
|
||||
}
|
||||
return
|
||||
}
|
||||
node = node.parentNode
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* Register a handler for contextmenu events and check whether the link target
|
||||
// opens a new window. If the link target is blank, prevent the default behavior
|
||||
and show a popup menu with the option to open a pad instead.
|
||||
*/
|
||||
window.addEventListener('contextmenu', e => {
|
||||
let node = e.target
|
||||
let url = null
|
||||
if (remote.getGlobal('multiUserMode')) {
|
||||
while (node !== null) {
|
||||
if (node.tagName === 'A' || node.tagName === 'a') {
|
||||
if (node.target instanceof SVGAnimatedString) {
|
||||
url = node.href.baseVal
|
||||
} else {
|
||||
url = node.href
|
||||
}
|
||||
e.preventDefault()
|
||||
let point = { x: e.clientX, y: e.clientY }
|
||||
PopupMenu.open(
|
||||
{
|
||||
'Open new Pad': () => openPad(url, e.clientX, e.clientY)
|
||||
},
|
||||
point,
|
||||
{ fontSize: '0.8em' }
|
||||
)
|
||||
return
|
||||
}
|
||||
node = node.parentNode
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* Special error handling if the rendere process sends a error notification
|
||||
log this error on the main console.
|
||||
*/
|
||||
let { Console } = require('console')
|
||||
let debugConsole = new Console(process.stdout, process.stderr)
|
||||
|
||||
let { ipcRenderer } = require('electron')
|
||||
window.addEventListener('error', event => {
|
||||
debugConsole.error('PAGE ERROR', event.error, event.filename)
|
||||
debugConsole.error('open', window.location.href)
|
||||
ipcRenderer.send('error', 1)
|
||||
})
|
||||
|
||||
ipcRenderer.on('newPad', (e, data) => {
|
||||
openPad(data, 0, 0)
|
||||
})
|
||||
@ -1,83 +0,0 @@
|
||||
let { remote } = require('electron')
|
||||
let { ipcRenderer } = require('electron')
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const webFrame = require('electron').webFrame
|
||||
console.log('Disable pinch zoom', webFrame)
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
|
||||
window.nodePath = path
|
||||
|
||||
window.nodeDirname = __dirname
|
||||
|
||||
window.nodeRequire = require
|
||||
delete window.require
|
||||
delete window.exports
|
||||
delete window.module
|
||||
|
||||
window.padLoadedHandler = []
|
||||
|
||||
let pointerCounter = 0
|
||||
|
||||
window.addEventListener('pointerdown', (e) => {
|
||||
//e.preventDefault()
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerDown')")
|
||||
ipcRenderer.sendToHost('webviewPointerDown')
|
||||
})
|
||||
|
||||
window.addEventListener('pointerup', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerUp')")
|
||||
ipcRenderer.sendToHost('webviewPointerUp')
|
||||
})
|
||||
|
||||
window.addEventListener('pointerenter', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerEnter')")
|
||||
ipcRenderer.sendToHost('webviewPointerEnter')
|
||||
})
|
||||
|
||||
window.addEventListener('pointercancel', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerCancel')")
|
||||
ipcRenderer.sendToHost('webviewPointerCancel')
|
||||
})
|
||||
|
||||
window.addEventListener('pointerleave', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerLeave')")
|
||||
ipcRenderer.sendToHost('webviewPointerLeave')
|
||||
})
|
||||
|
||||
window.addEventListener('pointerout', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerOut')")
|
||||
ipcRenderer.sendToHost('webviewPointerOut')
|
||||
})
|
||||
|
||||
window.addEventListener('pointerover', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerOver')")
|
||||
ipcRenderer.sendToHost('webviewPointerOver')
|
||||
})
|
||||
|
||||
window.addEventListener('pointermove', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('webviewPointerMove')")
|
||||
ipcRenderer.sendToHost('webviewPointerMove')
|
||||
})
|
||||
|
||||
window.addEventListener('touchmove', (e) => {
|
||||
// console.log("ipcRenderer.sendToHost('touchmove')")
|
||||
ipcRenderer.sendToHost('touchMove')
|
||||
})
|
||||
|
||||
window.addEventListener('touchstart', (e) => {
|
||||
pointerCounter++
|
||||
// console.log("ipcRenderer.sendToHost('touchstart')")
|
||||
ipcRenderer.sendToHost('touchStart')
|
||||
})
|
||||
|
||||
window.addEventListener('touchend', (e) => {
|
||||
pointerCounter--
|
||||
// console.log("ipcRenderer.sendToHost('touchend')")
|
||||
ipcRenderer.sendToHost('touchEnd')
|
||||
})
|
||||
|
||||
ipcRenderer.on('overlayEvent', function () {
|
||||
console.log('hello world From Preload')
|
||||
})
|
||||
@ -1,47 +0,0 @@
|
||||
const electron = require('electron')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
class Store {
|
||||
|
||||
constructor(opts) {
|
||||
|
||||
// Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
|
||||
// app.getPath('userData') will return a string of the user's app data directory path.
|
||||
const userDataPath = (electron.app || electron.remote.app).getPath('userData')
|
||||
// We'll use the `configName` property to set the file name and path.join to bring it all together as a string
|
||||
this.path = path.join(userDataPath, opts.configName + '.json')
|
||||
|
||||
this.data = parseDataFile(this.path, opts.defaults)
|
||||
this.data = Object.assign(opts.defaults, this.data)
|
||||
}
|
||||
|
||||
// This will just return the property on the `data` object
|
||||
get(key) {
|
||||
return this.data[key]
|
||||
}
|
||||
|
||||
// ...and this will set it
|
||||
set(key, val) {
|
||||
this.data[key] = val
|
||||
// Wait, I thought using the node.js' synchronous APIs was bad form?
|
||||
// We're not writing a server so there's not nearly the same IO demand on the process
|
||||
// Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
|
||||
// we might lose that data. Note that in a real app, we would try/catch this.
|
||||
fs.writeFileSync(this.path, JSON.stringify(this.data))
|
||||
}
|
||||
}
|
||||
|
||||
function parseDataFile(filePath, defaults) {
|
||||
// We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
|
||||
// `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(filePath))
|
||||
} catch(error) {
|
||||
// if there was some kind of error, return the passed in defaults instead.
|
||||
return defaults
|
||||
}
|
||||
}
|
||||
|
||||
// expose the class
|
||||
module.exports = Store
|
||||
113
browser/test.js
@ -1,113 +0,0 @@
|
||||
let fs = require('fs')
|
||||
let path = require('path')
|
||||
let {thumbnail} = require('./utils.js')
|
||||
|
||||
let pairs = []
|
||||
let urlMap = new Map()
|
||||
function isFile(path) {
|
||||
try {
|
||||
return !fs.lstatSync(path).isDirectory()
|
||||
} catch(e) {
|
||||
if (e.code == 'ENOENT'){
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function listPairs(src, dst, skipFiles=true) {
|
||||
let dir = fs.readdirSync(src)
|
||||
for(let name of dir) {
|
||||
let srcPath = src + name
|
||||
if (isFile(srcPath) && !skipFiles) {
|
||||
if (srcPath.endsWith('.html')) {
|
||||
let dstPath = dst + name.replace(/.html/, '.png')
|
||||
pairs.push([srcPath, dstPath])
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (srcPath.endsWith('.'))
|
||||
continue
|
||||
let indexPath = srcPath + path.sep + 'index.html'
|
||||
if (isFile(indexPath)) {
|
||||
let thumbnailPath = indexPath.replace(/index.html/, 'thumbnail.png')
|
||||
pairs.push([indexPath, thumbnailPath])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function capturePage(focusedWindow, dstPath) {
|
||||
focusedWindow.capturePage( (image) => {
|
||||
fs.writeFile(dstPath, thumbnail(image), (err) => {
|
||||
if (err) throw err;
|
||||
nextLoadTest(focusedWindow)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function testLoading(focusedWindow, filePath, dstPath) {
|
||||
let urlPath = filePath.replace(path.sep, '/')
|
||||
let basePath = `${__dirname}`.replace('/browser', '')
|
||||
let shortURL = `file://${basePath}/${urlPath}`
|
||||
let fullURL = `file://${__dirname}/../../${urlPath}`
|
||||
// console.log({basePath, shortURL, fullURL})
|
||||
if (focusedWindow) {
|
||||
urlMap.set(shortURL, dstPath)
|
||||
focusedWindow.webContents.session.clearCache(() => console.log('Cache cleared'))
|
||||
focusedWindow.webContents.loadURL(shortURL)
|
||||
}
|
||||
}
|
||||
|
||||
function listLibPairs() {
|
||||
let src = "lib" + path.sep
|
||||
let dst = "lib" + path.sep + 'thumbnails' + path.sep
|
||||
listPairs(src, dst, false)
|
||||
}
|
||||
|
||||
function listAppPairs() {
|
||||
let src = "apps" + path.sep
|
||||
let dst = "apps" + path.sep
|
||||
listPairs(src, dst)
|
||||
}
|
||||
|
||||
function listSrcPairs() {
|
||||
let src = "src" + path.sep
|
||||
let dst = "src" + path.sep
|
||||
listPairs(src, dst)
|
||||
}
|
||||
|
||||
function nextLoadTest(focusedWindow) {
|
||||
if (global.errorCount > 0 && global.stopTestsOnError) {
|
||||
console.log("Test aborted")
|
||||
return
|
||||
}
|
||||
if (pairs.length > 0) {
|
||||
let [file, image] = pairs.pop()
|
||||
testLoading(focusedWindow, file, image)
|
||||
}
|
||||
else {
|
||||
console.log("All thumbnails created")
|
||||
}
|
||||
}
|
||||
|
||||
function loadTests(focusedWindow) {
|
||||
global.errorCount = 0
|
||||
focusedWindow.webContents.on('did-finish-load', (e) => {
|
||||
setTimeout(() => {
|
||||
let url = e.sender.history[e.sender.history.length-1]
|
||||
dstPath = urlMap.get(url)
|
||||
capturePage(focusedWindow, dstPath)
|
||||
}, 5000)
|
||||
})
|
||||
|
||||
listLibPairs()
|
||||
listSrcPairs()
|
||||
listAppPairs()
|
||||
nextLoadTest(focusedWindow)
|
||||
}
|
||||
|
||||
module.exports = loadTests
|
||||
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
|
||||
function fileURL(src) {
|
||||
let dir = __dirname.replace(/\\/g, '/')
|
||||
return `file://${dir}/${src}`
|
||||
}
|
||||
|
||||
function loadScript(src, callback) {
|
||||
let url = fileURL(src)
|
||||
let script = document.createElement('script')
|
||||
script.onload = () => {
|
||||
if (callback) {
|
||||
callback.call(this, script)
|
||||
}
|
||||
}
|
||||
script.src = url
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
function thumbnail(screenshot) {
|
||||
return screenshot.resize({ width: 1024 }).toPNG()
|
||||
}
|
||||
|
||||
let hiddenCursor = fileURL('../assets/cursor/cur0000.cur')
|
||||
let defaultCursor = fileURL('../assets/cursor/cur1054.cur')
|
||||
|
||||
function hideCursor() {
|
||||
// console.log("hideCursor")
|
||||
document.body.style.cursor = `url('${hiddenCursor}'), default`
|
||||
}
|
||||
|
||||
function showCursor() {
|
||||
document.body.style.cursor = `url('${defaultCursor}'), default`
|
||||
// console.log("showCursor")
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fileURL, loadScript, thumbnail, hideCursor, showCursor
|
||||
}
|
||||
@ -18,7 +18,7 @@ html {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.dark-mode nav {
|
||||
.dark-mode nav{
|
||||
border-color: var(--white);
|
||||
}
|
||||
|
||||
@ -264,23 +264,3 @@ canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#ctxmenu {
|
||||
position: fixed;
|
||||
background: white;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
border: 1px lightgray solid;
|
||||
}
|
||||
|
||||
#ctxmenu > a {
|
||||
display: block;
|
||||
padding: 0.25rem 1rem;
|
||||
font-size: 18px;
|
||||
margin: 0.125rem;
|
||||
}
|
||||
|
||||
#ctxmenu > a:hover {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
|
||||
.flipWrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
@ -27,10 +27,6 @@ body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: white;
|
||||
padding: 4px;
|
||||
@ -38,9 +34,7 @@ h3 {
|
||||
background-color: rgba(0, 0, 15, 0.5);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a { text-decoration: none; }
|
||||
|
||||
div.wrapper {
|
||||
overflow: hidden;
|
||||
@ -52,48 +46,28 @@ div.wrapper {
|
||||
|
||||
/* Color animation from https://www.tjvantoll.com/2012/02/20/css3-color-animations/ */
|
||||
@-webkit-keyframes color_change {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: red;
|
||||
}
|
||||
from { background-color: rgba(0, 0, 0, 0); }
|
||||
to { background-color: red; }
|
||||
}
|
||||
|
||||
@-moz-keyframes color_change {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: red;
|
||||
}
|
||||
from { background-color: rgba(0, 0, 0, 0); }
|
||||
to { background-color: red; }
|
||||
}
|
||||
|
||||
@-ms-keyframes color_change {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: red;
|
||||
}
|
||||
from { background-color: rgba(0, 0, 0, 0); }
|
||||
to { background-color: red; }
|
||||
}
|
||||
|
||||
@-o-keyframes color_change {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: red;
|
||||
}
|
||||
from { background-color: rgba(0, 0, 0, 0); }
|
||||
to { background-color: red; }
|
||||
}
|
||||
|
||||
@keyframes color_change {
|
||||
from {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
background-color: red;
|
||||
}
|
||||
from { background-color: rgba(0, 0, 0, 0); }
|
||||
to { background-color: red; }
|
||||
}
|
||||
|
||||
/*** CSS taken from https://medium.com/@jamesfuthey/simulating-the-creation-of-website-thumbnail-screenshots-using-iframes-7145269891db#.7v7fshos5 ***/
|
||||
@ -109,7 +83,7 @@ div.wrapper {
|
||||
}
|
||||
|
||||
.thumbnail::after {
|
||||
content: '';
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -171,12 +145,12 @@ div.title {
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
display: -webkit-flex;
|
||||
-webkit-align-items: flex-start;
|
||||
align-items: flex-start;
|
||||
-webkit-align-items: flex-end;
|
||||
align-items: flex-end;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-align-content: flex-start;
|
||||
align-content: flex-start;
|
||||
-webkit-align-content: flex-end;
|
||||
align-content: flex-end;
|
||||
}
|
||||
|
||||
/** See https://github.com/electron/electron/issues/4420 */
|
||||
|
||||
134220
dist/iwmlib.3rdparty.js
vendored
254
dist/iwmlib.3rdparty.min.js
vendored
30
dist/iwmlib.3rdparty.preload.js
vendored
@ -8119,10 +8119,10 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
|
||||
css transforms without perspective projection)
|
||||
*/
|
||||
|
||||
;(function () {
|
||||
(function () {
|
||||
'use strict'
|
||||
|
||||
var I = typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix() : new WebKitCSSMatrix()
|
||||
var I = (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix() : new WebKitCSSMatrix()
|
||||
|
||||
function Point(x, y, z) {
|
||||
this.x = x
|
||||
@ -8137,8 +8137,8 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
|
||||
|
||||
function createMatrix(transform) {
|
||||
try {
|
||||
return typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
|
||||
} catch (e) {
|
||||
return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
|
||||
} catch(e) {
|
||||
console.warn(transform)
|
||||
console.warn(e.toString())
|
||||
return I
|
||||
@ -8163,9 +8163,8 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
|
||||
var left = +Infinity
|
||||
var top = +Infinity
|
||||
while (--i >= 0) {
|
||||
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(
|
||||
transformationMatrix
|
||||
)
|
||||
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h,
|
||||
0).transformBy(transformationMatrix)
|
||||
if (p.x < left) {
|
||||
left = p.x
|
||||
}
|
||||
@ -8174,19 +8173,20 @@ if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case Tween
|
||||
}
|
||||
}
|
||||
var rect = element.getBoundingClientRect()
|
||||
transformationMatrix = I.translate(
|
||||
window.pageXOffset + rect.left - left,
|
||||
window.pageYOffset + rect.top - top,
|
||||
0
|
||||
).multiply(transformationMatrix)
|
||||
transformationMatrix = I.translate(window.pageXOffset + rect.left - left,
|
||||
window.pageYOffset + rect.top - top, 0)
|
||||
.multiply(transformationMatrix)
|
||||
return transformationMatrix
|
||||
}
|
||||
|
||||
window.convertPointFromPageToNode = function (element, pageX, pageY) {
|
||||
return new Point(pageX, pageY, 0).transformBy(getTransformationMatrix(element).inverse())
|
||||
return new Point(pageX, pageY, 0).transformBy(
|
||||
getTransformationMatrix(element).inverse())
|
||||
}
|
||||
|
||||
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
|
||||
return new Point(offsetX, offsetY, 0).transformBy(getTransformationMatrix(element))
|
||||
return new Point(offsetX, offsetY, 0).transformBy(
|
||||
getTransformationMatrix(element))
|
||||
}
|
||||
})();
|
||||
|
||||
}());
|
||||
|
||||
2
dist/iwmlib.3rdparty.preload.min.js
vendored
761
dist/iwmlib.js
vendored
779
dist/iwmlib.pixi.js
vendored
249
doc/ast.html
@ -1,28 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.node circle {
|
||||
fill: #999;
|
||||
}
|
||||
|
||||
.node text {
|
||||
font: 10px sans-serif;
|
||||
}
|
||||
.node circle {
|
||||
fill: #999;
|
||||
}
|
||||
|
||||
.node--internal circle {
|
||||
fill: #555;
|
||||
}
|
||||
.node text {
|
||||
font: 10px sans-serif;
|
||||
}
|
||||
|
||||
.node--internal text {
|
||||
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
|
||||
}
|
||||
.node--internal circle {
|
||||
fill: #555;
|
||||
}
|
||||
|
||||
.node--internal text {
|
||||
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
|
||||
}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: #555;
|
||||
stroke-opacity: 0.4;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: #555;
|
||||
stroke-opacity: 0.4;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
</style>
|
||||
<svg width="960" height="512"></svg>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
@ -30,106 +32,104 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/4.0.11/acorn.min.js"></script>
|
||||
<script>
|
||||
fetch('../apps/loader/js/main.js')
|
||||
.then((response) => response.text())
|
||||
.then((text) => {
|
||||
const ast = acorn.parse(text, {
|
||||
sourceType: 'module',
|
||||
// collect ranges for each node
|
||||
ranges: true,
|
||||
// collect comments in Esprima's format
|
||||
onComment: null,
|
||||
// collect token ranges
|
||||
onToken: null
|
||||
})
|
||||
|
||||
console.info(ast)
|
||||
fetch("../apps/loader/js/main.js")
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
const ast = acorn.parse(text, {
|
||||
sourceType: "module",
|
||||
// collect ranges for each node
|
||||
ranges: true,
|
||||
// collect comments in Esprima's format
|
||||
onComment: null,
|
||||
// collect token ranges
|
||||
onToken: null
|
||||
})
|
||||
|
||||
console.info(ast)
|
||||
|
||||
drawAst(ast)
|
||||
})
|
||||
drawAst(ast)
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
function drawAst(ast) {
|
||||
// Create SVG element
|
||||
//---------------------------
|
||||
let svg = d3.select('svg')
|
||||
const width = svg.attr('width')
|
||||
const height = svg.attr('height')
|
||||
let g = svg.append('g').attr('transform', 'translate(40,0)')
|
||||
/*
|
||||
*
|
||||
*/
|
||||
function drawAst(ast) {
|
||||
|
||||
// Create SVG element
|
||||
//---------------------------
|
||||
let svg = d3.select("svg")
|
||||
const width = svg.attr("width")
|
||||
const height = svg.attr("height")
|
||||
let g = svg.append("g").attr("transform", "translate(40,0)")
|
||||
|
||||
// Convert data
|
||||
//---------------------------
|
||||
const data = acornToHierarchy(ast)
|
||||
|
||||
// Create D3 Hierarchy
|
||||
//---------------------------
|
||||
let root = d3.hierarchy(data).sort((a, b) => {
|
||||
return (a.height - b.height) || a.data.name.localeCompare(b.data.name);
|
||||
})
|
||||
|
||||
// Convert data
|
||||
//---------------------------
|
||||
const data = acornToHierarchy(ast)
|
||||
// Create D3 Cluster
|
||||
//---------------------------
|
||||
let tree = d3.cluster().size([height, width - 200])
|
||||
tree(root)
|
||||
|
||||
// Create SVG elements
|
||||
//---------------------------
|
||||
let link = g.selectAll(".link")
|
||||
.data(root.descendants().slice(1))
|
||||
.enter().append("path")
|
||||
.attr("class", "link")
|
||||
.attr("d", d => {
|
||||
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${d.parent.x}`
|
||||
})
|
||||
|
||||
let node = g.selectAll(".node")
|
||||
.data(root.descendants())
|
||||
.enter().append("g")
|
||||
.attr("class", d => "node" + (d.children ? " node--internal" : " node--leaf"))
|
||||
.attr("transform", d => `translate(${d.y},${d.x})`)
|
||||
|
||||
node.append("circle")
|
||||
.attr("r", 5)
|
||||
|
||||
node.append("text")
|
||||
.attr("dy", 3)
|
||||
.attr("x", d => d.children ? -8 : 8)
|
||||
.style("text-anchor", d => d.children ? "end" : "start")
|
||||
.text(d => d.data.name)
|
||||
}
|
||||
|
||||
// Create D3 Hierarchy
|
||||
//---------------------------
|
||||
let root = d3.hierarchy(data).sort((a, b) => {
|
||||
return a.height - b.height || a.data.name.localeCompare(b.data.name)
|
||||
})
|
||||
|
||||
// Create D3 Cluster
|
||||
//---------------------------
|
||||
let tree = d3.cluster().size([height, width - 200])
|
||||
tree(root)
|
||||
|
||||
// Create SVG elements
|
||||
//---------------------------
|
||||
let link = g
|
||||
.selectAll('.link')
|
||||
.data(root.descendants().slice(1))
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('class', 'link')
|
||||
.attr('d', (d) => {
|
||||
return `M${d.y},${d.x}C${d.parent.y + 100},${d.x} ${d.parent.y + 100},${d.parent.x} ${d.parent.y},${
|
||||
d.parent.x
|
||||
}`
|
||||
})
|
||||
|
||||
let node = g
|
||||
.selectAll('.node')
|
||||
.data(root.descendants())
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', (d) => 'node' + (d.children ? ' node--internal' : ' node--leaf'))
|
||||
.attr('transform', (d) => `translate(${d.y},${d.x})`)
|
||||
|
||||
node.append('circle').attr('r', 5)
|
||||
|
||||
node.append('text')
|
||||
.attr('dy', 3)
|
||||
.attr('x', (d) => (d.children ? -8 : 8))
|
||||
.style('text-anchor', (d) => (d.children ? 'end' : 'start'))
|
||||
.text((d) => d.data.name)
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
function acornToHierarchy(ast) {
|
||||
console.info(JSON.stringify(ast))
|
||||
|
||||
let data = {}
|
||||
|
||||
for (const clazz of ast.body) {
|
||||
if (clazz.type === 'ClassDeclaration') {
|
||||
data.name = clazz.id.name
|
||||
data.children = []
|
||||
|
||||
for (const method of clazz.body.body) {
|
||||
if (method.type === 'MethodDefinition') {
|
||||
data.children.push({
|
||||
name: method.key.name,
|
||||
children: []
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
*
|
||||
*/
|
||||
function acornToHierarchy(ast) {
|
||||
|
||||
console.info(JSON.stringify(ast))
|
||||
|
||||
let data = {}
|
||||
|
||||
for (const clazz of ast.body) {
|
||||
if (clazz.type === "ClassDeclaration") {
|
||||
data.name = clazz.id.name
|
||||
data.children = []
|
||||
|
||||
for (const method of clazz.body.body) {
|
||||
if (method.type === "MethodDefinition") {
|
||||
data.children.push({
|
||||
name: method.key.name,
|
||||
children: []
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const data = {
|
||||
"name": "Eve",
|
||||
"children": [{
|
||||
@ -153,7 +153,22 @@
|
||||
}]
|
||||
}
|
||||
*/
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@ -11,12 +11,12 @@ function vendors() {
|
||||
'./node_modules/optimal-select/dist/optimal-select.js',
|
||||
'./node_modules/hammerjs/hammer.js',
|
||||
'./node_modules/propagating-hammerjs/propagating.js',
|
||||
'./node_modules/pixi.js/dist/browser/pixi.js',
|
||||
'./node_modules/pixi-compressed-textures/lib/crn_decomp.js',
|
||||
'./node_modules/pixi.js/dist/pixi.js',
|
||||
'./node_modules/pixi-compressed-textures/lib/crn_decomp.js',
|
||||
'./node_modules/pixi-compressed-textures/dist/pixi-compressed-textures.js',
|
||||
'./node_modules/pixi-filters/dist/pixi-filters.js',
|
||||
'./node_modules/pixi-particles/dist/pixi-particles.js',
|
||||
'./node_modules/pixi-projection/dist/pixi-projection.umd.js',
|
||||
'./node_modules/pixi-projection/dist/pixi-projection.js',
|
||||
'./node_modules/gsap/src/uncompressed/TweenMax.js',
|
||||
'./node_modules/gsap/src/uncompressed/TimelineMax.js',
|
||||
'./lib/3rdparty/jquery.js',
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
30
lib/3rdparty/convertPointFromPageToNode.js
vendored
@ -10,10 +10,10 @@
|
||||
css transforms without perspective projection)
|
||||
*/
|
||||
|
||||
;(function () {
|
||||
(function () {
|
||||
'use strict'
|
||||
|
||||
var I = typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix() : new WebKitCSSMatrix()
|
||||
var I = (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix() : new WebKitCSSMatrix()
|
||||
|
||||
function Point(x, y, z) {
|
||||
this.x = x
|
||||
@ -28,8 +28,8 @@
|
||||
|
||||
function createMatrix(transform) {
|
||||
try {
|
||||
return typeof WebKitCSSMatrix == 'undefined' ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
|
||||
} catch (e) {
|
||||
return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
|
||||
} catch(e) {
|
||||
console.warn(transform)
|
||||
console.warn(e.toString())
|
||||
return I
|
||||
@ -54,9 +54,8 @@
|
||||
var left = +Infinity
|
||||
var top = +Infinity
|
||||
while (--i >= 0) {
|
||||
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(
|
||||
transformationMatrix
|
||||
)
|
||||
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h,
|
||||
0).transformBy(transformationMatrix)
|
||||
if (p.x < left) {
|
||||
left = p.x
|
||||
}
|
||||
@ -65,19 +64,20 @@
|
||||
}
|
||||
}
|
||||
var rect = element.getBoundingClientRect()
|
||||
transformationMatrix = I.translate(
|
||||
window.pageXOffset + rect.left - left,
|
||||
window.pageYOffset + rect.top - top,
|
||||
0
|
||||
).multiply(transformationMatrix)
|
||||
transformationMatrix = I.translate(window.pageXOffset + rect.left - left,
|
||||
window.pageYOffset + rect.top - top, 0)
|
||||
.multiply(transformationMatrix)
|
||||
return transformationMatrix
|
||||
}
|
||||
|
||||
window.convertPointFromPageToNode = function (element, pageX, pageY) {
|
||||
return new Point(pageX, pageY, 0).transformBy(getTransformationMatrix(element).inverse())
|
||||
return new Point(pageX, pageY, 0).transformBy(
|
||||
getTransformationMatrix(element).inverse())
|
||||
}
|
||||
|
||||
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
|
||||
return new Point(offsetX, offsetY, 0).transformBy(getTransformationMatrix(element))
|
||||
return new Point(offsetX, offsetY, 0).transformBy(
|
||||
getTransformationMatrix(element))
|
||||
}
|
||||
})();
|
||||
|
||||
}());
|
||||
|
||||
340
lib/3rdparty/jquery.hypher.js
vendored
@ -1,224 +1,216 @@
|
||||
;(function () {
|
||||
var module = {
|
||||
exports: null,
|
||||
}
|
||||
(function () {
|
||||
|
||||
var module = {
|
||||
exports: null
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
* @param {!{patterns: !Object, leftmin: !number, rightmin: !number}} language The language pattern file. Compatible with Hyphenator.js.
|
||||
*/
|
||||
function Hypher(language) {
|
||||
var exceptions = [],
|
||||
i = 0;
|
||||
/**
|
||||
* @constructor
|
||||
* @param {!{patterns: !Object, leftmin: !number, rightmin: !number}} language The language pattern file. Compatible with Hyphenator.js.
|
||||
* @type {!Hypher.TrieNode}
|
||||
*/
|
||||
function Hypher(language) {
|
||||
var exceptions = [],
|
||||
i = 0
|
||||
/**
|
||||
* @type {!Hypher.TrieNode}
|
||||
*/
|
||||
this.trie = this.createTrie(language['patterns'])
|
||||
this.trie = this.createTrie(language['patterns']);
|
||||
|
||||
/**
|
||||
* @type {!number}
|
||||
* @const
|
||||
*/
|
||||
this.leftMin = language['leftmin']
|
||||
/**
|
||||
* @type {!number}
|
||||
* @const
|
||||
*/
|
||||
this.leftMin = language['leftmin'];
|
||||
|
||||
/**
|
||||
* @type {!number}
|
||||
* @const
|
||||
*/
|
||||
this.rightMin = language['rightmin']
|
||||
/**
|
||||
* @type {!number}
|
||||
* @const
|
||||
*/
|
||||
this.rightMin = language['rightmin'];
|
||||
|
||||
/**
|
||||
* @type {!Object.<string, !Array.<string>>}
|
||||
*/
|
||||
this.exceptions = {}
|
||||
/**
|
||||
* @type {!Object.<string, !Array.<string>>}
|
||||
*/
|
||||
this.exceptions = {};
|
||||
|
||||
if (language['exceptions']) {
|
||||
exceptions = language['exceptions'].split(/,\s?/g)
|
||||
if (language['exceptions']) {
|
||||
exceptions = language['exceptions'].split(/,\s?/g);
|
||||
|
||||
for (; i < exceptions.length; i += 1) {
|
||||
this.exceptions[exceptions[i].replace(/\u2027/g, '').toLowerCase()] = new RegExp(
|
||||
'(' + exceptions[i].split('\u2027').join(')(') + ')',
|
||||
'i'
|
||||
)
|
||||
}
|
||||
for (; i < exceptions.length; i += 1) {
|
||||
this.exceptions[exceptions[i].replace(/\u2027/g, '').toLowerCase()] = new RegExp('(' + exceptions[i].split('\u2027').join(')(') + ')', 'i');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{_points: !Array.<number>}}
|
||||
*/
|
||||
Hypher.TrieNode
|
||||
/**
|
||||
* @typedef {{_points: !Array.<number>}}
|
||||
*/
|
||||
Hypher.TrieNode;
|
||||
|
||||
/**
|
||||
* Creates a trie from a language pattern.
|
||||
* @private
|
||||
* @param {!Object} patternObject An object with language patterns.
|
||||
* @return {!Hypher.TrieNode} An object trie.
|
||||
*/
|
||||
Hypher.prototype.createTrie = function (patternObject) {
|
||||
var size = 0,
|
||||
i = 0,
|
||||
c = 0,
|
||||
p = 0,
|
||||
chars = null,
|
||||
points = null,
|
||||
codePoint = null,
|
||||
t = null,
|
||||
tree = {
|
||||
_points: [],
|
||||
},
|
||||
patterns
|
||||
/**
|
||||
* Creates a trie from a language pattern.
|
||||
* @private
|
||||
* @param {!Object} patternObject An object with language patterns.
|
||||
* @return {!Hypher.TrieNode} An object trie.
|
||||
*/
|
||||
Hypher.prototype.createTrie = function (patternObject) {
|
||||
var size = 0,
|
||||
i = 0,
|
||||
c = 0,
|
||||
p = 0,
|
||||
chars = null,
|
||||
points = null,
|
||||
codePoint = null,
|
||||
t = null,
|
||||
tree = {
|
||||
_points: []
|
||||
},
|
||||
patterns;
|
||||
|
||||
for (size in patternObject) {
|
||||
if (patternObject.hasOwnProperty(size)) {
|
||||
patterns = patternObject[size].match(new RegExp('.{1,' + +size + '}', 'g'))
|
||||
for (size in patternObject) {
|
||||
if (patternObject.hasOwnProperty(size)) {
|
||||
patterns = patternObject[size].match(new RegExp('.{1,' + (+size) + '}', 'g'));
|
||||
|
||||
for (i = 0; i < patterns.length; i += 1) {
|
||||
chars = patterns[i].replace(/[0-9]/g, '').split('')
|
||||
points = patterns[i].split(/\D/)
|
||||
t = tree
|
||||
for (i = 0; i < patterns.length; i += 1) {
|
||||
chars = patterns[i].replace(/[0-9]/g, '').split('');
|
||||
points = patterns[i].split(/\D/);
|
||||
t = tree;
|
||||
|
||||
for (c = 0; c < chars.length; c += 1) {
|
||||
codePoint = chars[c].charCodeAt(0)
|
||||
for (c = 0; c < chars.length; c += 1) {
|
||||
codePoint = chars[c].charCodeAt(0);
|
||||
|
||||
if (!t[codePoint]) {
|
||||
t[codePoint] = {}
|
||||
}
|
||||
t = t[codePoint]
|
||||
if (!t[codePoint]) {
|
||||
t[codePoint] = {};
|
||||
}
|
||||
t = t[codePoint];
|
||||
}
|
||||
|
||||
t._points = []
|
||||
t._points = [];
|
||||
|
||||
for (p = 0; p < points.length; p += 1) {
|
||||
t._points[p] = points[p] || 0
|
||||
}
|
||||
for (p = 0; p < points.length; p += 1) {
|
||||
t._points[p] = points[p] || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree
|
||||
}
|
||||
return tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hyphenates a text.
|
||||
*
|
||||
* @param {!string} str The text to hyphenate.
|
||||
* @return {!string} The same text with soft hyphens inserted in the right positions.
|
||||
*/
|
||||
Hypher.prototype.hyphenateText = function (str, minLength) {
|
||||
minLength = minLength || 4
|
||||
/**
|
||||
* Hyphenates a text.
|
||||
*
|
||||
* @param {!string} str The text to hyphenate.
|
||||
* @return {!string} The same text with soft hyphens inserted in the right positions.
|
||||
*/
|
||||
Hypher.prototype.hyphenateText = function (str, minLength) {
|
||||
minLength = minLength || 4;
|
||||
|
||||
// Regexp("\b", "g") splits on word boundaries,
|
||||
// compound separators and ZWNJ so we don't need
|
||||
// any special cases for those characters. Unfortunately
|
||||
// it does not support unicode word boundaries, so
|
||||
// we implement it manually.
|
||||
var words = str.split(
|
||||
/([a-zA-Z0-9_\u0027\u00DF-\u00EA\u00EC-\u00EF\u00F1-\u00F6\u00F8-\u00FD\u0101\u0103\u0105\u0107\u0109\u010D\u010F\u0111\u0113\u0117\u0119\u011B\u011D\u011F\u0123\u0125\u012B\u012F\u0131\u0135\u0137\u013C\u013E\u0142\u0144\u0146\u0148\u0151\u0153\u0155\u0159\u015B\u015D\u015F\u0161\u0165\u016B\u016D\u016F\u0171\u0173\u017A\u017C\u017E\u017F\u0219\u021B\u02BC\u0390\u03AC-\u03CE\u03F2\u0401\u0410-\u044F\u0451\u0454\u0456\u0457\u045E\u0491\u0531-\u0556\u0561-\u0587\u0902\u0903\u0905-\u090B\u090E-\u0910\u0912\u0914-\u0928\u092A-\u0939\u093E-\u0943\u0946-\u0948\u094A-\u094D\u0982\u0983\u0985-\u098B\u098F\u0990\u0994-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BE-\u09C3\u09C7\u09C8\u09CB-\u09CD\u09D7\u0A02\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A14-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A82\u0A83\u0A85-\u0A8B\u0A8F\u0A90\u0A94-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABE-\u0AC3\u0AC7\u0AC8\u0ACB-\u0ACD\u0B02\u0B03\u0B05-\u0B0B\u0B0F\u0B10\u0B14-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B57\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C02\u0C03\u0C05-\u0C0B\u0C0E-\u0C10\u0C12\u0C14-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C43\u0C46-\u0C48\u0C4A-\u0C4D\u0C82\u0C83\u0C85-\u0C8B\u0C8E-\u0C90\u0C92\u0C94-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBE-\u0CC3\u0CC6-\u0CC8\u0CCA-\u0CCD\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60\u0D61\u0D7A-\u0D7F\u1F00-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB2-\u1FB4\u1FB6\u1FB7\u1FBD\u1FBF\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD2\u1FD3\u1FD6\u1FD7\u1FE2-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u200D\u2019]+)/g
|
||||
)
|
||||
// Regexp("\b", "g") splits on word boundaries,
|
||||
// compound separators and ZWNJ so we don't need
|
||||
// any special cases for those characters. Unfortunately
|
||||
// it does not support unicode word boundaries, so
|
||||
// we implement it manually.
|
||||
var words = str.split(/([a-zA-Z0-9_\u0027\u00DF-\u00EA\u00EC-\u00EF\u00F1-\u00F6\u00F8-\u00FD\u0101\u0103\u0105\u0107\u0109\u010D\u010F\u0111\u0113\u0117\u0119\u011B\u011D\u011F\u0123\u0125\u012B\u012F\u0131\u0135\u0137\u013C\u013E\u0142\u0144\u0146\u0148\u0151\u0153\u0155\u0159\u015B\u015D\u015F\u0161\u0165\u016B\u016D\u016F\u0171\u0173\u017A\u017C\u017E\u017F\u0219\u021B\u02BC\u0390\u03AC-\u03CE\u03F2\u0401\u0410-\u044F\u0451\u0454\u0456\u0457\u045E\u0491\u0531-\u0556\u0561-\u0587\u0902\u0903\u0905-\u090B\u090E-\u0910\u0912\u0914-\u0928\u092A-\u0939\u093E-\u0943\u0946-\u0948\u094A-\u094D\u0982\u0983\u0985-\u098B\u098F\u0990\u0994-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BE-\u09C3\u09C7\u09C8\u09CB-\u09CD\u09D7\u0A02\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A14-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A82\u0A83\u0A85-\u0A8B\u0A8F\u0A90\u0A94-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABE-\u0AC3\u0AC7\u0AC8\u0ACB-\u0ACD\u0B02\u0B03\u0B05-\u0B0B\u0B0F\u0B10\u0B14-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B57\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C02\u0C03\u0C05-\u0C0B\u0C0E-\u0C10\u0C12\u0C14-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3E-\u0C43\u0C46-\u0C48\u0C4A-\u0C4D\u0C82\u0C83\u0C85-\u0C8B\u0C8E-\u0C90\u0C92\u0C94-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBE-\u0CC3\u0CC6-\u0CC8\u0CCA-\u0CCD\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D60\u0D61\u0D7A-\u0D7F\u1F00-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB2-\u1FB4\u1FB6\u1FB7\u1FBD\u1FBF\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD2\u1FD3\u1FD6\u1FD7\u1FE2-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u200D\u2019]+)/g);
|
||||
|
||||
for (var i = 0; i < words.length; i += 1) {
|
||||
if (words[i].indexOf('/') !== -1) {
|
||||
// Don't insert a zero width space if the slash is at the beginning or end
|
||||
// of the text, or right after or before a space.
|
||||
if (i !== 0 && i !== words.length - 1 && !/\s+\/|\/\s+/.test(words[i])) {
|
||||
words[i] += '\u200B'
|
||||
}
|
||||
} else if (words[i].length > minLength) {
|
||||
words[i] = this.hyphenate(words[i]).join('\u00AD')
|
||||
for (var i = 0; i < words.length; i += 1) {
|
||||
if (words[i].indexOf('/') !== -1) {
|
||||
// Don't insert a zero width space if the slash is at the beginning or end
|
||||
// of the text, or right after or before a space.
|
||||
if (i !== 0 && i !== words.length - 1 && !(/\s+\/|\/\s+/.test(words[i]))) {
|
||||
words[i] += '\u200B';
|
||||
}
|
||||
} else if (words[i].length > minLength) {
|
||||
words[i] = this.hyphenate(words[i]).join('\u00AD');
|
||||
}
|
||||
return words.join('')
|
||||
}
|
||||
return words.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hyphenates a word.
|
||||
*
|
||||
* @param {!string} word The word to hyphenate
|
||||
* @return {!Array.<!string>} An array of word fragments indicating valid hyphenation points.
|
||||
*/
|
||||
Hypher.prototype.hyphenate = function (word) {
|
||||
var characters,
|
||||
characterPoints = [],
|
||||
originalCharacters,
|
||||
i,
|
||||
j,
|
||||
k,
|
||||
node,
|
||||
points = [],
|
||||
wordLength,
|
||||
lowerCaseWord = word.toLowerCase(),
|
||||
nodePoints,
|
||||
nodePointsLength,
|
||||
m = Math.max,
|
||||
trie = this.trie,
|
||||
result = [''];
|
||||
|
||||
if (this.exceptions.hasOwnProperty(lowerCaseWord)) {
|
||||
return word.match(this.exceptions[lowerCaseWord]).slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hyphenates a word.
|
||||
*
|
||||
* @param {!string} word The word to hyphenate
|
||||
* @return {!Array.<!string>} An array of word fragments indicating valid hyphenation points.
|
||||
*/
|
||||
Hypher.prototype.hyphenate = function (word) {
|
||||
var characters,
|
||||
characterPoints = [],
|
||||
originalCharacters,
|
||||
i,
|
||||
j,
|
||||
k,
|
||||
node,
|
||||
points = [],
|
||||
wordLength,
|
||||
lowerCaseWord = word.toLowerCase(),
|
||||
nodePoints,
|
||||
nodePointsLength,
|
||||
m = Math.max,
|
||||
trie = this.trie,
|
||||
result = ['']
|
||||
if (word.indexOf('\u00AD') !== -1) {
|
||||
return [word];
|
||||
}
|
||||
|
||||
if (this.exceptions.hasOwnProperty(lowerCaseWord)) {
|
||||
return word.match(this.exceptions[lowerCaseWord]).slice(1)
|
||||
}
|
||||
word = '_' + word + '_';
|
||||
|
||||
if (word.indexOf('\u00AD') !== -1) {
|
||||
return [word]
|
||||
}
|
||||
characters = word.toLowerCase().split('');
|
||||
originalCharacters = word.split('');
|
||||
wordLength = characters.length;
|
||||
|
||||
word = '_' + word + '_'
|
||||
for (i = 0; i < wordLength; i += 1) {
|
||||
points[i] = 0;
|
||||
characterPoints[i] = characters[i].charCodeAt(0);
|
||||
}
|
||||
|
||||
characters = word.toLowerCase().split('')
|
||||
originalCharacters = word.split('')
|
||||
wordLength = characters.length
|
||||
for (i = 0; i < wordLength; i += 1) {
|
||||
node = trie;
|
||||
for (j = i; j < wordLength; j += 1) {
|
||||
node = node[characterPoints[j]];
|
||||
|
||||
for (i = 0; i < wordLength; i += 1) {
|
||||
points[i] = 0
|
||||
characterPoints[i] = characters[i].charCodeAt(0)
|
||||
}
|
||||
|
||||
for (i = 0; i < wordLength; i += 1) {
|
||||
node = trie
|
||||
for (j = i; j < wordLength; j += 1) {
|
||||
node = node[characterPoints[j]]
|
||||
|
||||
if (node) {
|
||||
nodePoints = node._points
|
||||
if (nodePoints) {
|
||||
for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
|
||||
points[i + k] = m(points[i + k], nodePoints[k])
|
||||
}
|
||||
if (node) {
|
||||
nodePoints = node._points;
|
||||
if (nodePoints) {
|
||||
for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
|
||||
points[i + k] = m(points[i + k], nodePoints[k]);
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < wordLength - 1; i += 1) {
|
||||
if (i > this.leftMin && i < wordLength - this.rightMin && points[i] % 2) {
|
||||
result.push(originalCharacters[i])
|
||||
} else {
|
||||
result[result.length - 1] += originalCharacters[i]
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = Hypher
|
||||
window['Hypher'] = module.exports
|
||||
for (i = 1; i < wordLength - 1; i += 1) {
|
||||
if (i > this.leftMin && i < (wordLength - this.rightMin) && points[i] % 2) {
|
||||
result.push(originalCharacters[i]);
|
||||
} else {
|
||||
result[result.length - 1] += originalCharacters[i];
|
||||
}
|
||||
}
|
||||
|
||||
window['Hypher']['languages'] = {}
|
||||
})()
|
||||
;(function ($) {
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = Hypher;
|
||||
window['Hypher'] = module.exports;
|
||||
|
||||
window['Hypher']['languages'] = {};
|
||||
}());(function ($) {
|
||||
$.fn.hyphenate = function (language) {
|
||||
if (window['Hypher']['languages'][language]) {
|
||||
return this.each(function () {
|
||||
var i = 0,
|
||||
len = this.childNodes.length
|
||||
var i = 0, len = this.childNodes.length;
|
||||
for (; i < len; i += 1) {
|
||||
if (this.childNodes[i].nodeType === 3) {
|
||||
this.childNodes[i].nodeValue = window['Hypher']['languages'][language].hyphenateText(
|
||||
this.childNodes[i].nodeValue
|
||||
)
|
||||
this.childNodes[i].nodeValue = window['Hypher']['languages'][language].hyphenateText(this.childNodes[i].nodeValue);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
})(jQuery);
|
||||
};
|
||||
}(jQuery));
|
||||
4667
lib/3rdparty/pixi-ease.js
vendored
8179
lib/3rdparty/pixi-viewport.js
vendored
27
lib/_menu.js
@ -1,27 +0,0 @@
|
||||
const mapping = {
|
||||
'lib.Application': './app.html',
|
||||
'lib.Capabilities': './capabilities.html',
|
||||
'lib.Card': './card/index.html',
|
||||
'lib.Pixi': './pixi/index.html',
|
||||
'pixi.App': './pixi/app.html'
|
||||
}
|
||||
|
||||
function menu(event) {
|
||||
let key = event.target.innerText
|
||||
let html = ''
|
||||
|
||||
for (let k of Object.keys(mapping)) {
|
||||
if (k.startsWith(key)) {
|
||||
let rest = k.slice(key.length)
|
||||
let url = mapping[k]
|
||||
html += `<a href="${url}">${rest}</a>`
|
||||
}
|
||||
}
|
||||
event.preventDefault()
|
||||
let contextMenu = document.createElement('div')
|
||||
contextMenu.id = 'ctxmenu'
|
||||
contextMenu.style = `top:${event.pageY - 10}px;left:${event.pageX - 40}px`
|
||||
contextMenu.onmouseleave = () => (contextMenu.outerHTML = '')
|
||||
contextMenu.innerHTML = html
|
||||
document.body.appendChild(contextMenu)
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>App</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
@ -13,7 +12,7 @@
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="index.html">lib.</a>Application
|
||||
Application
|
||||
</h1>
|
||||
<p>
|
||||
IWM Browser Applications follow a common three phase pattern, shared by many programming environments as diverse as Processing, Arduino, Intern, etc.
|
||||
|
||||
10
lib/bootstrap.js
vendored
@ -122,17 +122,17 @@ class Bootstrap extends Object {
|
||||
baseURL: baseUrl,
|
||||
map: {
|
||||
'plugin-babel': baseUrl + '/3rdparty/systemjs/plugin-babel.js',
|
||||
'systemjs-babel-build': baseUrl + '/3rdparty/systemjs/systemjs-babel-browser.js',
|
||||
'systemjs-babel-build': baseUrl + '/3rdparty/systemjs/systemjs-babel-browser.js'
|
||||
},
|
||||
transpiler: 'plugin-babel',
|
||||
meta: {
|
||||
'*.js': {
|
||||
authorization: true,
|
||||
babelOptions: {
|
||||
es2015: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
es2015: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
InteractionDelta,
|
||||
InteractionMapper,
|
||||
InteractionDelegate,
|
||||
IInteractionMapperTarget,
|
||||
IInteractionMapperTarget
|
||||
} from './interaction.js'
|
||||
import {
|
||||
ITapDelegate,
|
||||
@ -31,7 +31,7 @@ import {
|
||||
AbstractScatter,
|
||||
DOMScatter,
|
||||
ScatterEvent,
|
||||
BaseEvent,
|
||||
BaseEvent
|
||||
} from './scatter.js'
|
||||
import {
|
||||
Cycle,
|
||||
@ -50,7 +50,7 @@ import {
|
||||
debounce,
|
||||
randomInt,
|
||||
randomFloat,
|
||||
LowPassFilter,
|
||||
LowPassFilter
|
||||
} from './utils.js'
|
||||
import UITest from './uitest.js'
|
||||
|
||||
|
||||
@ -1,56 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Doctests Capabilities</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script type="text/javascript" src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run(); CapabilitiesTests.testAll()">
|
||||
<main>
|
||||
<h1><a href="index.html">lib.</a>Capabilities</h1>
|
||||
<p>
|
||||
Browsers differ in many aspects, from touch support, support of CSS and HTML5 standards, to javascript
|
||||
versions. This page collects some of these differences.
|
||||
</p>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Doctests Capabilities</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script type="text/javascript" src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run(); CapabilitiesTests.testAll()">
|
||||
<main>
|
||||
<h1>
|
||||
Capabilities
|
||||
</h1>
|
||||
<p>Browsers differ in many aspects, from touch support, support of CSS and HTML5 standards, to
|
||||
javascript versions. This page collects some of these differences.
|
||||
<h3>
|
||||
User Agent
|
||||
</h3>
|
||||
<p id="user_agent">
|
||||
</p>
|
||||
<h3>
|
||||
Device Pixel Ratio
|
||||
</h3>
|
||||
<p id="device_pixel_ratio">
|
||||
</p>
|
||||
<h3>
|
||||
Multi Touch Table
|
||||
</h3>
|
||||
<p id="multi_touch_table">
|
||||
</p>
|
||||
<h3>
|
||||
Supported Events
|
||||
</h3>
|
||||
<p id="supported_events">
|
||||
</p>
|
||||
<script class="doctest">
|
||||
|
||||
<h3>User Agent</h3>
|
||||
<p id="user_agent"></p>
|
||||
<h3>Device Pixel Ratio</h3>
|
||||
<p id="device_pixel_ratio"></p>
|
||||
<h3>Multi Touch Table</h3>
|
||||
<p id="multi_touch_table"></p>
|
||||
<h3>Supported Events</h3>
|
||||
<p id="supported_events"></p>
|
||||
<script class="doctest">
|
||||
Doctest.expect(Capabilities.supportsMouseEvents(), true)
|
||||
Doctest.expect(Capabilities.supportsMouseEvents(), true)
|
||||
|
||||
if (Capabilities.supportsTouchEvents()) {
|
||||
Doctest.expect(Capabilities.supportsTouchEvents(), true)
|
||||
}
|
||||
if (Capabilities.supportsTouchEvents()) {
|
||||
Doctest.expect(Capabilities.supportsTouchEvents(), true)
|
||||
}
|
||||
|
||||
if (Capabilities.supportsPointerEvents()) {
|
||||
Doctest.expect(Capabilities.supportsPointerEvents(), true)
|
||||
}
|
||||
</script>
|
||||
<h3>Interactive Alerts</h3>
|
||||
<p>
|
||||
Standard alerts are displayed quite differently, on Windows 10, for instance the browser URL is
|
||||
encluded, and a checkbox that allows to hide the alert dialogs.
|
||||
</p>
|
||||
<button onclick="alert('Ok'); console.log('Alert')">Alert</button>
|
||||
<button onclick="CapabilitiesTests.testConfirm()">Confirm</button>
|
||||
<button onclick="CapabilitiesTests.testPrompt()">Prompt</button>
|
||||
<p id="demo">Result</p>
|
||||
<hr />
|
||||
if (Capabilities.supportsPointerEvents()) {
|
||||
Doctest.expect(Capabilities.supportsPointerEvents(), true)
|
||||
}
|
||||
</script>
|
||||
<h3>
|
||||
Interactive Alerts
|
||||
</h3>
|
||||
<p>
|
||||
Standard alerts are displayed quite differently, on Windows 10, for instance
|
||||
the browser URL is encluded, and a checkbox that allows to hide the
|
||||
alert dialogs.
|
||||
</p>
|
||||
<button onclick="alert('Ok'); console.log('Alert')">Alert</button>
|
||||
<button onclick="CapabilitiesTests.testConfirm()">Confirm</button>
|
||||
<button onclick="CapabilitiesTests.testPrompt()">Prompt</button>
|
||||
<p id="demo">
|
||||
Result
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li><a href="http://caniuse.com">Can I use</a></li>
|
||||
<li><a href="http://webglreport.com">WebGL Report</a></li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="http://caniuse.com">Can I use</a></li>
|
||||
<li><a href="http://webglreport.com">WebGL Report</a></li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
186
lib/card/card.js
@ -55,7 +55,7 @@ export default class Card {
|
||||
context.classList.add('info-card')
|
||||
context.setAttribute('data-id', Card.id++)
|
||||
|
||||
modules.forEach((module) => {
|
||||
modules.forEach(module => {
|
||||
if (module.apply(context)) {
|
||||
const moduleName = module.constructor.name
|
||||
context.modules.push(moduleName)
|
||||
@ -157,7 +157,7 @@ export default class Card {
|
||||
*/
|
||||
static _replaceAttributes(context, html, attribute, replaceFunc) {
|
||||
let attributeCarrier = html.querySelectorAll(`[${attribute}]`)
|
||||
attributeCarrier.forEach((element) => {
|
||||
attributeCarrier.forEach(element => {
|
||||
let attributeVal = element.getAttribute(attribute)
|
||||
element.removeAttribute(attribute)
|
||||
replaceFunc.call(this, context, element, attributeVal)
|
||||
@ -176,7 +176,7 @@ export default class Card {
|
||||
*/
|
||||
static _replaceCallback(context, element, attributeVal) {
|
||||
if (element.tagName == 'A') {
|
||||
element.addEventListener('click', (event) => {
|
||||
element.addEventListener('pointerdown', event => {
|
||||
event.preventDefault()
|
||||
})
|
||||
}
|
||||
@ -189,7 +189,7 @@ export default class Card {
|
||||
trimmedArgs = trimmedArgs.substring(0, trimmedArgs.length - 1)
|
||||
|
||||
let callParts = funcPart.split('.')
|
||||
let argsStrings = trimmedArgs.split(',').filter((entry) => {
|
||||
let argsStrings = trimmedArgs.split(',').filter(entry => {
|
||||
return entry.trim() != ''
|
||||
})
|
||||
/**
|
||||
@ -218,12 +218,12 @@ export default class Card {
|
||||
// These are 'hardcoded' inside the convert.js.
|
||||
if (element.tagName == 'circle') return false
|
||||
|
||||
this.registerEvent(context, interactionType, element, (event) => {
|
||||
this.registerEvent(context, interactionType, element, event => {
|
||||
/**
|
||||
* Replaces the strings from the listener with the corresponding variables.
|
||||
*/
|
||||
let args = []
|
||||
argsStrings.forEach((arg) => {
|
||||
argsStrings.forEach(arg => {
|
||||
arg = arg.trim()
|
||||
if (arg == 'this') args.push(event.target)
|
||||
else if (arg == 'event') args.push(event)
|
||||
@ -269,7 +269,7 @@ export default class Card {
|
||||
*/
|
||||
return html.replace(
|
||||
/<\s*(a|video|img|image|circle)\s(.*?)(xlink:href|href|src)\s*=\s*["'](\..*?)["']\s*(.*?)>/g,
|
||||
function () {
|
||||
function() {
|
||||
let path = that._getRelativePath(arguments[4])
|
||||
const tag = `<${arguments[1]} ${arguments[2]} ${arguments[3]}="${path}" ${arguments[5]}>`
|
||||
/* if (that.debug) */ console.log('Adjusted: ', tag)
|
||||
@ -298,7 +298,7 @@ export default class Card {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = new XMLHttpRequest()
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
request.onreadystatechange = function() {
|
||||
if (this.readyState == 4) {
|
||||
if (this.status == 200 || Card._isLocal()) {
|
||||
try {
|
||||
@ -405,12 +405,6 @@ export default class Card {
|
||||
static _openPopup(context, src, position, content, options = {}) {
|
||||
if (this.debug) console.log('Card._openPopup', position)
|
||||
|
||||
console.log('context', context)
|
||||
console.log('src', src)
|
||||
console.log('position', position)
|
||||
console.log('content', content)
|
||||
console.log('options', options)
|
||||
|
||||
//logging
|
||||
if (src) {
|
||||
let strparts = src.split('/')
|
||||
@ -429,7 +423,7 @@ export default class Card {
|
||||
}
|
||||
|
||||
this._createPopup(context, position, content, options)
|
||||
.then((popup) => {
|
||||
.then(popup => {
|
||||
if (
|
||||
//Test if meanwhile another popup was registered...
|
||||
this._getPopup(context) ||
|
||||
@ -447,9 +441,9 @@ export default class Card {
|
||||
// let unnecessaryPopupElement = popup.element.querySelector(".popupContent > .popup")
|
||||
// unnecessaryPopupElement.classList.remove("popup")
|
||||
|
||||
popupParagraphs.forEach((popupParagraph) => {
|
||||
popupParagraphs.forEach(popupParagraph => {
|
||||
popupParagraph.setAttribute('draggable', false)
|
||||
popupParagraph.addEventListener('mousedown', (event) => {
|
||||
popupParagraph.addEventListener('mousedown', event => {
|
||||
event.preventDefault()
|
||||
})
|
||||
})
|
||||
@ -457,7 +451,7 @@ export default class Card {
|
||||
this._setPopup(context, popup, src)
|
||||
}
|
||||
})
|
||||
.catch((e) => console.error(e))
|
||||
.catch(e => console.error(e))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -497,14 +491,14 @@ export default class Card {
|
||||
Object.assign(
|
||||
{
|
||||
parent: context,
|
||||
content,
|
||||
content
|
||||
},
|
||||
Object.assign(
|
||||
{
|
||||
noStyle: true,
|
||||
// TODO: Remove offset when positioning according to element position
|
||||
// is working.
|
||||
posOffset: 10,
|
||||
posOffset: 10
|
||||
},
|
||||
options
|
||||
)
|
||||
@ -516,7 +510,7 @@ export default class Card {
|
||||
// We manually prevent this here.
|
||||
popup.element.style.display = 'none'
|
||||
|
||||
let promise = new Promise((resolve) => {
|
||||
let promise = new Promise(resolve => {
|
||||
if (popup.loaded) resolve(popup)
|
||||
else {
|
||||
popup.onload = () => {
|
||||
@ -525,7 +519,7 @@ export default class Card {
|
||||
}
|
||||
})
|
||||
|
||||
promise.then((popup) => {
|
||||
promise.then(popup => {
|
||||
popup.element.style.display = 'block'
|
||||
popup.element.style.visibility = 'hidden'
|
||||
popup.element.style.opacity = 0
|
||||
@ -537,12 +531,12 @@ export default class Card {
|
||||
})
|
||||
|
||||
Object.assign(popup.element.style, {
|
||||
zIndex: this.zIndices.popup,
|
||||
zIndex: this.zIndices.popup
|
||||
})
|
||||
|
||||
TweenLite.to(popup.element, this.animation.popup, {
|
||||
autoAlpha: 1,
|
||||
ease: Power2.easeIn,
|
||||
ease: Power2.easeIn
|
||||
})
|
||||
})
|
||||
|
||||
@ -566,7 +560,7 @@ export default class Card {
|
||||
popup.remove()
|
||||
//this._cleanup(context)
|
||||
//overlay.parentNode.removeChild(overlay)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -595,9 +589,7 @@ export default class Card {
|
||||
|
||||
// Prevents loading the link in the current tab.
|
||||
// Prevents loading the link in the current tab.
|
||||
if (event.type != 'Follow') {
|
||||
event.preventDefault()
|
||||
}
|
||||
if (event.type != 'Follow') event.preventDefault()
|
||||
|
||||
if (editable && event.type == 'click') {
|
||||
return false
|
||||
@ -626,7 +618,7 @@ export default class Card {
|
||||
let popupPage = parser.parseFromString(xhr.responseText, 'text/html')
|
||||
|
||||
//Fix the relative path of loaded images in the popup.
|
||||
popupPage.querySelectorAll('img').forEach((node) => {
|
||||
popupPage.querySelectorAll('img').forEach(node => {
|
||||
node.setAttribute('src', that._getRelativePath(node.getAttribute('src')))
|
||||
})
|
||||
let html = popupPage.body.innerHTML
|
||||
@ -645,8 +637,6 @@ export default class Card {
|
||||
let selector = Card.popupHtmlSelector
|
||||
let content = { html, selector }
|
||||
|
||||
console.log('loadPopup', selector, html)
|
||||
|
||||
let isSame = Card._checkForActiveSource(context, src)
|
||||
Card._cleanup(context)
|
||||
|
||||
@ -658,7 +648,7 @@ export default class Card {
|
||||
if (editable) {
|
||||
let isDirty = mainController.askSaveNode()
|
||||
if (isDirty)
|
||||
mainController.saveNode(html.innerHTML, (url) => {
|
||||
mainController.saveNode(html.innerHTML, url => {
|
||||
if (callback) {
|
||||
callback()
|
||||
}
|
||||
@ -680,12 +670,12 @@ export default class Card {
|
||||
}
|
||||
|
||||
Card._openPopup(context, src, local, content, {
|
||||
closeCommand: callback,
|
||||
closeCommand: callback
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
overlay.onclick = (e) => {
|
||||
overlay.onclick = e => {
|
||||
if (editable) e.preventDefault()
|
||||
}
|
||||
//console.log("onreadystatechange", editable)
|
||||
@ -722,7 +712,7 @@ export default class Card {
|
||||
for (let highlight of correspondingHighlights) {
|
||||
if (highlight.parentNode && highlight.parentNode.nodeName.toLowerCase() == 'g') {
|
||||
Highlight.openHighlight(highlight, {
|
||||
animation: Card.highlightAnimation,
|
||||
animation: Card.highlightAnimation
|
||||
})
|
||||
this._addHighlight(context, highlight)
|
||||
}
|
||||
@ -766,6 +756,7 @@ export default class Card {
|
||||
}
|
||||
|
||||
static _calculateCenterRelativeTo(target, image) {
|
||||
// console.log('_calculateCenterRelativeTo', target, image)
|
||||
let bbox = image.getBBox()
|
||||
let width = bbox.width
|
||||
let height = bbox.height
|
||||
@ -850,19 +841,19 @@ export default class Card {
|
||||
// TODO: Adjust to load while animating (Problem: Unload when cancelled).
|
||||
// console.log('loadHighlightPopup', src, position, local)
|
||||
this._loadPopupContent(context, src)
|
||||
.then((content) => {
|
||||
.then(content => {
|
||||
this._openPopup(context, src, local, content, {
|
||||
highlight: node,
|
||||
closeCommand: (popup) => {
|
||||
closeCommand: popup => {
|
||||
this._overlayCleanup(context, overlay)
|
||||
popup.remove()
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -946,7 +937,7 @@ export default class Card {
|
||||
|
||||
let globalBottomRight = {
|
||||
x: imageWidth,
|
||||
y: imageHeight,
|
||||
y: imageHeight
|
||||
}
|
||||
|
||||
globalBottomRight = Points.fromNodeToPage(zoomable, globalBottomRight)
|
||||
@ -1012,7 +1003,7 @@ export default class Card {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 200,
|
||||
zIndex: 200
|
||||
})
|
||||
|
||||
wrapper.appendChild(zoomContainer)
|
||||
@ -1080,13 +1071,13 @@ export default class Card {
|
||||
y: current.y,
|
||||
width: current.width + borderX,
|
||||
height: current.height + borderY,
|
||||
transformOrigin,
|
||||
transformOrigin
|
||||
})
|
||||
TweenLite.set(zoomable, { opacity: 0 })
|
||||
|
||||
let icon = zoomedFig.querySelector('.icon')
|
||||
TweenLite.set(icon, {
|
||||
transformOrigin,
|
||||
transformOrigin
|
||||
})
|
||||
zoomedFig.style.transformOrigin =
|
||||
'calc(100% - ' +
|
||||
@ -1106,8 +1097,8 @@ export default class Card {
|
||||
ease: Power2.easeIn,
|
||||
css: {
|
||||
scaleX: scaleFactor,
|
||||
scaleY: scaleFactor,
|
||||
},
|
||||
scaleY: scaleFactor
|
||||
}
|
||||
},
|
||||
0
|
||||
)
|
||||
@ -1116,11 +1107,11 @@ export default class Card {
|
||||
display: 'block',
|
||||
opacity: 0,
|
||||
x: -parseFloat(zoomedFigStyle.borderLeftWidth),
|
||||
width: current.width + borderX,
|
||||
},
|
||||
width: current.width + borderX
|
||||
}
|
||||
})
|
||||
.to(zoomCaption, this.animation.fade, {
|
||||
autoAlpha: 1,
|
||||
autoAlpha: 1
|
||||
})
|
||||
} else this._openZoomableEditorBehaviour(wrapper, img, zoomable, zoomedFig, current)
|
||||
}
|
||||
@ -1169,7 +1160,7 @@ export default class Card {
|
||||
x: current.x,
|
||||
y: current.y,
|
||||
width: current.width,
|
||||
height: current.height,
|
||||
height: current.height
|
||||
})
|
||||
let editor = mainController.topController().ensureEditor(img)
|
||||
let savedDisplay = zoomIcon.style.display
|
||||
@ -1196,13 +1187,13 @@ export default class Card {
|
||||
wrapper.appendChild(iconClone)
|
||||
TweenLite.set(iconClone, { x: current.iconPos.x, y: current.iconPos.y })
|
||||
|
||||
zoomable.onmousedown = (event) => {
|
||||
zoomable.onmousedown = event => {
|
||||
if (this.debug) console.log('mousedown', event.target)
|
||||
event.preventDefault()
|
||||
zoomable.dragging = true
|
||||
zoomable.dragStartPos = { x: event.pageX, y: event.pageY }
|
||||
}
|
||||
zoomable.onmousemove = (event) => {
|
||||
zoomable.onmousemove = event => {
|
||||
if (this.debug) console.log('onmousemove', event.target)
|
||||
if (zoomable.dragging) {
|
||||
event.preventDefault()
|
||||
@ -1210,7 +1201,7 @@ export default class Card {
|
||||
let dy = event.pageY - zoomable.dragStartPos.y
|
||||
TweenLite.set([zoomable, iconClone], {
|
||||
x: '+=' + dx,
|
||||
y: '+=' + dy,
|
||||
y: '+=' + dy
|
||||
})
|
||||
zoomable.dragStartPos = { x: event.pageX, y: event.pageY }
|
||||
if (editor) {
|
||||
@ -1223,7 +1214,7 @@ export default class Card {
|
||||
}
|
||||
|
||||
let startZoom = 1
|
||||
zoomable.onmousewheel = (event) => {
|
||||
zoomable.onmousewheel = event => {
|
||||
event.preventDefault()
|
||||
let direction = event.detail < 0 || event.wheelDelta > 0
|
||||
const zoomFactor = 1.1
|
||||
@ -1259,24 +1250,24 @@ export default class Card {
|
||||
let zoomedCaption = zoomedFig.querySelector('figcaption.zoomcap')
|
||||
|
||||
TweenLite.to(zoomedCaption, this.animation.fade, {
|
||||
autoAlpha: 0,
|
||||
autoAlpha: 0
|
||||
})
|
||||
|
||||
TweenLite.to(zoomedFig, this.animation.zoomable, {
|
||||
css: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
scaleY: 1
|
||||
},
|
||||
onComplete: () => {
|
||||
TweenLite.set(zoomable, {
|
||||
opacity: 1,
|
||||
opacity: 1
|
||||
})
|
||||
|
||||
let div = zoomedFig.parentNode
|
||||
let videoElement = div.querySelector('video')
|
||||
if (videoElement) videoElement.pause()
|
||||
div.parentNode.removeChild(div)
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
InteractionMapper.off(zoomedFig)
|
||||
@ -1350,12 +1341,12 @@ export default class Card {
|
||||
height: globalIndexCardRect.height,
|
||||
maxWidth: '100%',
|
||||
margin: 0,
|
||||
zIndex: this.zIndices.article,
|
||||
},
|
||||
zIndex: this.zIndices.article
|
||||
}
|
||||
})
|
||||
|
||||
TweenLite.set(articleClone, {
|
||||
autoAlpha: 0,
|
||||
autoAlpha: 0
|
||||
})
|
||||
|
||||
TweenLite.set(card, { css: { maxWidth: '100%' } })
|
||||
@ -1365,7 +1356,7 @@ export default class Card {
|
||||
scaleX,
|
||||
scaleY,
|
||||
transformOrigin: '0% 0%',
|
||||
rotation: angle,
|
||||
rotation: angle
|
||||
})
|
||||
indexbox.prepend(clone)
|
||||
clone.setAttribute('data-source', src)
|
||||
@ -1374,7 +1365,7 @@ export default class Card {
|
||||
let title = titlebar.querySelector('h2')
|
||||
let titlebarStyle = window.getComputedStyle(titlebar)
|
||||
let start = {
|
||||
height: parseInt(titlebarStyle.height),
|
||||
height: parseInt(titlebarStyle.height)
|
||||
}
|
||||
|
||||
if (this.dynamicHeight) {
|
||||
@ -1394,7 +1385,10 @@ export default class Card {
|
||||
|
||||
//jquery hyphenate below
|
||||
if (this._isJQueryPresent()) {
|
||||
$('.column').not('.overview').children('p').hyphenate('de')
|
||||
$('.column')
|
||||
.not('.overview')
|
||||
.children('p')
|
||||
.hyphenate('de')
|
||||
}
|
||||
|
||||
//logging
|
||||
@ -1420,23 +1414,23 @@ export default class Card {
|
||||
card.classList.add('visited')
|
||||
},
|
||||
onUpdateParams: ['{self}'],
|
||||
onUpdate: (self) => {
|
||||
onUpdate: self => {
|
||||
let transform = self.target._gsTransform
|
||||
TweenLite.set(title, {
|
||||
scale: 1 / transform.scaleX,
|
||||
scale: 1 / transform.scaleX
|
||||
})
|
||||
TweenLite.set(titlebar, {
|
||||
height: (start.height * 1) / transform.scaleY,
|
||||
height: (start.height * 1) / transform.scaleY
|
||||
})
|
||||
|
||||
// Retain the border at same visual thickness.
|
||||
titlebar.style.borderBottomWidth = desiredBorderBottomWidth / transform.scaleY + 'px'
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
TweenLite.to([articleClone], this.animation.articleTransition / 2, {
|
||||
delay: this.animation.articleTransition / 2,
|
||||
autoAlpha: 1,
|
||||
autoAlpha: 1
|
||||
})
|
||||
|
||||
if (editable) {
|
||||
@ -1485,11 +1479,11 @@ export default class Card {
|
||||
if (editable) {
|
||||
let isDirty = mainController.askSaveNode()
|
||||
if (isDirty) {
|
||||
mainController.saveNode(html.innerHTML, (url) => {
|
||||
mainController.saveNode(html.innerHTML, url => {
|
||||
callback(url)
|
||||
this._closeIndexCard(context, card, clone, articleClone, {
|
||||
eventElements,
|
||||
src,
|
||||
src
|
||||
})
|
||||
})
|
||||
} else {
|
||||
@ -1528,7 +1522,7 @@ export default class Card {
|
||||
|
||||
let scale = {
|
||||
x: globalPreviewRect.width / globalIndexCardRect.width,
|
||||
y: globalPreviewRect.height / globalIndexCardRect.height,
|
||||
y: globalPreviewRect.height / globalIndexCardRect.height
|
||||
}
|
||||
|
||||
let titlebar = clonedSubcard.querySelector('.titlebar')
|
||||
@ -1557,16 +1551,16 @@ export default class Card {
|
||||
let titlebarStyle = window.getComputedStyle(previewTitlebar)
|
||||
|
||||
TweenLite.to(titlebar, this.animation.articleTransition, {
|
||||
height: parseInt(titlebarStyle.height),
|
||||
height: parseInt(titlebarStyle.height)
|
||||
})
|
||||
|
||||
TweenLite.to(clonedArticle, this.animation.articleTransition / 2, {
|
||||
autoAlpha: 0,
|
||||
autoAlpha: 0
|
||||
})
|
||||
|
||||
let title = titlebar.querySelector('h2')
|
||||
let original = {
|
||||
height: parseInt(titlebarStyle.height),
|
||||
height: parseInt(titlebarStyle.height)
|
||||
}
|
||||
|
||||
if (this.dynamicHeight) {
|
||||
@ -1595,24 +1589,24 @@ export default class Card {
|
||||
mainController.popController()
|
||||
}
|
||||
clonedSubcard.remove()
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
onUpdateParams: ['{self}'],
|
||||
onUpdate: function (self) {
|
||||
onUpdate: function(self) {
|
||||
let transform = self.target._gsTransform
|
||||
|
||||
TweenLite.set(title, {
|
||||
scale: 1 / transform.scaleX,
|
||||
scale: 1 / transform.scaleX
|
||||
})
|
||||
|
||||
TweenLite.set(titlebar, {
|
||||
height: (original.height * 1) / transform.scaleY,
|
||||
height: (original.height * 1) / transform.scaleY
|
||||
})
|
||||
|
||||
// Retain the border at same visual thickness.
|
||||
titlebar.style.borderBottomWidth = desiredBorderBottomWidth / transform.scaleY + 'px'
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1659,7 +1653,7 @@ export default class Card {
|
||||
* Called by the expandIndexCard(...)
|
||||
*/
|
||||
let target = event.target
|
||||
const saveCallback = (url) => {
|
||||
const saveCallback = url => {
|
||||
let handler = `Card.openIndexCard(event, '${url}')`
|
||||
if (this.debug) console.log('File has changed', target, handler)
|
||||
|
||||
@ -1750,9 +1744,9 @@ export default class Card {
|
||||
}
|
||||
|
||||
let highlights = this._getHighlights(context)
|
||||
highlights.forEach((highlight) => {
|
||||
highlights.forEach(highlight => {
|
||||
Highlight.closeHighlight(highlight, {
|
||||
animation: Card.highlightAnimation,
|
||||
animation: Card.highlightAnimation
|
||||
})
|
||||
})
|
||||
|
||||
@ -1774,13 +1768,13 @@ export default class Card {
|
||||
let global = this._getGlobalRect(element)
|
||||
let localPosition = Points.fromPageToNode(context, {
|
||||
x: global.x,
|
||||
y: global.y,
|
||||
y: global.y
|
||||
})
|
||||
return DOMRectReadOnly.fromRect({
|
||||
x: localPosition.x,
|
||||
y: localPosition.y,
|
||||
width: global.width,
|
||||
height: global.height,
|
||||
height: global.height
|
||||
})
|
||||
}
|
||||
|
||||
@ -1803,7 +1797,7 @@ export default class Card {
|
||||
x: globalPosition.x,
|
||||
y: globalPosition.y,
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
height: cardHeight
|
||||
})
|
||||
}
|
||||
|
||||
@ -1825,19 +1819,19 @@ export default class Card {
|
||||
this._replaceAttributes(context, html, 'onclick', this._replaceCallback)
|
||||
}
|
||||
let zoomableWrappers = html.querySelectorAll('.svg-wrapper')
|
||||
zoomableWrappers.forEach((wrapper) => {
|
||||
zoomableWrappers.forEach(wrapper => {
|
||||
let svg = wrapper.querySelector('svg')
|
||||
Object.assign(wrapper.style, {
|
||||
width: svg.getAttribute('width') + 'px',
|
||||
height: svg.getAttribute('height') + 'px',
|
||||
height: svg.getAttribute('height') + 'px'
|
||||
})
|
||||
})
|
||||
let zoomableVideoWrappers = html.querySelectorAll('.video-wrapper')
|
||||
zoomableVideoWrappers.forEach((wrapper) => {
|
||||
zoomableVideoWrappers.forEach(wrapper => {
|
||||
let video = wrapper.querySelector('video')
|
||||
Object.assign(wrapper.style, {
|
||||
width: video.getAttribute('width') + 'px',
|
||||
height: video.getAttribute('height') + 'px',
|
||||
height: video.getAttribute('height') + 'px'
|
||||
})
|
||||
})
|
||||
|
||||
@ -1876,12 +1870,12 @@ export default class Card {
|
||||
let globalClick = event.center ? event.center : { x: event.x, y: event.y }
|
||||
let localClick = Points.fromPageToNode(indexbox, globalClick)
|
||||
|
||||
let linkRects = links.map((link) => {
|
||||
let linkRects = links.map(link => {
|
||||
let rect = link.getBoundingClientRect()
|
||||
let topLeft = Points.fromPageToNode(indexbox, rect)
|
||||
let center = Points.fromPageToNode(indexbox, {
|
||||
x: rect.x + rect.width / 2,
|
||||
y: rect.y + rect.height / 2,
|
||||
y: rect.y + rect.height / 2
|
||||
})
|
||||
return {
|
||||
x: topLeft.x,
|
||||
@ -1889,12 +1883,12 @@ export default class Card {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
center,
|
||||
link,
|
||||
link
|
||||
}
|
||||
})
|
||||
|
||||
let distances = []
|
||||
linkRects.forEach((rect) => {
|
||||
linkRects.forEach(rect => {
|
||||
let distance = Card.pointRectDist(localClick, rect)
|
||||
if (distance == 0.0) {
|
||||
// Distance == 0.0 indicates an inside relation. Since these
|
||||
@ -2101,7 +2095,7 @@ Card.zIndices = {
|
||||
article: 10,
|
||||
popup: 100,
|
||||
zoomable: 101,
|
||||
zoomedFigure: 102,
|
||||
zoomedFigure: 102
|
||||
}
|
||||
|
||||
Card.animation = {
|
||||
@ -2109,5 +2103,5 @@ Card.animation = {
|
||||
fade: 0.2,
|
||||
popup: 0.1,
|
||||
highlight: 0.4,
|
||||
zoomable: 0.5,
|
||||
zoomable: 0.5
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ export default class Highlight extends Object {
|
||||
obj.classList.add(this.expandedClass)
|
||||
obj.setAttribute('stroke-width', stroke / scale)
|
||||
if (onComplete) onComplete()
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ export default class Highlight extends Object {
|
||||
obj.classList.remove('zooming')
|
||||
obj.classList.remove(this.expandedClass)
|
||||
obj.setAttribute('stroke-width', stroke)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ export default class Highlight extends Object {
|
||||
this.shrink(maskImage, { stroke })
|
||||
return
|
||||
}
|
||||
let circles = Array.from(circleGroup.children).filter((e) => e.tagName == 'circle')
|
||||
let circles = Array.from(circleGroup.children).filter(e => e.tagName == 'circle')
|
||||
for (let c of circles) {
|
||||
//console.log("shrinking all circles")
|
||||
this.shrink(c, { stroke })
|
||||
@ -210,17 +210,18 @@ export default class Highlight extends Object {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let [mask, maskImage] = this._getSVGMask(target, {
|
||||
svgRoot,
|
||||
image,
|
||||
image
|
||||
})
|
||||
let center = this._calculateCenterRelativeTo(target, image)
|
||||
console.log('_calculateCenterRelativeTo', center)
|
||||
TweenLite.set(maskImage, {
|
||||
transformOrigin: `${center.x} ${center.y}`,
|
||||
transformOrigin: `${center.x} ${center.y}`
|
||||
})
|
||||
TweenLite.set(target, { transformOrigin: '50% 50%' })
|
||||
|
||||
TweenLite.to([target, maskImage], animation, {
|
||||
scale,
|
||||
onComplete: onExpanded,
|
||||
onComplete: onExpanded
|
||||
})
|
||||
|
||||
target.classList.add(this.expandedClass)
|
||||
@ -258,7 +259,7 @@ export default class Highlight extends Object {
|
||||
[mask, maskImage] = this._createSVGMask(circle, {
|
||||
svgRoot,
|
||||
image,
|
||||
id,
|
||||
id
|
||||
})
|
||||
|
||||
return [mask, maskImage]
|
||||
@ -352,7 +353,7 @@ export default class Highlight extends Object {
|
||||
let [mask, maskImage] = this._getSVGMask(target)
|
||||
// console.log('Close Highlight', maskImage)
|
||||
TweenLite.to([target, maskImage], animation, {
|
||||
scale: 1,
|
||||
scale: 1
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
<body onload="Doctest.run();">
|
||||
<h1>
|
||||
<a href="../index.html">lib.</a><a href="index.html">card.</a>Cards
|
||||
Cards
|
||||
</h1>
|
||||
<p>
|
||||
Cards implement a central UI metaphor for multiuser applications. They allow users to explore information spaces
|
||||
|
||||
@ -63,7 +63,7 @@ export class CardPluginBase {
|
||||
let requirements = this._collectAllRequirements()
|
||||
let missing = []
|
||||
|
||||
requirements.forEach((module) => {
|
||||
requirements.forEach(module => {
|
||||
if (context.modules.indexOf(module.name) == -1) {
|
||||
missing.push(module.name)
|
||||
}
|
||||
@ -121,12 +121,12 @@ CardPlugin.LightBox = class LightBox extends CardPluginBase {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
height: '100%'
|
||||
},
|
||||
this.style,
|
||||
{
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
position: 'absolute'
|
||||
}
|
||||
)
|
||||
|
||||
@ -199,7 +199,7 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
wrapper.appendChild(icon)
|
||||
|
||||
Object.assign(wrapper.style, {
|
||||
cursor: 'pointer',
|
||||
cursor: 'pointer'
|
||||
})
|
||||
|
||||
InteractionMapper.on(this.interactionType, wrapper, () => {
|
||||
@ -221,13 +221,13 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
|
||||
Object.assign(imageWrapper.style, {
|
||||
maxWidth: 'none',
|
||||
maxHeight: 'none',
|
||||
maxHeight: 'none'
|
||||
})
|
||||
|
||||
Object.assign(image.style, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
objectFit: 'cover'
|
||||
})
|
||||
|
||||
this._replaceIcon(imageWrapper)
|
||||
@ -250,7 +250,7 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
|
||||
const max = {
|
||||
width: context.offsetWidth * maxFillRatio,
|
||||
height: context.offsetHeight * maxFillRatio,
|
||||
height: context.offsetHeight * maxFillRatio
|
||||
}
|
||||
|
||||
let majorSide
|
||||
@ -284,14 +284,14 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
|
||||
let targetDimensions = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
height: 0
|
||||
}
|
||||
|
||||
let position = Points.fromPageToNode(context, Points.fromNodeToPage(source, { x: 0, y: 0 }))
|
||||
|
||||
let targetOffset = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
targetDimensions[majorSide.name] = size
|
||||
@ -311,22 +311,22 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
y: position.y,
|
||||
position: 'absolute',
|
||||
width: parseInt(sourceStyle.width),
|
||||
height: parseInt(sourceStyle.height),
|
||||
height: parseInt(sourceStyle.height)
|
||||
})
|
||||
|
||||
TweenMax.set(overlay, {
|
||||
display: 'flex',
|
||||
autoAlpha: 0,
|
||||
autoAlpha: 0
|
||||
})
|
||||
|
||||
TweenMax.to(imageWrapper, this.zoomAnimationDuration, {
|
||||
x: targetOffset.x,
|
||||
y: targetOffset.y,
|
||||
width: targetDimensions.width,
|
||||
height: targetDimensions.height,
|
||||
height: targetDimensions.height
|
||||
})
|
||||
TweenMax.to(overlay, this.fadeAnimationTime, {
|
||||
autoAlpha: 1,
|
||||
autoAlpha: 1
|
||||
})
|
||||
}
|
||||
|
||||
@ -358,10 +358,10 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
|
||||
|
||||
timeline
|
||||
.to(overlay, this.fadeAnimationDuration, {
|
||||
autoAlpha: 0,
|
||||
autoAlpha: 0
|
||||
})
|
||||
.set(overlay, {
|
||||
display: 'none',
|
||||
display: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -418,7 +418,7 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
|
||||
this._end = this._end.bind(this)
|
||||
|
||||
this._setupUtterance()
|
||||
this.utterance.addEventListener('end', (event) => {
|
||||
this.utterance.addEventListener('end', event => {
|
||||
this._end()
|
||||
})
|
||||
}
|
||||
@ -451,7 +451,7 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
|
||||
} else {
|
||||
if (subcard) {
|
||||
let clone = subcard.cloneNode(true)
|
||||
clone.querySelectorAll('figure').forEach((figure) => {
|
||||
clone.querySelectorAll('figure').forEach(figure => {
|
||||
figure.parentNode.removeChild(figure)
|
||||
})
|
||||
|
||||
@ -554,10 +554,10 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
|
||||
}
|
||||
|
||||
async _stop() {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
if (this.activeUtterance) {
|
||||
this.activeUtterance.addEventListener('end', resolve, {
|
||||
once: true,
|
||||
once: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -66,12 +66,12 @@ export default class ScatterCard extends Card {
|
||||
scatterContainer.element.appendChild(element)
|
||||
new DOMScatter(element, scatterContainer, {
|
||||
width: 1400,
|
||||
height: 1200,
|
||||
height: 1200
|
||||
})
|
||||
|
||||
this.setup(element, html, {
|
||||
basePath,
|
||||
modules,
|
||||
modules
|
||||
})
|
||||
return element
|
||||
}
|
||||
@ -132,15 +132,15 @@ export default class ScatterCard extends Card {
|
||||
let url = basePath + '/' + item + '/index.html'
|
||||
console.log('Loading', url)
|
||||
this.loadHTML(url)
|
||||
.then((html) => {
|
||||
.then(html => {
|
||||
console.log('Received', html)
|
||||
let element = this.createCardScatter(html, scatterContainer, {
|
||||
basePath,
|
||||
modules,
|
||||
modules
|
||||
})
|
||||
resolve(element)
|
||||
})
|
||||
.catch((e) => reject(e))
|
||||
.catch(e => reject(e))
|
||||
})
|
||||
}
|
||||
|
||||
@ -157,6 +157,6 @@ ScatterCard.selectedLanguage = 0
|
||||
ScatterCard.languages = ['Deutsch', 'English']
|
||||
ScatterCard.languageTags = {
|
||||
Deutsch: 'de',
|
||||
English: 'en',
|
||||
English: 'en'
|
||||
}
|
||||
ScatterCard.scatterContainer = null
|
||||
|
||||
@ -20,7 +20,7 @@ export default class Theme {
|
||||
path = path ? path : './config.json'
|
||||
|
||||
let xhttp = new XMLHttpRequest()
|
||||
xhttp.onreadystatechange = function () {
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4) {
|
||||
if (this.status == 200 || Theme._isLocal()) {
|
||||
try {
|
||||
|
||||
@ -17,7 +17,7 @@ export default class CardWrapper extends Object {
|
||||
handleClicks() {
|
||||
this.domNode.addEventListener(
|
||||
'click',
|
||||
(event) => {
|
||||
event => {
|
||||
if (event.isTrusted) {
|
||||
Events.stop(event)
|
||||
if (this.triggerSVGClicks && this.isSVGNode(event.target)) {
|
||||
@ -32,7 +32,7 @@ export default class CardWrapper extends Object {
|
||||
handleClicksAsTaps() {
|
||||
this.domNode.addEventListener(
|
||||
'click',
|
||||
(event) => {
|
||||
event => {
|
||||
if (event.isTrusted) {
|
||||
Events.stop(event)
|
||||
}
|
||||
@ -94,14 +94,42 @@ export default class CardWrapper extends Object {
|
||||
}
|
||||
|
||||
nearestActive(event) {
|
||||
let element = this.domNode
|
||||
let activeNodes = this.activeNodes()
|
||||
let globalClick = event.center ? event.center : { x: event.x, y: event.y }
|
||||
let distances = []
|
||||
activeNodes.forEach((link) => {
|
||||
let localClick = Points.fromPageToNode(element, globalClick)
|
||||
|
||||
let clickRects = activeNodes.map(link => {
|
||||
let rect = link.getBoundingClientRect()
|
||||
let distance = Points.distanceToRect(globalClick, rect)
|
||||
// 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 width = Math.abs(bottomRight.x - topLeft.x)
|
||||
let height = Math.abs(bottomRight.y - topLeft.y)
|
||||
let center = Points.fromPageToNode(element, {
|
||||
x: rect.x + width / 2,
|
||||
y: rect.y + height / 2
|
||||
})
|
||||
return {
|
||||
x: topLeft.x,
|
||||
y: topLeft.y,
|
||||
width,
|
||||
height,
|
||||
center,
|
||||
link
|
||||
}
|
||||
})
|
||||
|
||||
let distances = []
|
||||
clickRects.forEach(rect => {
|
||||
let distance = Points.distanceToRect(localClick, rect)
|
||||
distances.push(parseInt(distance))
|
||||
})
|
||||
|
||||
let closestClickIndex = distances.indexOf(Math.min(...distances))
|
||||
let closestClickable = activeNodes[closestClickIndex]
|
||||
if (distances[closestClickIndex] < this.allowClickDistance) {
|
||||
@ -134,6 +162,11 @@ export default class CardWrapper extends Object {
|
||||
}
|
||||
|
||||
nodeTapped(node, event) {
|
||||
console.log('nodeTapped', node, this.isClickable(node))
|
||||
if (this.isClickable(node)) {
|
||||
this.simulateClick(node, event)
|
||||
return true
|
||||
}
|
||||
if (this.tapNodes.has(node)) {
|
||||
let handler = this.tapNodes.get(node)
|
||||
handler(event, node)
|
||||
@ -148,16 +181,13 @@ export default class CardWrapper extends Object {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.isClickable(node)) {
|
||||
this.simulateClick(node, event)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
tap(event, calledBy = 'unknown') {
|
||||
if (event.isTrusted) {
|
||||
let node = this.nearestActive(event)
|
||||
console.log('tap', node)
|
||||
this.nodeTapped(node, event)
|
||||
|
||||
/* let node = document.elementFromPoint(event.clientX, event.clientY)
|
||||
|
||||
@ -1,115 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Coordinates Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
<script>
|
||||
function drawPolygons() {
|
||||
canvas.width = main.getBoundingClientRect().width
|
||||
let context = canvas.getContext('2d')
|
||||
context.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
let stage = scatterContainer.polygon
|
||||
stage.draw(context, { stroke: '#FF0000' })
|
||||
for (let scatter of scatterContainer.scatter.values()) {
|
||||
let polygon = scatter.polygon
|
||||
polygon.draw(context, { stroke: '#FF0000' })
|
||||
}
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Coordinates Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
<script>
|
||||
function drawPolygons() {
|
||||
canvas.width = main.getBoundingClientRect().width
|
||||
let context = canvas.getContext('2d')
|
||||
context.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
let stage = scatterContainer.polygon
|
||||
stage.draw(context, { stroke: '#FF0000' })
|
||||
for (let scatter of scatterContainer.scatter.values()) {
|
||||
let polygon = scatter.polygon
|
||||
polygon.draw(context, { stroke: '#FF0000' })
|
||||
}
|
||||
}
|
||||
|
||||
function animate(callback) {
|
||||
requestAnimationFrame((dt) => {
|
||||
drawPolygons()
|
||||
callback()
|
||||
animate(callback)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
function animate(callback) {
|
||||
requestAnimationFrame((dt) => {
|
||||
drawPolygons()
|
||||
callback()
|
||||
animate(callback)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Coordinates</h1>
|
||||
<p>
|
||||
To position objects in defined spatial relationships presupposes a clear understanding of the involved
|
||||
coordinate systems. Unfortunately, several systems with several conventions are involved:
|
||||
<a href="https://javascript.info/coordinates">DOM & CSS</a>,
|
||||
<a href="https://www.sarasoueidan.com/blog/svg-coordinate-systems/SVG">SVG</a>,
|
||||
<a href="https://www.w3schools.com/graphics/canvas_coordinates.asp">Canvas</a>
|
||||
</p>
|
||||
<p>
|
||||
We need a common reference system to switch between these coordinate systems. As the uttermost context, the
|
||||
browser page coordinate system is the most natural one. A simple API was long missing but has now been
|
||||
established in most modern browsers with
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/convertPointFromNoteToPage"
|
||||
>window.convertPointFromNoteToPage</a
|
||||
>
|
||||
and the inverse
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/convertPointFromPageToNode"
|
||||
>window.convertPointFromPageToNode</a
|
||||
>. Although MDN Web Docs warns about their Non-standard nature the methods work in browsers targeted by the
|
||||
IWM Browser project. This doctest assures that this assumption can be tested.
|
||||
</p>
|
||||
<p>
|
||||
Let's look at a scatter object with a rotatable local coordinate system. We try to follow a point in this
|
||||
local coordinate system by showing a marker outside the scatter that follows the point.
|
||||
</p>
|
||||
<div id="main" class="grayBorder interactive" style="position: relative; width: 100%; height: 280px">
|
||||
<!-- Note that we need to set draggable to false to avoid conflicts. The DOM elements
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
Coordinates
|
||||
</h1>
|
||||
<p>
|
||||
To position objects in defined spatial relationships presupposes a clear understanding of the involved coordinate systems.
|
||||
Unfortunately, several systems with several conventions are involved:
|
||||
<a href="https://javascript.info/coordinates">DOM & CSS</a>,
|
||||
<a href="https://www.sarasoueidan.com/blog/svg-coordinate-systems/SVG">SVG</a>,
|
||||
<a href="https://www.w3schools.com/graphics/canvas_coordinates.asp">Canvas</a>
|
||||
</p>
|
||||
<p>
|
||||
We need a common reference system to switch between these coordinate systems. As the uttermost context, the browser page
|
||||
coordinate system is the most natural one. A simple API was long missing but has now been established in most modern
|
||||
browsers with
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/convertPointFromNoteToPage">window.convertPointFromNoteToPage</a> and the inverse
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/convertPointFromPageToNode">window.convertPointFromPageToNode</a>.
|
||||
Although MDN Web Docs warns about their Non-standard nature the methods work in browsers targeted
|
||||
by the IWM Browser project. This doctest assures that this assumption can be tested.
|
||||
</p>
|
||||
<p>Let's look at a scatter object with a rotatable local coordinate system. We try to follow a point in this local coordinate
|
||||
system by showing a marker outside the scatter that follows the point.
|
||||
</p>
|
||||
<div id="main" class="grayBorder interactive" style="position: relative; width: 100%; height: 280px;">
|
||||
<!-- Note that we need to set draggable to false to avoid conflicts. The DOM elements
|
||||
must also be positioned absolutely. -->
|
||||
<img id="women" draggable="false" style="position: absolute" src="examples/women.jpeg" />
|
||||
<img id="women" draggable="false" style="position: absolute;" src="examples/women.jpeg" />
|
||||
|
||||
<canvas
|
||||
id="canvas"
|
||||
height="280"
|
||||
style="z-index: 100000; pointer-events: none; position: absolute; border: 1px solid red"
|
||||
>
|
||||
Canvas not supported.
|
||||
</canvas>
|
||||
</div>
|
||||
<canvas id="canvas" height="280" style="z-index: 100000; pointer-events: none; position: absolute; border: 1px solid red;">
|
||||
Canvas not supported.
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
<script class="doctest">
|
||||
let dx = 44
|
||||
<script class="doctest">
|
||||
let dx = 44
|
||||
|
||||
let app = new App()
|
||||
let scatterContainer = new DOMScatterContainer(main)
|
||||
let angle = 15
|
||||
let image = document.getElementById('women')
|
||||
// The DOMScatter needs initial width and height. Therefore we
|
||||
// define the scatter when the image size is known, i.e. after loading...
|
||||
image.onload = (e) => {
|
||||
let scatter = new DOMScatter(image, scatterContainer, {
|
||||
x: dx,
|
||||
y: 44,
|
||||
width: e.target.naturalWidth,
|
||||
height: e.target.naturalHeight,
|
||||
rotationDegrees: angle,
|
||||
throwVisibility: 88,
|
||||
minScale: 0.5,
|
||||
maxScale: 1.5
|
||||
})
|
||||
dx += 300
|
||||
angle = -angle
|
||||
}
|
||||
let app = new App()
|
||||
let scatterContainer = new DOMScatterContainer(main)
|
||||
let angle = 15
|
||||
let image = document.getElementById('women')
|
||||
// The DOMScatter needs initial width and height. Therefore we
|
||||
// define the scatter when the image size is known, i.e. after loading...
|
||||
image.onload = (e) => {
|
||||
let scatter = new DOMScatter(image, scatterContainer, {
|
||||
x: dx,
|
||||
y: 44,
|
||||
width: e.target.naturalWidth,
|
||||
height: e.target.naturalHeight,
|
||||
rotationDegrees: angle,
|
||||
throwVisibility: 88,
|
||||
minScale: 0.5,
|
||||
maxScale: 1.5
|
||||
})
|
||||
dx += 300
|
||||
angle = -angle
|
||||
}
|
||||
|
||||
app.run()
|
||||
app.run()
|
||||
|
||||
function followPoint() {
|
||||
let context = canvas.getContext('2d')
|
||||
let localPoint = { x: 100, y: 100 }
|
||||
let globalPoint = convertPointFromNodeToPage(image, localPoint.x, localPoint.y)
|
||||
let canvasPoint = convertPointFromPageToNode(canvas, globalPoint.x, globalPoint.y)
|
||||
function followPoint() {
|
||||
let context = canvas.getContext('2d')
|
||||
let localPoint = { x: 100, y: 100 }
|
||||
let globalPoint = convertPointFromNodeToPage(image, localPoint.x, localPoint.y)
|
||||
let canvasPoint = convertPointFromPageToNode(canvas, globalPoint.x, globalPoint.y)
|
||||
|
||||
context.strokeStyle = 'red'
|
||||
context.beginPath()
|
||||
context.arc(canvasPoint.x, canvasPoint.y, 12, 0, Math.PI * 2)
|
||||
context.stroke()
|
||||
}
|
||||
animate(followPoint)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
context.strokeStyle = 'red'
|
||||
context.beginPath()
|
||||
context.arc(canvasPoint.x, canvasPoint.y, 12, 0, Math.PI * 2)
|
||||
context.stroke()
|
||||
|
||||
}
|
||||
animate(followPoint)
|
||||
</script>
|
||||
|
||||
</body>
|
||||
@ -12,7 +12,7 @@
|
||||
<body onload="Doctest.run()">
|
||||
<main>
|
||||
<h1>
|
||||
<a href="index.html">lib.</a>Doctests
|
||||
Doctests
|
||||
</h1>
|
||||
<p>
|
||||
Doctests are explanatory descriptions of programs with executable code examples.
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
|
||||
var docTestLogMessages = []
|
||||
|
||||
Array.prototype.equals = function (array) {
|
||||
Array.prototype.equals = function(array) {
|
||||
return (
|
||||
this.length == array.length &&
|
||||
this.every(function (this_i, i) {
|
||||
this.every(function(this_i, i) {
|
||||
return this_i == array[i]
|
||||
})
|
||||
)
|
||||
|
||||
@ -1,48 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Electron Node.js Test</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="./3rdparty/all.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<main>
|
||||
<h1>Electron Node.js Test</h1>
|
||||
<p>
|
||||
This doctest is expected to work only within the IWMBrowser. IWMBrowser windows are opened with a
|
||||
preload.js which is evaluated before the HTML is loaded. According to
|
||||
<a href="https://electron.atom.io/docs/faq/"
|
||||
>"I can not use jQuery/RequireJS/Meteor/AngularJS in Electron"</a
|
||||
>
|
||||
we have to rename the symbols in the page before other libraries are included. In order to access
|
||||
node.js modules we can use `nodeRequire` instead.
|
||||
</p>
|
||||
<p>As a simple test we try to load a file from the filesystem:</p>
|
||||
<script class="doctest">
|
||||
if (typeof nodeRequire != 'undefined') {
|
||||
let fs = nodeRequire('fs')
|
||||
let content = fs.readFileSync('./index.html')
|
||||
let lines = content.toString().split(/\n/)
|
||||
console.log('First line', lines[0])
|
||||
Doctest.expect(lines[0], '<html>')
|
||||
}
|
||||
</script>
|
||||
<p>
|
||||
As simple as this test is, it shows that within the IWMBrowser one import all node.js modules. Don't
|
||||
forget to test for nodeRequire to avoid runtime errors in other browsers.
|
||||
</p>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://electron.atom.io/docs/faq/"
|
||||
>I can not use jQuery/RequireJS/Meteor/AngularJS in Electron</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Electron Node.js Test</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="./3rdparty/all.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<main>
|
||||
<h1>
|
||||
Electron Node.js Test
|
||||
</h1>
|
||||
<p>
|
||||
This doctest is expected to work only within the IWMBrowser. IWMBrowser windows
|
||||
are opened with a preload.js which is evaluated before the HTML is loaded.
|
||||
According to
|
||||
<a href="https://electron.atom.io/docs/faq/">"I can not use jQuery/RequireJS/Meteor/AngularJS in Electron"</a> we
|
||||
have to rename the symbols in the page before other libraries are included.
|
||||
In order to access node.js modules we can use `nodeRequire` instead.
|
||||
</p>
|
||||
<p>As a simple test we try to load a file from the filesystem:</p>
|
||||
<script class="doctest">
|
||||
|
||||
if (typeof(nodeRequire) != 'undefined') {
|
||||
let fs = nodeRequire('fs')
|
||||
let content = fs.readFileSync('./index.html')
|
||||
let lines = content.toString().split(/\n/)
|
||||
console.log("First line", lines[0] )
|
||||
Doctest.expect(lines[0], '<html>')
|
||||
}
|
||||
|
||||
</script>
|
||||
<p>As simple as this test is, it shows that within the IWMBrowser one import all node.js
|
||||
modules. Don't forget to test for nodeRequire to avoid runtime errors in other browsers.
|
||||
</p>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="https://electron.atom.io/docs/faq/">I can not use jQuery/RequireJS/Meteor/AngularJS in Electron</a></li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@ -33,7 +33,7 @@ export default class Errors {
|
||||
errors = document.createElement('div')
|
||||
errors.setAttribute('id', 'runtime-errors')
|
||||
this.setStyle(document.body, {
|
||||
border: '2px solid red',
|
||||
border: '2px solid red'
|
||||
})
|
||||
this.setStyle(errors, {
|
||||
position: 'absolute',
|
||||
@ -41,7 +41,7 @@ export default class Errors {
|
||||
padding: '8px',
|
||||
width: '100%',
|
||||
background: 'red',
|
||||
color: 'white',
|
||||
color: 'white'
|
||||
})
|
||||
document.body.appendChild(errors)
|
||||
let counter = document.createElement('div')
|
||||
@ -55,7 +55,7 @@ export default class Errors {
|
||||
fontSize: '18px',
|
||||
textAlign: 'center',
|
||||
lineHeight: '32px',
|
||||
verticalAlign: 'middle',
|
||||
verticalAlign: 'middle'
|
||||
})
|
||||
counter.innerHTML = '1'
|
||||
errors.appendChild(counter)
|
||||
@ -66,7 +66,7 @@ export default class Errors {
|
||||
top: '6px',
|
||||
left: '48px',
|
||||
height: '44px',
|
||||
fontSize: '32px',
|
||||
fontSize: '32px'
|
||||
})
|
||||
header.innerHTML = 'Runtime Errors'
|
||||
errors.appendChild(header)
|
||||
@ -97,7 +97,7 @@ export default class Errors {
|
||||
let errors = document.getElementById('runtime-errors')
|
||||
let infos = errors.querySelectorAll('.info')
|
||||
if (infos.length > 0) {
|
||||
infos.forEach((info) => errors.removeChild(info))
|
||||
infos.forEach(info => errors.removeChild(info))
|
||||
} else {
|
||||
this.expandErrors()
|
||||
}
|
||||
@ -116,7 +116,7 @@ export default class Errors {
|
||||
// Register more informative error handler
|
||||
window.addEventListener(
|
||||
'error',
|
||||
(event) => {
|
||||
event => {
|
||||
if (typeof event.error == 'undefined') {
|
||||
// This sometimes happens in Edge. Since we have no error
|
||||
// position, we cannot do much beside an info log.
|
||||
@ -128,7 +128,7 @@ export default class Errors {
|
||||
true
|
||||
)
|
||||
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
this.showErrors()
|
||||
})
|
||||
}
|
||||
|
||||
128
lib/events.html
@ -1,25 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Events</h1>
|
||||
<p>
|
||||
For functional tests it can be useful to simulate event or record and playback events. This module provides
|
||||
basic support for extracting data from events and serializing events into a JSON format that allows to save
|
||||
and load sequences of events.
|
||||
</p>
|
||||
<p>
|
||||
Let's look at an example of a HTML structure with click handlers. The click handler actions log messages
|
||||
that can be tested.
|
||||
</p>
|
||||
<pre><code class="html">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>
|
||||
Events
|
||||
</h1>
|
||||
<p>
|
||||
For functional tests it can be useful to simulate event or record and playback events.
|
||||
This module provides basic support for extracting data from events and serializing
|
||||
events into a JSON format that allows to save and load sequences of events.
|
||||
</p>
|
||||
<p>
|
||||
Let's look at an example of a HTML structure with click handlers. The click
|
||||
handler actions log messages that can be tested.</p>
|
||||
<pre><code class="html">
|
||||
<div>
|
||||
<img id="women" src="examples/women.jpeg"
|
||||
onclick="record(event); Doctest.log('Lady clicked')"/>
|
||||
@ -30,53 +31,46 @@
|
||||
</vide>
|
||||
</div>
|
||||
</code></pre>
|
||||
<div id="example" class="interactive" style="position: relative; width: 100%; border: 1px solid lightgray">
|
||||
<img
|
||||
style="margin: 8px"
|
||||
id="women"
|
||||
src="examples/women.jpeg"
|
||||
onclick="record(event); Doctest.log('Lady clicked')"
|
||||
/>
|
||||
<video
|
||||
id="movie"
|
||||
style="margin: 8px"
|
||||
width="250"
|
||||
data-zoomcap="Kugellaufuhr"
|
||||
onclick="record(event); Doctest.log('Movie clicked')"
|
||||
onmousedown="record(event)"
|
||||
onmouseup="record(event)"
|
||||
controls
|
||||
>
|
||||
<source src="examples/movie.mp4" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<button onclick="eventRecorder.stopRecording(); eventRecorder.startReplay()">Replay</button>
|
||||
<script class="doctest">
|
||||
var eventRecorder = new EventRecorder()
|
||||
<div id="example" class="interactive"
|
||||
style="position:relative; width: 100%; border: 1px solid lightgray">
|
||||
<img style="margin:8px" id="women" src="examples/women.jpeg"
|
||||
onclick="record(event); Doctest.log('Lady clicked')"/>
|
||||
<video id="movie" style="margin:8px" width="250" data-zoomcap="Kugellaufuhr"
|
||||
onclick="record(event); Doctest.log('Movie clicked')"
|
||||
onmousedown="record(event)"
|
||||
onmouseup="record(event)"
|
||||
controls>
|
||||
<source src="examples/movie.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
<button onclick="eventRecorder.stopRecording(); eventRecorder.startReplay()">Replay</button>
|
||||
<script class="doctest">
|
||||
|
||||
function record(event) {
|
||||
let target = event.target
|
||||
target.style.boxShadow = '0px 5px 10px gray'
|
||||
setTimeout(() => (target.style.boxShadow = ''), 1000)
|
||||
eventRecorder.record(event)
|
||||
}
|
||||
var eventRecorder = new EventRecorder()
|
||||
|
||||
let womenSel = Events.selector(women)
|
||||
let movieSel = Events.selector(movie)
|
||||
function record(event) {
|
||||
let target = event.target
|
||||
target.style.boxShadow = "0px 5px 10px gray"
|
||||
setTimeout(() => target.style.boxShadow = "", 1000)
|
||||
eventRecorder.record(event)
|
||||
}
|
||||
|
||||
Events.simulateEvent('click', MouseEvent, { targetSelector: womenSel })
|
||||
Events.simulateEvent('click', MouseEvent, { targetSelector: movieSel })
|
||||
let womenSel = Events.selector(women)
|
||||
let movieSel = Events.selector(movie)
|
||||
|
||||
Doctest.expectLog('Lady clicked', 'Movie clicked')
|
||||
</script>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li><a href="https://gist.github.com/iahu/aafc2492d83d70e42c98">Safari Touch Emulator</a></li>
|
||||
<li>
|
||||
<a href="https://www.reddit.com/r/javascript/comments/2laqaf/how_to_trigger_a_touch_event/"
|
||||
>How to Trigger Touch Events</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
Events.simulateEvent('click', MouseEvent, { targetSelector: womenSel})
|
||||
Events.simulateEvent('click', MouseEvent, { targetSelector: movieSel})
|
||||
|
||||
Doctest.expectLog('Lady clicked',
|
||||
'Movie clicked')
|
||||
|
||||
</script>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="https://gist.github.com/iahu/aafc2492d83d70e42c98">Safari Touch Emulator</a></li>
|
||||
<li><a href="https://www.reddit.com/r/javascript/comments/2laqaf/how_to_trigger_a_touch_event/">How to Trigger Touch Events</a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
@ -2,7 +2,7 @@ export default class Events {
|
||||
static stop(event) {
|
||||
event.preventDefault()
|
||||
// I removed this, as it destroys all the Hammer.js events.
|
||||
// And also the click event.
|
||||
// And also the click event.
|
||||
// It seems to have no (apparent) negative impact. -SO
|
||||
// event.stopPropagation()
|
||||
}
|
||||
@ -65,7 +65,7 @@ export default class Events {
|
||||
clientX: t.clientX,
|
||||
clientY: t.clientY,
|
||||
pageX: t.pageX,
|
||||
pageY: t.pageY,
|
||||
pageY: t.pageY
|
||||
})
|
||||
}
|
||||
return touches
|
||||
@ -105,8 +105,8 @@ export default class Events {
|
||||
ctrlKey: event.ctrlKey,
|
||||
altKey: event.altKey,
|
||||
shiftKey: event.shiftKey,
|
||||
metaKey: event.metaKey,
|
||||
},
|
||||
metaKey: event.metaKey
|
||||
}
|
||||
}
|
||||
if (event.type.startsWith('touch')) {
|
||||
// On Safari-WebKit the TouchEvent has layerX, layerY coordinates
|
||||
@ -219,7 +219,7 @@ export default class Events {
|
||||
width: '480px',
|
||||
height: '640px',
|
||||
overflow: 'auto',
|
||||
backgroundColor: 'lightgray',
|
||||
backgroundColor: 'lightgray'
|
||||
})
|
||||
document.body.appendChild(element)
|
||||
this.popup = element
|
||||
@ -240,7 +240,7 @@ export default class Events {
|
||||
}
|
||||
Elements.setStyle(this.popup, {
|
||||
left: event.clientX + 'px',
|
||||
top: event.clientY + 'px',
|
||||
top: event.clientY + 'px'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 13 MiB |
|
Before Width: | Height: | Size: 568 KiB |
|
Before Width: | Height: | Size: 755 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 168 KiB |
@ -1,43 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Flippable Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Flippable Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="../css/flipeffect.css" />
|
||||
<template id="flipTemplate">
|
||||
<div class="flipWrapper">
|
||||
<div class="flipCard">
|
||||
<div class="flipFace front"></div>
|
||||
<div class="flipFace back" style="visibility: hidden"></div>
|
||||
</div>
|
||||
<link rel="stylesheet" href="../css/flipeffect.css">
|
||||
<template id="flipTemplate">
|
||||
<div class="flipWrapper">
|
||||
<div class="flipCard">
|
||||
<div class="flipFace front"></div>
|
||||
<div class="flipFace back" style="visibility:hidden;"></div>
|
||||
</div>
|
||||
<!-- Very tricky problem to scale svgs: see https://css-tricks.com/scale-svg/ -->
|
||||
<!-- SVG viewPort interferes with DOMMatrix calculations: see
|
||||
https://stackoverflow.com/questions/70696387/how-to-get-transform-matrix-of-a-dom-element-->
|
||||
<div class="flipButton backBtn" style="visibility:hidden;">
|
||||
<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" style="width:inherit; height:inherit;">
|
||||
<g stroke-width="8" stroke="white">
|
||||
<circle cx="50" cy="50" r="44" fill="gray" />
|
||||
<line x1="30" y1="30" x2="70" y2="70" />
|
||||
<line x1="30" y1="70" x2="70" y2="30" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<svg class="flipButton backBtn" style="visibility:hidden;" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
|
||||
<g stroke-width="8" stroke="white">
|
||||
<circle cx="50" cy="50" r="44" fill="gray" />
|
||||
<line x1="30" y1="30" x2="70" y2="70" />
|
||||
<line x1="30" y1="70" x2="70" y2="30" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div class="flipButton infoBtn">
|
||||
<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" style="width:inherit; height:inherit;">
|
||||
<circle cx="50" cy="50" r="44" stroke="white" stroke-width="8" fill="gray" />
|
||||
<circle cx="50" cy="32" r="7" fill="white" />
|
||||
<line x1="50" y1="46" x2="50" y2="78" stroke="white" stroke-width="12" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<svg class="flipButton infoBtn" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
|
||||
<circle cx="50" cy="50" r="44" stroke="white" stroke-width="8" fill="gray" />
|
||||
<circle cx="50" cy="32" r="7" fill="white" />
|
||||
<line x1="50" y1="46" x2="50" y2="78" stroke="white" stroke-width="12" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -54,10 +46,6 @@ via a HTML template that defines the placeholders for front and back views. The
|
||||
style file "css/flipeffect.css" holds reasonable default styles for this kind of
|
||||
templates.
|
||||
</p>
|
||||
<p>
|
||||
The SVG buttons have to be wrapped in an HTML DOM element which handles events. Otherwise,
|
||||
the viewbox of the SVG will interfere with the coordinate transformation.
|
||||
</p>
|
||||
<pre><code>
|
||||
<template id="flipTemplate">
|
||||
<div class="flipWrapper">
|
||||
@ -65,45 +53,33 @@ the viewbox of the SVG will interfere with the coordinate transformation.
|
||||
<div class="flipFace front"></div>
|
||||
<div class="flipFace back" style="visibility:hidden;"></div>
|
||||
</div>
|
||||
<div class="flipButton backBtn" .../>
|
||||
<svg .../>
|
||||
</div>
|
||||
<div class="flipButton infoBtn" .../>
|
||||
<svg .../>
|
||||
</div>
|
||||
<svg class="flipButton backBtn" .../>
|
||||
<svg class="flipButton infoBtn" .../>
|
||||
</div>
|
||||
</template>
|
||||
</code>
|
||||
</pre>
|
||||
<h3>Example</h3>
|
||||
<main id="main" style="border: 1px solid gray; position: relative; height: 256px"></main>
|
||||
<script class="doctest">
|
||||
let scatterContainer = new DOMScatterContainer(main, { stopEvents: false })
|
||||
if (Capabilities.supportsTemplate()) {
|
||||
let flip1 = new DOMFlip(
|
||||
scatterContainer,
|
||||
flipTemplate,
|
||||
new ImageLoader('./examples/king.jpeg'),
|
||||
new ImageLoader('./examples/women.jpeg'),
|
||||
{ /*tapDelegateFactory: CardWrapper,*/ preloadBack: true }
|
||||
)
|
||||
flip1.load().then((flip) => {
|
||||
flip.centerAt({ x: 150, y: 120 })
|
||||
})
|
||||
<h3>
|
||||
Example
|
||||
</h3>
|
||||
<main id="main" style="border: 1px solid gray; position: relative; height: 256px;" >
|
||||
|
||||
let flip2 = new DOMFlip(
|
||||
scatterContainer,
|
||||
flipTemplate,
|
||||
new ImageLoader('./examples/king.jpeg'),
|
||||
new ImageLoader('./examples/queen.jpeg'),
|
||||
{ /*tapDelegateFactory: CardWrapper,*/ preloadBack: true }
|
||||
)
|
||||
flip2.load().then((flip) => {
|
||||
flip.centerAt({ x: 650, y: 120 })
|
||||
})
|
||||
} else {
|
||||
alert('Templates not supported, use Edge, Chrome, Safari or Firefox.')
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</main>
|
||||
<script class="doctest">
|
||||
let scatterContainer = new DOMScatterContainer(main, {stopEvents: false})
|
||||
if (Capabilities.supportsTemplate()) {
|
||||
|
||||
let flip = new DOMFlip(scatterContainer,
|
||||
flipTemplate,
|
||||
new ImageLoader('./examples/king.jpeg'),
|
||||
new ImageLoader('./examples/women.jpeg'),
|
||||
{ tapDelegateFactory: CardWrapper, preloadBack: true})
|
||||
flip.load().then((flip) => {
|
||||
flip.centerAt({ x: 150, y: 120})
|
||||
})
|
||||
}
|
||||
else {
|
||||
alert("Templates not supported, use Edge, Chrome, Safari or Firefox.")
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -52,8 +52,8 @@ export class PDFLoader extends CardLoader {
|
||||
|
||||
load(domNode) {
|
||||
return new Promise((resolve, reject) => {
|
||||
PDFJS.getDocument(this.src).then((pdf) => {
|
||||
pdf.getPage(1).then((page) => {
|
||||
PDFJS.getDocument(this.src).then(pdf => {
|
||||
pdf.getPage(1).then(page => {
|
||||
let scale = this.scale * app.renderer.resolution
|
||||
let invScale = 1 / scale
|
||||
let viewport = page.getViewport(scale)
|
||||
@ -87,7 +87,7 @@ export class ImageLoader extends CardLoader {
|
||||
return new Promise((resolve, reject) => {
|
||||
let isImage = domNode instanceof HTMLImageElement
|
||||
let image = isImage ? domNode : document.createElement('img')
|
||||
image.onload = (e) => {
|
||||
image.onload = e => {
|
||||
if (!isImage) {
|
||||
domNode.appendChild(image)
|
||||
this.addedNode = image
|
||||
@ -103,7 +103,7 @@ export class ImageLoader extends CardLoader {
|
||||
image.height = image.naturalHeight
|
||||
resolve(this)
|
||||
}
|
||||
image.onerror = (e) => {
|
||||
image.onerror = e => {
|
||||
reject(this)
|
||||
}
|
||||
image.src = this.src
|
||||
@ -125,10 +125,10 @@ export class FrameLoader extends CardLoader {
|
||||
domNode.appendChild(iframe)
|
||||
this.addedNode = iframe
|
||||
}
|
||||
iframe.onload = (e) => {
|
||||
iframe.onload = e => {
|
||||
resolve(this)
|
||||
}
|
||||
iframe.onerror = (e) => {
|
||||
iframe.onerror = e => {
|
||||
reject(this)
|
||||
}
|
||||
iframe.src = this.src
|
||||
@ -141,7 +141,7 @@ export class HTMLLoader extends CardLoader {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', this.src, false)
|
||||
xhr.onreadystatechange = (e) => {
|
||||
xhr.onreadystatechange = e => {
|
||||
if (xhr.readyState == 4) {
|
||||
domNode.innerHTML = this.prepare(xhr.response)
|
||||
this.addedNode = domNode.firstElementChild
|
||||
@ -151,7 +151,7 @@ export class HTMLLoader extends CardLoader {
|
||||
resolve(this)
|
||||
}
|
||||
}
|
||||
xhr.onerror = (e) => {
|
||||
xhr.onerror = e => {
|
||||
reject(this)
|
||||
}
|
||||
xhr.send()
|
||||
@ -251,8 +251,8 @@ export class DOMFlip {
|
||||
// call we can access the new dom element by id
|
||||
this.cardWrapper = dom.querySelector('#' + this.id)
|
||||
let front = this.cardWrapper.querySelector('.front')
|
||||
this.frontLoader.load(front).then((loader) => {
|
||||
this.frontLoaded(loader).then((obj) => {
|
||||
this.frontLoader.load(front).then(loader => {
|
||||
this.frontLoaded(loader).then(obj => {
|
||||
if (this.onLoaded) this.onLoaded()
|
||||
resolve(this)
|
||||
})
|
||||
@ -284,7 +284,7 @@ export class DOMFlip {
|
||||
}
|
||||
|
||||
if (this.closeOnMinScale) {
|
||||
const removeOnMinScale = function () {
|
||||
const removeOnMinScale = function() {
|
||||
if (scatter.scale <= scatter.minScale) {
|
||||
this.flippable.close()
|
||||
|
||||
@ -306,7 +306,7 @@ export class DOMFlip {
|
||||
let back = this.cardWrapper.querySelector('.back')
|
||||
|
||||
if (this.preloadBack) {
|
||||
this.backLoader.load(back).then((loader) => {
|
||||
this.backLoader.load(back).then(loader => {
|
||||
this.setupFlippable(flippable, loader)
|
||||
})
|
||||
}
|
||||
@ -340,7 +340,7 @@ export class DOMFlip {
|
||||
} else {
|
||||
let back = this.cardWrapper.querySelector('.back')
|
||||
let flippable = this.flippable
|
||||
this.backLoader.load(back).then((loader) => {
|
||||
this.backLoader.load(back).then(loader => {
|
||||
this.setupFlippable(flippable, loader)
|
||||
flippable.start({ duration: this.flipDuration, targetCenter })
|
||||
})
|
||||
@ -412,18 +412,18 @@ export class DOMFlippable {
|
||||
scatter.tapDelegate = tapDelegate
|
||||
}
|
||||
if (this.infoBtn) {
|
||||
scatter.tapDelegate.onTap(this.infoBtn, (event) => {
|
||||
scatter.tapDelegate.onTap(this.infoBtn, event => {
|
||||
this.flip.start()
|
||||
})
|
||||
this.enable(this.infoBtn)
|
||||
}
|
||||
if (this.backBtn) {
|
||||
scatter.tapDelegate.onTap(this.backBtn, (event) => {
|
||||
scatter.tapDelegate.onTap(this.backBtn, event => {
|
||||
this.start()
|
||||
})
|
||||
}
|
||||
if (this.closeBtn) {
|
||||
scatter.tapDelegate.onTap(this.closeBtn, (event) => {
|
||||
scatter.tapDelegate.onTap(this.closeBtn, event => {
|
||||
this.close()
|
||||
})
|
||||
this.enable(this.closeBtn)
|
||||
@ -589,7 +589,7 @@ export class DOMFlippable {
|
||||
ease: Power1.easeOut,
|
||||
transformOrigin: '50% 50%',
|
||||
onUpdate,
|
||||
onComplete: (e) => {
|
||||
onComplete: e => {
|
||||
if (this.flipped) {
|
||||
//this.hide(this.front)
|
||||
this.enable(this.backBtn)
|
||||
@ -621,8 +621,7 @@ export class DOMFlippable {
|
||||
force3D: true
|
||||
})
|
||||
// See https://greensock.com/forums/topic/7997-rotate-the-shortest-way/
|
||||
const duration = this.flipDuration / 2
|
||||
TweenLite.to(this.element, duration, {
|
||||
TweenLite.to(this.element, this.flipDuration / 2, {
|
||||
scale: targetScale,
|
||||
ease: Power1.easeOut,
|
||||
rotationZ: targetZ + '_short',
|
||||
@ -631,8 +630,7 @@ export class DOMFlippable {
|
||||
height: h,
|
||||
x: x,
|
||||
y: y,
|
||||
onComplete: (e) => {
|
||||
console.log('onComplete', e)
|
||||
onComplete: e => {
|
||||
if (this.flipped) {
|
||||
this.hide(this.front)
|
||||
// this.hide(this.infoBtn)
|
||||
@ -642,30 +640,5 @@ export class DOMFlippable {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//uo: check for special case that the front image must be adapted to the back size
|
||||
let frontImage = this.front.querySelector('img')
|
||||
if (frontImage) {
|
||||
// Assumes that startWidth and startHeight are encoded in px
|
||||
let sh = parseInt(this.startHeight)
|
||||
let sw = parseInt(this.startWidth)
|
||||
if (this.flipped) {
|
||||
let scaleY = h / sh
|
||||
let scaleX = w / sw
|
||||
TweenLite.to(frontImage, duration, {
|
||||
ease: Power1.easeOut,
|
||||
transformOrigin: '0% 0%',
|
||||
scaleY,
|
||||
scaleX
|
||||
})
|
||||
} else {
|
||||
TweenLite.to(frontImage, duration, {
|
||||
ease: Power1.easeOut,
|
||||
transformOrigin: '0% 0%',
|
||||
scaleY: 1.0,
|
||||
scaleX: 1.0
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
155
lib/frames.html
@ -1,51 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Frames</h1>
|
||||
<p>
|
||||
Frames are a major way to modularize the design of complex applications. Since pages presented in frames are
|
||||
independent of each other they can fail without impact on other pages. In addition preparing content in
|
||||
individual HTML files largely simplfies the workflow of content production.
|
||||
</p>
|
||||
<p>This approach, however, has limitations:</p>
|
||||
<script>
|
||||
function appleError() {
|
||||
alert(
|
||||
"Refused to display 'http://www.apple.com/de/' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'."
|
||||
)
|
||||
}
|
||||
</script>
|
||||
<ul>
|
||||
<li>
|
||||
Some pages may prevent embedding them by 'X-Frame-Options', e.g.
|
||||
<a href="javascript:appleError()">www.apple.com</a>
|
||||
</li>
|
||||
<li>
|
||||
Sites with responsive design might not be able to detect the available space, e.g.
|
||||
<a href="https:///de.wikipedia.org">de.wikipedia.org</a>
|
||||
</li>
|
||||
<li>
|
||||
Touch events are not dispatched correctly to multiple frames on platforms with <b>TouchEvents</b>, e.g.
|
||||
if frame one receives touch1, all related touch points touch2, ... touchN, are send to frame1 although
|
||||
they might occur over frame two.
|
||||
</li>
|
||||
</ul>
|
||||
<p>To solve the last mentioned problem, we prevent frames form touch events by assigning a</p>
|
||||
<pre>pointer-events: none;</pre>
|
||||
style. A wrapping div is used to capture the events instead. Captured events are collected by an
|
||||
InteractionMapper and distributed as synthesized mouse or touch events to the wrapped iframes.
|
||||
<p>Let's look at an example of two HTML IFrames embedded in this Doctest.</p>
|
||||
<pre><code class="html">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>
|
||||
Frames
|
||||
</h1>
|
||||
<p>
|
||||
Frames are a major way to modularize the design of complex applications. Since
|
||||
pages presented in frames are independent of each other they can fail without
|
||||
impact on other pages. In addition preparing content in individual HTML files
|
||||
largely simplfies the workflow of content production.
|
||||
</p>
|
||||
<p>This approach, however, has limitations:</p>
|
||||
<script>
|
||||
function appleError() {
|
||||
alert("Refused to display 'http://www.apple.com/de/' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.")
|
||||
}
|
||||
</script>
|
||||
<ul><li>Some pages may prevent embedding them
|
||||
by 'X-Frame-Options', e.g. <a href="javascript:appleError()">www.apple.com</a>
|
||||
</li>
|
||||
<li>Sites with responsive design might not be able to detect the available space,
|
||||
e.g. <a href="https:///de.wikipedia.org">de.wikipedia.org</a>
|
||||
</li>
|
||||
<li>Touch events are not dispatched correctly to multiple frames on platforms with
|
||||
<b>TouchEvents</b>, e.g. if frame one
|
||||
receives touch1, all related touch points touch2, ... touchN, are send to frame1
|
||||
although they might occur over frame two.
|
||||
</li>
|
||||
</ul>
|
||||
<p>To solve the last mentioned problem, we prevent frames form touch events by
|
||||
assigning a <pre>pointer-events: none;</pre> style. A wrapping div is used to capture
|
||||
the events instead. Captured events are collected by an InteractionMapper and
|
||||
distributed as synthesized mouse or touch events to the wrapped iframes.
|
||||
<p>
|
||||
Let's look at an example of two HTML IFrames embedded in this Doctest.</p>
|
||||
<pre><code class="html">
|
||||
<div id="frameWrapper1">
|
||||
<iframe style="pointer-events: none;" src="examples/multitouch.html"></iframe>
|
||||
</div>
|
||||
@ -54,41 +53,29 @@
|
||||
</div>
|
||||
|
||||
</code></pre>
|
||||
<div class="grayBorder" id="container" style="display: flex; justify-content: space-around">
|
||||
<div id="frameWrapper1" style="padding: 4px">
|
||||
<iframe
|
||||
style="width: 400px; height: 360px; border: 0; pointer-events: none"
|
||||
src="examples/multitouch.html"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</div>
|
||||
<div id="frameWrapper2" style="padding: 4px">
|
||||
<iframe
|
||||
style="width: 400px; height: 360px; border: 0; pointer-events: none"
|
||||
src="examples/multitouch.html"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
The distribution of events is handled by the enclosing container. The container registers a
|
||||
InteractionMapper and provides adapter for iframes, that implement IInteractionTarget by sending
|
||||
programmatically generated events. If you test these frames on a multitouch device you will notice that the
|
||||
scatters within the frames can be manipulated independently of each other:
|
||||
</p>
|
||||
<div class="grayBorder" id="container" style="display: flex; justify-content: space-around;">
|
||||
<div id="frameWrapper1" style="padding: 4px">
|
||||
<iframe style="width:400px; height:360px; border:0; pointer-events: none;" src="examples/multitouch.html" allowfullscreen></iframe>
|
||||
</div>
|
||||
<div id="frameWrapper2" style="padding: 4px">
|
||||
<iframe style="width:400px; height:360px; border:0; pointer-events: none;" src="examples/multitouch.html" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<p>The distribution of events is handled by the enclosing container. The container
|
||||
registers a InteractionMapper and provides adapter for iframes, that implement
|
||||
IInteractionTarget by sending programmatically generated events. If you test
|
||||
these frames on a multitouch device you will notice that the scatters within
|
||||
the frames can be manipulated independently of each other:
|
||||
<p/>
|
||||
<script class="doctest">
|
||||
let frameContainer = new FrameContainer(container)
|
||||
|
||||
<p />
|
||||
<script class="doctest">
|
||||
let frameContainer = new FrameContainer(container)
|
||||
</script>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://stackoverflow.com/questions/8068578/how-do-i-use-multiple-iframes-in-my-html-page"
|
||||
>Multiple iFrames</a
|
||||
>
|
||||
</li>
|
||||
<li><a href="https://benmarshall.me/responsive-iframes/">Responsive iFrames</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</script>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="http://stackoverflow.com/questions/8068578/how-do-i-use-multiple-iframes-in-my-html-page">Multiple iFrames</a></li>
|
||||
<li><a href="https://benmarshall.me/responsive-iframes/">Responsive iFrames</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
@ -5,7 +5,7 @@ export class FrameContainer {
|
||||
constructor(element) {
|
||||
this.element = element
|
||||
this.delegate = new InteractionMapper(element, this, {
|
||||
mouseWheelElement: window,
|
||||
mouseWheelElement: window
|
||||
})
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ export class FrameTarget {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: p.x,
|
||||
clientY: p.y,
|
||||
clientY: p.y
|
||||
})
|
||||
this.target.dispatchEvent(event)
|
||||
}
|
||||
@ -79,7 +79,7 @@ export class FrameTarget {
|
||||
radiusX: 2.5,
|
||||
radiusY: 2.5,
|
||||
rotationAngle: 10,
|
||||
force: 0.5,
|
||||
force: 0.5
|
||||
})
|
||||
|
||||
const touchEvent = new TouchEvent(type, {
|
||||
@ -88,7 +88,7 @@ export class FrameTarget {
|
||||
touches: [touchObj],
|
||||
targetTouches: [touchObj],
|
||||
changedTouches: [touchObj],
|
||||
shiftKey: false,
|
||||
shiftKey: false
|
||||
})
|
||||
if (this.debug) console.log('simulateTouchEventChrome', touchEvent)
|
||||
this.target.dispatchEvent(touchEvent)
|
||||
@ -101,7 +101,7 @@ export class FrameTarget {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: p.x,
|
||||
clientY: p.y,
|
||||
clientY: p.y
|
||||
}
|
||||
data[touchEventKey] = this.createTouchList(pointMap)
|
||||
let event = new TouchEvent(type, data)
|
||||
|
||||
@ -1,50 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="./3rdparty/all.js"></script>
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="./3rdparty/all.js"></script>
|
||||
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Image Loader Worker</h1>
|
||||
<p>
|
||||
The loading of multiple small images (e.g. loadimng tiles of a zoomable map) is a time consuming task that
|
||||
leads to small but noticeable delays in touch interaction if standard DOM events are used. With a worker we
|
||||
can try to do most of the time consuming processing in the background.
|
||||
</p>
|
||||
<p>Let's look at an example of a image loader worker:</p>
|
||||
<img id="img1" width="160" height="120" class="grayBorder interactive" src="" />
|
||||
<img id="img2" width="160" height="120" class="grayBorder interactive" src="" />
|
||||
<img id="img3" width="160" height="120" class="grayBorder interactive" src="" />
|
||||
<img id="img4" width="160" height="120" class="grayBorder interactive" src="" />
|
||||
<script class="doctest">
|
||||
let urls = [
|
||||
'http://i.imgur.com/JmvCQXd.jpg',
|
||||
'http://i.imgur.com/L4ipvCE.jpg',
|
||||
'http://i.imgur.com/fKDIYIP.jpg',
|
||||
'http://i.imgur.com/4ad4bo5.jpg'
|
||||
]
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
|
||||
let imgs = [img1, img2, img3, img4]
|
||||
let count = 0
|
||||
let worker = new Worker('imageloader.js')
|
||||
worker.onmessage = (event) => {
|
||||
console.log('Loaded', event.data)
|
||||
if (event.data.success) {
|
||||
console.log('Loaded', event.data.url)
|
||||
imgs[count].src = event.data.url
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>Image Loader Worker</h1>
|
||||
<p>
|
||||
The loading of multiple small images (e.g. loadimng tiles of a zoomable
|
||||
map) is a time consuming task that leads to small but noticeable delays
|
||||
in touch interaction if standard DOM events are used. With a worker we
|
||||
can try to do most of the time consuming processing in the background.
|
||||
</p>
|
||||
<p>Let's look at an example of a image loader worker:</p>
|
||||
<img id="img1" width="160" height="120" class="grayBorder interactive" src=""/>
|
||||
<img id="img2" width="160" height="120" class="grayBorder interactive" src=""/>
|
||||
<img id="img3" width="160" height="120" class="grayBorder interactive" src=""/>
|
||||
<img id="img4" width="160" height="120" class="grayBorder interactive" src=""/>
|
||||
<script class="doctest">
|
||||
|
||||
worker.postMessage({ command: 'load', urls: urls })
|
||||
worker.postMessage({ command: 'abort', urls: urls })
|
||||
worker.postMessage({ command: 'load', urls: urls })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
let urls = [
|
||||
'http://i.imgur.com/JmvCQXd.jpg',
|
||||
'http://i.imgur.com/L4ipvCE.jpg',
|
||||
'http://i.imgur.com/fKDIYIP.jpg',
|
||||
'http://i.imgur.com/4ad4bo5.jpg'
|
||||
]
|
||||
|
||||
let imgs = [img1, img2, img3, img4]
|
||||
let count = 0
|
||||
let worker = new Worker("imageloader.js")
|
||||
worker.onmessage = (event) => {
|
||||
console.log("Loaded", event.data)
|
||||
if (event.data.success) {
|
||||
console.log("Loaded", event.data.url)
|
||||
imgs[count].src = event.data.url
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
worker.postMessage({command: "load", urls: urls})
|
||||
worker.postMessage({command: "abort", urls: urls})
|
||||
worker.postMessage({command: "load", urls: urls})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -14,7 +14,7 @@ function onerror(event) {
|
||||
}
|
||||
|
||||
function load() {
|
||||
loadQueue.forEach((url) => {
|
||||
loadQueue.forEach(url => {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = onload
|
||||
@ -25,7 +25,7 @@ function load() {
|
||||
})
|
||||
}
|
||||
|
||||
self.onmessage = (event) => {
|
||||
self.onmessage = event => {
|
||||
let msg = event.data
|
||||
switch (msg.command) {
|
||||
case 'load':
|
||||
|
||||
@ -1,55 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Lib Doctests</title>
|
||||
<meta charset="utf-8" />
|
||||
<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" />
|
||||
<head>
|
||||
<title>Lib Doctests</title>
|
||||
<meta charset="utf-8"/>
|
||||
<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">
|
||||
|
||||
<!-- following not necc for index.js included in iwmlib.js -->
|
||||
<!-- <script src="./index.js"></script> -->
|
||||
<!-- following not necc for index.js included in iwmlib.js -->
|
||||
<!-- <script src="./index.js"></script> -->
|
||||
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<h2><a href="index.html">lib.</a>Doctests</h2>
|
||||
<div id="container" class="container"></div>
|
||||
<script>
|
||||
let index = new Index(itemTemplate, [
|
||||
['Doctest', 'doctest.html'],
|
||||
['Capabilities', 'capabilities.html'],
|
||||
['Coordinates', 'coordinates.html'],
|
||||
['Interface', 'interface.html'],
|
||||
['Interaction', 'interaction.html'],
|
||||
['Events', 'events.html'],
|
||||
['Frames', 'frames.html'],
|
||||
['Popup', 'popup.html'],
|
||||
['Popup Menu', 'popupmenu.html'],
|
||||
['Scatter', 'scatter.html'],
|
||||
['Flippable', 'flippable.html'],
|
||||
['Styleguide', 'styleguide.html'],
|
||||
['UITest', 'uitest.html'],
|
||||
['PIXI Doctests', 'pixi/index.html']
|
||||
])
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
<div class="title"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" class="container">
|
||||
<a style="position: absolute; left: 22px; top: 12px;" target="_blank" href="http://www.iwm-tuebingen.de">IWM</a>
|
||||
</div>
|
||||
<script>
|
||||
let index = new Index(itemTemplate, [
|
||||
['Doctest', 'doctest.html'],
|
||||
['Capabilities', 'capabilities.html'],
|
||||
['Coordinates', 'coordinates.html'],
|
||||
['Interface', 'interface.html'],
|
||||
['Interaction', 'interaction.html'],
|
||||
['Events', 'events.html'],
|
||||
['Frames', 'frames.html'],
|
||||
['Popup', 'popup.html'],
|
||||
['Popup Menu', 'popupmenu.html'],
|
||||
['Scatter', 'scatter.html'],
|
||||
['Flippable', 'flippable.html'],
|
||||
['Styleguide', 'styleguide.html'],
|
||||
['UITest', 'uitest.html'],
|
||||
['PIXI Doctests', 'pixi/index.html']
|
||||
])
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -21,7 +21,7 @@ export default class Index {
|
||||
|
||||
let icon = wrapper.querySelector('.icon')
|
||||
|
||||
icon.onerror = (e) => {
|
||||
icon.onerror = e => {
|
||||
if (this.notfound) icon.src = this.notfound
|
||||
}
|
||||
let iconSrc = src.replace('.html', '.png')
|
||||
@ -49,7 +49,7 @@ export default class Index {
|
||||
let icon = wrapper.querySelector('.icon')
|
||||
|
||||
icon.parentNode.replaceChild(iframe, icon)
|
||||
iframe.onload = (e) => {
|
||||
iframe.onload = e => {
|
||||
this.frames()
|
||||
}
|
||||
iframe.src = src + window.location.search
|
||||
|
||||
@ -1,41 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run(); test()">
|
||||
<h1><a href="index.html">lib.</a>Code and Class Inspection</h1>
|
||||
<p>
|
||||
To Do: Use SystemJS to load modules and main code. This ensures that all code can be parsed by acorn into an
|
||||
Abstract Syntax Tree which in turn allows to extract class statements and related extends phrases.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
function test() {
|
||||
let sources = Inspect.allScriptSources()
|
||||
console.log(sources)
|
||||
}
|
||||
</script>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://nystudio107.com/blog/using-systemjs-as-javascript-loader"
|
||||
>Using SystemJS as JavaScript Loader</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://stackoverflow.com/questions/2051678/getting-all-variables-in-scope"
|
||||
>Getting all Variables in Scope</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/"
|
||||
>Metaprogramming in JavaScript</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run(); test()" >
|
||||
<h1>
|
||||
Code and Class Inspection
|
||||
</h1>
|
||||
<p>
|
||||
To Do: Use SystemJS to load modules and main code. This ensures that
|
||||
all code can be parsed by acorn into an Abstract Syntax Tree which
|
||||
in turn allows to extract class statements and related extends phrases.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
|
||||
function test() {
|
||||
let sources = Inspect.allScriptSources()
|
||||
console.log(sources)
|
||||
}
|
||||
|
||||
</script>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
|
||||
<li><a href="https://nystudio107.com/blog/using-systemjs-as-javascript-loader">Using SystemJS as JavaScript Loader</a></li>
|
||||
<li><a href="http://stackoverflow.com/questions/2051678/getting-all-variables-in-scope">Getting all Variables in Scope</a></li>
|
||||
<li><a href="https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/">Metaprogramming in JavaScript</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
@ -1,495 +1,401 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Interaction Mapper Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Interaction Mapper Doctest</title>
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>
|
||||
Interaction Pattern
|
||||
</h1>
|
||||
<p>
|
||||
Since the correct handling of the divergent browser specific multitouch
|
||||
implementations is a difficult and recurring task we decided to encapsulate
|
||||
all related handlers for <code>TouchEvent</code> (WebKit, Mozilla) and
|
||||
<code>PointerEvent</code> (IE, Edge, Chrome) in
|
||||
a single delegate pattern.
|
||||
</p>
|
||||
<p>The main differences are that <code>PointerEvent</code> are fired for each
|
||||
touch point, whereas the <code>TouchEvent</code> collects multiple
|
||||
<code>TouchPoints</code> into a single event. The basic PointMap and Interaction
|
||||
classes unify this behavior by collecting all contact points regardless
|
||||
of their original mouse, touch, or pointer events.</p>
|
||||
<h2>
|
||||
Point Maps
|
||||
</h2>
|
||||
<p>The touch and pointer positions are collected in PointMaps which provide
|
||||
access to the positions via stringified touch and pointer ids. For mouse events the
|
||||
special id "mouse" is used. PointMaps can be cloned and pretty printed. In addition
|
||||
they provide auxiliary methods like <code>mean</code> and <code>farthests</code>
|
||||
which can be used to simplify the computation of gestures. In general
|
||||
<code>mean</code> can be used to compute the "center of interaction", i.e. the
|
||||
best guess of the anchor point for rotation and scaling operations.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
let mouse = new PointMap({ mouse: {x:0, y:0}})
|
||||
let touches = new PointMap({ "touch1": {x:0, y:0}, "touch2": {x: 10, y: 10}})
|
||||
|
||||
<script type="module">
|
||||
import * as Interaction from './interaction.js'
|
||||
</script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Interaction</h1>
|
||||
<p>
|
||||
Since the correct handling of the divergent browser specific multitouch implementations is a difficult and
|
||||
recurring task we decided to encapsulate all related handlers for <code>TouchEvent</code> (WebKit, Mozilla)
|
||||
and <code>PointerEvent</code> (IE, Edge, Chrome) in a single delegate pattern.
|
||||
</p>
|
||||
<p>
|
||||
The main differences are that <code>PointerEvent</code> are fired for each touch point, whereas the
|
||||
<code>TouchEvent</code> collects multiple <code>TouchPoints</code> into a single event. The basic PointMap
|
||||
and Interaction classes unify this behavior by collecting all contact points regardless of their original
|
||||
mouse, touch, or pointer events.
|
||||
</p>
|
||||
<h2>Point Maps</h2>
|
||||
<p>
|
||||
The touch and pointer positions are collected in PointMaps which provide access to the positions via
|
||||
stringified touch and pointer ids. For mouse events the special id "mouse" is used. PointMaps can be cloned
|
||||
and pretty printed. In addition they provide auxiliary methods like <code>mean</code> and
|
||||
<code>farthests</code>
|
||||
which can be used to simplify the computation of gestures. In general
|
||||
<code>mean</code> can be used to compute the "center of interaction", i.e. the best guess of the anchor
|
||||
point for rotation and scaling operations.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
let mouse = new PointMap({ mouse: { x: 0, y: 0 } })
|
||||
let touches = new PointMap({ touch1: { x: 0, y: 0 }, touch2: { x: 10, y: 10 } })
|
||||
Doctest.expect(touches,
|
||||
"[PointMap touch1:{x:0, y:0}, touch2:{x:10, y:10}]")
|
||||
Doctest.expect(touches.clone(),
|
||||
"[PointMap touch1:{x:0, y:0}, touch2:{x:10, y:10}]")
|
||||
Doctest.expect(touches.mean(), {"x":5,"y":5})
|
||||
</script>
|
||||
<p>If more than two touch points are involved it may be best to look for the
|
||||
pair of points which are farthest away from each other. These points will
|
||||
represent the fingers farthest away from each other, a more simple substitute
|
||||
for 3, 4 or 5 touch points. Here we add a third point to our example touches
|
||||
and test whether the maximal distant points are found:
|
||||
<script class="doctest">
|
||||
touches.set("touch3", {x:5, y:5})
|
||||
Doctest.expect(touches.farthests(), [{"x":0,"y":0},{"x":10,"y":10}])
|
||||
</script>
|
||||
<h2>
|
||||
Interaction Points and Interactions
|
||||
</h2>
|
||||
Events and points change in time and gestures are computed from this dynamic behavior.
|
||||
To collect theses changes and to simplify the computation of gestures we
|
||||
collect PointMaps in a composite class InteractionPoints, which distinguishes
|
||||
start, current, previous, and ended point coordinates as well as the start timestamps.
|
||||
<script class="doctest">
|
||||
|
||||
Doctest.expect(touches, '[PointMap touch1:{x:0, y:0}, touch2:{x:10, y:10}]')
|
||||
Doctest.expect(touches.clone(), '[PointMap touch1:{x:0, y:0}, touch2:{x:10, y:10}]')
|
||||
Doctest.expect(touches.mean(), { x: 5, y: 5 })
|
||||
</script>
|
||||
<p>
|
||||
If more than two touch points are involved it may be best to look for the pair of points which are farthest
|
||||
away from each other. These points will represent the fingers farthest away from each other, a more simple
|
||||
substitute for 3, 4 or 5 touch points. Here we add a third point to our example touches and test whether the
|
||||
maximal distant points are found:
|
||||
<script class="doctest">
|
||||
touches.set('touch3', { x: 5, y: 5 })
|
||||
Doctest.expect(touches.farthests(), [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 10, y: 10 }
|
||||
])
|
||||
</script>
|
||||
</p>
|
||||
let interactionPoints = new InteractionPoints()
|
||||
|
||||
<h2>Interaction Points and Interactions</h2>
|
||||
Events and points change in time and gestures are computed from this dynamic behavior. To collect theses changes
|
||||
and to simplify the computation of gestures we collect PointMaps in a composite class InteractionPoints, which
|
||||
distinguishes start, current, previous, and ended point coordinates as well as the start timestamps.
|
||||
<script class="doctest">
|
||||
let interactionPoints = new InteractionPoints()
|
||||
interactionPoints.update("touch1", {x:0, y:0})
|
||||
interactionPoints.update("touch2", {x:5, y:5})
|
||||
interactionPoints.update("touch3", {x:10, y:10})
|
||||
Doctest.expect(interactionPoints.current.size, 3)
|
||||
|
||||
interactionPoints.update('touch1', { x: 0, y: 0 })
|
||||
interactionPoints.update('touch2', { x: 5, y: 5 })
|
||||
interactionPoints.update('touch3', { x: 10, y: 10 })
|
||||
Doctest.expect(interactionPoints.current.size, 3)
|
||||
// Initially current and previous points are equal
|
||||
Doctest.expect(interactionPoints.current, interactionPoints.previous)
|
||||
// Using updatePrevious we copy the current points to the previous ones.
|
||||
// This is always needed after change events
|
||||
interactionPoints.updatePrevious()
|
||||
|
||||
// Initially current and previous points are equal
|
||||
Doctest.expect(interactionPoints.current, interactionPoints.previous)
|
||||
// Using updatePrevious we copy the current points to the previous ones.
|
||||
// This is always needed after change events
|
||||
interactionPoints.updatePrevious()
|
||||
// After this call current and previous can be used to compure the deltas:
|
||||
interactionPoints.update("touch1", {x: -2, y: -5})
|
||||
interactionPoints.update("touch2", {x: 5, y: 9})
|
||||
interactionPoints.update("touch3", {x: 15, y: 20})
|
||||
Doctest.expect(interactionPoints.current,
|
||||
"[PointMap touch1:{x:-2, y:-5}, touch2:{x:5, y:9}, touch3:{x:15, y:20}]")
|
||||
// "[PointMap touch1:{x:-2, y:-5}, touch2:{x:5, y:7}, touch3:{x:15, y:20}]")
|
||||
|
||||
// After this call current and previous can be used to compure the deltas:
|
||||
interactionPoints.update('touch1', { x: -2, y: -5 })
|
||||
interactionPoints.update('touch2', { x: 5, y: 9 })
|
||||
interactionPoints.update('touch3', { x: 15, y: 20 })
|
||||
Doctest.expect(
|
||||
interactionPoints.current,
|
||||
'[PointMap touch1:{x:-2, y:-5}, touch2:{x:5, y:9}, touch3:{x:15, y:20}]'
|
||||
)
|
||||
// "[PointMap touch1:{x:-2, y:-5}, touch2:{x:5, y:7}, touch3:{x:15, y:20}]")
|
||||
// The delta object is a convenience object to access translation, scaling,
|
||||
// and rotation values as well as the center of transformation
|
||||
let delta = interactionPoints.delta()
|
||||
|
||||
// The delta object is a convenience object to access translation, scaling,
|
||||
// and rotation values as well as the center of transformation
|
||||
let delta = interactionPoints.delta()
|
||||
Doctest.expect(delta.x, 1.5)
|
||||
Doctest.expect(delta.y, 2.5)
|
||||
Doctest.expect(delta.zoom > 1.5, true)
|
||||
Doctest.expect(delta.rotate < 0.2, true)
|
||||
Doctest.expect(delta.about, {x:6.5, y:7.5})
|
||||
|
||||
// Doctest.expect(delta.x, 1.5) // Doctest ERROR! Occurs for an unspecified period of time.
|
||||
// Doctest.expect(delta.y, 2.5) // Doctest ERROR! Occurs for an unspecified period of time.
|
||||
// Doctest.expect(delta.zoom > 1.5, true) // Doctest ERROR! Occurs for an unspecified period of time.
|
||||
// Doctest.expect(delta.rotate < 0.2, true) // Doctest ERROR! Occurs for an unspecified period of time.
|
||||
// Doctest.expect(delta.about, {x: 6.5, y: 7.5}) // Doctest ERROR! Occurs for an unspecified period of time.
|
||||
</script>
|
||||
<p>
|
||||
Interaction objects extend the idea of mapping touch ids to points to multiple target objects. Each touch id
|
||||
is mapped not only to the changing points of this touch but also to the object that has been hit by the
|
||||
starting touch point. This object is the target of the interaction and remains for the whole duration of the
|
||||
multitouch gesture.
|
||||
</p>
|
||||
</script>
|
||||
<p>Interaction objects extend the idea of mapping touch ids to
|
||||
points to multiple target objects. Each touch id is mapped not only to the
|
||||
changing points of this touch but also to the object that has been
|
||||
hit by the starting touch point. This object is the target of the interaction
|
||||
and remains for the whole duration of the multitouch gesture.
|
||||
|
||||
<h2>Interaction Delegate</h2>
|
||||
<p>
|
||||
The delegator registers all needed <code>TouchEvent</code>, <code>PointerEvent</code>, and
|
||||
<code>MouseEvent</code>
|
||||
handlers on a provided DOM elememt for a given target object, ensures that the events are captured by the
|
||||
target and boils the event handling down to simple
|
||||
<code>onStart</code>, <code>onMove</code>, <code>onEnd</code> events.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's look at an example of an InteractionDelegate and a target object that implements the
|
||||
<code>IInteractionTarget</code> interface. Typically you setup the delegator in the constructor of the class
|
||||
that uses the interation.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
class InteractionTarget {
|
||||
// The constructor of the target creates the InteractionDelegate
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionDelegate(domElement, this)
|
||||
}
|
||||
<h2>
|
||||
Interaction Delegate
|
||||
</h2>
|
||||
<p>The delegator registers all needed <code>TouchEvent</code>,
|
||||
<code>PointerEvent</code>, and <code>MouseEvent</code>
|
||||
handlers on a provided DOM elememt for a given target object, ensures that the
|
||||
events are captured by the target and boils the event handling down to simple
|
||||
<code>onStart</code>, <code>onMove</code>, <code>onEnd</code> events.
|
||||
|
||||
// The following methods are needed by the IInteractionTarget interface
|
||||
|
||||
// Indicates that we want all events
|
||||
capture(event) {
|
||||
return true
|
||||
}
|
||||
<p>Let's look at an example of an InteractionDelegate and a target object that
|
||||
implements the <code>IInteractionTarget</code> interface. Typically you setup
|
||||
the delegator in the constructor of the class that uses the interation.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
|
||||
// Handle collected touch points on start
|
||||
onStart(event, points) {}
|
||||
class InteractionTarget {
|
||||
|
||||
// Handle collected touch points on update
|
||||
onMove(event, points) {}
|
||||
// The constructor of the target creates the InteractionDelegate
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionDelegate(domElement, this)
|
||||
}
|
||||
|
||||
// Handle collected touch points on end
|
||||
onEnd(event, points, ended) {}
|
||||
// The following methods are needed by the IInteractionTarget interface
|
||||
|
||||
// Handle mouse wheel event
|
||||
onMouseWheel(event) {}
|
||||
}
|
||||
</script>
|
||||
<p>We can now check whether the promised interface methods are implemented by the class:</p>
|
||||
<script class="doctest">
|
||||
Doctest.expect(IInteractionTarget.implementedBy(InteractionTarget), true)
|
||||
</script>
|
||||
<p>
|
||||
If we define an InteractionTarget that violates the IInteractionTarget interface we get an error. The
|
||||
following example of an interaction target uses an InteractionDelegate but does not implement the necessary
|
||||
methods:
|
||||
</p>
|
||||
<script class="doctest">
|
||||
class InvalidInteractionTarget {
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionDelegate(domElement, this, { debug: true })
|
||||
}
|
||||
// Indicates that we want all events
|
||||
capture(event) { return true }
|
||||
|
||||
// Handle collected touch points on start
|
||||
onStart(event, points) {}
|
||||
|
||||
// Handle collected touch points on update
|
||||
onMove(event, points) {}
|
||||
|
||||
// Handle collected touch points on end
|
||||
onEnd(event, points, ended) {}
|
||||
|
||||
// Handle mouse wheel event
|
||||
onMouseWheel(event) {}
|
||||
}
|
||||
|
||||
</script>
|
||||
<p>We can now check whether the promised interface methods are implemented by the
|
||||
class:</p>
|
||||
<script class="doctest">
|
||||
Doctest.expect(IInteractionTarget.implementedBy(InteractionTarget), true)
|
||||
</script>
|
||||
<p>If we define an InteractionTarget that violates the IInteractionTarget interface
|
||||
we get an error. The following example of an interaction target uses an
|
||||
InteractionDelegate but does not implement the necessary methods:
|
||||
</p>
|
||||
<script class="doctest">
|
||||
class InvalidInteractionTarget {
|
||||
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionDelegate(domElement, this, { debug: true})
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
new InvalidInteractionTarget(null)
|
||||
} catch (error) {
|
||||
Doctest.expectError(error, "Expected IInteractionTarget")
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<h2>
|
||||
Interaction Mapper
|
||||
</h2>
|
||||
<p>Often we need to assign UI elements to touch and pointer events. This is
|
||||
supported by a special InteractionMapper delegate. A InteractionMapper
|
||||
maps events to specific parts of a container interaction target. The
|
||||
InteractionTarget must implement a findTarget method that returns an
|
||||
object implementing the IInteractionTarget interface.
|
||||
</p>
|
||||
<p>
|
||||
If the InteractionTarget also implements a <code>mapPositionToPoint</code> method this
|
||||
is used to map the points to the local coordinate space of the the target.
|
||||
This makes it easier to lookup elements and relate events to local
|
||||
positions.
|
||||
</p>
|
||||
<p>Let's see an example. A graph that uses an <code>InterationMapper</code> for it´s child
|
||||
objects:
|
||||
</p>
|
||||
<script class="doctest">
|
||||
|
||||
class Graph {
|
||||
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionMapper(domElement, this)
|
||||
this.nodes = [
|
||||
new Node('a'),
|
||||
new Node('b')
|
||||
]
|
||||
}
|
||||
|
||||
capture(event) { return true }
|
||||
|
||||
findTarget() {
|
||||
for(let node of this.nodes) {
|
||||
return node
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
new InvalidInteractionTarget(null)
|
||||
} catch (error) {
|
||||
Doctest.expectError(error, 'Expected IInteractionTarget')
|
||||
}
|
||||
</script>
|
||||
class Node {
|
||||
|
||||
<h2>Interaction Mapper</h2>
|
||||
<p>
|
||||
Often we need to assign UI elements to touch and pointer events. This is supported by a special
|
||||
InteractionMapper delegate. A InteractionMapper maps events to specific parts of a container interaction
|
||||
target. The InteractionTarget must implement a findTarget method that returns an object implementing the
|
||||
IInteractionTarget interface.
|
||||
</p>
|
||||
<p>
|
||||
If the InteractionTarget also implements a <code>mapPositionToPoint</code> method this is used to map the
|
||||
points to the local coordinate space of the the target. This makes it easier to lookup elements and relate
|
||||
events to local positions.
|
||||
</p>
|
||||
<p>Let's see an example. A graph that uses an <code>InterationMapper</code> for it´s child objects:</p>
|
||||
<script class="doctest">
|
||||
class Graph {
|
||||
constructor(domElement) {
|
||||
this.interaction = new InteractionMapper(domElement, this)
|
||||
this.nodes = [new Node('a'), new Node('b')]
|
||||
}
|
||||
constructor(name) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
capture(event) {
|
||||
return true
|
||||
}
|
||||
capture(event) { return true }
|
||||
|
||||
findTarget() {
|
||||
for (let node of this.nodes) {
|
||||
return node
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
onStart(event, interaction) {
|
||||
Doctest.log("onStart called")
|
||||
}
|
||||
|
||||
class Node {
|
||||
constructor(name) {
|
||||
this.name = name
|
||||
}
|
||||
onMove(event, interaction) {
|
||||
Doctest.log("onMove called")
|
||||
}
|
||||
|
||||
capture(event) {
|
||||
return true
|
||||
}
|
||||
onEnd(event, interaction) {
|
||||
Doctest.log("onEnd called")
|
||||
}
|
||||
|
||||
onStart(event, interaction) {
|
||||
Doctest.log('onStart called')
|
||||
}
|
||||
}
|
||||
|
||||
onMove(event, interaction) {
|
||||
Doctest.log('onMove called')
|
||||
}
|
||||
</script>
|
||||
<p>Now we simulate a sequence of <code>onStart, onMove, onEnd</code> events by calling
|
||||
the registered event handlers programmatically. Note that the defined
|
||||
event handlers log their calls.</p>
|
||||
<script class="doctest">
|
||||
|
||||
onEnd(event, interaction) {
|
||||
Doctest.log('onEnd called')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<p>
|
||||
Now we simulate a sequence of <code>onStart, onMove, onEnd</code> events by calling the registered event
|
||||
handlers programmatically. Note that the defined event handlers log their calls.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
let graph = new Graph(window)
|
||||
window.dispatchEvent(Doctest.event('mousedown'))
|
||||
window.dispatchEvent(Doctest.event('mousemove'))
|
||||
window.dispatchEvent(Doctest.event('mouseup'))
|
||||
let graph = new Graph(window)
|
||||
window.dispatchEvent(Doctest.event('mousedown'))
|
||||
window.dispatchEvent(Doctest.event('mousemove'))
|
||||
window.dispatchEvent(Doctest.event('mouseup'))
|
||||
|
||||
Doctest.expectLog('onStart called', 'onMove called', 'onEnd called')
|
||||
</script>
|
||||
<h2>Simple Dragging</h2>
|
||||
<p>
|
||||
Drag & Drop is a common interaction pattern. This behavior can be accomplished by a class that implements
|
||||
IInteractionMapperTarget as well as IInteractionTarget. You can grab the blue circle with touches or mouse
|
||||
and drag it around.
|
||||
</p>
|
||||
<div class="grayBorder" style="position: relative; width: 100%; height: 200px">
|
||||
<div
|
||||
id="circle"
|
||||
style="
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
top: 50px;
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-color: blue;
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<script class="doctest">
|
||||
class Dragger {
|
||||
constructor(element, container) {
|
||||
/* The events are captured by the container but send to this
|
||||
Doctest.expectLog('onStart called',
|
||||
'onMove called',
|
||||
'onEnd called')
|
||||
|
||||
</script>
|
||||
<h2>
|
||||
Simple Dragging
|
||||
</h2>
|
||||
<p>Drag & Drop is a common interaction pattern. This behavior can be accomplished
|
||||
by a class that implements IInteractionMapperTarget as well as IInteractionTarget.
|
||||
You can grab the blue circle with touches or mouse and drag it around.</p>
|
||||
<div class="grayBorder" style="position: relative; width: 100%; height: 200px">
|
||||
<div id="circle" style="position: absolute; left:50px; top: 50px; border-radius: 50%; width: 32px; height: 32px; background-color: blue;"></div>
|
||||
</div>
|
||||
<script class="doctest">
|
||||
class Dragger {
|
||||
|
||||
constructor(element, container) {
|
||||
/* The events are captured by the container but send to this
|
||||
wrapper object, if the event target is identical to the wrapped
|
||||
object. */
|
||||
this.target = element
|
||||
this.interaction = new InteractionMapper(container, this)
|
||||
}
|
||||
this.target = element
|
||||
this.interaction = new InteractionMapper(container, this)
|
||||
}
|
||||
|
||||
capture(event) {
|
||||
return true
|
||||
}
|
||||
capture(event) { return true }
|
||||
|
||||
findTarget(event, localPoint, globalPoint) {
|
||||
return event.target == this.target ? this : null
|
||||
}
|
||||
findTarget(event, localPoint, globalPoint) {
|
||||
return (event.target == this.target) ? this : null
|
||||
}
|
||||
|
||||
onStart(event, interaction) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
onStart(event, interaction) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
|
||||
onMove(event, interaction) {
|
||||
let move = interaction.move()
|
||||
let x = parseInt(this.target.style.left) + move.x
|
||||
let y = parseInt(this.target.style.top) + move.y
|
||||
this.target.style.left = x + 'px'
|
||||
this.target.style.top = y + 'px'
|
||||
}
|
||||
onMove(event, interaction) {
|
||||
let move = interaction.move()
|
||||
let x = parseInt(this.target.style.left) + move.x
|
||||
let y = parseInt(this.target.style.top) + move.y
|
||||
this.target.style.left = x + "px"
|
||||
this.target.style.top = y + "px"
|
||||
}
|
||||
|
||||
onEnd(event, interaction) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
onEnd(event, interaction) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
|
||||
onMouseWheel(event) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
}
|
||||
onMouseWheel(event) {
|
||||
// Only needed to fulfill the IInteractionTarget interface
|
||||
}
|
||||
}
|
||||
|
||||
Doctest.expect(IInteractionMapperTarget.implementedBy(Dragger), true)
|
||||
Doctest.expect(IInteractionTarget.implementedBy(Dragger), true)
|
||||
Doctest.expect(IInteractionMapperTarget.implementedBy(Dragger), true)
|
||||
Doctest.expect(IInteractionTarget.implementedBy(Dragger), true)
|
||||
|
||||
new Dragger(circle, document.body)
|
||||
</script>
|
||||
new Dragger(circle, document.body)
|
||||
</script>
|
||||
|
||||
<h2>Multitouch</h2>
|
||||
<p>
|
||||
Multitouch-Events (simultaneous events) in browsers cannot be used by default. Even libraries like jQuery do
|
||||
not fix this problem. The static method "on" of the InteractionMapper allows simultaneous events and thus
|
||||
multitouch. The following events (and their specializations) can be used in addition to the default browser
|
||||
events: tap, doubletap, press, pan, swipe, pinch and rotate. See http://hammerjs.github.io for more details.
|
||||
</p>
|
||||
<svg
|
||||
width="100%"
|
||||
height="300"
|
||||
viewBox="0 0 400 200"
|
||||
class="grayBorder"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:bx="https://boxy-svg.com"
|
||||
>
|
||||
<defs>
|
||||
<pattern
|
||||
id="pattern-1"
|
||||
viewBox="0 0 100 100"
|
||||
patternUnits="userSpaceOnUse"
|
||||
preserveAspectRatio="none"
|
||||
width="100"
|
||||
height="100"
|
||||
/>
|
||||
<linearGradient
|
||||
id="gradient-1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="235.294"
|
||||
y1="5.386"
|
||||
x2="235.294"
|
||||
y2="63.218"
|
||||
gradientTransform="matrix(0.479375, 0.877612, -1.161752, 0.599143, 216.009222, -193.782169)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgba(216, 216, 216, 1)" />
|
||||
<stop offset="1" style="stop-color: rgb(45, 175, 182)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="gradient-4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="193.252"
|
||||
y1="126.988"
|
||||
x2="193.252"
|
||||
y2="163.836"
|
||||
gradientTransform="matrix(0.978752, 0, 0, 1.126983, 11.124972, -21.238213)"
|
||||
>
|
||||
<stop offset="0" style="stop-color: rgba(161, 110, 0, 1)" />
|
||||
<stop offset="1" style="stop-color: rgba(59, 40, 0, 1)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="hammer-1">
|
||||
<rect
|
||||
x="55.329"
|
||||
y="20.25"
|
||||
width="42.523"
|
||||
height="42.523"
|
||||
style="fill: rgb(236, 229, 24); stroke: rgb(0, 179, 207); stroke-width: 2; stroke-linejoin: bevel"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="68.736" y="45.811">tap</text>
|
||||
</g>
|
||||
<g id="hammer-2">
|
||||
<path
|
||||
d="M 372 149 m -25.496 0 a 25.496 26.092 0 1 0 50.992 0 a 25.496 26.092 0 1 0 -50.992 0 Z M 372 149 m -15.297 0 a 15.297 15.654 0 0 1 30.594 0 a 15.297 15.654 0 0 1 -30.594 0 Z"
|
||||
transform="matrix(-0.535925, 0.844266, -0.844265, -0.535925, 499.054353, -194.103207)"
|
||||
style="fill: rgb(194, 59, 59); stroke: rgb(141, 10, 91); stroke-width: 2"
|
||||
bx:shape="ring 372 149 15.297 15.654 25.496 26.092 1@9ddd52c9"
|
||||
/>
|
||||
<text
|
||||
transform="matrix(1.226643, 0, 0, 1.226643, 42.737137, 26.559669)"
|
||||
style="fill: rgb(51, 51, 51); font-size: 9.7828px; white-space: pre"
|
||||
>
|
||||
<tspan x="94.401" y="44.224">press</tspan>
|
||||
<tspan x="94.401" dy="1em"></tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g>
|
||||
<polygon
|
||||
id="hammer-3"
|
||||
style="fill: url(#gradient-1); stroke: rgb(182, 40, 92)"
|
||||
points="272.369 20.761 234.949 23.029 227.862 34.652 236.65 46.558 253.943 55.63 293.347 59.315 340.406 62.434 371.306 49.96 374.708 32.951 356.282 29.549 333.319 21.044 311.774 9.705 307.238 23.029 322.263 33.518 347.777 44.007 339.839 48.259 315.459 48.826 292.781 45.991 281.725 32.667 285.977 17.643 281.158 4.602 267.55 6.303 252.525 6.587 252.809 11.973 255.36 17.076 263.014 16.225 267.834 13.674 273.787 13.39 276.622 14.808"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="296.849" y="80.823">pan</text>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse
|
||||
transform="matrix(-0.707107, 0.707107, -0.707107, -0.707107, 362.152622, 115.748229)"
|
||||
cx="221.437"
|
||||
cy="181.098"
|
||||
rx="27.616"
|
||||
ry="27.616"
|
||||
style="fill: rgb(149, 26, 133); stroke: rgb(73, 4, 62); stroke-width: 4; fill-opacity: 0.69"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="61.759" y="190.447">
|
||||
swipe
|
||||
</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect
|
||||
id="hammer-5"
|
||||
x="146.389"
|
||||
y="121.875"
|
||||
width="107.762"
|
||||
height="41.527"
|
||||
style="fill: url(#gradient-4); stroke-linejoin: round; stroke: rgb(0, 0, 0)"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="187.854" y="190.447">
|
||||
pinch
|
||||
</text>
|
||||
</g>
|
||||
<g transform="matrix(1.286049, 0, 0, 1.286049, -103.444145, -48.307945)">
|
||||
<path
|
||||
class="star"
|
||||
d="M 937 394.847 L 946.206 421.33 L 974.238 421.901 L 951.895 438.84 L 960.014 465.675 L 937 449.661 L 913.986 465.675 L 922.105 438.84 L 899.762 421.901 L 927.794 421.33 Z"
|
||||
transform="matrix(-0.809017, 0.587785, -0.587785, -0.809018, 1346.787902, -60.391979)"
|
||||
style="
|
||||
fill: rgb(83, 230, 226);
|
||||
stroke: rgb(24, 111, 116);
|
||||
stroke-width: 2;
|
||||
stroke-linejoin: round;
|
||||
stroke-dasharray: 2px;
|
||||
"
|
||||
bx:shape="star 937 434 39.154 39.153 0.4 5 1@05a6f642"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="316.854" y="190.447">
|
||||
rotate
|
||||
</text>
|
||||
</g>
|
||||
<g transform="matrix(1.286049, 0, 0, 1.286049, -28.431454, -48.307941)">
|
||||
<path
|
||||
class="star"
|
||||
d="M 937 394.847 L 946.206 421.33 L 974.238 421.901 L 951.895 438.84 L 960.014 465.675 L 937 449.661 L 913.986 465.675 L 922.105 438.84 L 899.762 421.901 L 927.794 421.33 Z"
|
||||
transform="matrix(-0.809017, 0.587785, -0.587785, -0.809018, 1346.787902, -60.391979)"
|
||||
style="
|
||||
fill: rgb(83, 230, 226);
|
||||
stroke: rgb(24, 111, 116);
|
||||
stroke-width: 2;
|
||||
stroke-linejoin: round;
|
||||
stroke-dasharray: 2px;
|
||||
"
|
||||
bx:shape="star 937 434 39.154 39.153 0.4 5 1@05a6f642"
|
||||
/>
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre" x="316.854" y="190.447">
|
||||
rotate
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
<h2>
|
||||
Multitouch
|
||||
</h2>
|
||||
<p>
|
||||
Multitouch-Events (simultaneous events) in browsers cannot be used by default.
|
||||
Even libraries like jQuery do not fix this problem. The static method "on" of the
|
||||
InteractionMapper allows simultaneous events and thus multitouch. The following
|
||||
events (and their specializations) can be used in addition to the default browser
|
||||
events: tap, doubletap, press, pan, swipe, pinch and rotate. See http://hammerjs.github.io
|
||||
for more details.
|
||||
</p>
|
||||
<svg width="100%" height="300" viewBox="0 0 400 200" class="grayBorder" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
|
||||
<defs>
|
||||
<pattern id="pattern-1" viewBox="0 0 100 100" patternUnits="userSpaceOnUse" preserveAspectRatio="none" width="100" height="100" />
|
||||
<linearGradient id="gradient-1" gradientUnits="userSpaceOnUse" x1="235.294" y1="5.386" x2="235.294" y2="63.218" gradientTransform="matrix(0.479375, 0.877612, -1.161752, 0.599143, 216.009222, -193.782169)">
|
||||
<stop offset="0" style="stop-color: rgba(216, 216, 216, 1)" />
|
||||
<stop offset="1" style="stop-color: rgb(45, 175, 182);" />
|
||||
</linearGradient>
|
||||
<linearGradient id="gradient-4" gradientUnits="userSpaceOnUse" x1="193.252" y1="126.988" x2="193.252" y2="163.836" gradientTransform="matrix(0.978752, 0, 0, 1.126983, 11.124972, -21.238213)">
|
||||
<stop offset="0" style="stop-color: rgba(161, 110, 0, 1)" />
|
||||
<stop offset="1" style="stop-color: rgba(59, 40, 0, 1)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="hammer-1">
|
||||
<rect x="55.329" y="20.25" width="42.523" height="42.523" style="fill: rgb(236, 229, 24); stroke: rgb(0, 179, 207); stroke-width: 2; stroke-linejoin: bevel;" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="68.736" y="45.811">tap</text>
|
||||
</g>
|
||||
<g id="hammer-2">
|
||||
<path d="M 372 149 m -25.496 0 a 25.496 26.092 0 1 0 50.992 0 a 25.496 26.092 0 1 0 -50.992 0 Z M 372 149 m -15.297 0 a 15.297 15.654 0 0 1 30.594 0 a 15.297 15.654 0 0 1 -30.594 0 Z" transform="matrix(-0.535925, 0.844266, -0.844265, -0.535925, 499.054353, -194.103207)" style="fill: rgb(194, 59, 59); stroke: rgb(141, 10, 91); stroke-width: 2;" bx:shape="ring 372 149 15.297 15.654 25.496 26.092 1@9ddd52c9" />
|
||||
<text transform="matrix(1.226643, 0, 0, 1.226643, 42.737137, 26.559669)" style="fill: rgb(51, 51, 51); font-size: 9.7828px; white-space: pre;">
|
||||
<tspan x="94.401" y="44.224">press</tspan>
|
||||
<tspan x="94.401" dy="1em"></tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g>
|
||||
<polygon id="hammer-3" style="fill: url(#gradient-1); stroke: rgb(182, 40, 92);" points="272.369 20.761 234.949 23.029 227.862 34.652 236.65 46.558 253.943 55.63 293.347 59.315 340.406 62.434 371.306 49.96 374.708 32.951 356.282 29.549 333.319 21.044 311.774 9.705 307.238 23.029 322.263 33.518 347.777 44.007 339.839 48.259 315.459 48.826 292.781 45.991 281.725 32.667 285.977 17.643 281.158 4.602 267.55 6.303 252.525 6.587 252.809 11.973 255.36 17.076 263.014 16.225 267.834 13.674 273.787 13.39 276.622 14.808" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="296.849" y="80.823">pan</text>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse transform="matrix(-0.707107, 0.707107, -0.707107, -0.707107, 362.152622, 115.748229)" cx="221.437" cy="181.098" rx="27.616" ry="27.616" style="fill: rgb(149, 26, 133); stroke: rgb(73, 4, 62); stroke-width: 4; fill-opacity: 0.69;" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="61.759" y="190.447">swipe</text>
|
||||
</g>
|
||||
<g>
|
||||
<rect id="hammer-5" x="146.389" y="121.875" width="107.762" height="41.527" style="fill: url(#gradient-4); stroke-linejoin: round; stroke: rgb(0, 0, 0);" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="187.854" y="190.447">pinch</text>
|
||||
</g>
|
||||
<g transform="matrix(1.286049, 0, 0, 1.286049, -103.444145, -48.307945)">
|
||||
<path class="star" d="M 937 394.847 L 946.206 421.33 L 974.238 421.901 L 951.895 438.84 L 960.014 465.675 L 937 449.661 L 913.986 465.675 L 922.105 438.84 L 899.762 421.901 L 927.794 421.33 Z" transform="matrix(-0.809017, 0.587785, -0.587785, -0.809018, 1346.787902, -60.391979)" style="fill: rgb(83, 230, 226); stroke: rgb(24, 111, 116); stroke-width: 2; stroke-linejoin: round; stroke-dasharray: 2px;" bx:shape="star 937 434 39.154 39.153 0.4 5 1@05a6f642" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="316.854" y="190.447">rotate</text>
|
||||
</g>
|
||||
<g transform="matrix(1.286049, 0, 0, 1.286049, -28.431454, -48.307941)">
|
||||
<path class="star" d="M 937 394.847 L 946.206 421.33 L 974.238 421.901 L 951.895 438.84 L 960.014 465.675 L 937 449.661 L 913.986 465.675 L 922.105 438.84 L 899.762 421.901 L 927.794 421.33 Z" transform="matrix(-0.809017, 0.587785, -0.587785, -0.809018, 1346.787902, -60.391979)" style="fill: rgb(83, 230, 226); stroke: rgb(24, 111, 116); stroke-width: 2; stroke-linejoin: round; stroke-dasharray: 2px;" bx:shape="star 937 434 39.154 39.153 0.4 5 1@05a6f642" />
|
||||
<text style="fill: rgb(51, 51, 51); font-size: 12px; white-space: pre;" x="316.854" y="190.447">rotate</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<script class="doctest">
|
||||
const from = { scale: 1 }
|
||||
const to = { scale: 1.3, transformOrigin: 'center', repeat: 1, yoyo: true }
|
||||
<script class="doctest">
|
||||
|
||||
InteractionMapper.on('tap', document.getElementById('hammer-1'), (event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
})
|
||||
const from = {scale: 1}
|
||||
const to = {scale: 1.3, transformOrigin: 'center', repeat: 1, yoyo: true}
|
||||
|
||||
InteractionMapper.on('tap', document.getElementById('hammer-1'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
})
|
||||
|
||||
InteractionMapper.on(
|
||||
'press',
|
||||
document.getElementById('hammer-2'),
|
||||
(event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
},
|
||||
{ time: 1000 }
|
||||
)
|
||||
InteractionMapper.on('press', document.getElementById('hammer-2'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
}, {time: 1000})
|
||||
|
||||
InteractionMapper.on('panright pandown', document.getElementById('hammer-3'), (event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
})
|
||||
InteractionMapper.on('panright pandown', document.getElementById('hammer-3'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
})
|
||||
|
||||
InteractionMapper.on(['swipeleft', 'swipedown'], document.getElementsByTagName('ellipse'), (event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
})
|
||||
InteractionMapper.on(['swipeleft', 'swipedown'], document.getElementsByTagName('ellipse'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
})
|
||||
|
||||
InteractionMapper.on('pinch', document.getElementById('hammer-5'), (event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
})
|
||||
InteractionMapper
|
||||
.on('pinch', document.getElementById('hammer-5'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
})
|
||||
.on('rotate', document.querySelectorAll('svg g > path.star'), event => {
|
||||
TweenLite.fromTo(event.target, .2, from, to)
|
||||
})
|
||||
.on('click', document.getElementById('hammer-1'), event => {
|
||||
console.log(event)
|
||||
})
|
||||
</script>
|
||||
|
||||
InteractionMapper.on('rotate', document.querySelectorAll('svg g > path.star'), (event) => {
|
||||
TweenLite.fromTo(event.target, 0.2, from, to)
|
||||
})
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/dp/0201633612">Design Patterns [p. 20]</a></li>
|
||||
<li><a href="http://hammerjs.github.io">Hammer.js</a></li>
|
||||
</ul>
|
||||
|
||||
InteractionMapper.on('click', document.getElementById('hammer-1'), (event) => {
|
||||
console.log(event)
|
||||
})
|
||||
</script>
|
||||
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/dp/0201633612"
|
||||
>Design Patterns [p. 20]</a
|
||||
>
|
||||
</li>
|
||||
<li><a href="http://hammerjs.github.io">Hammer.js</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
@ -553,7 +553,6 @@ export class InteractionDelegate {
|
||||
useCapture = true,
|
||||
capturePointerEvents = true,
|
||||
cancelOnWindowOut = true,
|
||||
preventPointerClicks = true,
|
||||
debug = false
|
||||
} = {}
|
||||
) {
|
||||
@ -565,7 +564,6 @@ export class InteractionDelegate {
|
||||
this.useCapture = useCapture
|
||||
this.capturePointerEvents = capturePointerEvents
|
||||
this.cancelOnWindowOut = cancelOnWindowOut
|
||||
this.preventPointerClicks = preventPointerClicks
|
||||
this.setupInteraction()
|
||||
}
|
||||
|
||||
@ -598,7 +596,7 @@ export class InteractionDelegate {
|
||||
try {
|
||||
element.setPointerCapture(e.pointerId)
|
||||
} catch (e) {
|
||||
console.warn('Cannot setPointerCapture', e.setPointerCapture)
|
||||
console.warn('Cannot setPointerCapture')
|
||||
}
|
||||
}
|
||||
this.onStart(e)
|
||||
@ -785,20 +783,6 @@ export class InteractionDelegate {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.preventPointerClicks) {
|
||||
window.addEventListener(
|
||||
'click',
|
||||
e => {
|
||||
if (e instanceof PointerEvent) {
|
||||
console.warn('Prevented pointer click')
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
},
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
isDescendant(parent, child) {
|
||||
@ -984,7 +968,6 @@ export class InteractionMapper extends InteractionDelegate {
|
||||
useCapture = true,
|
||||
capturePointerEvents = true,
|
||||
mouseWheelElement = null,
|
||||
preventPointerClicks = true,
|
||||
logInteractionsAbove = 12
|
||||
} = {}
|
||||
) {
|
||||
@ -992,7 +975,6 @@ export class InteractionMapper extends InteractionDelegate {
|
||||
tapDistance,
|
||||
useCapture,
|
||||
capturePointerEvents,
|
||||
preventPointerClicks,
|
||||
longPressTime,
|
||||
mouseWheelElement
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 1002 KiB |
@ -1,43 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Interfaces</h1>
|
||||
<p>
|
||||
Interfaces are objects that specify (document) the external behavior of objects that “provide” them. An
|
||||
interface specifies behavior through method definitions that specify functions and their signatures.
|
||||
</p>
|
||||
<p>Let's look at an example of an interface and a class implementing the interface:</p>
|
||||
<script class="doctest">
|
||||
class ITestable extends Interface {
|
||||
reset() {}
|
||||
run() {}
|
||||
}
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>
|
||||
Interfaces
|
||||
</h1>
|
||||
<p>
|
||||
Interfaces are objects that specify (document) the external behavior of objects
|
||||
that “provide” them. An interface specifies behavior through method definitions
|
||||
that specify functions and their signatures.
|
||||
</p>
|
||||
<p>Let's look at an example of an interface and a class implementing the interface:</p>
|
||||
<script class="doctest">
|
||||
|
||||
class Testable {
|
||||
reset() {
|
||||
print('Resetting testable object')
|
||||
}
|
||||
class ITestable extends Interface {
|
||||
reset() {}
|
||||
run() {}
|
||||
}
|
||||
|
||||
run() {
|
||||
print('Running testable object')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<p>We can now check whether the promised interface methods are implemented by the class:</p>
|
||||
<script class="doctest">
|
||||
Doctest.expect(ITestable.implementedBy(Testable), true)
|
||||
</script>
|
||||
<p></p>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li><a href="https://zopeinterface.readthedocs.io">Zope Interfaces</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
class Testable {
|
||||
|
||||
reset() {
|
||||
print("Resetting testable object")
|
||||
}
|
||||
|
||||
run() {
|
||||
print("Running testable object")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<p>We can now check whether the promised interface methods are implemented by the
|
||||
class:</p>
|
||||
<script class="doctest">
|
||||
Doctest.expect(ITestable.implementedBy(Testable), true)
|
||||
</script>
|
||||
<p>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="https://zopeinterface.readthedocs.io">Zope Interfaces</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
@ -1,30 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Logging Doctest</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../css/doctest.css" />
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
|
||||
<body id="page" onload="Doctest.run()">
|
||||
<h1><a href="index.html">lib.</a>Logging</h1>
|
||||
<p>Store informations of your app permanently or use app specific logging functions.</p>
|
||||
<script class="doctest">
|
||||
Logging.log('app started')
|
||||
Logging.warn("shouldn't happen")
|
||||
Logging.error('restart')
|
||||
<head>
|
||||
<title>Logging Doctest</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../css/doctest.css">
|
||||
<script src="./3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
|
||||
Logging.setup({ log: (message) => console.log('app specific' + message) })
|
||||
Logging.log('now app related')
|
||||
</script>
|
||||
<p>You can overwrite the log, warn, and error handler by using Logging.setup with app specific functions.</p>
|
||||
<script class="doctest">
|
||||
Logging.setup({ log: (message) => console.log('app specific' + message) })
|
||||
Logging.log('now app related')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<body id="page" onload="Doctest.run()">
|
||||
<h1>
|
||||
Logging
|
||||
</h1>
|
||||
<p>Store informations of your app permanently or use app specific logging functions.</p>
|
||||
<script class="doctest">
|
||||
Logging.log('app started')
|
||||
Logging.warn("shouldn't happen")
|
||||
Logging.error('restart')
|
||||
|
||||
Logging.setup({ log: message => console.log("app specific" + message) })
|
||||
Logging.log("now app related")
|
||||
</script>
|
||||
<p>You can overwrite the log, warn, and error handler by using Logging.setup with
|
||||
app specific functions.</p>
|
||||
<script class="doctest">
|
||||
Logging.setup({ log: message => console.log("app specific" + message) })
|
||||
Logging.log("now app related")
|
||||
</script>
|
||||
</body>
|
||||
@ -6,14 +6,14 @@ let logMessages = new Set()
|
||||
let logHandlers = {
|
||||
log: console.log,
|
||||
warn: console.warn,
|
||||
error: console.error,
|
||||
error: console.error
|
||||
}
|
||||
|
||||
try {
|
||||
ipc = window.ipcRenderer || require('electron').ipcRenderer
|
||||
logHandlers.log = (message) => ipc.send('log', message)
|
||||
logHandlers.warn = (message) => ipc.send('warn', message)
|
||||
logHandlers.error = (message) => ipc.send('error', message)
|
||||
logHandlers.log = message => ipc.send('log', message)
|
||||
logHandlers.warn = message => ipc.send('warn', message)
|
||||
logHandlers.error = message => ipc.send('error', message)
|
||||
} catch (e) {
|
||||
console.log('Cannot use electron logging.')
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ export default class AbstractPopup extends PIXI.Graphics {
|
||||
radius: theme.radius,
|
||||
onHidden: null,
|
||||
visible: true,
|
||||
orientation: null,
|
||||
orientation: null
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -105,7 +105,7 @@ export default class AbstractPopup extends PIXI.Graphics {
|
||||
// interaction
|
||||
//-----------------
|
||||
this.interactive = true
|
||||
this.on('added', (e) => {
|
||||
this.on('added', e => {
|
||||
this.show()
|
||||
})
|
||||
}
|
||||
@ -285,7 +285,7 @@ export default class AbstractPopup extends PIXI.Graphics {
|
||||
if (cb) {
|
||||
cb.call(this)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
return this
|
||||
@ -305,7 +305,7 @@ export default class AbstractPopup extends PIXI.Graphics {
|
||||
if (cb) {
|
||||
cb.call(this)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
if (this.opts.onHidden) {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="max-width: none;">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>PIXI Fullscreen Application Doctest</title>
|
||||
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0;">
|
||||
<canvas id="canvas" style="width: 100%; height: 100%;"></canvas>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
fpsLogging: true,
|
||||
transparent: false
|
||||
})
|
||||
|
||||
app.setup()
|
||||
app.run()
|
||||
|
||||
let highlightBtn = new PIXI.Graphics()
|
||||
highlightBtn.lineStyle(4, 0xff6900)
|
||||
highlightBtn.drawRoundedRect(150, 40, 30, 30, 4)
|
||||
highlightBtn.endFill()
|
||||
app.stage.addChild(highlightBtn)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -8,8 +8,10 @@
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../../lib/3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src=".././3rdparty/all.js"></script>
|
||||
|
||||
<script src=".../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Application</h1>
|
||||
<h1>Application</h1>
|
||||
<p>
|
||||
The class PIXIApp is the main entry point to create a new PIXI Application.
|
||||
It inherits from PIXI.Application, set meaningfull defaults, creates a scene and
|
||||
@ -50,21 +50,21 @@ const app = new PIXIApp({
|
||||
app.setup()
|
||||
app.run()
|
||||
|
||||
// let highlightBtn = new PIXI.Graphics();
|
||||
// highlightBtn.lineStyle(2, 0x033792);
|
||||
// highlightBtn.drawRoundedRect(15, 40, 30, 30, 10);
|
||||
// highlightBtn.endFill();
|
||||
// app.stage.addChild(highlightBtn);
|
||||
let highlightBtn = new PIXI.Graphics();
|
||||
highlightBtn.lineStyle(2, 0x033792);
|
||||
highlightBtn.drawRoundedRect(15, 40, 30, 30, 10);
|
||||
highlightBtn.endFill();
|
||||
app.stage.addChild(highlightBtn);
|
||||
|
||||
app.loadSprites("assets/app-circle.png", sprites => {
|
||||
let circle = sprites.get("assets/app-circle.png")
|
||||
circle.anchor.set(0.5)
|
||||
circle.x = app.screen.width / 2
|
||||
circle.y = app.screen.height / 2
|
||||
circle.width = 80
|
||||
circle.height = 80
|
||||
app.scene.addChild(circle)
|
||||
app.run()
|
||||
})
|
||||
// app.loadSprites("assets/app-circle.png", sprites => {
|
||||
// let circle = sprites.get("assets/app-circle.png")
|
||||
// circle.anchor.set(0.5)
|
||||
// circle.x = app.screen.width / 2
|
||||
// circle.y = app.screen.height / 2
|
||||
// circle.width = 80
|
||||
// circle.height = 80
|
||||
// app.scene.addChild(circle)
|
||||
// app.run()
|
||||
// })
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -16,11 +16,11 @@ import { debounce } from '../utils.js'
|
||||
*
|
||||
* @private
|
||||
* @class
|
||||
* @extends PIXI.InteractionManager
|
||||
* @extends PIXI.interaction.InteractionManager
|
||||
* @see {@link http://pixijs.download/dev/docs/PIXI.interaction.InteractionManager.html|PIXI.interaction.InteractionManager}
|
||||
* @see {@link https://stackoverflow.com/questions/29710696/webgl-drawing-buffer-size-does-not-equal-canvas-size}
|
||||
*/
|
||||
class FullscreenInteractionManager extends PIXI.InteractionManager {
|
||||
class FullscreenInteractionManager extends PIXI.interaction.InteractionManager {
|
||||
mapPositionToPoint(point, x, y) {
|
||||
let resolution = this.renderer.resolution
|
||||
let extendWidth = 1.0
|
||||
@ -71,7 +71,7 @@ export default class PIXIApp extends PIXI.Application {
|
||||
* @param {HTMLElement} [opts.view] - The canvas HTML element. If not set, a render-element is added inside the body.
|
||||
* @param {boolean} [opts.transparent=true] - Should the render view be transparent?
|
||||
* @param {boolean} [opts.antialias=true] - Sets antialias (only applicable in chrome at the moment).
|
||||
* @param {number} [opts.resolution=window.devicePixelRatio || 1] - The resolution / device pixel ratio of the renderer, retina would be 2.
|
||||
* @param {number} [opts.resolution=window.devicePixelRatio | 1] - The resolution / device pixel ratio of the renderer, retina would be 2.
|
||||
* @param {boolean} [opts.autoResize=true] - Should the canvas-element be resized automatically if the resolution was set?
|
||||
* @param {number} [opts.backgroundColor=0x282828] - The color of the background.
|
||||
* @param {string|Theme} [opts.theme=dark] - The name of the theme (dark, light, red) or a Theme object to use for styling.
|
||||
@ -81,7 +81,6 @@ export default class PIXIApp extends PIXI.Application {
|
||||
* @param {boolean} [opts.roundPixels=true] - Align PIXI.DisplayObject coordinates to screen resolution.
|
||||
* @param {boolean} [opts.monkeyPatchMapping=true] - Monkey patch for canvas fullscreen support on large displays.
|
||||
* @param {boolean} [opts.adaptive=true] - Adds Graphics adaptive calculation of quadratic curve and arc subdivision.
|
||||
* @param {boolean} [opts.autoDensity=true] - Automatically adapts width to devicePixelRation
|
||||
*/
|
||||
constructor({
|
||||
width = null,
|
||||
@ -91,7 +90,7 @@ export default class PIXIApp extends PIXI.Application {
|
||||
backgroundColor = 0x282828,
|
||||
theme = 'dark',
|
||||
antialias = true,
|
||||
resolution = window.devicePixelRatio || 1, // Needed for text resolution https://www.html5gamedevs.com/topic/46418-text-and-resolution/
|
||||
resolution = window.devicePixelRatio || 1,
|
||||
autoResize = true,
|
||||
fpsLogging = false,
|
||||
progress = {},
|
||||
@ -99,8 +98,7 @@ export default class PIXIApp extends PIXI.Application {
|
||||
roundPixels = true,
|
||||
monkeyPatchMapping = true,
|
||||
adaptive = true,
|
||||
graphql = false,
|
||||
autoDensity = true // Needed for text resolution https://www.html5gamedevs.com/topic/46418-text-and-resolution/
|
||||
graphql = false
|
||||
}) {
|
||||
const fullScreen = !width || !height
|
||||
|
||||
@ -113,13 +111,12 @@ export default class PIXIApp extends PIXI.Application {
|
||||
view,
|
||||
width,
|
||||
height,
|
||||
backgroundAlpha: transparent,
|
||||
transparent,
|
||||
antialias,
|
||||
resolution,
|
||||
autoResize,
|
||||
backgroundColor,
|
||||
forceCanvas,
|
||||
autoDensity
|
||||
forceCanvas
|
||||
})
|
||||
|
||||
this.width = width
|
||||
@ -140,7 +137,7 @@ export default class PIXIApp extends PIXI.Application {
|
||||
this.graphql = graphql
|
||||
if (fullScreen || autoResize) {
|
||||
console.log('App is in fullScreen mode or autoResize mode')
|
||||
const resizeDebounced = debounce(event => this.resizeApp(event), 50)
|
||||
const resizeDebounced = debounce(event => this.resize(event), 50)
|
||||
window.addEventListener('resize', resizeDebounced)
|
||||
document.body.addEventListener('orientationchange', this.checkOrientation.bind(this))
|
||||
}
|
||||
@ -315,19 +312,6 @@ export default class PIXIApp extends PIXI.Application {
|
||||
* @return {PIXIApp} - Returns the PIXIApp for chaining.
|
||||
*/
|
||||
resize(event, { width = window.innerWidth, height = window.innerHeight } = {}) {
|
||||
return this.resizeApp(event, { width, height })
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the renderer to fit into the window or given width and height.
|
||||
*
|
||||
* @param {object} [event] - The event.
|
||||
* @param {object=} [opts={}] - The event.
|
||||
* @param {number} [opts.width=window.innerWidth] - The width of the app to resize to.
|
||||
* @param {number} [opts.height=window.innerHeight] - The height of the app to resize to.
|
||||
* @return {PIXIApp} - Returns the PIXIApp for chaining.
|
||||
*/
|
||||
resizeApp(event, { width = window.innerWidth, height = window.innerHeight } = {}) {
|
||||
this.width = width
|
||||
this.height = height
|
||||
this.expandRenderer()
|
||||
|
||||
BIN
lib/pixi/app.png
|
Before Width: | Height: | Size: 491 KiB |
@ -1,40 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI.Application Doctest</title>
|
||||
<title>PIXI.Application Doctest</title>
|
||||
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PIXI.Application with nothing!</h1>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Vanilla PIXI.Application</h1>
|
||||
<script>
|
||||
const app = new PIXI.Application({
|
||||
width: 450,
|
||||
height: 150
|
||||
})
|
||||
|
||||
<script>
|
||||
const app = new PIXI.Application({
|
||||
width: 450,
|
||||
height: 150
|
||||
})
|
||||
// Add the view to the DOM
|
||||
document.body.appendChild(app.view)
|
||||
|
||||
// Add the view to the DOM
|
||||
document.body.appendChild(app.view)
|
||||
// ex, add display objects
|
||||
const sprite = PIXI.Sprite.from('./assets/app-circle.png')
|
||||
sprite.scale.set(.3, .3)
|
||||
app.stage.addChild(sprite)
|
||||
|
||||
// ex, add display objects
|
||||
const sprite = PIXI.Sprite.from('./assets/app-circle.png')
|
||||
sprite.scale.set(0.3, 0.3)
|
||||
app.stage.addChild(sprite)
|
||||
|
||||
sprite.interactive = true
|
||||
sprite.buttonMode = true
|
||||
sprite.on('click', (e) => {
|
||||
console.log('sprite clicked')
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
sprite.interactive = true
|
||||
sprite.buttonMode = true
|
||||
sprite.on('click', e => {
|
||||
console.log('sprite clicked')
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
Before Width: | Height: | Size: 94 KiB |
@ -5,7 +5,10 @@
|
||||
|
||||
<title>PIXI Badge</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="../3rdparty/highlight/styles/default.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
@ -15,12 +18,16 @@
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Badge</h1>
|
||||
<p>Small and adaptive tag for adding context to just about any content.</p>
|
||||
<h1>Badge</h1>
|
||||
<p>
|
||||
Small and adaptive tag for adding context to just about any content.
|
||||
</p>
|
||||
<p>Let's look at some badge examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Badges, badges, badges...</p>
|
||||
<p>
|
||||
What you should see: Badges, badges, badges...
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
@ -113,11 +120,13 @@
|
||||
fill: 0xfe9727
|
||||
})
|
||||
|
||||
let sprite1 = new PIXI.Sprite(PIXI.Texture.from('./assets/badge-1.mp4'))
|
||||
let sprite1 = new PIXI.Sprite(
|
||||
PIXI.Texture.from('./assets/badge-1.mp4')
|
||||
)
|
||||
sprite1.scale.set(0.05, 0.05)
|
||||
|
||||
let texture1 = PIXI.Texture.from('./assets/badge-1.mp4')
|
||||
texture1.baseTexture.on('loaded', (e) => {
|
||||
texture1.baseTexture.on('loaded', e => {
|
||||
let sprite1 = new PIXI.Sprite(texture1)
|
||||
sprite1.scale.set(0.05, 0.05)
|
||||
sprite1.alpha = 0.5
|
||||
@ -136,7 +145,14 @@
|
||||
})
|
||||
|
||||
app.scene.addChild(circle1, circle2)
|
||||
app.scene.addChild(button1, button2, button3, button4, button5, button6)
|
||||
app.scene.addChild(
|
||||
button1,
|
||||
button2,
|
||||
button3,
|
||||
button4,
|
||||
button5,
|
||||
button6
|
||||
)
|
||||
app.scene.addChild(badge1, badge2, badge3)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -50,7 +50,7 @@ export default class Badge extends AbstractPopup {
|
||||
minWidth: 0,
|
||||
minHeight: 0,
|
||||
padding: theme.padding / 2,
|
||||
tooltip: null,
|
||||
tooltip: null
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -84,7 +84,7 @@ export default class Badge extends AbstractPopup {
|
||||
if (typeof this.opts.tooltip === 'string') {
|
||||
this.tooltip = new Tooltip({
|
||||
object: this,
|
||||
content: this.opts.tooltip,
|
||||
content: this.opts.tooltip
|
||||
})
|
||||
} else {
|
||||
this.opts.tooltip = Object.assign({}, { object: this }, this.opts.tooltip)
|
||||
|
||||
|
Before Width: | Height: | Size: 506 KiB |
@ -1,51 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI BlurFilter</title>
|
||||
<title>PIXI BlurFilter</title>
|
||||
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>BlurFilter</h1>
|
||||
<p>
|
||||
The BlurFilter class creates a blur filter on the renderer. In contrast to the PIXI BlurFilter, you can
|
||||
specify a range (defined as a PIXI.Rectangle) on which the filter should be applied.
|
||||
</p>
|
||||
<h2>Example with Image</h2>
|
||||
<p>Let's look at an example of creating a new blur filter near the bottom:</p>
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: A sniffing hedgehog and three blurred areas (with different strengths of blur).</p>
|
||||
<script class="doctest">
|
||||
// Create the app
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 480,
|
||||
height: 270,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>BlurFilter</h1>
|
||||
<p>
|
||||
The BlurFilter class creates a blur filter on the renderer. In contrast to the PIXI BlurFilter, you can specify
|
||||
a range (defined as a PIXI.Rectangle) on which the filter should be applied.
|
||||
</p>
|
||||
<h2>Example with Image</h2>
|
||||
<p>Let's look at an example of creating a new blur filter near the bottom:</p>
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: A sniffing hedgehog and three blurred areas (with different strengths of blur).
|
||||
</p>
|
||||
<script class="doctest">
|
||||
// Create the app
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 480,
|
||||
height: 270,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
// Load a video and add it to the scene
|
||||
const videoSprite = new PIXI.Sprite(PIXI.Texture.from('assets/blurfilter.mp4'))
|
||||
videoSprite.width = app.size.width
|
||||
videoSprite.height = app.size.height
|
||||
app.scene.addChild(videoSprite)
|
||||
// Load a video and add it to the scene
|
||||
const videoSprite = new PIXI.Sprite(PIXI.Texture.from("assets/blurfilter.mp4"))
|
||||
videoSprite.width = app.size.width
|
||||
videoSprite.height = app.size.height
|
||||
app.scene.addChild(videoSprite)
|
||||
|
||||
// Create three filters and assign them to the scene
|
||||
const blurFilter1 = new BlurFilter(new PIXI.Rectangle(40, 40, 120, 80))
|
||||
const blurFilter2 = new BlurFilter(new PIXI.Circle(240, 140, 60), 150)
|
||||
const blurFilter3 = new BlurFilter(new PIXI.Rectangle(380, 40, 100, 100), 20)
|
||||
app.scene.filters = [blurFilter1, blurFilter2, blurFilter3]
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
// Create three filters and assign them to the scene
|
||||
const blurFilter1 = new BlurFilter(new PIXI.Rectangle(40, 40, 120, 80))
|
||||
const blurFilter2 = new BlurFilter(new PIXI.Circle(240, 140, 60), 150)
|
||||
const blurFilter3 = new BlurFilter(new PIXI.Rectangle(380, 40, 100, 100), 20)
|
||||
app.scene.filters = [blurFilter1, blurFilter2, blurFilter3]
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -93,7 +93,7 @@ export default class BlurFilter extends PIXI.Filter {
|
||||
x: value.x,
|
||||
y: value.y,
|
||||
width: value.width,
|
||||
height: value.height,
|
||||
height: value.height
|
||||
}
|
||||
} else {
|
||||
const bounds = value.getBounds()
|
||||
@ -102,7 +102,7 @@ export default class BlurFilter extends PIXI.Filter {
|
||||
x: bounds.x,
|
||||
y: bounds.y,
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
height: bounds.height
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
@ -76,7 +76,7 @@ import Mercator from './maps/projections/mercator.js'
|
||||
import Robinson from './maps/projections/robinson.js'
|
||||
window.Projection = {
|
||||
Mercator,
|
||||
Robinson,
|
||||
Robinson
|
||||
}
|
||||
|
||||
import MapViewport from './maps/mapviewport.js'
|
||||
@ -91,7 +91,7 @@ import {
|
||||
RigidContainer,
|
||||
CompactScatter,
|
||||
CoverScatter,
|
||||
MapObjectScatter,
|
||||
MapObjectScatter
|
||||
} from './maps/scatter.js'
|
||||
|
||||
window.AdvancedScatterContainer = AdvancedScatterContainer
|
||||
|
||||
@ -1,445 +1,338 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Button</title>
|
||||
<title>PIXI Button</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Button</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms,
|
||||
dialogs, and more with support for multiple sizes, states, and more. Buttons will appear pressed when
|
||||
active. Make buttons look inactive by setting the disabled state to true. To allow changing the state
|
||||
between active/inactive, set the button type to "checkbox".
|
||||
</p>
|
||||
<p><a href="../../doc/out/Button.html">JavaScript API</a></p>
|
||||
<p>Let's look at some button examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many buttons with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 600,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Button</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms, dialogs,
|
||||
and more with support for multiple sizes, states, and more. Buttons will appear pressed when active. Make
|
||||
buttons look inactive by setting the disabled state to true. To allow changing the state between active/inactive, set
|
||||
the button type to "checkbox".
|
||||
</p>
|
||||
<p><a href="../../doc/out/Button.html">JavaScript API</a></p>
|
||||
<p>Let's look at some button examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many buttons with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 600,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
const button1 = new Button({ x: 10, y: 10 })
|
||||
const button1 = new Button({x: 10, y: 10})
|
||||
|
||||
const button2 = new Button({
|
||||
theme: 'red',
|
||||
x: 60,
|
||||
y: 10,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
action: (e) => {
|
||||
console.info('Button clicked')
|
||||
}
|
||||
})
|
||||
const button2 = new Button({
|
||||
theme: 'red',
|
||||
x: 60,
|
||||
y: 10,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
action: e => {
|
||||
console.info('Button clicked')
|
||||
}
|
||||
})
|
||||
|
||||
const button3 = new Button({
|
||||
x: 150,
|
||||
y: 10,
|
||||
label: 'Checkbox button',
|
||||
type: 'checkbox',
|
||||
action: (e) => {
|
||||
console.info('Button clicked', e)
|
||||
}
|
||||
})
|
||||
const button3 = new Button({
|
||||
x: 150,
|
||||
y: 10,
|
||||
label: 'Checkbox button',
|
||||
type: 'checkbox',
|
||||
action: e => {
|
||||
console.info('Button clicked', e)
|
||||
}
|
||||
})
|
||||
|
||||
const button4 = new Button({
|
||||
x: 330,
|
||||
y: 10,
|
||||
label: 'Disabled button',
|
||||
disabled: true,
|
||||
action: (e) => {
|
||||
console.info('Disabled button clicked')
|
||||
}
|
||||
})
|
||||
const button4 = new Button({
|
||||
x: 330,
|
||||
y: 10,
|
||||
label: 'Disabled button',
|
||||
disabled: true,
|
||||
action: e => {
|
||||
console.info('Disabled button clicked')
|
||||
}
|
||||
})
|
||||
|
||||
const button5 = new Button({
|
||||
x: 500,
|
||||
y: 10,
|
||||
label: 'Active button',
|
||||
active: true
|
||||
})
|
||||
const button5 = new Button({
|
||||
x: 500,
|
||||
y: 10,
|
||||
label: 'Active button',
|
||||
active: true
|
||||
})
|
||||
|
||||
const button6 = new Button({
|
||||
x: 650,
|
||||
y: 10,
|
||||
label: 'Active disabled button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
disabled: true
|
||||
})
|
||||
const button6 = new Button({
|
||||
x: 650,
|
||||
y: 10,
|
||||
label: 'Active disabled button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
disabled: true
|
||||
})
|
||||
|
||||
const button7 = new Button({
|
||||
x: 10,
|
||||
y: 70,
|
||||
label: 'Icon button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
icon: 'arrow_back'
|
||||
})
|
||||
const button7 = new Button({
|
||||
x: 10,
|
||||
y: 70,
|
||||
label: 'Icon button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
icon: 'arrow_back'
|
||||
})
|
||||
|
||||
const button8 = new Button({
|
||||
x: 180,
|
||||
y: 70,
|
||||
theme: 'light',
|
||||
label: 'Icon button',
|
||||
icon: 'arrow_forward',
|
||||
type: 'checkbox',
|
||||
iconPosition: 'right'
|
||||
})
|
||||
const button8 = new Button({
|
||||
x: 180,
|
||||
y: 70,
|
||||
theme: 'light',
|
||||
label: 'Icon button',
|
||||
icon: 'arrow_forward',
|
||||
type: 'checkbox',
|
||||
iconPosition: 'right'
|
||||
})
|
||||
|
||||
const button9 = new Button({
|
||||
x: 10,
|
||||
y: 130,
|
||||
type: 'checkbox',
|
||||
icon: 'play_arrow',
|
||||
iconActive: 'pause'
|
||||
})
|
||||
const button9 = new Button({
|
||||
x: 10,
|
||||
y: 130,
|
||||
type: 'checkbox',
|
||||
icon: 'play_arrow',
|
||||
iconActive: 'pause'
|
||||
})
|
||||
|
||||
const button10 = new Button({
|
||||
x: 60,
|
||||
y: 130,
|
||||
icon: 'stop',
|
||||
action: function () {
|
||||
this.iconColor = Math.round(Math.random() * 16777215)
|
||||
}
|
||||
})
|
||||
const button10 = new Button({
|
||||
x: 60,
|
||||
y: 130,
|
||||
icon: 'stop',
|
||||
action: function() {
|
||||
this.iconColor = Math.round(Math.random() * 16777215)
|
||||
}
|
||||
})
|
||||
|
||||
const button11 = new Button({
|
||||
x: 110,
|
||||
y: 130,
|
||||
icon: 'star_border',
|
||||
tooltip: 'Bookmark'
|
||||
})
|
||||
const button11 = new Button({
|
||||
x: 110,
|
||||
y: 130,
|
||||
icon: 'star_border',
|
||||
tooltip: 'Bookmark'
|
||||
})
|
||||
|
||||
const button12 = new Button({
|
||||
x: 10,
|
||||
y: 190,
|
||||
icon: 'airplay',
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
iconColor: 0xdd0000,
|
||||
iconColorActive: 0x00dd00,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0,
|
||||
type: 'checkbox'
|
||||
})
|
||||
const button12 = new Button({
|
||||
x: 10,
|
||||
y: 190,
|
||||
icon: 'airplay',
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
iconColor: 0xdd0000,
|
||||
iconColorActive: 0x00dd00,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0,
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
const button13 = new Button({
|
||||
x: 50,
|
||||
y: 190,
|
||||
label: 'Button',
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0,
|
||||
textStyle: {
|
||||
fontSize: 20,
|
||||
stroke: 'brown',
|
||||
fill: 'orange',
|
||||
strokeThickness: 4,
|
||||
miterLimit: 1,
|
||||
letterSpacing: 6
|
||||
},
|
||||
textStyleActive: {
|
||||
fontSize: 20,
|
||||
stroke: 'orange',
|
||||
fill: 'brown',
|
||||
strokeThickness: 4,
|
||||
fontWeight: 'bold',
|
||||
miterLimit: 1,
|
||||
letterSpacing: 5
|
||||
},
|
||||
type: 'checkbox'
|
||||
})
|
||||
const button13 = new Button({
|
||||
x: 50,
|
||||
y: 190,
|
||||
label: 'Button',
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0,
|
||||
textStyle: {
|
||||
fontSize: 20,
|
||||
stroke: 'brown',
|
||||
fill: 'orange',
|
||||
strokeThickness: 4,
|
||||
miterLimit: 1,
|
||||
letterSpacing: 6
|
||||
},
|
||||
textStyleActive: {
|
||||
fontSize: 20,
|
||||
stroke: 'orange',
|
||||
fill: 'brown',
|
||||
strokeThickness: 4,
|
||||
fontWeight: 'bold',
|
||||
miterLimit: 1,
|
||||
letterSpacing: 5
|
||||
},
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
const button14 = new Button({
|
||||
x: 10,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: null,
|
||||
iconActive: 'add_circle'
|
||||
})
|
||||
const button14 = new Button({
|
||||
x: 10,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: null,
|
||||
iconActive: 'add_circle'
|
||||
})
|
||||
|
||||
const button15 = new Button({
|
||||
x: 200,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: 'add_circle',
|
||||
iconActive: null
|
||||
})
|
||||
const button15 = new Button({
|
||||
x: 200,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: 'add_circle',
|
||||
iconActive: null
|
||||
})
|
||||
|
||||
const button16 = new Button({
|
||||
x: 400,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: null,
|
||||
iconActive: 'add_circle',
|
||||
active: true
|
||||
})
|
||||
const button16 = new Button({
|
||||
x: 400,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: null,
|
||||
iconActive: 'add_circle',
|
||||
active: true
|
||||
})
|
||||
|
||||
const button17 = new Button({
|
||||
x: 600,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: 'add_circle',
|
||||
iconActive: null,
|
||||
active: true
|
||||
})
|
||||
const button17 = new Button({
|
||||
x: 600,
|
||||
y: 250,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: 'add_circle',
|
||||
iconActive: null,
|
||||
active: true
|
||||
})
|
||||
|
||||
let graphic1 = new PIXI.Graphics()
|
||||
graphic1.beginFill(0xd7a3f9)
|
||||
graphic1.drawCircle(10, 10, 10)
|
||||
let graphic1 = new PIXI.Graphics()
|
||||
graphic1.beginFill(0xd7a3f9)
|
||||
graphic1.drawCircle(10, 10, 10)
|
||||
|
||||
let graphic2 = new PIXI.Graphics()
|
||||
graphic2.beginFill(0x40c3f2)
|
||||
graphic2.drawCircle(30, 30, 30)
|
||||
let graphic2 = new PIXI.Graphics()
|
||||
graphic2.beginFill(0x40c3f2)
|
||||
graphic2.drawCircle(30, 30, 30)
|
||||
|
||||
const button18 = new Button({
|
||||
x: 10,
|
||||
y: 310,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: graphic1,
|
||||
iconActive: graphic2
|
||||
})
|
||||
const button18 = new Button({
|
||||
x: 10,
|
||||
y: 310,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: graphic1,
|
||||
iconActive: graphic2
|
||||
})
|
||||
|
||||
let graphic3 = new PIXI.Graphics()
|
||||
graphic3.beginFill(0xfd6b6a)
|
||||
graphic3.drawCircle(2, 2, 2)
|
||||
let graphic3 = new PIXI.Graphics()
|
||||
graphic3.beginFill(0xfd6b6a)
|
||||
graphic3.drawCircle(2, 2, 2)
|
||||
|
||||
let graphic4 = new PIXI.Graphics()
|
||||
graphic4.beginFill(0xf8ce2d)
|
||||
graphic4.drawCircle(40, 40, 40)
|
||||
let graphic4 = new PIXI.Graphics()
|
||||
graphic4.beginFill(0xf8ce2d)
|
||||
graphic4.drawCircle(40, 40, 40)
|
||||
|
||||
const button19 = new Button({
|
||||
x: 200,
|
||||
y: 310,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: graphic3,
|
||||
iconActive: graphic4,
|
||||
active: true,
|
||||
iconPosition: 'right'
|
||||
})
|
||||
const button19 = new Button({
|
||||
x: 200,
|
||||
y: 310,
|
||||
label: 'Button',
|
||||
type: 'checkbox',
|
||||
icon: graphic3,
|
||||
iconActive: graphic4,
|
||||
active: true,
|
||||
iconPosition: 'right'
|
||||
})
|
||||
|
||||
const button20 = new Button({
|
||||
x: 400,
|
||||
y: 310,
|
||||
label: 'Link Button',
|
||||
type: 'checkbox',
|
||||
style: 'link',
|
||||
action: (event) => {
|
||||
console.log('Link button clicked')
|
||||
}
|
||||
})
|
||||
const button20 = new Button({
|
||||
x: 400,
|
||||
y: 310,
|
||||
label: 'Link Button',
|
||||
type: 'checkbox',
|
||||
style: 'link',
|
||||
action: event => {
|
||||
console.log('Link button clicked')
|
||||
}
|
||||
})
|
||||
|
||||
const button21 = new Button({
|
||||
x: 600,
|
||||
y: 310,
|
||||
minWidth: 70,
|
||||
minHeight: 70,
|
||||
icon: 'loop',
|
||||
type: 'checkbox',
|
||||
style: 'link'
|
||||
})
|
||||
const button21 = new Button({
|
||||
x: 600,
|
||||
y: 310,
|
||||
minWidth: 70,
|
||||
minHeight: 70,
|
||||
icon: 'loop',
|
||||
type: 'checkbox',
|
||||
style: 'link'
|
||||
})
|
||||
|
||||
const button22 = new Button({
|
||||
x: 10,
|
||||
y: 440,
|
||||
icon: 'play_arrow',
|
||||
badge: '19'
|
||||
})
|
||||
const button22 = new Button({
|
||||
x: 10,
|
||||
y: 440,
|
||||
icon: 'play_arrow',
|
||||
badge: '19'
|
||||
})
|
||||
|
||||
const button23 = new Button({
|
||||
x: 100,
|
||||
y: 440,
|
||||
icon: 'stop',
|
||||
badge: 'Stop'
|
||||
})
|
||||
const button23 = new Button({
|
||||
x: 100,
|
||||
y: 440,
|
||||
icon: 'stop',
|
||||
badge: 'Stop'
|
||||
})
|
||||
|
||||
const button24 = new Button({
|
||||
x: 200,
|
||||
y: 440,
|
||||
icon: 'star_border',
|
||||
badge: {
|
||||
content: 'Bookmark',
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom',
|
||||
offsetTop: 8,
|
||||
radius: 14,
|
||||
fill: 0xfe832d
|
||||
}
|
||||
})
|
||||
const button24 = new Button({
|
||||
x: 200,
|
||||
y: 440,
|
||||
icon: 'star_border',
|
||||
badge: {
|
||||
content: 'Bookmark',
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom',
|
||||
offsetTop: 8,
|
||||
radius: 14,
|
||||
fill: 0xfe832d
|
||||
}
|
||||
})
|
||||
|
||||
const button25 = new Button({
|
||||
x: 300,
|
||||
y: 460,
|
||||
icon: 'add',
|
||||
badge: {
|
||||
content: 'Sweden',
|
||||
align: 'center',
|
||||
verticalAlign: 'top',
|
||||
offsetTop: -20,
|
||||
radius: 12,
|
||||
fill: 0x5856d6
|
||||
}
|
||||
})
|
||||
const button25 = new Button({
|
||||
x: 300,
|
||||
y: 460,
|
||||
icon: 'add',
|
||||
badge: {
|
||||
content: 'Sweden',
|
||||
align: 'center',
|
||||
verticalAlign: 'top',
|
||||
offsetTop: -20,
|
||||
radius: 12,
|
||||
fill: 0x5856d6
|
||||
}
|
||||
})
|
||||
|
||||
const countries = [
|
||||
'Tajikistan',
|
||||
'Zambia',
|
||||
'Dominica',
|
||||
'Australia',
|
||||
'Botswana',
|
||||
'Mozambique',
|
||||
'Lesotho',
|
||||
'Thailand',
|
||||
'Gabon',
|
||||
'Cuba',
|
||||
'Mexico',
|
||||
'Central African Republic',
|
||||
'Réunion',
|
||||
'Montenegro',
|
||||
'Romania',
|
||||
'Jamaica',
|
||||
'Thailand',
|
||||
'Cameroon',
|
||||
'French Guiana',
|
||||
'Nigeria',
|
||||
'Tokelau',
|
||||
'Slovenia',
|
||||
'Kuwait',
|
||||
'Palestinian Territories',
|
||||
'Estonia',
|
||||
'Germany',
|
||||
'Cameroon',
|
||||
'Somalia',
|
||||
'El Salvador',
|
||||
'San Marino',
|
||||
'Sierra Leone',
|
||||
'Sierra Leone',
|
||||
'Gibraltar',
|
||||
'Benin',
|
||||
'Russia',
|
||||
'Iraq',
|
||||
'Tunisia',
|
||||
'Greenland',
|
||||
"Côte d'Ivoire",
|
||||
'Tanzania',
|
||||
'Zambia',
|
||||
'Bermuda',
|
||||
'Somalia',
|
||||
'Malaysia',
|
||||
'Croatia',
|
||||
'Togo',
|
||||
'Belgium',
|
||||
'Uruguay',
|
||||
'Equatorial Guinea',
|
||||
'Nigeria',
|
||||
'St. Martin',
|
||||
'Tuvalu',
|
||||
'South Africa',
|
||||
'Hong Kong SAR China',
|
||||
'Palau',
|
||||
'Canary Islands',
|
||||
'Algeria',
|
||||
'Hong Kong SAR China',
|
||||
'Brunei',
|
||||
'Dominican Republic',
|
||||
'Sierra Leone',
|
||||
'Moldova',
|
||||
'Indonesia',
|
||||
'Central African Republic',
|
||||
'Anguilla',
|
||||
'Malaysia',
|
||||
'Bahrain',
|
||||
'Indonesia',
|
||||
'Peru',
|
||||
'Namibia',
|
||||
'Congo - Brazzaville',
|
||||
'Micronesia',
|
||||
'Cambodia',
|
||||
'Réunion',
|
||||
'Honduras',
|
||||
'Hungary',
|
||||
'Brazil',
|
||||
'Trinidad & Tobago',
|
||||
'Hungary',
|
||||
'Madagascar',
|
||||
'Sierra Leone',
|
||||
'Seychelles',
|
||||
'St. Martin',
|
||||
'New Caledonia',
|
||||
'Tokelau',
|
||||
'Macedonia',
|
||||
'Netherlands',
|
||||
'Panama',
|
||||
'Venezuela',
|
||||
'Nepal',
|
||||
'Guernsey',
|
||||
'Papua New Guinea',
|
||||
'Finland',
|
||||
'Malaysia',
|
||||
'Hong Kong SAR China',
|
||||
'Trinidad & Tobago',
|
||||
'Montserrat',
|
||||
'Comoros',
|
||||
'Benin',
|
||||
'South Korea',
|
||||
'Peru',
|
||||
'Botswana',
|
||||
'Cambodia',
|
||||
'Isle of Man',
|
||||
'Mozambique'
|
||||
]
|
||||
setInterval(() => {
|
||||
button25.badge.content = countries[Math.floor(Math.random() * countries.length)]
|
||||
button25.layout()
|
||||
}, 1000)
|
||||
const countries = ['Tajikistan', 'Zambia', 'Dominica', 'Australia', 'Botswana', 'Mozambique', 'Lesotho', 'Thailand', 'Gabon', 'Cuba', 'Mexico', 'Central African Republic', 'Réunion', 'Montenegro', 'Romania', 'Jamaica', 'Thailand', 'Cameroon', 'French Guiana', 'Nigeria', 'Tokelau', 'Slovenia', 'Kuwait', 'Palestinian Territories', 'Estonia', 'Germany', 'Cameroon', 'Somalia', 'El Salvador', 'San Marino', 'Sierra Leone', 'Sierra Leone', 'Gibraltar', 'Benin', 'Russia', 'Iraq', 'Tunisia', 'Greenland', 'Côte d\'Ivoire', 'Tanzania', 'Zambia', 'Bermuda', 'Somalia', 'Malaysia', 'Croatia', 'Togo', 'Belgium', 'Uruguay', 'Equatorial Guinea', 'Nigeria', 'St. Martin', 'Tuvalu', 'South Africa', 'Hong Kong SAR China', 'Palau', 'Canary Islands', 'Algeria', 'Hong Kong SAR China', 'Brunei', 'Dominican Republic', 'Sierra Leone', 'Moldova', 'Indonesia', 'Central African Republic', 'Anguilla', 'Malaysia', 'Bahrain', 'Indonesia', 'Peru', 'Namibia', 'Congo - Brazzaville', 'Micronesia', 'Cambodia', 'Réunion', 'Honduras', 'Hungary', 'Brazil', 'Trinidad & Tobago', 'Hungary', 'Madagascar', 'Sierra Leone', 'Seychelles', 'St. Martin', 'New Caledonia', 'Tokelau', 'Macedonia', 'Netherlands', 'Panama', 'Venezuela', 'Nepal', 'Guernsey', 'Papua New Guinea', 'Finland', 'Malaysia', 'Hong Kong SAR China', 'Trinidad & Tobago', 'Montserrat', 'Comoros', 'Benin', 'South Korea', 'Peru', 'Botswana', 'Cambodia', 'Isle of Man', 'Mozambique']
|
||||
setInterval(() => {
|
||||
button25.badge.content = countries[Math.floor(Math.random() * countries.length)]
|
||||
button25.layout()
|
||||
}, 1000)
|
||||
|
||||
const button26 = new Button({
|
||||
x: 10,
|
||||
y: 520,
|
||||
label: 'add',
|
||||
type: 'checkbox',
|
||||
strokeActive: 0x28a745,
|
||||
textStyleActive: {
|
||||
fill: 0x28a745
|
||||
},
|
||||
textAlpha: 0.2,
|
||||
textActiveAlpha: 0.6
|
||||
})
|
||||
const button26 = new Button({
|
||||
x: 10,
|
||||
y: 520,
|
||||
label: 'add',
|
||||
type: 'checkbox',
|
||||
strokeActive: 0x28a745,
|
||||
textStyleActive: {
|
||||
fill: 0x28a745
|
||||
},
|
||||
textAlpha: .2,
|
||||
textActiveAlpha: .6
|
||||
})
|
||||
|
||||
app.scene.addChild(button1, button2, button3, button4, button5, button6)
|
||||
app.scene.addChild(button7, button8)
|
||||
app.scene.addChild(button9, button10, button11)
|
||||
app.scene.addChild(button12, button13)
|
||||
app.scene.addChild(button14, button15, button16, button17)
|
||||
app.scene.addChild(button18, button19, button20, button21)
|
||||
app.scene.addChild(button22, button23, button24, button25)
|
||||
app.scene.addChild(button26)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(button1, button2, button3, button4, button5, button6)
|
||||
app.scene.addChild(button7, button8)
|
||||
app.scene.addChild(button9, button10, button11)
|
||||
app.scene.addChild(button12, button13)
|
||||
app.scene.addChild(button14, button15, button16, button17)
|
||||
app.scene.addChild(button18, button19, button20, button21)
|
||||
app.scene.addChild(button22, button23, button24, button25)
|
||||
app.scene.addChild(button26)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -156,7 +156,7 @@ export default class Button extends PIXI.Container {
|
||||
verticalAlign: 'middle',
|
||||
tooltip: null,
|
||||
badge: null,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -177,7 +177,7 @@ export default class Button extends PIXI.Container {
|
||||
strokeAlpha: this.HIDDEN_ALPHA,
|
||||
strokeActiveAlpha: this.HIDDEN_ALPHA,
|
||||
fillAlpha: this.HIDDEN_ALPHA,
|
||||
fillActiveAlpha: this.HIDDEN_ALPHA,
|
||||
fillActiveAlpha: this.HIDDEN_ALPHA
|
||||
})
|
||||
}
|
||||
|
||||
@ -249,15 +249,15 @@ export default class Button extends PIXI.Container {
|
||||
|
||||
// interaction
|
||||
//-----------------
|
||||
this.button.on('pointerover', (e) => {
|
||||
this.button.on('pointerover', e => {
|
||||
this.capture(e)
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.83,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
this.button.on('pointermove', (e) => {
|
||||
this.button.on('pointermove', e => {
|
||||
this.capture(e)
|
||||
})
|
||||
|
||||
@ -268,17 +268,17 @@ export default class Button extends PIXI.Container {
|
||||
this.button.on('scroll', this.onEnd.bind(this))
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.button.on('pointerdown', (e) => {
|
||||
this.button.on('pointerdown', e => {
|
||||
//this.capture(e)
|
||||
this.__start.x = e.data.global.x
|
||||
this.__start.y = e.data.global.y
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.7,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
this.button.on('pointerup', (e) => {
|
||||
this.button.on('pointerup', e => {
|
||||
this.capture(e)
|
||||
|
||||
const distance = Points.distance(e.data.global, this.__start)
|
||||
@ -290,7 +290,7 @@ export default class Button extends PIXI.Container {
|
||||
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.83,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
|
||||
if (this.opts.type === 'checkbox') {
|
||||
@ -321,7 +321,7 @@ export default class Button extends PIXI.Container {
|
||||
if (typeof this.opts.tooltip === 'string') {
|
||||
this.tooltip = new Tooltip({
|
||||
object: this,
|
||||
content: this.opts.tooltip,
|
||||
content: this.opts.tooltip
|
||||
})
|
||||
} else {
|
||||
this.opts.tooltip = Object.assign({}, { object: this }, this.opts.tooltip)
|
||||
@ -338,7 +338,7 @@ export default class Button extends PIXI.Container {
|
||||
align: 'right',
|
||||
verticalAlign: 'top',
|
||||
offsetLeft: 0,
|
||||
offsetTop: 0,
|
||||
offsetTop: 0
|
||||
}
|
||||
)
|
||||
if (typeof this.opts.badge === 'string') {
|
||||
@ -716,7 +716,7 @@ export default class Button extends PIXI.Container {
|
||||
this.capture(event)
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 1,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 509 KiB |
@ -1,390 +1,375 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-eqv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-eqv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI ButtonGroup</title>
|
||||
<title>PIXI ButtonGroup</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/gsap/src/uncompressed/plugins/ThrowPropsPlugin.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/gsap/src/uncompressed/plugins/ThrowPropsPlugin.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>ButtonGroup</h1>
|
||||
<p>Group a series of buttons together on a single line with the button group.</p>
|
||||
<p><a href="../../doc/out/ButtonGroup.html">JavaScript API</a></p>
|
||||
<p>Let's look at some button groups:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many button groups with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 1000,
|
||||
height: 1700
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>ButtonGroup</h1>
|
||||
<p>
|
||||
Group a series of buttons together on a single line with the button group.
|
||||
</p>
|
||||
<p><a href="../../doc/out/ButtonGroup.html">JavaScript API</a></p>
|
||||
<p>Let's look at some button groups:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many button groups with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 1000,
|
||||
height: 1700
|
||||
}).setup().run()
|
||||
|
||||
const buttonGroup1 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{ icon: 'keyboard_arrow_left' },
|
||||
{ icon: 'keyboard_arrow_up' },
|
||||
{ icon: 'keyboard_arrow_down' },
|
||||
{ icon: 'keyboard_arrow_right' }
|
||||
]
|
||||
})
|
||||
const buttonGroup1 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{icon: 'keyboard_arrow_left'},
|
||||
{icon: 'keyboard_arrow_up'},
|
||||
{icon: 'keyboard_arrow_down'},
|
||||
{icon: 'keyboard_arrow_right'}
|
||||
]
|
||||
})
|
||||
|
||||
const buttonGroup2 = new ButtonGroup({
|
||||
x: 260,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{ icon: 'directions_walk', tooltip: 'Gehen' },
|
||||
{ icon: 'directions_run', tooltip: 'Laufen' },
|
||||
{ icon: 'directions_bike', tooltip: 'Fahrrad' },
|
||||
{ icon: 'directions_bus', tooltip: 'Bus' },
|
||||
{ icon: 'directions_car', tooltip: 'Auto' },
|
||||
{ icon: 'directions_boat', tooltip: 'Schiff' },
|
||||
{ icon: 'directions_railway', tooltip: 'Bahn' }
|
||||
],
|
||||
margin: 0,
|
||||
stroke: 0x0088ff,
|
||||
strokeWidth: 3
|
||||
})
|
||||
const buttonGroup2 = new ButtonGroup({
|
||||
x: 260,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{icon: 'directions_walk', tooltip: 'Gehen'},
|
||||
{icon: 'directions_run', tooltip: 'Laufen'},
|
||||
{icon: 'directions_bike', tooltip: 'Fahrrad'},
|
||||
{icon: 'directions_bus', tooltip: 'Bus'},
|
||||
{icon: 'directions_car', tooltip: 'Auto'},
|
||||
{icon: 'directions_boat', tooltip: 'Schiff'},
|
||||
{icon: 'directions_railway', tooltip: 'Bahn'}
|
||||
],
|
||||
margin: 0,
|
||||
stroke: 0x0088ff,
|
||||
strokeWidth: 3
|
||||
})
|
||||
|
||||
const buttonGroup3 = new ButtonGroup({
|
||||
x: 610,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{ icon: 'laptop' },
|
||||
{ label: 'Linux' },
|
||||
{ icon: 'laptop_windows', label: 'Windows', align: 'center' },
|
||||
{ icon: 'laptop_mac', iconPosition: 'right', label: 'macOS' }
|
||||
],
|
||||
margin: 0,
|
||||
stroke: 0xffffff,
|
||||
strokeWidth: 1
|
||||
})
|
||||
const buttonGroup3 = new ButtonGroup({
|
||||
x: 610,
|
||||
y: 10,
|
||||
buttons: [
|
||||
{icon: 'laptop'},
|
||||
{label: 'Linux'},
|
||||
{icon: 'laptop_windows', label: 'Windows', align: 'center'},
|
||||
{icon: 'laptop_mac', iconPosition: 'right', label: 'macOS'}
|
||||
],
|
||||
margin: 0,
|
||||
stroke: 0xffffff,
|
||||
strokeWidth: 1
|
||||
})
|
||||
|
||||
const buttonGroup4 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 90,
|
||||
buttons: [
|
||||
{ label: 'Button 1', action: (event, button) => console.log(button.id) },
|
||||
{ label: 'Button 2', action: (event, button) => console.log(button.id), radius: 0 },
|
||||
{
|
||||
label: 'Button 3',
|
||||
textStyle: { fill: '#fd6b6a' },
|
||||
stroke: 0xd7a3f9,
|
||||
strokeWidth: 8,
|
||||
strokeAlpha: 0.8
|
||||
},
|
||||
{
|
||||
label: 'Button 4',
|
||||
textStyle: { fill: '#40c3f2' },
|
||||
radius: 20,
|
||||
icon: 'looks',
|
||||
iconPosition: 'right',
|
||||
iconColor: 0xd7ff30
|
||||
}
|
||||
],
|
||||
margin: 40,
|
||||
minWidth: 180,
|
||||
minHeight: 60,
|
||||
textStyle: {
|
||||
fill: '#f8ce2d'
|
||||
},
|
||||
stroke: 0xffffff,
|
||||
strokeWidth: 1
|
||||
})
|
||||
const buttonGroup4 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 90,
|
||||
buttons: [
|
||||
{label: 'Button 1', action: (event, button) => console.log(button.id)},
|
||||
{label: 'Button 2', action: (event, button) => console.log(button.id), radius: 0},
|
||||
{label: 'Button 3', textStyle: {fill: '#fd6b6a'}, stroke: 0xd7a3f9, strokeWidth: 8, strokeAlpha: .8},
|
||||
{label: 'Button 4', textStyle: {fill: '#40c3f2'}, radius: 20, icon: 'looks', iconPosition: 'right', iconColor: 0xd7ff30}
|
||||
],
|
||||
margin: 40,
|
||||
minWidth: 180,
|
||||
minHeight: 60,
|
||||
textStyle: {
|
||||
fill: '#f8ce2d'
|
||||
},
|
||||
stroke: 0xffffff,
|
||||
strokeWidth: 1
|
||||
})
|
||||
|
||||
const buttonGroup5 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 180,
|
||||
buttons: [
|
||||
{ label: 'ButtonGroup' },
|
||||
{ label: 'of', active: true },
|
||||
{ label: 'type' },
|
||||
{ minWidth: 30, style: 'link' },
|
||||
{ label: 'checkbox', active: true }
|
||||
],
|
||||
margin: 6,
|
||||
type: 'checkbox'
|
||||
})
|
||||
const buttonGroup5 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 180,
|
||||
buttons: [
|
||||
{label: 'ButtonGroup'},
|
||||
{label: 'of', active: true},
|
||||
{label: 'type'},
|
||||
{minWidth: 30, style: 'link'},
|
||||
{label: 'checkbox', active: true}
|
||||
],
|
||||
margin: 6,
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
const buttonGroup6 = new ButtonGroup({
|
||||
x: 450,
|
||||
y: 180,
|
||||
buttons: [
|
||||
{ label: 'ButtonGroup' },
|
||||
{ label: 'of' },
|
||||
{ label: 'type', active: true },
|
||||
{ label: 'radio' }
|
||||
],
|
||||
margin: 0,
|
||||
type: 'radio'
|
||||
})
|
||||
const buttonGroup6 = new ButtonGroup({
|
||||
x: 450,
|
||||
y: 180,
|
||||
buttons: [
|
||||
{label: 'ButtonGroup'},
|
||||
{label: 'of'},
|
||||
{label: 'type', active: true},
|
||||
{label: 'radio'}
|
||||
],
|
||||
margin: 0,
|
||||
type: 'radio'
|
||||
})
|
||||
|
||||
const buttonGroup7 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 250,
|
||||
theme: 'light',
|
||||
buttons: [
|
||||
{ label: 'ButtonGroup' },
|
||||
{ label: 'of' },
|
||||
{ label: 'style' },
|
||||
{ label: 'link' },
|
||||
{ label: 'with' },
|
||||
{ label: 'one exception', style: 'default' }
|
||||
],
|
||||
style: 'link'
|
||||
})
|
||||
const buttonGroup7 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 250,
|
||||
theme: 'light',
|
||||
buttons: [
|
||||
{label: 'ButtonGroup'},
|
||||
{label: 'of'},
|
||||
{label: 'style'},
|
||||
{label: 'link'},
|
||||
{label: 'with'},
|
||||
{label: 'one exception', style: 'default'}
|
||||
],
|
||||
style: 'link'
|
||||
})
|
||||
|
||||
const buttonGroup8 = new ButtonGroup({
|
||||
x: 610,
|
||||
y: 250,
|
||||
buttons: [
|
||||
{ icon: 'airline_seat_legroom_extra' },
|
||||
{ icon: 'airline_seat_legroom_normal' },
|
||||
{ icon: 'airline_seat_legroom_reduced' },
|
||||
{ icon: 'wifi_tethering', type: 'checkbox' }
|
||||
],
|
||||
type: 'radio',
|
||||
margin: 0
|
||||
})
|
||||
const buttonGroup8 = new ButtonGroup({
|
||||
x: 610,
|
||||
y: 250,
|
||||
buttons: [
|
||||
{icon: 'airline_seat_legroom_extra'},
|
||||
{icon: 'airline_seat_legroom_normal'},
|
||||
{icon: 'airline_seat_legroom_reduced'},
|
||||
{icon: 'wifi_tethering', type: 'checkbox'}
|
||||
],
|
||||
type: 'radio',
|
||||
margin: 0
|
||||
})
|
||||
|
||||
const buttonGroup9 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 320,
|
||||
buttons: [{ icon: 'attachment' }, { icon: 'autorenew' }, { icon: 'backup' }, { icon: 'apps' }],
|
||||
orientation: 'vertical',
|
||||
minWidth: 70
|
||||
})
|
||||
const buttonGroup9 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{icon: 'attachment'},
|
||||
{icon: 'autorenew'},
|
||||
{icon: 'backup'},
|
||||
{icon: 'apps'}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
minWidth: 70
|
||||
})
|
||||
|
||||
const buttonGroup10 = new ButtonGroup({
|
||||
x: 100,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{ label: 'Vertical' },
|
||||
{ label: 'ButtonGroup' },
|
||||
{ label: 'align: left', active: true },
|
||||
{ label: 'margin: 0' }
|
||||
],
|
||||
orientation: 'vertical',
|
||||
stroke: 0xff0000,
|
||||
strokeWidth: 3,
|
||||
align: 'left',
|
||||
margin: 0
|
||||
})
|
||||
const buttonGroup10 = new ButtonGroup({
|
||||
x: 100,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{label: 'Vertical'},
|
||||
{label: 'ButtonGroup'},
|
||||
{label: 'align: left', active: true},
|
||||
{label: 'margin: 0'}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
stroke: 0xff0000,
|
||||
strokeWidth: 3,
|
||||
align: 'left',
|
||||
margin: 0
|
||||
})
|
||||
|
||||
const buttonGroup11 = new ButtonGroup({
|
||||
x: 250,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{ label: 'Vertical', active: true, verticalAlign: 'top' },
|
||||
{ label: 'ButtonGroup' },
|
||||
{ label: 'centered', active: true, disabled: true, verticalAlign: 'middle' },
|
||||
{ label: 'of', disabled: true, align: 'left' },
|
||||
{ label: 'type' },
|
||||
{ label: 'checkbox', align: 'right', verticalAlign: 'bottom' }
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom',
|
||||
minHeight: 100,
|
||||
minWidth: 100,
|
||||
stroke: 0x22ee22,
|
||||
type: 'checkbox'
|
||||
})
|
||||
const buttonGroup11 = new ButtonGroup({
|
||||
x: 250,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{label: 'Vertical', active: true, verticalAlign: 'top'},
|
||||
{label: 'ButtonGroup'},
|
||||
{label: 'centered', active: true, disabled: true, verticalAlign: 'middle'},
|
||||
{label: 'of', disabled: true, align: 'left'},
|
||||
{label: 'type'},
|
||||
{label: 'checkbox', align: 'right', verticalAlign: 'bottom'}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom',
|
||||
minHeight: 100,
|
||||
minWidth: 100,
|
||||
stroke: 0x22ee22,
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
const buttonGroup12 = new ButtonGroup({
|
||||
x: 400,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{ label: 'Controls', disabled: true },
|
||||
{ icon: 'play_arrow' },
|
||||
{ icon: 'pause', active: true, align: 'left' },
|
||||
{ icon: 'stop', verticalAlign: 'bottom' }
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
align: 'right',
|
||||
type: 'radio'
|
||||
})
|
||||
const buttonGroup12 = new ButtonGroup({
|
||||
x: 400,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{label: 'Controls', disabled: true},
|
||||
{icon: 'play_arrow'},
|
||||
{icon: 'pause', active: true, align: 'left'},
|
||||
{icon: 'stop', verticalAlign: 'bottom'}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
align: 'right',
|
||||
type: 'radio'
|
||||
})
|
||||
|
||||
const buttonGroup13 = new ButtonGroup({
|
||||
x: 520,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{ label: 'Volume', align: 'center', disabled: true },
|
||||
{ icon: 'volume_off', label: 'Aus', align: 'left', iconColor: 0x99ffff, verticalAlign: 'top' },
|
||||
{ icon: 'volume_mute', label: 'Lautlos', active: true, iconColorActive: 0xd7a3f9 },
|
||||
{ icon: 'volume_down', label: 'Leiser', align: 'right', iconPosition: 'right' },
|
||||
{
|
||||
icon: 'volume_up',
|
||||
label: 'Lauter',
|
||||
align: 'right',
|
||||
iconPosition: 'right',
|
||||
verticalAlign: 'bottom'
|
||||
}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
type: 'radio',
|
||||
stroke: 0x7b4073,
|
||||
strokeWidth: 4,
|
||||
minWidth: 200,
|
||||
minHeight: 100
|
||||
})
|
||||
const buttonGroup13 = new ButtonGroup({
|
||||
x: 520,
|
||||
y: 320,
|
||||
buttons: [
|
||||
{label: 'Volume', align: 'center', disabled: true},
|
||||
{icon: 'volume_off', label: 'Aus', align: 'left', iconColor: 0x99ffff, verticalAlign: 'top'},
|
||||
{icon: 'volume_mute', label: 'Lautlos', active: true, iconColorActive: 0xd7a3f9},
|
||||
{icon: 'volume_down', label: 'Leiser', align: 'right', iconPosition: 'right'},
|
||||
{icon: 'volume_up', label: 'Lauter', align: 'right', iconPosition: 'right', verticalAlign: 'bottom'}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 0,
|
||||
type: 'radio',
|
||||
stroke: 0x7b4073,
|
||||
strokeWidth: 4,
|
||||
minWidth: 200,
|
||||
minHeight: 100
|
||||
})
|
||||
|
||||
const buttonGroup14 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 960,
|
||||
buttons: [
|
||||
{ label: 'Stacked button 1', action: (event) => console.log('clicked 1') },
|
||||
{ label: 'Stacked button 2', action: (event) => console.log('clicked 2') },
|
||||
{ label: 'Stacked button 3', action: (event) => console.log('clicked 3') },
|
||||
{ label: 'Stacked button 4', action: (event) => console.log('clicked 4') },
|
||||
{ label: 'Stacked button 5', action: (event) => console.log('clicked 5') },
|
||||
{ label: 'Stacked button 6', action: (event) => console.log('clicked 6') },
|
||||
{ label: 'Stacked button 7', action: (event) => console.log('clicked 7') },
|
||||
{ label: 'Stacked button 8', action: (event) => console.log('clicked 8') }
|
||||
],
|
||||
stackPadding: 6,
|
||||
maxWidth: 620,
|
||||
app
|
||||
})
|
||||
const buttonGroup14 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 960,
|
||||
buttons: [
|
||||
{label: 'Stacked button 1', action: event => console.log('clicked 1')},
|
||||
{label: 'Stacked button 2', action: event => console.log('clicked 2')},
|
||||
{label: 'Stacked button 3', action: event => console.log('clicked 3')},
|
||||
{label: 'Stacked button 4', action: event => console.log('clicked 4')},
|
||||
{label: 'Stacked button 5', action: event => console.log('clicked 5')},
|
||||
{label: 'Stacked button 6', action: event => console.log('clicked 6')},
|
||||
{label: 'Stacked button 7', action: event => console.log('clicked 7')},
|
||||
{label: 'Stacked button 8', action: event => console.log('clicked 8')}
|
||||
],
|
||||
stackPadding: 6,
|
||||
maxWidth: 620,
|
||||
app
|
||||
})
|
||||
|
||||
const buttonGroup15 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1040,
|
||||
buttons: [
|
||||
{ icon: 'battery_charging_20', type: 'checkbox', iconColorActive: 0xd43e36 },
|
||||
{ icon: 'battery_charging_30', type: 'checkbox', iconColorActive: 0xf99927 },
|
||||
{ icon: 'battery_charging_50', type: 'checkbox', iconColorActive: 0xefc201 },
|
||||
{ icon: 'battery_charging_60', type: 'checkbox', iconColorActive: 0x839b00 },
|
||||
{ icon: 'battery_charging_80', type: 'checkbox', iconColorActive: 0x4ba8af },
|
||||
{ icon: 'battery_charging_90', type: 'checkbox', iconColorActive: 0x5386bc },
|
||||
{ icon: 'battery_charging_full', type: 'checkbox', iconColorActive: 0x9c71b7 }
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 1,
|
||||
maxHeight: 200,
|
||||
app
|
||||
})
|
||||
const buttonGroup15 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1040,
|
||||
buttons: [
|
||||
{icon: 'battery_charging_20', type: 'checkbox', iconColorActive: 0xd43e36},
|
||||
{icon: 'battery_charging_30', type: 'checkbox', iconColorActive: 0xf99927},
|
||||
{icon: 'battery_charging_50', type: 'checkbox', iconColorActive: 0xefc201},
|
||||
{icon: 'battery_charging_60', type: 'checkbox', iconColorActive: 0x839b00},
|
||||
{icon: 'battery_charging_80', type: 'checkbox', iconColorActive: 0x4ba8af},
|
||||
{icon: 'battery_charging_90', type: 'checkbox', iconColorActive: 0x5386bc},
|
||||
{icon: 'battery_charging_full', type: 'checkbox', iconColorActive: 0x9c71b7}
|
||||
],
|
||||
orientation: 'vertical',
|
||||
margin: 1,
|
||||
maxHeight: 200,
|
||||
app
|
||||
})
|
||||
|
||||
const buttons16 = []
|
||||
for (let i = 1; i < 101; i++) {
|
||||
buttons16.push({
|
||||
label: `Button ${i}`,
|
||||
stroke: Math.floor(Math.random() * 16777215),
|
||||
strokeWidth: 3,
|
||||
radius: 16
|
||||
})
|
||||
}
|
||||
const buttons16 = []
|
||||
for (let i = 1; i < 101; i++) {
|
||||
buttons16.push({label: `Button ${i}`, stroke: Math.floor(Math.random() * 16777215), strokeWidth: 3, radius: 16})
|
||||
}
|
||||
|
||||
buttons16.splice(6, 0, { minWidth: 50, style: 'link' })
|
||||
const buttonGroup16 = new ButtonGroup({
|
||||
x: 90,
|
||||
y: 1040,
|
||||
buttons: buttons16,
|
||||
stackPadding: 3,
|
||||
maxWidth: 900,
|
||||
app
|
||||
})
|
||||
buttons16.splice(6, 0, {minWidth: 50, style: 'link'})
|
||||
const buttonGroup16 = new ButtonGroup({
|
||||
x: 90,
|
||||
y: 1040,
|
||||
buttons: buttons16,
|
||||
stackPadding: 3,
|
||||
maxWidth: 900,
|
||||
app
|
||||
})
|
||||
|
||||
const buttonGroup17 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1270,
|
||||
buttons: [
|
||||
{ icon: 'local_airport', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Airport' },
|
||||
{ icon: 'local_bar', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Bar' },
|
||||
{ icon: 'local_cafe', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Cafe' },
|
||||
{ icon: 'local_car_wash', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Car wash' },
|
||||
{ icon: 'local_dining', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Dining' },
|
||||
{ icon: 'local_florist', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Florist' },
|
||||
{ icon: 'local_gas_station', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Gas station' },
|
||||
{
|
||||
icon: 'local_grocery_store',
|
||||
type: 'checkbox',
|
||||
iconColorActive: 0xefc201,
|
||||
badge: 'Grocery store'
|
||||
},
|
||||
{ icon: 'local_mall', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Mall' },
|
||||
{ icon: 'local_pizza', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Pizza' },
|
||||
{ icon: 'local_printshop', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Printshop' },
|
||||
{ icon: 'local_pharmacy', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Pharmacy' }
|
||||
],
|
||||
margin: 50,
|
||||
maxWidth: 400,
|
||||
app
|
||||
})
|
||||
const buttonGroup17 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1270,
|
||||
buttons: [
|
||||
{icon: 'local_airport', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Airport'},
|
||||
{icon: 'local_bar', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Bar'},
|
||||
{icon: 'local_cafe', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Cafe'},
|
||||
{icon: 'local_car_wash', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Car wash'},
|
||||
{icon: 'local_dining', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Dining'},
|
||||
{icon: 'local_florist', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Florist'},
|
||||
{icon: 'local_gas_station', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Gas station'},
|
||||
{icon: 'local_grocery_store', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Grocery store'},
|
||||
{icon: 'local_mall', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Mall'},
|
||||
{icon: 'local_pizza', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Pizza'},
|
||||
{icon: 'local_printshop', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Printshop'},
|
||||
{icon: 'local_pharmacy', type: 'checkbox', iconColorActive: 0xefc201, badge: 'Pharmacy'}
|
||||
],
|
||||
margin: 50,
|
||||
maxWidth: 400,
|
||||
app
|
||||
})
|
||||
|
||||
const buttonGroup18 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1340,
|
||||
buttons: [
|
||||
{ label: 'move' },
|
||||
{ label: 'explanation dried' },
|
||||
{ label: 'out catch' },
|
||||
{ label: 'late either' },
|
||||
{ label: 'tell pour' },
|
||||
{ label: 'willing apart airplane' },
|
||||
{ label: 'high war' },
|
||||
{ label: 'future struck' },
|
||||
{ label: 'sense image' },
|
||||
{ label: 'never' },
|
||||
{ label: 'mark cloth' },
|
||||
{ label: 'everywhere due large' }
|
||||
],
|
||||
maxWidth: 500,
|
||||
app
|
||||
})
|
||||
const buttonGroup18 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1340,
|
||||
buttons: [
|
||||
{label: 'move'},
|
||||
{label: 'explanation dried'},
|
||||
{label: 'out catch'},
|
||||
{label: 'late either'},
|
||||
{label: 'tell pour'},
|
||||
{label: 'willing apart airplane'},
|
||||
{label: 'high war'},
|
||||
{label: 'future struck'},
|
||||
{label: 'sense image'},
|
||||
{label: 'never'},
|
||||
{label: 'mark cloth'},
|
||||
{label: 'everywhere due large'}
|
||||
],
|
||||
maxWidth: 500,
|
||||
app
|
||||
})
|
||||
|
||||
const buttonGroup19 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1420,
|
||||
buttons: [{ label: 'move' }, { label: 'explanation dried' }, { label: 'out catch' }],
|
||||
maxWidth: 500,
|
||||
app
|
||||
})
|
||||
const buttonGroup19 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1420,
|
||||
buttons: [
|
||||
{label: 'move'},
|
||||
{label: 'explanation dried'},
|
||||
{label: 'out catch'}
|
||||
],
|
||||
maxWidth: 500,
|
||||
app
|
||||
})
|
||||
|
||||
const buttonGroup20 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1520,
|
||||
type: 'checkbox',
|
||||
buttons: [{ label: 'one' }, { label: 'two' }, { label: 'three' }],
|
||||
textAlpha: 0.7,
|
||||
textActiveAlpha: 0.2
|
||||
})
|
||||
const buttonGroup20 = new ButtonGroup({
|
||||
x: 10,
|
||||
y: 1520,
|
||||
type: 'checkbox',
|
||||
buttons: [
|
||||
{label: 'one'},
|
||||
{label: 'two'},
|
||||
{label: 'three'}
|
||||
],
|
||||
textAlpha: .7,
|
||||
textActiveAlpha: .2
|
||||
})
|
||||
|
||||
const buttonGroup21 = new ButtonGroup({
|
||||
x: 300,
|
||||
y: 1520,
|
||||
type: 'checkbox',
|
||||
buttons: [
|
||||
{ label: 'eins', textAlpha: 1, textActiveAlpha: 0.2 },
|
||||
{ label: 'zwei', textAlpha: 0.2, textActiveAlpha: 1 },
|
||||
{ label: 'drei' }
|
||||
]
|
||||
})
|
||||
const buttonGroup21 = new ButtonGroup({
|
||||
x: 300,
|
||||
y: 1520,
|
||||
type: 'checkbox',
|
||||
buttons: [
|
||||
{label: 'eins', textAlpha: 1, textActiveAlpha: .2},
|
||||
{label: 'zwei', textAlpha: .2, textActiveAlpha: 1},
|
||||
{label: 'drei'}
|
||||
]
|
||||
})
|
||||
|
||||
app.scene.addChild(buttonGroup1, buttonGroup2, buttonGroup3)
|
||||
app.scene.addChild(buttonGroup4)
|
||||
app.scene.addChild(buttonGroup5, buttonGroup6)
|
||||
app.scene.addChild(buttonGroup7, buttonGroup8)
|
||||
app.scene.addChild(buttonGroup9, buttonGroup10, buttonGroup11, buttonGroup12, buttonGroup13)
|
||||
app.scene.addChild(buttonGroup14, buttonGroup15, buttonGroup16, buttonGroup17, buttonGroup18, buttonGroup19)
|
||||
app.scene.addChild(buttonGroup20, buttonGroup21)
|
||||
</script>
|
||||
</body>
|
||||
app.scene.addChild(buttonGroup1, buttonGroup2, buttonGroup3)
|
||||
app.scene.addChild(buttonGroup4)
|
||||
app.scene.addChild(buttonGroup5, buttonGroup6)
|
||||
app.scene.addChild(buttonGroup7, buttonGroup8)
|
||||
app.scene.addChild(buttonGroup9, buttonGroup10, buttonGroup11, buttonGroup12, buttonGroup13)
|
||||
app.scene.addChild(buttonGroup14, buttonGroup15, buttonGroup16, buttonGroup17, buttonGroup18, buttonGroup19)
|
||||
app.scene.addChild(buttonGroup20, buttonGroup21)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -126,7 +126,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
orientation: 'horizontal',
|
||||
align: 'center', // left, center, right
|
||||
verticalAlign: 'middle', // top, middle, bottom
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -216,7 +216,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
it.verticalAlign = it.verticalAlign || this.opts.verticalAlign
|
||||
it.afterAction = (event, button) => {
|
||||
if (this.opts.type === 'radio' && button.opts.type === 'default') {
|
||||
this.buttons.forEach((it) => {
|
||||
this.buttons.forEach(it => {
|
||||
if (it.opts.type === 'default') {
|
||||
it.active = false
|
||||
}
|
||||
@ -243,7 +243,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
|
||||
button.__originalPosition = {
|
||||
x: button.x,
|
||||
y: button.y,
|
||||
y: button.y
|
||||
}
|
||||
|
||||
position += (this.opts.orientation === 'horizontal' ? button.width : button.height) + this.opts.margin
|
||||
@ -255,7 +255,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
if (this.opts.orientation === 'vertical') {
|
||||
const maxWidth = this.getMaxButtonWidth()
|
||||
|
||||
this.buttons.forEach((it) => {
|
||||
this.buttons.forEach(it => {
|
||||
it.opts.minWidth = maxWidth
|
||||
it.layout()
|
||||
})
|
||||
@ -283,7 +283,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
//--------------------
|
||||
if (this.opts.app) {
|
||||
const app = this.opts.app
|
||||
app.view.addEventListener('mousewheel', (event) => {
|
||||
app.view.addEventListener('mousewheel', event => {
|
||||
const bounds = this.getBounds()
|
||||
const x = event.clientX - app.view.getBoundingClientRect().left
|
||||
const y = event.clientY - app.view.getBoundingClientRect().top
|
||||
@ -338,7 +338,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
*/
|
||||
draw() {
|
||||
if (this.opts.margin === 0) {
|
||||
this.buttons.forEach((it) => it.hide())
|
||||
this.buttons.forEach(it => it.hide())
|
||||
|
||||
this.container.clear()
|
||||
this.container.lineStyle(this.opts.strokeWidth, this.opts.stroke, this.opts.strokeAlpha)
|
||||
@ -378,7 +378,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
set disabled(value) {
|
||||
this._disabled = value
|
||||
|
||||
this.buttons.forEach((it) => (it.disabled = value))
|
||||
this.buttons.forEach(it => (it.disabled = value))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -416,7 +416,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
* @return {number} The maximum with of a button of the button group.
|
||||
*/
|
||||
getMaxButtonWidth() {
|
||||
let widths = this.buttons.map((it) => it.width)
|
||||
let widths = this.buttons.map(it => it.width)
|
||||
|
||||
return Math.max(...widths)
|
||||
}
|
||||
@ -459,7 +459,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
|
||||
this.__delta = {
|
||||
x: this.container.position.x - event.data.global.x,
|
||||
y: this.container.position.y - event.data.global.y,
|
||||
y: this.container.position.y - event.data.global.y
|
||||
}
|
||||
|
||||
TweenLite.killTweensOf(this.container.position, { x: true, y: true })
|
||||
@ -539,7 +539,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
throwProps,
|
||||
ease: Strong.easeOut,
|
||||
onUpdate: () => this.stack(),
|
||||
onComplete: () => ThrowPropsPlugin.untrack(this.container.position),
|
||||
onComplete: () => ThrowPropsPlugin.untrack(this.container.position)
|
||||
},
|
||||
0.8,
|
||||
0.4
|
||||
@ -635,8 +635,8 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
sorted.push(it)
|
||||
})
|
||||
|
||||
const min = Math.min(...sorted.map((it) => it.x))
|
||||
const max = Math.max(...sorted.map((it) => it.x + it.button.width))
|
||||
const min = Math.min(...sorted.map(it => it.x))
|
||||
const max = Math.max(...sorted.map(it => it.x + it.button.width))
|
||||
const center = (min + max) / 2
|
||||
|
||||
// z-index
|
||||
@ -661,7 +661,7 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
|
||||
return 0
|
||||
})
|
||||
.forEach((it) => it.parent.addChild(it))
|
||||
.forEach(it => it.parent.addChild(it))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -692,8 +692,8 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
sorted.push(it)
|
||||
})
|
||||
|
||||
const min = Math.min(...sorted.map((it) => it.y))
|
||||
const max = Math.max(...sorted.map((it) => it.y + it.button.height))
|
||||
const min = Math.min(...sorted.map(it => it.y))
|
||||
const max = Math.max(...sorted.map(it => it.y + it.button.height))
|
||||
const center = (min + max) / 2
|
||||
|
||||
// z-index
|
||||
@ -718,6 +718,6 @@ export default class ButtonGroup extends PIXI.Container {
|
||||
|
||||
return 0
|
||||
})
|
||||
.forEach((it) => it.parent.addChild(it))
|
||||
.forEach(it => it.parent.addChild(it))
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 508 KiB |
@ -15,7 +15,7 @@
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="../index.html">lib.</a><a href="index.html">pixi.</a>Coordinates
|
||||
Coordinates
|
||||
</h1>
|
||||
<p>
|
||||
To position objects in defined spatial relationships presupposes a clear understanding of the involved coordinate systems.
|
||||
|
||||
|
Before Width: | Height: | Size: 688 KiB |
@ -1,226 +1,219 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>DeepZoomImage Doctests</title>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<link rel="stylesheet" href="../../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../../css/doctest.css" />
|
||||
<title>DeepZoomImage Doctests</title>
|
||||
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<link rel="stylesheet" href="../../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../../css/doctest.css">
|
||||
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#app > * {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Double DeepZoomImage</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom level. This gives
|
||||
the user the impression that even huge pictures (up to gigapixel-images) can be zoomed instantaneously, since the
|
||||
tiles at smaller levels are scaled immediately and overloaded by more detailed tiles at the larger level as fast
|
||||
as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="div1" style="float: left;"></div>
|
||||
<div id="div2" style="float: right;"></div>
|
||||
<div style="clear: left; margin-top: 540px;" />
|
||||
<script class="doctest">
|
||||
|
||||
// deepZoom
|
||||
//--------------------
|
||||
const deepZoomInfo = new DeepZoomInfo({
|
||||
"tileSize": 128,
|
||||
"format": "jpg",
|
||||
"overlap": 0,
|
||||
"type": "map",
|
||||
"height": 4096,
|
||||
"width": 4096,
|
||||
"path": "../assets/maps/test",
|
||||
"urlTileTemplate": "{path}/{level}/{column}/{row}.{format}"
|
||||
})
|
||||
// const deepZoomInfo = new DeepZoomInfo({
|
||||
// compression: [
|
||||
// "dds"
|
||||
// ],
|
||||
// clip: {
|
||||
// minLevel: 12,
|
||||
// maxLevel: 20,
|
||||
// startCol: 275215,
|
||||
// startRow: 181050,
|
||||
// bounds: {
|
||||
// min: [48.458353, 8.96484374976547],
|
||||
// max: [48.5747899110263, 9.14062499976523]
|
||||
// }
|
||||
// },
|
||||
// tileSize: 512,
|
||||
// format: "png",
|
||||
// overlap: 0,
|
||||
// type: "map",
|
||||
// height: 131072,
|
||||
// width: 131072,
|
||||
// path: "../../../var/tuesch/luftbild_2016_full",
|
||||
// urlTileTemplate: "{path}/{level}/{row}/{column}.{format}"
|
||||
// })
|
||||
|
||||
// app
|
||||
//--------------------
|
||||
window.app = new PIXIApp({
|
||||
width: 400,
|
||||
height: 500,
|
||||
backgroundColor: 0xFFCCCCCC
|
||||
}).setup().run()
|
||||
|
||||
div1.appendChild(app.view)
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer1 = new ScatterContainer(app.renderer, {showBounds: true, app: app})
|
||||
app.scene.addChild(scatterContainer1)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
setTimeout(() => {
|
||||
const deepZoomImage1 = new DeepZoomImage(deepZoomInfo, {app, world: scatterContainer1})
|
||||
deepZoomImage1.scatter = new DisplayObjectScatter(deepZoomImage1, app.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 50,
|
||||
onTransform: event => {
|
||||
//console.log('currentLevel', deepZoomImage1.currentLevel)
|
||||
deepZoomImage1.transformed(event)
|
||||
}
|
||||
})
|
||||
|
||||
scatterContainer1.addChild(deepZoomImage1)
|
||||
}, 1000)
|
||||
|
||||
|
||||
// app2
|
||||
//--------------------
|
||||
const app2 = new PIXIApp({
|
||||
width: 400,
|
||||
height: 500,
|
||||
backgroundColor: 0xFFCCCCCC
|
||||
}).setup().run()
|
||||
|
||||
div2.appendChild(app2.view)
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer2 = new ScatterContainer(app2.renderer, {showBounds: true, app: app2})
|
||||
app2.scene.addChild(scatterContainer2)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
const deepZoomImage2 = new DeepZoomImage(deepZoomInfo, {app: app2})
|
||||
deepZoomImage2.scatter = new DisplayObjectScatter(deepZoomImage2, app2.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage2.transformed(event)
|
||||
}
|
||||
})
|
||||
|
||||
#app > * {
|
||||
margin-bottom: 5px;
|
||||
scatterContainer2.addChild(deepZoomImage2)
|
||||
|
||||
</script>
|
||||
|
||||
<h1>DeepZoomImage in DeepZoomImage</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom level. This gives
|
||||
the user the impression that even huge pictures (up to gigapixel-images) can be zoomed instantaneously, since the
|
||||
tiles at smaller levels are scaled immediately and overloaded by more detailed tiles at the larger level as fast
|
||||
as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="div3"></div>
|
||||
<script class="doctest">
|
||||
|
||||
// app3
|
||||
//--------------------
|
||||
const app3 = new PIXIApp({
|
||||
width: 900,
|
||||
height: 500,
|
||||
backgroundColor: 0xFFCCCCCC
|
||||
}).setup().run()
|
||||
|
||||
window.app3 = app3
|
||||
|
||||
div3.appendChild(app3.view)
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer3 = new ScatterContainer(app3.renderer, {app: app3, showBounds: true, claimEvent: false, stopEvents: false})
|
||||
app3.scene.addChild(scatterContainer3)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
const deepZoomImage3 = new DeepZoomImage(deepZoomInfo, {app: app3})
|
||||
deepZoomImage3.scatter = new DisplayObjectScatter(deepZoomImage3, app3.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
startScale: 2,
|
||||
autoBringToFront: false,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage3.transformed(event)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
})
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">deepzoom.</a>
|
||||
DeepZoom
|
||||
</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom
|
||||
level. This gives the user the impression that even huge pictures (up to gigapixel-images) can be zoomed
|
||||
instantaneously, since the tiles at smaller levels are scaled immediately and overloaded by more detailed
|
||||
tiles at the larger level as fast as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="div1" style="float: left"></div>
|
||||
<div id="div2" style="float: right"></div>
|
||||
<div style="clear: left; margin-top: 540px" />
|
||||
<script class="doctest">
|
||||
// deepZoom
|
||||
//--------------------
|
||||
const deepZoomInfo = new DeepZoomInfo({
|
||||
tileSize: 128,
|
||||
format: 'jpg',
|
||||
overlap: 0,
|
||||
type: 'map',
|
||||
height: 4096,
|
||||
width: 4096,
|
||||
path: '../assets/maps/test',
|
||||
urlTileTemplate: '{path}/{level}/{column}/{row}.{format}'
|
||||
})
|
||||
// const deepZoomInfo = new DeepZoomInfo({
|
||||
// compression: [
|
||||
// "dds"
|
||||
// ],
|
||||
// clip: {
|
||||
// minLevel: 12,
|
||||
// maxLevel: 20,
|
||||
// startCol: 275215,
|
||||
// startRow: 181050,
|
||||
// bounds: {
|
||||
// min: [48.458353, 8.96484374976547],
|
||||
// max: [48.5747899110263, 9.14062499976523]
|
||||
// }
|
||||
// },
|
||||
// tileSize: 512,
|
||||
// format: "png",
|
||||
// overlap: 0,
|
||||
// type: "map",
|
||||
// height: 131072,
|
||||
// width: 131072,
|
||||
// path: "../../../var/tuesch/luftbild_2016_full",
|
||||
// urlTileTemplate: "{path}/{level}/{row}/{column}.{format}"
|
||||
// })
|
||||
app3._deepZoomImage3 = deepZoomImage3
|
||||
|
||||
// app
|
||||
//--------------------
|
||||
window.app = new PIXIApp({
|
||||
width: 400,
|
||||
height: 500,
|
||||
backgroundColor: 0xffcccccc
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
scatterContainer3.addChild(deepZoomImage3)
|
||||
|
||||
div1.appendChild(app.view)
|
||||
// Create the second DeepZoomImage
|
||||
//--------------------
|
||||
const border = new PIXI.Graphics()
|
||||
border.beginFill(0x282828, 1)
|
||||
border.drawRect(0, 0, 264, 244)
|
||||
scatterContainer3.addChild(border)
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer1 = new ScatterContainer(app.renderer, { showBounds: true, app: app })
|
||||
app.scene.addChild(scatterContainer1)
|
||||
const mask = new PIXI.Graphics()
|
||||
mask.beginFill(0x282828, 1)
|
||||
mask.drawRect(0, 0, 260, 240)
|
||||
scatterContainer3.addChild(mask)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
setTimeout(() => {
|
||||
const deepZoomImage1 = new DeepZoomImage(deepZoomInfo, { app, world: scatterContainer1 })
|
||||
deepZoomImage1.scatter = new DisplayObjectScatter(deepZoomImage1, app.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 50,
|
||||
onTransform: (event) => {
|
||||
//console.log('currentLevel', deepZoomImage1.currentLevel)
|
||||
deepZoomImage1.transformed(event)
|
||||
}
|
||||
})
|
||||
const deepZoomImage4 = new DeepZoomImage(deepZoomInfo, {app: app3})
|
||||
deepZoomImage4.x = 4
|
||||
deepZoomImage4.y = 4
|
||||
deepZoomImage4.scatter = new DisplayObjectScatter(deepZoomImage4, app3.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage4.transformed(event)
|
||||
}
|
||||
})
|
||||
deepZoomImage4.mask = mask
|
||||
|
||||
scatterContainer1.addChild(deepZoomImage1)
|
||||
}, 1000)
|
||||
app3._deepZoomImage4 = deepZoomImage4
|
||||
|
||||
// app2
|
||||
//--------------------
|
||||
const app2 = new PIXIApp({
|
||||
width: 400,
|
||||
height: 500,
|
||||
backgroundColor: 0xffcccccc
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
scatterContainer3.addChild(deepZoomImage4)
|
||||
|
||||
div2.appendChild(app2.view)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer2 = new ScatterContainer(app2.renderer, { showBounds: true, app: app2 })
|
||||
app2.scene.addChild(scatterContainer2)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
const deepZoomImage2 = new DeepZoomImage(deepZoomInfo, { app: app2 })
|
||||
deepZoomImage2.scatter = new DisplayObjectScatter(deepZoomImage2, app2.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage2.transformed(event)
|
||||
}
|
||||
})
|
||||
|
||||
scatterContainer2.addChild(deepZoomImage2)
|
||||
</script>
|
||||
|
||||
<h1>DeepZoomImage in DeepZoomImage</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom
|
||||
level. This gives the user the impression that even huge pictures (up to gigapixel-images) can be zoomed
|
||||
instantaneously, since the tiles at smaller levels are scaled immediately and overloaded by more detailed
|
||||
tiles at the larger level as fast as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="div3"></div>
|
||||
<script class="doctest">
|
||||
// app3
|
||||
//--------------------
|
||||
const app3 = new PIXIApp({
|
||||
width: 900,
|
||||
height: 500,
|
||||
backgroundColor: 0xffcccccc
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
|
||||
window.app3 = app3
|
||||
|
||||
div3.appendChild(app3.view)
|
||||
|
||||
// create the ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer3 = new ScatterContainer(app3.renderer, {
|
||||
app: app3,
|
||||
showBounds: true,
|
||||
claimEvent: false,
|
||||
stopEvents: false
|
||||
})
|
||||
app3.scene.addChild(scatterContainer3)
|
||||
|
||||
// Create the DeepZoomImage
|
||||
//--------------------
|
||||
const deepZoomImage3 = new DeepZoomImage(deepZoomInfo, { app: app3 })
|
||||
deepZoomImage3.scatter = new DisplayObjectScatter(deepZoomImage3, app3.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
startScale: 2,
|
||||
autoBringToFront: false,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage3.transformed(event)
|
||||
}
|
||||
})
|
||||
|
||||
app3._deepZoomImage3 = deepZoomImage3
|
||||
|
||||
scatterContainer3.addChild(deepZoomImage3)
|
||||
|
||||
// Create the second DeepZoomImage
|
||||
//--------------------
|
||||
const border = new PIXI.Graphics()
|
||||
border.beginFill(0x282828, 1)
|
||||
border.drawRect(0, 0, 264, 244)
|
||||
scatterContainer3.addChild(border)
|
||||
|
||||
const mask = new PIXI.Graphics()
|
||||
mask.beginFill(0x282828, 1)
|
||||
mask.drawRect(0, 0, 260, 240)
|
||||
scatterContainer3.addChild(mask)
|
||||
|
||||
const deepZoomImage4 = new DeepZoomImage(deepZoomInfo, { app: app3 })
|
||||
deepZoomImage4.x = 4
|
||||
deepZoomImage4.y = 4
|
||||
deepZoomImage4.scatter = new DisplayObjectScatter(deepZoomImage4, app3.renderer, {
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
onTransform: (event) => {
|
||||
deepZoomImage4.transformed(event)
|
||||
}
|
||||
})
|
||||
deepZoomImage4.mask = mask
|
||||
|
||||
app3._deepZoomImage4 = deepZoomImage4
|
||||
|
||||
scatterContainer3.addChild(deepZoomImage4)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Before Width: | Height: | Size: 429 KiB |
@ -1,135 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>DeepZoomImage Doctests</title>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<link rel="stylesheet" href="../../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../../css/doctest.css" />
|
||||
<title>DeepZoomImage Doctests</title>
|
||||
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<link rel="stylesheet" href="../../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../../css/doctest.css">
|
||||
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#app > * {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>DeepZoomImage</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom level. This gives
|
||||
the user the impression that even huge pictures (up to gigapixel-images) can be zoomed instantaneously, since the
|
||||
tiles at smaller levels are scaled immediately and overloaded by more detailed tiles at the larger level as fast
|
||||
as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="app">
|
||||
<button id="change_dpr">Change Pixel Ratio</button>
|
||||
<div id="canvas_container"></div>
|
||||
<div id="info"></div>
|
||||
</div>
|
||||
<script class="doctest">
|
||||
|
||||
// When an element is added, the ScatterApp wrapps it in it's own Scatter Container.
|
||||
// Just as in the doctest: scatter.html
|
||||
class ScatterApp extends PIXIApp {
|
||||
sceneFactory() {
|
||||
return new ScatterContainer(this.renderer, { showBounds: true, app: this })
|
||||
}
|
||||
}
|
||||
|
||||
let app
|
||||
let state = 0
|
||||
|
||||
//Destroys the PIXIApp element and the corresponding canvas,
|
||||
//to reinstantiate the entire application.
|
||||
changePIXI()
|
||||
|
||||
function changePIXI() {
|
||||
if (typeof app != 'undefined') {
|
||||
//The parameter destroys the canvas, when destroying the app.
|
||||
// Not deleting a new canvas resulted in some
|
||||
// weird PIXI error.
|
||||
app.destroy(true)
|
||||
}
|
||||
|
||||
#app > * {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a
|
||||
><a href="index.html">deepzoom.</a>DeepZoomImage
|
||||
</h1>
|
||||
<p>
|
||||
The main class of a deeply zoomable image that is represented by a hierarchy of tile layers for each zoom
|
||||
level. This gives the user the impression that even huge pictures (up to gigapixel-images) can be zoomed
|
||||
instantaneously, since the tiles at smaller levels are scaled immediately and overloaded by more detailed
|
||||
tiles at the larger level as fast as possible.
|
||||
</p>
|
||||
<br />
|
||||
<div id="app">
|
||||
<button id="change_dpr">Change Pixel Ratio</button>
|
||||
<div id="canvas_container"></div>
|
||||
<div id="info"></div>
|
||||
</div>
|
||||
<script class="doctest">
|
||||
// When an element is added, the ScatterApp wrapps it in it's own Scatter Container.
|
||||
// Just as in the doctest: scatter.html
|
||||
class ScatterApp extends PIXIApp {
|
||||
sceneFactory() {
|
||||
return new ScatterContainer(this.renderer, { showBounds: true, app: this })
|
||||
//A new canvas has to be created
|
||||
//for the new view.
|
||||
var canvas = document.createElement("canvas")
|
||||
canvas_container.appendChild(canvas);
|
||||
|
||||
app = new ScatterApp({
|
||||
resolution: state + 1,
|
||||
|
||||
//Default parameters
|
||||
view: canvas,
|
||||
autoResize: false,
|
||||
width: 128,
|
||||
height: 128,
|
||||
backgroundColor: 0xFFCCCCCC
|
||||
}).setup().run()
|
||||
|
||||
|
||||
// To create a DeepZoomImage, a DeepZoomInfo has to
|
||||
// be provided. It contains all the necessary informations
|
||||
// for the DeepZoomImage, to behave as intended.
|
||||
// (E.g. that it displays the right level of tiles for the current view distance.)
|
||||
|
||||
deepZoomInfo = new DeepZoomInfo(
|
||||
{
|
||||
"tileSize": 128,
|
||||
"format": "jpg",
|
||||
"overlap": 0,
|
||||
"type": "map",
|
||||
"height": 4096,
|
||||
"width": 4096,
|
||||
"path": "../assets/maps/test",
|
||||
"urlTileTemplate": "{path}/{level}/{column}/{row}.{format}"
|
||||
});
|
||||
|
||||
|
||||
// Create the DeepZoomImage
|
||||
deepZoomImage = new DeepZoomImage(deepZoomInfo, {
|
||||
highResolution: !!state,
|
||||
app
|
||||
});
|
||||
|
||||
|
||||
|
||||
deepZoomImage.scatter = new DisplayObjectScatter(deepZoomImage, app.renderer, {
|
||||
// Allow more flexible scaling for debugging purposes.
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
// Notify the DeepZoomImage, when it's container has
|
||||
// been transformed (translated, scaled, rotated, ...)
|
||||
onTransform: (event) => {
|
||||
deepZoomImage.transformed(event)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let app
|
||||
let state = 0
|
||||
|
||||
//Destroys the PIXIApp element and the corresponding canvas,
|
||||
//to reinstantiate the entire application.
|
||||
// Add the DeepZoomImage to the scene.
|
||||
app.scene.addChild(deepZoomImage)
|
||||
|
||||
//Set info text.
|
||||
info.innerHTML = "resolution: " + app.renderer.resolution +
|
||||
"<br>high resolution: " + !!state;
|
||||
}
|
||||
|
||||
|
||||
// Add functionality to the button.
|
||||
change_dpr.addEventListener("click", (event) => {
|
||||
state = (state + 1) % 2
|
||||
changePIXI()
|
||||
})
|
||||
|
||||
function changePIXI() {
|
||||
if (typeof app != 'undefined') {
|
||||
//The parameter destroys the canvas, when destroying the app.
|
||||
// Not deleting a new canvas resulted in some
|
||||
// weird PIXI error.
|
||||
app.destroy(true)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
//A new canvas has to be created
|
||||
//for the new view.
|
||||
var canvas = document.createElement('canvas')
|
||||
canvas_container.appendChild(canvas)
|
||||
|
||||
app = new ScatterApp({
|
||||
resolution: state + 1,
|
||||
|
||||
//Default parameters
|
||||
view: canvas,
|
||||
autoResize: false,
|
||||
width: 128,
|
||||
height: 128,
|
||||
backgroundColor: 0xffcccccc
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
|
||||
// To create a DeepZoomImage, a DeepZoomInfo has to
|
||||
// be provided. It contains all the necessary informations
|
||||
// for the DeepZoomImage, to behave as intended.
|
||||
// (E.g. that it displays the right level of tiles for the current view distance.)
|
||||
|
||||
deepZoomInfo = new DeepZoomInfo({
|
||||
tileSize: 128,
|
||||
format: 'jpg',
|
||||
overlap: 0,
|
||||
type: 'map',
|
||||
height: 4096,
|
||||
width: 4096,
|
||||
path: '../assets/maps/test',
|
||||
urlTileTemplate: '{path}/{level}/{column}/{row}.{format}'
|
||||
})
|
||||
|
||||
// Create the DeepZoomImage
|
||||
deepZoomImage = new DeepZoomImage(deepZoomInfo, {
|
||||
highResolution: !!state,
|
||||
app
|
||||
})
|
||||
|
||||
deepZoomImage.scatter = new DisplayObjectScatter(deepZoomImage, app.renderer, {
|
||||
// Allow more flexible scaling for debugging purposes.
|
||||
minScale: 0,
|
||||
maxScale: 100,
|
||||
// Notify the DeepZoomImage, when it's container has
|
||||
// been transformed (translated, scaled, rotated, ...)
|
||||
onTransform: (event) => {
|
||||
deepZoomImage.transformed(event)
|
||||
}
|
||||
})
|
||||
|
||||
// Add the DeepZoomImage to the scene.
|
||||
app.scene.addChild(deepZoomImage)
|
||||
|
||||
//Set info text.
|
||||
info.innerHTML = 'resolution: ' + app.renderer.resolution + '<br>high resolution: ' + !!state
|
||||
}
|
||||
|
||||
// Add functionality to the button.
|
||||
change_dpr.addEventListener('click', (event) => {
|
||||
state = (state + 1) % 2
|
||||
changePIXI()
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -887,26 +887,6 @@ export class DeepZoomImage extends PIXI.Container {
|
||||
})
|
||||
}
|
||||
|
||||
/** Destroys all tiles and laywer above the current level to ensure that the memory can
|
||||
* be reused. This must be called from time to time to free load worker which otherwise would
|
||||
* consume memory and threads permanentely.
|
||||
*/
|
||||
destroyUnusedTilesAndLayers() {
|
||||
this.destroyTilesAboveLevel(this.currentLevel)
|
||||
let candidates = []
|
||||
Object.keys(this.tileLayers).forEach(key => {
|
||||
let tiles = this.tileLayers[key]
|
||||
if (tiles.level > this.currentLevel) {
|
||||
candidates.push(key)
|
||||
}
|
||||
})
|
||||
for (let key of candidates) {
|
||||
let tiles = this.tileLayers[key]
|
||||
tiles.destroy()
|
||||
delete this.tileLayers[key]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tint tiles in all layers that are no longer needed
|
||||
*
|
||||
|
||||
|
Before Width: | Height: | Size: 650 KiB |
@ -1,45 +1,38 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>PIXI Lib 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" />
|
||||
<head>
|
||||
<title>PIXI Lib 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>
|
||||
<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" />
|
||||
<!-- <iframe src="" frameborder="0"></iframe> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="title"></div>
|
||||
<template id="itemTemplate">
|
||||
<a class="wrapper" href="">
|
||||
<div class="preview">
|
||||
<div class="thumbnail-container">
|
||||
<div class="thumbnail">
|
||||
<img class="icon" >
|
||||
<!-- <iframe src="" frameborder="0"></iframe> -->
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<h2>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a
|
||||
><a href="../index.html">deepzoom.</a>Doctests
|
||||
</h2>
|
||||
<div id="container" class="container"></div>
|
||||
<script>
|
||||
const index = new Index(
|
||||
itemTemplate,
|
||||
[
|
||||
['Deepzoom', 'deepzoom.html'],
|
||||
['Image', 'image.html']
|
||||
],
|
||||
null
|
||||
)
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
<div class="title"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" class="container">
|
||||
<a style="position: absolute; left: 22px; top: 12px;" target="_blank" href="http://www.iwm-tuebingen.de">IWM</a>
|
||||
</div>
|
||||
<script>
|
||||
const index = new Index(itemTemplate, [
|
||||
['Deepzoom', 'deepzoom.html'],
|
||||
['Image', 'image.html'],
|
||||
|
||||
],
|
||||
null)
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Before Width: | Height: | Size: 163 KiB |
@ -85,8 +85,8 @@ export class PIXITileLoader extends TileLoader {
|
||||
super(tiles)
|
||||
this.destroyed = false
|
||||
this.loader = new PIXI.Loader()
|
||||
this.loader.onLoad.add(this._onLoaded.bind(this))
|
||||
this.loader.onError.add(this._onError.bind(this))
|
||||
this.loader.on('load', this._onLoaded.bind(this))
|
||||
this.loader.on('error', this._onError.bind(this))
|
||||
if (compression) {
|
||||
this.loader.use(PIXI.compressedTextures.ImageParser.use)
|
||||
}
|
||||
@ -317,7 +317,7 @@ export class RequestTileLoader extends TileLoader {
|
||||
export class WorkerTileLoader extends TileLoader {
|
||||
constructor(tiles, workerPath) {
|
||||
super(tiles)
|
||||
this.debug = false
|
||||
|
||||
let worker = (this.worker = new Worker(workerPath))
|
||||
|
||||
worker.onmessage = event => {
|
||||
@ -353,13 +353,11 @@ export class WorkerTileLoader extends TileLoader {
|
||||
}
|
||||
|
||||
cancel() {
|
||||
if (this.debug) console.log('canceling worker')
|
||||
super.cancel()
|
||||
this.worker.postMessage({ command: 'abort' })
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.debug) console.log('destroying worker')
|
||||
this.worker.postMessage({ command: 'abort' })
|
||||
this.worker.terminate()
|
||||
this.worker = null
|
||||
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 44 KiB |
@ -1,54 +1,31 @@
|
||||
let loadQueue = []
|
||||
let requestPool = []
|
||||
let pendingRequests = new Map()
|
||||
let requestCount = 0
|
||||
const batchSize = 8
|
||||
const debug = false
|
||||
|
||||
function recycledXMLHttpRequest() {
|
||||
// https://nullprogram.com/blog/2013/02/08/
|
||||
if (requestPool.length > 0) {
|
||||
return requestPool.pop()
|
||||
}
|
||||
requestCount += 1
|
||||
if (debug) console.log('create XMLHttpRequest', requestCount)
|
||||
let xhr = new XMLHttpRequest()
|
||||
return xhr
|
||||
}
|
||||
|
||||
function load() {
|
||||
while (loadQueue.length > 0 && pendingRequests.size < batchSize) {
|
||||
let tile = loadQueue.shift()
|
||||
let [col, row, url] = tile
|
||||
let xhr = recycledXMLHttpRequest()
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.responseType = 'arraybuffer'
|
||||
xhr.onload = event => {
|
||||
pendingRequests.delete(url)
|
||||
let buffer = xhr.response
|
||||
postMessage({ success: true, url, col, row, buffer }, [buffer])
|
||||
pendingRequests.delete(url)
|
||||
}
|
||||
xhr.onerror = event => {
|
||||
pendingRequests.delete(url)
|
||||
let buffer = null
|
||||
postMessage({ success: false, url, col, row, buffer })
|
||||
pendingRequests.delete(url)
|
||||
}
|
||||
xhr.onreadystatechange = () => {
|
||||
// In local files, status is 0 upon success in Mozilla Firefox
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
pendingRequests.delete(url)
|
||||
requestPool.push(xhr)
|
||||
if (debug) console.log('resuse XMLHttpRequest')
|
||||
}
|
||||
}
|
||||
if (debug) console.log('open XMLHttpRequest')
|
||||
xhr.open('GET', url, true)
|
||||
xhr.responseType = 'arraybuffer'
|
||||
if (debug) console.log('send XMLHttpRequest')
|
||||
xhr.send()
|
||||
pendingRequests.set(url, xhr)
|
||||
}
|
||||
if (loadQueue.length > 0) setTimeout(load, 1000 / 120)
|
||||
else {
|
||||
if (debug) console.log('tileloader ready')
|
||||
if (debug) console.log('Ready')
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,12 +40,10 @@ self.onmessage = event => {
|
||||
break
|
||||
case 'abort':
|
||||
loadQueue = []
|
||||
requestPool = []
|
||||
for (let xhr of pendingRequests.values()) {
|
||||
xhr.abort()
|
||||
}
|
||||
pendingRequests.clear()
|
||||
if (debug) console.log('tileloader aborted')
|
||||
if (debug) console.log('Abort')
|
||||
break
|
||||
default:
|
||||
console.warn('Unknown worker command: ' + msg.command)
|
||||
|
||||
@ -51,7 +51,7 @@ export class Tiles extends PIXI.Container {
|
||||
|
||||
this.infoColor = Colors.random()
|
||||
this.pprint()
|
||||
//this.destroyed = false
|
||||
this.destroyed = false
|
||||
}
|
||||
|
||||
/** Tests whether all tiles are loaded. **/
|
||||
@ -169,7 +169,7 @@ export class Tiles extends PIXI.Container {
|
||||
if (this.showGrid) {
|
||||
this.highlightTile(refCol, refRow)
|
||||
}
|
||||
urlpos.forEach((d) => {
|
||||
urlpos.forEach(d => {
|
||||
let [url, col, row] = d
|
||||
if (this.loader.schedule(url, col, row)) {
|
||||
if (onlyone) {
|
||||
@ -229,7 +229,7 @@ export class Tiles extends PIXI.Container {
|
||||
* cancelled.
|
||||
**/
|
||||
destroy() {
|
||||
//this.destroyed = true
|
||||
this.destroyed = true
|
||||
this.loader.destroy()
|
||||
super.destroy({ children: true }) // Calls destroyChildren
|
||||
this.available.clear()
|
||||
|
||||
@ -16,12 +16,12 @@
|
||||
<div class="flipWrapper">
|
||||
<div class="flipCard">
|
||||
<img class="flipFace front" src="" />
|
||||
<div class="flipFace back" style="visibility: hidden"></div>
|
||||
<div class="flipFace back" style="visibility:hidden;"></div>
|
||||
</div>
|
||||
<!-- Very tricky problem to scale svgs: see https://css-tricks.com/scale-svg/ -->
|
||||
<svg
|
||||
class="flipButton backBtn"
|
||||
style="visibility: hidden"
|
||||
style="visibility:hidden;"
|
||||
viewBox="0 0 100 100"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
>
|
||||
@ -41,7 +41,9 @@
|
||||
</template>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Flip Effect</h1>
|
||||
<h1>
|
||||
Flip Effect
|
||||
</h1>
|
||||
<p>
|
||||
The flip effect, which simulates a flip between a front and back view of an object by means of a 3D
|
||||
rotation, is an interaction between a PIXI scatter object and a DOM Flip effect. The PIXI scatter is used as
|
||||
@ -61,8 +63,10 @@
|
||||
</li>
|
||||
<li>If the back card is closed, the DOM nodes are removed and the PIXI scatter is shown again.</li>
|
||||
</ul>
|
||||
<h3>Example</h3>
|
||||
<main id="main" style="border: 1px solid red; position: relative">
|
||||
<h3>
|
||||
Example
|
||||
</h3>
|
||||
<main id="main" style="border: 1px solid red; position: relative;">
|
||||
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
</main>
|
||||
<script class="doctest">
|
||||
|
||||
@ -47,7 +47,7 @@ export class ScatterLoader extends CardLoader {
|
||||
width: w,
|
||||
height: h,
|
||||
view: canvas,
|
||||
resolution: resolution,
|
||||
resolution: resolution
|
||||
})
|
||||
|
||||
let displayObject = this.scatter.displayObject
|
||||
@ -88,7 +88,7 @@ export class ScatterLoader extends CardLoader {
|
||||
let image = isImage ? domNode : document.createElement('img')
|
||||
let [x, y, w, h, cloneURL] = this.cloneScatterImage()
|
||||
let [ww, hh] = this.unscaledSize()
|
||||
image.onload = (e) => {
|
||||
image.onload = e => {
|
||||
if (!isImage) domNode.appendChild(image)
|
||||
this.x = x
|
||||
this.y = y
|
||||
@ -98,7 +98,7 @@ export class ScatterLoader extends CardLoader {
|
||||
this.rotation = this.scatter.rotation
|
||||
resolve(this)
|
||||
}
|
||||
image.onerror = (e) => {
|
||||
image.onerror = e => {
|
||||
reject(this)
|
||||
}
|
||||
image.src = cloneURL
|
||||
@ -113,7 +113,7 @@ export default class FlipEffect {
|
||||
this.backLoader = backLoader
|
||||
this.scatterLoader = new ScatterLoader(scatter)
|
||||
this.domFlip = new DOMFlip(domScatterContainer, flipTemplate, this.scatterLoader, backLoader, {
|
||||
onBack: this.backCardClosed.bind(this),
|
||||
onBack: this.backCardClosed.bind(this)
|
||||
})
|
||||
this.setupInfoButton()
|
||||
}
|
||||
@ -121,7 +121,7 @@ export default class FlipEffect {
|
||||
startFlip() {
|
||||
let center = this.flipCenter()
|
||||
let loader = this.backLoader
|
||||
this.domFlip.load().then((domFlip) => {
|
||||
this.domFlip.load().then(domFlip => {
|
||||
this.scatter.displayObject.visible = false
|
||||
domFlip.centerAt(center)
|
||||
domFlip.zoom(this.scatter.scale)
|
||||
@ -176,10 +176,10 @@ export default class FlipEffect {
|
||||
this.infoBtn.lineTo(0, 14)
|
||||
this.infoBtn.endFill()
|
||||
|
||||
this.infoBtn.on('click', (e) => {
|
||||
this.infoBtn.on('click', e => {
|
||||
this.infoSelected()
|
||||
})
|
||||
this.infoBtn.on('tap', (e) => {
|
||||
this.infoBtn.on('tap', e => {
|
||||
this.infoSelected()
|
||||
})
|
||||
|
||||
@ -200,7 +200,7 @@ export default class FlipEffect {
|
||||
displayObject.addChild(this.infoBtn)
|
||||
}
|
||||
|
||||
this.scatter.addTransformEventCallback((e) => {
|
||||
this.scatter.addTransformEventCallback(e => {
|
||||
let displayObject = this.scatter.displayObject
|
||||
if (displayObject.foreground) {
|
||||
if (e.scale) {
|
||||
@ -217,7 +217,7 @@ export default class FlipEffect {
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.width = 88 * 4
|
||||
canvas.height = 44 * 4
|
||||
svgImage.onload = (e) => {
|
||||
svgImage.onload = e => {
|
||||
let displayObject = this.scatter.displayObject
|
||||
canvas.getContext('2d').drawImage(svgImage, 0, 0, canvas.width, canvas.height)
|
||||
let texure = new PIXI.Texture(new PIXI.BaseTexture(canvas))
|
||||
@ -234,10 +234,10 @@ export default class FlipEffect {
|
||||
this.infoBtn.position = new PIXI.Point(w, h)
|
||||
this.infoBtn.interactive = true
|
||||
this.infoBtn.updateTransform()
|
||||
this.infoBtn.on('click', (e) => {
|
||||
this.infoBtn.on('click', e => {
|
||||
this.infoSelected()
|
||||
})
|
||||
this.infoBtn.on('tap', (e) => {
|
||||
this.infoBtn.on('tap', e => {
|
||||
this.infoSelected()
|
||||
})
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 739 KiB |
@ -1,180 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Flippable</title>
|
||||
<title>PIXI Flippable</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<script src="../3rdparty/gsap/src/minified/TweenMax.min.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Flippable</h1>
|
||||
<p>
|
||||
Using the Flippable class, any PIXI element (PIXI.DisplayObject) can be back-mounted (which can include
|
||||
another PIXI.DisplayObject), and turning it over to the back can be adjusted by many parameters in speed and
|
||||
behavior.
|
||||
</p>
|
||||
<p><a href="../../doc/out/Flippable.html">JavaScript API</a></p>
|
||||
<p>Let's look at some flippable examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Six flippable elements and one button.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../3rdparty/gsap/src/minified/TweenMax.min.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Flippable</h1>
|
||||
<p>
|
||||
Using the Flippable class, any PIXI element (PIXI.DisplayObject) can be back-mounted
|
||||
(which can include another PIXI.DisplayObject), and turning it over to the back can
|
||||
be adjusted by many parameters in speed and behavior.
|
||||
</p>
|
||||
<p><a href="../../doc/out/Flippable.html">JavaScript API</a></p>
|
||||
<p>Let's look at some flippable examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Six flippable elements and one button.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
app.loadTextures(
|
||||
[
|
||||
'./assets/fruit-1.jpg',
|
||||
'./assets/fruit-2.jpg',
|
||||
'./assets/fruit-3.jpg',
|
||||
'./assets/fruit-4.jpg',
|
||||
'./assets/fruit-5.jpg',
|
||||
'./assets/fruit-6.jpg',
|
||||
'./assets/fruit-7.jpg',
|
||||
'./assets/fruit-8.jpg',
|
||||
'./assets/fruit-9.jpg',
|
||||
'./assets/fruit-10.jpg'
|
||||
],
|
||||
(textures) => {
|
||||
// Example 1
|
||||
//--------------------
|
||||
const sprite1 = new PIXI.Sprite(textures.get('./assets/fruit-1.jpg'))
|
||||
sprite1.position.set(10, 10)
|
||||
sprite1.scale.set(0.2, 0.2)
|
||||
const sprite2 = new PIXI.Sprite(textures.get('./assets/fruit-2.jpg'))
|
||||
app.loadTextures([
|
||||
'./assets/fruit-1.jpg',
|
||||
'./assets/fruit-2.jpg',
|
||||
'./assets/fruit-3.jpg',
|
||||
'./assets/fruit-4.jpg',
|
||||
'./assets/fruit-5.jpg',
|
||||
'./assets/fruit-6.jpg',
|
||||
'./assets/fruit-7.jpg',
|
||||
'./assets/fruit-8.jpg',
|
||||
'./assets/fruit-9.jpg',
|
||||
'./assets/fruit-10.jpg'
|
||||
], textures => {
|
||||
|
||||
const flippable1 = new Flippable(sprite1, sprite2, app.renderer)
|
||||
// Example 1
|
||||
//--------------------
|
||||
const sprite1 = new PIXI.Sprite(textures.get('./assets/fruit-1.jpg'))
|
||||
sprite1.position.set(10, 10)
|
||||
sprite1.scale.set(.2, .2)
|
||||
const sprite2 = new PIXI.Sprite(textures.get('./assets/fruit-2.jpg'))
|
||||
|
||||
// Example 2
|
||||
//--------------------
|
||||
const sprite3 = new PIXI.Sprite(textures.get('./assets/fruit-3.jpg'))
|
||||
sprite3.position.set(10, 120)
|
||||
sprite3.scale.set(0.2, 0.2)
|
||||
const sprite4 = new PIXI.Sprite(textures.get('./assets/fruit-4.jpg'))
|
||||
const flippable1 = new Flippable(sprite1, sprite2, app.renderer)
|
||||
|
||||
const flippable2 = new Flippable(sprite3, sprite4, app.renderer, {
|
||||
duration: 6,
|
||||
ease: Bounce.easeOut,
|
||||
shadow: true,
|
||||
eulerX: 0.8
|
||||
})
|
||||
// Example 2
|
||||
//--------------------
|
||||
const sprite3 = new PIXI.Sprite(textures.get('./assets/fruit-3.jpg'))
|
||||
sprite3.position.set(10, 120)
|
||||
sprite3.scale.set(.2, .2)
|
||||
const sprite4 = new PIXI.Sprite(textures.get('./assets/fruit-4.jpg'))
|
||||
|
||||
// Example 3
|
||||
//--------------------
|
||||
const sprite5 = new PIXI.Sprite(textures.get('./assets/fruit-5.jpg'))
|
||||
sprite5.position.set(10, 240)
|
||||
sprite5.scale.set(0.2, 0.2)
|
||||
const sprite6 = new PIXI.Sprite(textures.get('./assets/fruit-6.jpg'))
|
||||
sprite6.position.set(400, 180)
|
||||
sprite6.scale.set(0.3, 0.3)
|
||||
sprite6.rotation = 0.3
|
||||
const flippable2 = new Flippable(sprite3, sprite4, app.renderer, {
|
||||
duration: 6,
|
||||
ease: Bounce.easeOut,
|
||||
shadow: true,
|
||||
eulerX: .8
|
||||
})
|
||||
|
||||
const flippable3 = new Flippable(sprite5, sprite6, app.renderer, {
|
||||
duration: 4,
|
||||
ease: Circ.easeInOut,
|
||||
shadow: true,
|
||||
useBackTransforms: true
|
||||
})
|
||||
// Example 3
|
||||
//--------------------
|
||||
const sprite5 = new PIXI.Sprite(textures.get('./assets/fruit-5.jpg'))
|
||||
sprite5.position.set(10, 240)
|
||||
sprite5.scale.set(.2, .2)
|
||||
const sprite6 = new PIXI.Sprite(textures.get('./assets/fruit-6.jpg'))
|
||||
sprite6.position.set(400, 180)
|
||||
sprite6.scale.set(.3, .3)
|
||||
sprite6.rotation = .3
|
||||
|
||||
// Example 4
|
||||
//--------------------
|
||||
const sprite7 = new PIXI.Sprite(textures.get('./assets/fruit-7.jpg'))
|
||||
sprite7.position.set(700, 10)
|
||||
sprite7.scale.set(0.2, 0.2)
|
||||
const sprite8 = new PIXI.Sprite(textures.get('./assets/fruit-8.jpg'))
|
||||
sprite8.position.set(550, 180)
|
||||
sprite8.scale.set(0.15, 0.15)
|
||||
sprite8.skew.set(0, 0.1)
|
||||
const flippable3 = new Flippable(sprite5, sprite6, app.renderer, {
|
||||
duration: 4,
|
||||
ease: Circ.easeInOut,
|
||||
shadow: true,
|
||||
useBackTransforms: true
|
||||
})
|
||||
|
||||
const flippable4 = new Flippable(sprite7, sprite8, app.renderer, {
|
||||
duration: 5,
|
||||
ease: Elastic.easeOut.config(1, 0.3),
|
||||
transformEase: Elastic.easeOut.config(1, 0.3),
|
||||
shadow: true,
|
||||
focus: 600,
|
||||
near: 50,
|
||||
far: 10000,
|
||||
useBackTransforms: true
|
||||
})
|
||||
// Example 4
|
||||
//--------------------
|
||||
const sprite7 = new PIXI.Sprite(textures.get('./assets/fruit-7.jpg'))
|
||||
sprite7.position.set(700, 10)
|
||||
sprite7.scale.set(.2, .2)
|
||||
const sprite8 = new PIXI.Sprite(textures.get('./assets/fruit-8.jpg'))
|
||||
sprite8.position.set(550, 180)
|
||||
sprite8.scale.set(.15, .15)
|
||||
sprite8.skew.set(0, .1)
|
||||
|
||||
// Example 5
|
||||
//--------------------
|
||||
const sprite9 = new PIXI.Sprite(textures.get('./assets/fruit-9.jpg'))
|
||||
sprite9.position.set(700, 130)
|
||||
sprite9.scale.set(0.2, 0.2)
|
||||
sprite9.skew.set(0.2, 0.2)
|
||||
const sprite10 = new PIXI.Sprite(textures.get('./assets/fruit-10.jpg'))
|
||||
sprite10.position.set(700, 130)
|
||||
sprite10.scale.set(0.2, 0.2)
|
||||
sprite10.skew.set(-0.2, -0.2)
|
||||
const flippable4 = new Flippable(sprite7, sprite8, app.renderer, {
|
||||
duration: 5,
|
||||
ease: Elastic.easeOut.config(1, 0.3),
|
||||
transformEase: Elastic.easeOut.config(1, 0.3),
|
||||
shadow: true,
|
||||
focus: 600,
|
||||
near: 50,
|
||||
far: 10000,
|
||||
useBackTransforms: true
|
||||
})
|
||||
|
||||
const flippable5 = new Flippable(sprite9, sprite10, app.renderer, {
|
||||
duration: 2,
|
||||
useBackTransforms: true
|
||||
})
|
||||
// Example 5
|
||||
//--------------------
|
||||
const sprite9 = new PIXI.Sprite(textures.get('./assets/fruit-9.jpg'))
|
||||
sprite9.position.set(700, 130)
|
||||
sprite9.scale.set(.2, .2)
|
||||
sprite9.skew.set(.2, .2)
|
||||
const sprite10 = new PIXI.Sprite(textures.get('./assets/fruit-10.jpg'))
|
||||
sprite10.position.set(700, 130)
|
||||
sprite10.scale.set(.2, .2)
|
||||
sprite10.skew.set(-.2, -.2)
|
||||
|
||||
// Example 6
|
||||
//--------------------
|
||||
const graphic1 = new PIXI.Graphics()
|
||||
graphic1.position.set(700, 280)
|
||||
graphic1.beginFill(0x6b6acf, 1)
|
||||
graphic1.drawRect(0, 0, 160, 100)
|
||||
graphic1.lineStyle(1, 0xe7bc51, 1)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
graphic1.drawCircle(Math.random() * 160, Math.random() * 100, 2)
|
||||
}
|
||||
const flippable5 = new Flippable(sprite9, sprite10, app.renderer, {
|
||||
duration: 2,
|
||||
useBackTransforms: true
|
||||
})
|
||||
|
||||
const graphic2 = new PIXI.Graphics()
|
||||
graphic2.position.set(700, 280)
|
||||
graphic2.beginFill(0xcedc9c, 1)
|
||||
graphic2.drawRect(0, 0, 160, 100)
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
graphic2.beginFill((Math.random() * 0xffffff) << 0, 1)
|
||||
graphic2.lineStyle(1, (Math.random() * 0xffffff) << 0, 1)
|
||||
graphic2.drawCircle(Math.random() * 160, Math.random() * 100, 2)
|
||||
}
|
||||
// Example 6
|
||||
//--------------------
|
||||
const graphic1 = new PIXI.Graphics()
|
||||
graphic1.position.set(700, 280)
|
||||
graphic1.beginFill(0x6b6acf, 1)
|
||||
graphic1.drawRect(0, 0, 160, 100)
|
||||
graphic1.lineStyle(1, 0xe7bc51, 1)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
graphic1.drawCircle(Math.random() * 160, Math.random() * 100, 2)
|
||||
}
|
||||
|
||||
const flippable6 = new Flippable(graphic1, graphic2, app.renderer, {
|
||||
eulerX: -0.3
|
||||
})
|
||||
const graphic2 = new PIXI.Graphics()
|
||||
graphic2.position.set(700, 280)
|
||||
graphic2.beginFill(0xcedc9c, 1)
|
||||
graphic2.drawRect(0, 0, 160, 100)
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
graphic2.beginFill(Math.random() * 0xffffff << 0, 1)
|
||||
graphic2.lineStyle(1, Math.random() * 0xffffff << 0, 1)
|
||||
graphic2.drawCircle(Math.random() * 160, Math.random() * 100, 2)
|
||||
}
|
||||
|
||||
// Button
|
||||
//--------------------
|
||||
const button = new Button({
|
||||
x: 400,
|
||||
y: 10,
|
||||
label: 'Toggle',
|
||||
type: 'checkbox',
|
||||
action: (e) => {
|
||||
flippable1.toggle()
|
||||
flippable2.toggle()
|
||||
flippable3.toggle()
|
||||
flippable4.toggle()
|
||||
flippable5.toggle()
|
||||
flippable6.toggle()
|
||||
}
|
||||
})
|
||||
const flippable6 = new Flippable(graphic1, graphic2, app.renderer, {
|
||||
eulerX: -.3
|
||||
})
|
||||
|
||||
app.scene.addChild(sprite1, sprite3, sprite5, sprite7, sprite9, graphic1, button)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
// Button
|
||||
//--------------------
|
||||
const button = new Button({
|
||||
x: 400,
|
||||
y: 10,
|
||||
label: 'Toggle',
|
||||
type: 'checkbox',
|
||||
action: e => {
|
||||
flippable1.toggle()
|
||||
flippable2.toggle()
|
||||
flippable3.toggle()
|
||||
flippable4.toggle()
|
||||
flippable5.toggle()
|
||||
flippable6.toggle()
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(sprite1, sprite3, sprite5, sprite7, sprite9, graphic1, button)
|
||||
|
||||
}, {resolutionDependent: false})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -86,7 +86,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
focus: 800,
|
||||
near: 10,
|
||||
far: 10000,
|
||||
orthographic: false,
|
||||
orthographic: false
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -228,7 +228,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
height: this.opts.useBackTransforms ? toObject.height * 2 : fromObject.height * 2,
|
||||
rotation: this.opts.useBackTransforms ? toObject.rotation : fromObject.rotation,
|
||||
skewX: this.opts.useBackTransforms ? toObject.skew.x : fromObject.skew.x,
|
||||
skewY: this.opts.useBackTransforms ? toObject.skew.y : fromObject.skew.y,
|
||||
skewY: this.opts.useBackTransforms ? toObject.skew.y : fromObject.skew.y
|
||||
}
|
||||
|
||||
// set toObject end values
|
||||
@ -265,7 +265,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
if (this.opts.onComplete) {
|
||||
this.opts.onComplete(this, this)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// x & y
|
||||
@ -273,7 +273,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
TweenLite.to(this, this.opts.duration, {
|
||||
x: to.x,
|
||||
y: to.y,
|
||||
ease: this.opts.transformEase,
|
||||
ease: this.opts.transformEase
|
||||
})
|
||||
|
||||
// width & height
|
||||
@ -281,7 +281,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
TweenLite.to([front, back], this.opts.duration, {
|
||||
width: to.width,
|
||||
height: to.height,
|
||||
ease: this.opts.transformEase,
|
||||
ease: this.opts.transformEase
|
||||
})
|
||||
|
||||
// rotation
|
||||
@ -289,9 +289,9 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
TweenLite.to(this, this.opts.duration, {
|
||||
directionalRotation: {
|
||||
rotation: `${to.rotation}_short`,
|
||||
useRadians: true,
|
||||
useRadians: true
|
||||
},
|
||||
ease: this.opts.transformEase,
|
||||
ease: this.opts.transformEase
|
||||
})
|
||||
|
||||
// skewX & skewY
|
||||
@ -299,7 +299,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
TweenLite.to(this.skew, this.opts.duration, {
|
||||
x: to.skewX,
|
||||
y: to.skewY,
|
||||
ease: this.opts.transformEase,
|
||||
ease: this.opts.transformEase
|
||||
})
|
||||
|
||||
// camera
|
||||
@ -308,7 +308,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
.to(this.euler, half, {
|
||||
x: this.opts.eulerX,
|
||||
y: this.opts.eulerY,
|
||||
ease,
|
||||
ease
|
||||
})
|
||||
.to(this.euler, half, { x: 0, y: 0, ease })
|
||||
|
||||
@ -385,7 +385,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
const bounds = displayObject.getBounds()
|
||||
return {
|
||||
x: bounds.x + bounds.width / 2,
|
||||
y: bounds.y + bounds.height / 2,
|
||||
y: bounds.y + bounds.height / 2
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,7 +411,7 @@ export default class Flippable extends PIXI.projection.Camera3d {
|
||||
displayObject.skew.x,
|
||||
displayObject.skew.y,
|
||||
displayObject.pivot.x,
|
||||
displayObject.pivot.y,
|
||||
displayObject.pivot.y
|
||||
]
|
||||
|
||||
displayObject.position.set(0, 0)
|
||||
|
||||
|
Before Width: | Height: | Size: 1022 KiB |
@ -13,7 +13,7 @@
|
||||
</head>
|
||||
<body onload="Doctest.run();" >
|
||||
<h1>
|
||||
<a href="../index.html">lib.</a><a href="index.html">pixi.</a>Functional Tests
|
||||
Functional Tests
|
||||
</h1>
|
||||
<p>
|
||||
If you want to test the UI in all functional aspects, it'is important to be able
|
||||
|
||||
@ -1,180 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI ForceLayout</title>
|
||||
<title>PIXI ForceLayout</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<script src="./lib/graphology.min.js"></script>
|
||||
<script src="./lib/graphology-layout-forceatlas2.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>ForceLayout</h1>
|
||||
<p>
|
||||
Comparison of a <a href="https://github.com/d3/d3-force/blob/master/README.md">D3 ForceLayout</a> with a
|
||||
<a href="https://github.com/graphology/graphology-layout-forceatlas2">ForceAtlas 2</a> forcelayout.
|
||||
</p>
|
||||
<h2>Let's look at the D3 ForceLayout:</h2>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="./lib/graphology.min.js"></script>
|
||||
<script src="./lib/graphology-layout-forceatlas2.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>ForceLayout</h1>
|
||||
<p>
|
||||
Comparison of a <a href="https://github.com/d3/d3-force/blob/master/README.md">D3 ForceLayout</a> with a <a href="https://github.com/graphology/graphology-layout-forceatlas2">ForceAtlas 2</a> forcelayout.
|
||||
</p>
|
||||
<h2>Let's look at the D3 ForceLayout:</h2><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
|
||||
app.loadTextures(
|
||||
['./assets/circle.png'],
|
||||
(textures) => {
|
||||
// add sprites
|
||||
//--------------------
|
||||
const sprites = []
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const sprite = new PIXI.Sprite(textures.get('./assets/circle.png'))
|
||||
sprite.x = randomInt(0, app.size.width)
|
||||
sprite.y = randomInt(0, app.size.height)
|
||||
sprite.width = sprite.height = 2
|
||||
sprite.anchor.set(0.5, 0.5)
|
||||
sprite.__random = Math.random()
|
||||
sprites.push(sprite)
|
||||
}
|
||||
app.loadTextures([
|
||||
'./assets/circle.png'
|
||||
], textures => {
|
||||
|
||||
app.scene.addChild(...sprites)
|
||||
// add sprites
|
||||
//--------------------
|
||||
const sprites = []
|
||||
|
||||
// force simulation
|
||||
//--------------------
|
||||
const forceCollide = d3.forceCollide().radius((d) => d.width / 2 + 1)
|
||||
const simulation = d3
|
||||
.forceSimulation(sprites)
|
||||
.on('tick', () => {
|
||||
//forceCollide.radius(d => d.radius)
|
||||
})
|
||||
.force('collide', forceCollide)
|
||||
.force('x', d3.forceX(app.center.x))
|
||||
.force('y', d3.forceY(app.center.y))
|
||||
.stop()
|
||||
.force(
|
||||
'radial',
|
||||
d3.forceRadial(
|
||||
(d) => {
|
||||
return d.__random < 0.5 ? 60 : 160
|
||||
},
|
||||
app.center.x,
|
||||
app.center.y
|
||||
)
|
||||
)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const sprite = new PIXI.Sprite(textures.get('./assets/circle.png'))
|
||||
sprite.x = randomInt(0, app.size.width)
|
||||
sprite.y = randomInt(0, app.size.height)
|
||||
sprite.width = sprite.height = 2
|
||||
sprite.anchor.set(.5, .5)
|
||||
sprite.__random = Math.random()
|
||||
sprites.push(sprite)
|
||||
}
|
||||
|
||||
d3.timeout(() => {
|
||||
simulation.restart()
|
||||
}, 500)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
app.scene.addChild(...sprites)
|
||||
|
||||
<h2>D3 ForceLayout with links:</h2>
|
||||
<br />
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
// force simulation
|
||||
//--------------------
|
||||
const forceCollide = d3.forceCollide().radius(d => d.width / 2 + 1)
|
||||
const simulation = d3.forceSimulation(sprites)
|
||||
.on('tick', () => {
|
||||
//forceCollide.radius(d => d.radius)
|
||||
})
|
||||
.force('collide', forceCollide)
|
||||
.force('x', d3.forceX(app.center.x))
|
||||
.force('y', d3.forceY(app.center.y))
|
||||
.stop()
|
||||
.force('radial', d3.forceRadial(d => {
|
||||
return d.__random < .5 ? 60 : 160
|
||||
}, app.center.x, app.center.y))
|
||||
|
||||
app2.loadTextures(
|
||||
['./assets/circle2.png'],
|
||||
(textures) => {
|
||||
// add sprites
|
||||
//--------------------
|
||||
const sprites = []
|
||||
d3.timeout(() => {
|
||||
simulation.restart()
|
||||
}, 500)
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const sprite = new PIXI.Sprite(textures.get('./assets/circle2.png'))
|
||||
sprite.id = i
|
||||
sprite.x = randomInt(0, app2.size.width)
|
||||
sprite.y = randomInt(0, app2.size.height)
|
||||
sprite.width = sprite.height = 16
|
||||
sprite.anchor.set(0.5, 0.5)
|
||||
sprites.push(sprite)
|
||||
}
|
||||
}, {resolutionDependent: false})
|
||||
|
||||
app2.scene.addChild(...sprites)
|
||||
</script>
|
||||
|
||||
const links = new PIXI.Graphics()
|
||||
app2.scene.addChildAt(links, 0)
|
||||
<h2>D3 ForceLayout with links:</h2><br />
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
|
||||
// force simulation
|
||||
//--------------------
|
||||
const forceCollide = d3.forceCollide().radius((d) => d.width / 2 + 4)
|
||||
const forceLink = d3
|
||||
.forceLink([
|
||||
{ source: 88, target: 8 },
|
||||
{ source: 47, target: 55 },
|
||||
{ source: 70, target: 1 },
|
||||
{ source: 12, target: 12 },
|
||||
{ source: 26, target: 33 },
|
||||
{ source: 48, target: 53 },
|
||||
{ source: 10, target: 70 },
|
||||
{ source: 68, target: 61 },
|
||||
{ source: 28, target: 65 },
|
||||
{ source: 12, target: 34 },
|
||||
{ source: 6, target: 55 },
|
||||
{ source: 9, target: 16 },
|
||||
{ source: 87, target: 96 },
|
||||
{ source: 64, target: 24 },
|
||||
{ source: 98, target: 14 },
|
||||
{ source: 18, target: 23 },
|
||||
{ source: 53, target: 62 },
|
||||
{ source: 11, target: 53 },
|
||||
{ source: 43, target: 23 },
|
||||
{ source: 80, target: 9 },
|
||||
{ source: 72, target: 88 },
|
||||
{ source: 62, target: 3 },
|
||||
{ source: 72, target: 15 },
|
||||
{ source: 84, target: 25 },
|
||||
{ source: 57, target: 58 },
|
||||
{ source: 87, target: 19 }
|
||||
])
|
||||
.id((d) => d.id)
|
||||
.strength(0.05)
|
||||
const simulation = d3
|
||||
.forceSimulation(sprites)
|
||||
.on('tick', () => {
|
||||
links.clear()
|
||||
links.lineStyle(1, 0xfdc02f)
|
||||
for (let link of forceLink.links()) {
|
||||
links.moveTo(link.source.x, link.source.y)
|
||||
links.lineTo(link.target.x, link.target.y)
|
||||
}
|
||||
})
|
||||
.force('collide', forceCollide)
|
||||
.force('link', forceLink)
|
||||
.stop()
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
d3.timeout(() => {
|
||||
simulation.restart()
|
||||
}, 1000)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app2.loadTextures([
|
||||
'./assets/circle2.png'
|
||||
], textures => {
|
||||
|
||||
// add sprites
|
||||
//--------------------
|
||||
const sprites = []
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const sprite = new PIXI.Sprite(textures.get('./assets/circle2.png'))
|
||||
sprite.id = i
|
||||
sprite.x = randomInt(0, app2.size.width)
|
||||
sprite.y = randomInt(0, app2.size.height)
|
||||
sprite.width = sprite.height = 16
|
||||
sprite.anchor.set(.5, .5)
|
||||
sprites.push(sprite)
|
||||
}
|
||||
|
||||
app2.scene.addChild(...sprites)
|
||||
|
||||
const links = new PIXI.Graphics()
|
||||
app2.scene.addChildAt(links, 0)
|
||||
|
||||
// force simulation
|
||||
//--------------------
|
||||
const forceCollide = d3.forceCollide().radius(d => d.width / 2 + 4)
|
||||
const forceLink = d3.forceLink([
|
||||
{source: 88, target: 8},
|
||||
{source: 47, target: 55},
|
||||
{source: 70, target: 1},
|
||||
{source: 12, target: 12},
|
||||
{source: 26, target: 33},
|
||||
{source: 48, target: 53},
|
||||
{source: 10, target: 70},
|
||||
{source: 68, target: 61},
|
||||
{source: 28, target: 65},
|
||||
{source: 12, target: 34},
|
||||
{source: 6, target: 55},
|
||||
{source: 9, target: 16},
|
||||
{source: 87, target: 96},
|
||||
{source: 64, target: 24},
|
||||
{source: 98, target: 14},
|
||||
{source: 18, target: 23},
|
||||
{source: 53, target: 62},
|
||||
{source: 11, target: 53},
|
||||
{source: 43, target: 23},
|
||||
{source: 80, target: 9},
|
||||
{source: 72, target: 88},
|
||||
{source: 62, target: 3},
|
||||
{source: 72, target: 15},
|
||||
{source: 84, target: 25},
|
||||
{source: 57, target: 58},
|
||||
{source: 87, target: 19}
|
||||
]).id(d => d.id).strength(.05)
|
||||
const simulation = d3.forceSimulation(sprites)
|
||||
.on('tick', () => {
|
||||
links.clear()
|
||||
links.lineStyle(1, 0xfdc02f)
|
||||
for (let link of forceLink.links()) {
|
||||
links.moveTo(link.source.x, link.source.y)
|
||||
links.lineTo(link.target.x, link.target.y)
|
||||
}
|
||||
})
|
||||
.force('collide', forceCollide)
|
||||
.force('link', forceLink)
|
||||
.stop()
|
||||
|
||||
d3.timeout(() => {
|
||||
simulation.restart()
|
||||
}, 1000)
|
||||
|
||||
}, {resolutionDependent: false})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -1,68 +1,63 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>PIXI Lib 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" />
|
||||
<head>
|
||||
<title>PIXI Lib 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>
|
||||
<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>
|
||||
<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>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<h2><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Doctests</h2>
|
||||
<div id="container" class="container"></div>
|
||||
<script>
|
||||
const index = new Index(
|
||||
itemTemplate,
|
||||
[
|
||||
['PIXI.Application', 'application.html'],
|
||||
['Application', 'app.html'],
|
||||
['Badge', 'badge.html'],
|
||||
['Button', 'button.html'],
|
||||
['ButtonGroup', 'buttongroup.html'],
|
||||
['Coordinates', 'coordinates.html'],
|
||||
['DeepZoom', 'deepzoom/index.html'],
|
||||
['Flippable', 'flippable.html'],
|
||||
['LabeledGraphics', 'labeledgraphics.html'],
|
||||
['List', 'list.html'],
|
||||
['Maps', 'maps/index.html'],
|
||||
['Message', 'message.html'],
|
||||
['Modal', 'modal.html'],
|
||||
['Tooltip', 'tooltip.html'],
|
||||
['Popover', 'popover.html'],
|
||||
['Popup', 'popup.html'],
|
||||
['PopupMenu', 'popupmenu.html'],
|
||||
['Progress', 'progress.html'],
|
||||
['Slider', 'slider.html'],
|
||||
['Switch', 'switch.html'],
|
||||
['Volatile', 'volatile.html'],
|
||||
['Scatter', 'scatter.html'],
|
||||
['Flip Effect', 'flipeffect.html'],
|
||||
['Blur Filter', 'blurfilter.html'],
|
||||
['Text', 'text.html'],
|
||||
['Text Transform', 'text-transform.html'],
|
||||
['Scrollview', 'scrollview.html'],
|
||||
['Stylus', 'stylus.html']
|
||||
],
|
||||
null
|
||||
)
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
<div class="title"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container" class="container">
|
||||
<a style="position: absolute; left: 22px; top: 12px;" target="_blank" href="http://www.iwm-tuebingen.de">IWM</a>
|
||||
</div>
|
||||
<script>
|
||||
const index = new Index(itemTemplate, [
|
||||
['PIXI.Application', 'application.html'],
|
||||
['Application', 'app.html'],
|
||||
['Badge', 'badge.html'],
|
||||
['Button', 'button.html'],
|
||||
['ButtonGroup', 'buttongroup.html'],
|
||||
['Coordinates', 'coordinates.html'],
|
||||
['DeepZoom', 'deepzoom/index.html'],
|
||||
['Flippable', 'flippable.html'],
|
||||
['LabeledGraphics', 'labeledgraphics.html'],
|
||||
['List', 'list.html'],
|
||||
['Maps', 'maps/index.html'],
|
||||
['Message', 'message.html'],
|
||||
['Modal', 'modal.html'],
|
||||
['Tooltip', 'tooltip.html'],
|
||||
['Popover', 'popover.html'],
|
||||
['Popup', 'popup.html'],
|
||||
['PopupMenu', 'popupmenu.html'],
|
||||
['Progress', 'progress.html'],
|
||||
['Slider', 'slider.html'],
|
||||
['Switch', 'switch.html'],
|
||||
['Volatile', 'volatile.html'],
|
||||
['Scatter', 'scatter.html'],
|
||||
['Flip Effect', 'flipeffect.html'],
|
||||
['Blur Filter', 'blurfilter.html'],
|
||||
['Text', 'text.html'],
|
||||
['Text Transform', 'text-transform.html'],
|
||||
['Scrollview', 'scrollview.html'],
|
||||
['Stylus', 'stylus.html']
|
||||
],
|
||||
null)
|
||||
index.load()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 MiB |
@ -1,92 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI LabeledGraphics</title>
|
||||
<title>PIXI LabeledGraphics</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>LabeledGraphics</h1>
|
||||
<p>
|
||||
A labeled graphics extends the PIXI.Graphics class with an ensureLabel method that allows to place and reuse
|
||||
labels, i.e. PIXI.Text objects. The labels are cached by a given key and only rendered anew if necessary.
|
||||
</p>
|
||||
<p><a href="../../doc/out/LabeledGraphics.html">JavaScript API</a></p>
|
||||
<p>Let's look at an example:</p>
|
||||
<br />
|
||||
<canvas id="canvas1" class="interactive"></canvas>
|
||||
<p>What you should see: A box with a label.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas1,
|
||||
width: 900,
|
||||
height: 150
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>LabeledGraphics</h1>
|
||||
<p>
|
||||
A labeled graphics extends the PIXI.Graphics class with an ensureLabel method that allows
|
||||
to place and reuse labels, i.e. PIXI.Text objects. The labels are cached by a given key
|
||||
and only rendered anew if necessary.
|
||||
</p>
|
||||
<p><a href="../../doc/out/LabeledGraphics.html">JavaScript API</a></p>
|
||||
<p>Let's look at an example:</p><br />
|
||||
<canvas id="canvas1" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: A box with a label.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas1,
|
||||
width: 900,
|
||||
height: 150
|
||||
}).setup().run()
|
||||
|
||||
const labeledBox = new LabeledGraphics()
|
||||
labeledBox.ensureLabel('key', 'This is a label in a box', { justify: 'top' })
|
||||
labeledBox.beginFill(0x333333)
|
||||
labeledBox.drawRect(0, 0, 300, 100)
|
||||
labeledBox.endFill()
|
||||
const labeledBox = new LabeledGraphics()
|
||||
labeledBox.ensureLabel('key', 'This is a label in a box', { justify: 'top'})
|
||||
labeledBox.beginFill(0x333333)
|
||||
labeledBox.drawRect(0, 0, 300, 100)
|
||||
labeledBox.endFill()
|
||||
|
||||
app.scene.addChild(labeledBox)
|
||||
</script>
|
||||
<h2>Zoomable Labels</h2>
|
||||
<p>
|
||||
Labeled graphics can also be used to represent zoomable text columns in more complex layouts. Use the
|
||||
mousewheel to zoom the following text column:
|
||||
</p>
|
||||
app.scene.addChild(labeledBox)
|
||||
</script>
|
||||
<h2>Zoomable Labels</h2>
|
||||
<p>Labeled graphics can also be used to represent zoomable text columns in more complex layouts.
|
||||
Use the mousewheel to zoom the following text column:
|
||||
</p>
|
||||
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 150
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 150
|
||||
}).setup().run()
|
||||
|
||||
const loremIpsum = `Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
const loremIpsum = `Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
At vero eos et accusam et justo duo dolores et ea rebum.`
|
||||
|
||||
const column = new LabeledGraphics()
|
||||
const text = column.ensureLabel('key', loremIpsum, {
|
||||
maxWidth: 250,
|
||||
zoomFonts: true,
|
||||
justify: 'top',
|
||||
align: 'align'
|
||||
})
|
||||
column.beginFill(0x333333)
|
||||
column.drawRect(0, 0, 900, 150)
|
||||
column.endFill()
|
||||
const column = new LabeledGraphics()
|
||||
const text = column.ensureLabel('key', loremIpsum, { maxWidth: 250, zoomFonts: true, justify: 'top', align: 'align'})
|
||||
column.beginFill(0x333333)
|
||||
column.drawRect(0, 0, 900, 150)
|
||||
column.endFill()
|
||||
|
||||
column.interactive = true
|
||||
text.interactive = true
|
||||
text.getLocalBounds()
|
||||
column.interactive = true
|
||||
text.interactive = true
|
||||
text.getLocalBounds()
|
||||
|
||||
text.on('zoom', (event) => {
|
||||
let factor = 1.0 + event.wheelDelta / 1000
|
||||
text.zoom(factor)
|
||||
})
|
||||
text.on('zoom', (event) => {
|
||||
let factor = 1.0 + event.wheelDelta / 1000
|
||||
text.zoom(factor)
|
||||
})
|
||||
|
||||
app2.view.addEventListener('mousewheel', (event) => {
|
||||
text.emit('zoom', event)
|
||||
event.preventDefault()
|
||||
})
|
||||
app2.view.addEventListener('mousewheel', (event) => {
|
||||
text.emit('zoom', event)
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
app2.scene.addChild(column)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app2.scene.addChild(column)
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@ -30,7 +30,7 @@ export class Hypenate {
|
||||
result.push(p + '-')
|
||||
}
|
||||
result.push(last)
|
||||
return result.filter((p) => p.length > 0)
|
||||
return result.filter(p => p.length > 0)
|
||||
}
|
||||
|
||||
static splitWord(word) {
|
||||
@ -288,7 +288,7 @@ export class LabeledGraphics extends PIXI.Graphics {
|
||||
}
|
||||
return {
|
||||
text: `${data.text}${i > 0 ? ' ' : ''}${words[i]}`,
|
||||
length: data.length + wordLength + spaceLength,
|
||||
length: data.length + wordLength + spaceLength
|
||||
}
|
||||
},
|
||||
{ text: '', length: dotsLength }
|
||||
|
||||
|
Before Width: | Height: | Size: 609 KiB |
@ -1,191 +1,191 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI List</title>
|
||||
<title>PIXI List</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/gsap/src/uncompressed/plugins/ThrowPropsPlugin.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/gsap/src/uncompressed/plugins/ThrowPropsPlugin.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>List</h1>
|
||||
<p>Using the List class, any PIXI elements (PIXI.DisplayObject) can be included in a scrollable list.</p>
|
||||
<p><a href="../../doc/out/List.html">JavaScript API</a></p>
|
||||
<p>Let's look at some list examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Three lists, one horizontal and two vertical.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>List</h1>
|
||||
<p>
|
||||
Using the List class, any PIXI elements (PIXI.DisplayObject) can be included
|
||||
in a scrollable list.
|
||||
</p>
|
||||
<p><a href="../../doc/out/List.html">JavaScript API</a></p>
|
||||
<p>Let's look at some list examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Three lists, one horizontal and two vertical.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
app.loadTextures(
|
||||
[
|
||||
'./assets/elephant-1.jpg',
|
||||
'./assets/elephant-2.jpg',
|
||||
'./assets/elephant-3.jpg',
|
||||
'./assets/elephant-4.jpg',
|
||||
'./assets/elephant-5.jpg',
|
||||
'./assets/bamboo-1.jpg',
|
||||
'./assets/bamboo-2.jpg',
|
||||
'./assets/bamboo-3.jpg',
|
||||
'./assets/bamboo-4.jpg',
|
||||
'./assets/bamboo-5.jpg'
|
||||
],
|
||||
(textures) => {
|
||||
// Example 1
|
||||
//--------------------
|
||||
const elephant1 = new PIXI.Sprite(textures.get('./assets/elephant-1.jpg'))
|
||||
const elephant2 = new PIXI.Sprite(textures.get('./assets/elephant-2.jpg'))
|
||||
const elephant3 = new PIXI.Sprite(textures.get('./assets/elephant-3.jpg'))
|
||||
const elephant4 = new PIXI.Sprite(textures.get('./assets/elephant-4.jpg'))
|
||||
const elephant5 = new PIXI.Sprite(textures.get('./assets/elephant-5.jpg'))
|
||||
app.loadTextures([
|
||||
'./assets/elephant-1.jpg',
|
||||
'./assets/elephant-2.jpg',
|
||||
'./assets/elephant-3.jpg',
|
||||
'./assets/elephant-4.jpg',
|
||||
'./assets/elephant-5.jpg',
|
||||
'./assets/bamboo-1.jpg',
|
||||
'./assets/bamboo-2.jpg',
|
||||
'./assets/bamboo-3.jpg',
|
||||
'./assets/bamboo-4.jpg',
|
||||
'./assets/bamboo-5.jpg'
|
||||
], textures => {
|
||||
|
||||
const elephants = [elephant1, elephant2, elephant3, elephant4, elephant5]
|
||||
elephants.forEach((it) => it.scale.set(0.1, 0.1))
|
||||
// Example 1
|
||||
//--------------------
|
||||
const elephant1 = new PIXI.Sprite(textures.get('./assets/elephant-1.jpg'))
|
||||
const elephant2 = new PIXI.Sprite(textures.get('./assets/elephant-2.jpg'))
|
||||
const elephant3 = new PIXI.Sprite(textures.get('./assets/elephant-3.jpg'))
|
||||
const elephant4 = new PIXI.Sprite(textures.get('./assets/elephant-4.jpg'))
|
||||
const elephant5 = new PIXI.Sprite(textures.get('./assets/elephant-5.jpg'))
|
||||
|
||||
const elephantList = new List(elephants)
|
||||
elephantList.x = 10
|
||||
elephantList.y = 10
|
||||
const elephants = [elephant1, elephant2, elephant3, elephant4, elephant5]
|
||||
elephants.forEach(it => it.scale.set(.1, .1))
|
||||
|
||||
// Example 2
|
||||
//--------------------
|
||||
const bamboo1 = new PIXI.Sprite(textures.get('./assets/bamboo-1.jpg'))
|
||||
const bamboo2 = new PIXI.Sprite(textures.get('./assets/bamboo-2.jpg'))
|
||||
const bamboo3 = new PIXI.Sprite(textures.get('./assets/bamboo-3.jpg'))
|
||||
const bamboo4 = new PIXI.Sprite(textures.get('./assets/bamboo-4.jpg'))
|
||||
const bamboo5 = new PIXI.Sprite(textures.get('./assets/bamboo-5.jpg'))
|
||||
const elephantList = new List(elephants)
|
||||
elephantList.x = 10
|
||||
elephantList.y = 10
|
||||
|
||||
const bamboos = [bamboo1, bamboo2, bamboo3, bamboo4, bamboo5]
|
||||
bamboos.forEach((it) => it.scale.set(0.15, 0.15))
|
||||
// Example 2
|
||||
//--------------------
|
||||
const bamboo1 = new PIXI.Sprite(textures.get('./assets/bamboo-1.jpg'))
|
||||
const bamboo2 = new PIXI.Sprite(textures.get('./assets/bamboo-2.jpg'))
|
||||
const bamboo3 = new PIXI.Sprite(textures.get('./assets/bamboo-3.jpg'))
|
||||
const bamboo4 = new PIXI.Sprite(textures.get('./assets/bamboo-4.jpg'))
|
||||
const bamboo5 = new PIXI.Sprite(textures.get('./assets/bamboo-5.jpg'))
|
||||
|
||||
const bambooList = new List(bamboos, {
|
||||
orientation: 'horizontal',
|
||||
width: 300,
|
||||
app
|
||||
})
|
||||
bambooList.x = 200
|
||||
bambooList.y = 10
|
||||
const bamboos = [bamboo1, bamboo2, bamboo3, bamboo4, bamboo5]
|
||||
bamboos.forEach(it => it.scale.set(.15, .15))
|
||||
|
||||
window.bambooList = bambooList
|
||||
const bambooList = new List(bamboos, {
|
||||
orientation: 'horizontal',
|
||||
width: 300,
|
||||
app
|
||||
})
|
||||
bambooList.x = 200
|
||||
bambooList.y = 10
|
||||
|
||||
// Example 3
|
||||
//--------------------
|
||||
const style = { fontSize: 14, fill: 0xe7bc51 }
|
||||
window.bambooList = bambooList
|
||||
|
||||
const texts = []
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const text = new PIXI.Text(`Example Text ${i}`, style)
|
||||
text.interactive = true
|
||||
text.on('tap', (event) => console.log(`tap text ${i}`))
|
||||
text.on('click', (event) => console.log(`click text ${i}`))
|
||||
texts.push(text)
|
||||
}
|
||||
// Example 3
|
||||
//--------------------
|
||||
const style = {fontSize: 14, fill : 0xe7bc51}
|
||||
|
||||
const textList = new List(texts, {
|
||||
orientation: 'vertical',
|
||||
height: 200,
|
||||
padding: 2,
|
||||
app
|
||||
})
|
||||
textList.x = 200
|
||||
textList.y = 200
|
||||
const texts = []
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const text = new PIXI.Text(`Example Text ${i}`, style)
|
||||
text.interactive = true
|
||||
text.on('tap', event => console.log(`tap text ${i}`))
|
||||
text.on('click', event => console.log(`click text ${i}`))
|
||||
texts.push(text)
|
||||
}
|
||||
|
||||
// Add to scene
|
||||
//--------------------
|
||||
app.scene.addChild(elephantList, bambooList, textList)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
const textList = new List(texts, {
|
||||
orientation: 'vertical',
|
||||
height: 200,
|
||||
padding: 2,
|
||||
app
|
||||
})
|
||||
textList.x = 200
|
||||
textList.y = 200
|
||||
|
||||
<h1>List in a Scatter</h1>
|
||||
<p>A PixiJS UI List is displayed inside a ScatterObject.</p>
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<p>What you should see: A ScatterObject with a list in it.</p>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
// Add to scene
|
||||
//--------------------
|
||||
app.scene.addChild(elephantList, bambooList, textList)
|
||||
|
||||
app2.loadTextures(
|
||||
[
|
||||
'./assets/jungle.jpg',
|
||||
'./assets/elephant-1.jpg',
|
||||
'./assets/elephant-2.jpg',
|
||||
'./assets/elephant-3.jpg',
|
||||
'./assets/elephant-4.jpg',
|
||||
'./assets/elephant-5.jpg'
|
||||
],
|
||||
(textures) => {
|
||||
// ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer = new ScatterContainer(app2.renderer, {
|
||||
showBounds: true,
|
||||
showPolygon: true,
|
||||
app: app2,
|
||||
stopEvents: true,
|
||||
claimEvents: true
|
||||
})
|
||||
}, {resolutionDependent: false})
|
||||
</script>
|
||||
|
||||
app2.scene.addChild(scatterContainer)
|
||||
<h1>List in a Scatter</h1>
|
||||
<p>
|
||||
A PixiJS UI List is displayed inside a ScatterObject.
|
||||
</p>
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: A ScatterObject with a list in it.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
|
||||
// ScatterObject
|
||||
//--------------------
|
||||
const jungle = new PIXI.Sprite(textures.get('./assets/jungle.jpg'))
|
||||
jungle.interactive = true
|
||||
const scatter = new DisplayObjectScatter(jungle, app2.renderer, {
|
||||
x: 200,
|
||||
y: 20,
|
||||
startScale: 1,
|
||||
minScale: 0.25,
|
||||
maxScale: 1
|
||||
})
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 420,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
scatterContainer.addChild(jungle)
|
||||
app2.loadTextures([
|
||||
'./assets/jungle.jpg',
|
||||
'./assets/elephant-1.jpg',
|
||||
'./assets/elephant-2.jpg',
|
||||
'./assets/elephant-3.jpg',
|
||||
'./assets/elephant-4.jpg',
|
||||
'./assets/elephant-5.jpg'
|
||||
], textures => {
|
||||
|
||||
// Example 1
|
||||
//--------------------
|
||||
const elephant1 = new PIXI.Sprite(textures.get('./assets/elephant-1.jpg'))
|
||||
const elephant2 = new PIXI.Sprite(textures.get('./assets/elephant-2.jpg'))
|
||||
const elephant3 = new PIXI.Sprite(textures.get('./assets/elephant-3.jpg'))
|
||||
const elephant4 = new PIXI.Sprite(textures.get('./assets/elephant-4.jpg'))
|
||||
const elephant5 = new PIXI.Sprite(textures.get('./assets/elephant-5.jpg'))
|
||||
// ScatterContainer
|
||||
//--------------------
|
||||
const scatterContainer = new ScatterContainer(app2.renderer, {
|
||||
showBounds: true,
|
||||
showPolygon: true,
|
||||
app: app2,
|
||||
stopEvents: true,
|
||||
claimEvents: true
|
||||
})
|
||||
|
||||
const elephants = [elephant1, elephant2, elephant3, elephant4, elephant5]
|
||||
elephants.forEach((it) => it.scale.set(0.15, 0.15))
|
||||
app2.scene.addChild(scatterContainer)
|
||||
|
||||
const elephantList = new List(elephants, {
|
||||
height: 200
|
||||
})
|
||||
elephantList.x = 10
|
||||
elephantList.y = 10
|
||||
// ScatterObject
|
||||
//--------------------
|
||||
const jungle = new PIXI.Sprite(textures.get('./assets/jungle.jpg'))
|
||||
jungle.interactive = true
|
||||
const scatter = new DisplayObjectScatter(jungle, app2.renderer, {
|
||||
x: 200,
|
||||
y: 20,
|
||||
startScale: 1,
|
||||
minScale: 0.25,
|
||||
maxScale: 1
|
||||
})
|
||||
|
||||
// Add to scene
|
||||
//--------------------
|
||||
jungle.addChild(elephantList)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
scatterContainer.addChild(jungle)
|
||||
|
||||
// Example 1
|
||||
//--------------------
|
||||
const elephant1 = new PIXI.Sprite(textures.get('./assets/elephant-1.jpg'))
|
||||
const elephant2 = new PIXI.Sprite(textures.get('./assets/elephant-2.jpg'))
|
||||
const elephant3 = new PIXI.Sprite(textures.get('./assets/elephant-3.jpg'))
|
||||
const elephant4 = new PIXI.Sprite(textures.get('./assets/elephant-4.jpg'))
|
||||
const elephant5 = new PIXI.Sprite(textures.get('./assets/elephant-5.jpg'))
|
||||
|
||||
const elephants = [elephant1, elephant2, elephant3, elephant4, elephant5]
|
||||
elephants.forEach(it => it.scale.set(.15, .15))
|
||||
|
||||
const elephantList = new List(elephants, {
|
||||
height: 200
|
||||
})
|
||||
elephantList.x = 10
|
||||
elephantList.y = 10
|
||||
|
||||
// Add to scene
|
||||
//--------------------
|
||||
jungle.addChild(elephantList)
|
||||
|
||||
}, {resolutionDependent: false})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -54,7 +54,7 @@ export default class List extends PIXI.Container {
|
||||
verticalAlign: 'middle',
|
||||
width: null,
|
||||
height: null,
|
||||
app: null,
|
||||
app: null
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -107,7 +107,7 @@ export default class List extends PIXI.Container {
|
||||
//--------------------
|
||||
if (this.opts.app) {
|
||||
const app = this.opts.app
|
||||
app.view.addEventListener('mousewheel', (event) => {
|
||||
app.view.addEventListener('mousewheel', event => {
|
||||
const bounds = this.mask ? this.mask.getBounds() : this.getBounds()
|
||||
const x = event.clientX - app.view.getBoundingClientRect().left
|
||||
const y = event.clientY - app.view.getBoundingClientRect().top
|
||||
@ -165,13 +165,13 @@ export default class List extends PIXI.Container {
|
||||
if (this.opts.orientation === 'vertical') {
|
||||
switch (this.opts.align) {
|
||||
case 'center':
|
||||
this.__items.forEach((it) => (it.x = margin + this.width / 2 - it.width / 2))
|
||||
this.__items.forEach(it => (it.x = margin + this.width / 2 - it.width / 2))
|
||||
break
|
||||
case 'right':
|
||||
this.__items.forEach((it) => (it.x = margin + this.width - it.width))
|
||||
this.__items.forEach(it => (it.x = margin + this.width - it.width))
|
||||
break
|
||||
default:
|
||||
this.__items.forEach((it) => (it.x = margin))
|
||||
this.__items.forEach(it => (it.x = margin))
|
||||
break
|
||||
}
|
||||
|
||||
@ -191,13 +191,13 @@ export default class List extends PIXI.Container {
|
||||
if (this.opts.orientation === 'horizontal') {
|
||||
switch (this.opts.verticalAlign) {
|
||||
case 'top':
|
||||
this.__items.forEach((it) => (it.y = margin))
|
||||
this.__items.forEach(it => (it.y = margin))
|
||||
break
|
||||
case 'bottom':
|
||||
this.__items.forEach((it) => (it.y = margin + this.height - it.height))
|
||||
this.__items.forEach(it => (it.y = margin + this.height - it.height))
|
||||
break
|
||||
default:
|
||||
this.__items.forEach((it) => (it.y = margin + this.height / 2 - it.height / 2))
|
||||
this.__items.forEach(it => (it.y = margin + this.height / 2 - it.height / 2))
|
||||
break
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ export default class List extends PIXI.Container {
|
||||
get innerWidth() {
|
||||
let size = 0
|
||||
|
||||
this.__items.forEach((it) => (size += it.width))
|
||||
this.__items.forEach(it => (size += it.width))
|
||||
size += this.opts.padding * (this.__items.length - 1)
|
||||
size += 2 * this.opts.margin
|
||||
|
||||
@ -234,7 +234,7 @@ export default class List extends PIXI.Container {
|
||||
get innerHeight() {
|
||||
let size = 0
|
||||
|
||||
this.__items.forEach((it) => (size += it.height))
|
||||
this.__items.forEach(it => (size += it.height))
|
||||
size += this.opts.padding * (this.__items.length - 1)
|
||||
size += 2 * this.opts.margin
|
||||
|
||||
@ -268,7 +268,7 @@ export default class List extends PIXI.Container {
|
||||
|
||||
this.__delta = {
|
||||
x: this.container.position.x - event.data.global.x,
|
||||
y: this.container.position.y - event.data.global.y,
|
||||
y: this.container.position.y - event.data.global.y
|
||||
}
|
||||
|
||||
TweenLite.killTweensOf(this.container.position, { x: true, y: true })
|
||||
@ -313,7 +313,7 @@ export default class List extends PIXI.Container {
|
||||
throwProps.x = {
|
||||
velocity: 'auto',
|
||||
min,
|
||||
max: 0,
|
||||
max: 0
|
||||
}
|
||||
} else {
|
||||
let min = this.opts.height - this.innerHeight
|
||||
@ -321,7 +321,7 @@ export default class List extends PIXI.Container {
|
||||
throwProps.y = {
|
||||
velocity: 'auto',
|
||||
min,
|
||||
max: 0,
|
||||
max: 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,7 +331,7 @@ export default class List extends PIXI.Container {
|
||||
{
|
||||
throwProps,
|
||||
ease: Strong.easeOut,
|
||||
onComplete: () => ThrowPropsPlugin.untrack(this.container.position),
|
||||
onComplete: () => ThrowPropsPlugin.untrack(this.container.position)
|
||||
},
|
||||
0.8,
|
||||
0.4
|
||||
|
||||
|
Before Width: | Height: | Size: 1000 KiB |
@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
<body onload='Doctest.run()'>
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>GeoGraphics</h1>
|
||||
<h1>GeoGraphics</h1>
|
||||
<p> GeoGraphics are graphical objects, that does not store the graphics information
|
||||
in screen space, but in geographical coordinates. Therefore GeoGraphics must be
|
||||
placed on GeoLayers to work properly. </p>
|
||||
|
||||
|
Before Width: | Height: | Size: 537 KiB |
@ -85,7 +85,7 @@
|
||||
</head>
|
||||
|
||||
<body onload='Doctest.run()'>
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>GeoJson</h1>
|
||||
<h1>GeoJson</h1>
|
||||
<p>GeoJson is a standardized format of how to display geometry in a geographical context, using latitude/longitude
|
||||
pairs
|
||||
to display one (or multiple) Point, Line or Polygon.
|
||||
|
||||
|
Before Width: | Height: | Size: 360 KiB |
@ -1,113 +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>
|
||||
<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">
|
||||
|
||||
<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>
|
||||
<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 class="title"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
<div class="title"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
<style>
|
||||
body {
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#logo {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
}
|
||||
#logo {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
}
|
||||
|
||||
#logo > img {
|
||||
width: 80px;
|
||||
}
|
||||
#logo>img {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
header > h1 {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
word-spacing: 0.25em;
|
||||
margin-top: 0;
|
||||
}
|
||||
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>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;
|
||||
header {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
background-color: #4c4f4f;
|
||||
color: whitesmoke;
|
||||
|
||||
padding: 68px 50px 10px 150px;
|
||||
padding: 68px 50px 10px 150px;
|
||||
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.container {
|
||||
justify-content: center;
|
||||
.container {
|
||||
|
||||
flex: 1;
|
||||
height: auto;
|
||||
min-height: auto;
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
justify-content: center;
|
||||
|
||||
margin: 0 60px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
flex: 1;
|
||||
height: auto;
|
||||
min-height: auto;
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a
|
||||
><a href="../index.html">map.</a>Doctests
|
||||
</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>
|
||||
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>
|
||||
|
Before Width: | Height: | Size: 242 KiB |
@ -1,103 +1,123 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark-mode">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Map</title>
|
||||
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Map</title>
|
||||
|
||||
<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="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.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'>
|
||||
|
||||
<style>
|
||||
.controls {
|
||||
display: flex;
|
||||
<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>Map</h1>
|
||||
<p>
|
||||
The Map class shows a geographical map using a scatter element.
|
||||
</p>
|
||||
|
||||
<h2 id="DeepZoomMap">DeepZoomMap</h2>
|
||||
<p>Usually a DeepZoomMap will be used to display maps. It uses a <a
|
||||
href="../deepzoom/deepzoom.html">DeepZoomImage</a> to display the map in different resolutions depending on
|
||||
the zoom factor.</p>
|
||||
<canvas id="deepZoomCanvas">
|
||||
|
||||
</canvas>
|
||||
<script>
|
||||
|
||||
|
||||
</script>
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Script">
|
||||
|
||||
|
||||
(function () {
|
||||
|
||||
// Create the mapapp.
|
||||
let app = window.DeepZoomMapApp = new MapApp({
|
||||
view: deepZoomCanvas,
|
||||
coordsLogging: true,
|
||||
width: 512,
|
||||
height: 512
|
||||
})
|
||||
|
||||
|
||||
// Load or specify a tilesConfig as required by the DeepZoomImage.
|
||||
const tilesConfig = {
|
||||
"tileSize": 256,
|
||||
"format": "png",
|
||||
"overlap": 0,
|
||||
"type": "map",
|
||||
"height": 1024,
|
||||
"width": 1024,
|
||||
"path": "../assets/maps/osm",
|
||||
"urlTileTemplate": "{path}/{level}/{row}/{column}.{format}"
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>Map</h1>
|
||||
<p>The Map class shows a geographical map using a scatter element.</p>
|
||||
|
||||
<h2 id="DeepZoomMap">DeepZoomMap</h2>
|
||||
<p>
|
||||
Usually a DeepZoomMap will be used to display maps. It uses a
|
||||
<a href="../deepzoom/deepzoom.html">DeepZoomImage</a> to display the map in different resolutions depending
|
||||
on the zoom factor.
|
||||
</p>
|
||||
<canvas id="deepZoomCanvas"> </canvas>
|
||||
<script></script>
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Script">
|
||||
;(function () {
|
||||
// Create a projection.
|
||||
const projection = new Projection.Mercator()
|
||||
|
||||
// Create a map data object.
|
||||
const osmDeepZoomMapProjection = new DeepZoomMapProjection(projection, tilesConfig, { app })
|
||||
|
||||
// Create the map
|
||||
const osmMap = new DeepZoomMap(osmDeepZoomMapProjection, tilesConfig)
|
||||
|
||||
// Add the map to the app.
|
||||
app.addMap("osm", osmMap)
|
||||
|
||||
// Run the app when at least one map is set.
|
||||
app.setup().run()
|
||||
})()
|
||||
</script>
|
||||
|
||||
<h2 id="imageMap">ImageMap</h2>
|
||||
<p>Single images can be also used as maps. This can be useful for examples, debugging purposes or other use-cases
|
||||
when there are no different tiles required or available.</p>
|
||||
<canvas id="imageMapCanvas">
|
||||
|
||||
</canvas>
|
||||
<script>
|
||||
</script>
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Script">
|
||||
|
||||
|
||||
(function () {
|
||||
|
||||
// Create the mapapp.
|
||||
let app = (window.DeepZoomMapApp = new MapApp({
|
||||
view: deepZoomCanvas,
|
||||
coordsLogging: true,
|
||||
width: 512,
|
||||
height: 512
|
||||
}))
|
||||
|
||||
// Load or specify a tilesConfig as required by the DeepZoomImage.
|
||||
const tilesConfig = {
|
||||
tileSize: 256,
|
||||
format: 'png',
|
||||
overlap: 0,
|
||||
type: 'map',
|
||||
height: 1024,
|
||||
width: 1024,
|
||||
path: '../assets/maps/osm',
|
||||
urlTileTemplate: '{path}/{level}/{row}/{column}.{format}'
|
||||
}
|
||||
|
||||
// Create a projection.
|
||||
const projection = new Projection.Mercator()
|
||||
|
||||
// Create a map data object.
|
||||
const osmDeepZoomMapProjection = new DeepZoomMapProjection(projection, tilesConfig, { app })
|
||||
|
||||
// Create the map
|
||||
const osmMap = new DeepZoomMap(osmDeepZoomMapProjection, tilesConfig)
|
||||
|
||||
// Add the map to the app.
|
||||
app.addMap('osm', osmMap)
|
||||
|
||||
// Run the app when at least one map is set.
|
||||
app.setup().run()
|
||||
})()
|
||||
</script>
|
||||
|
||||
<h2 id="imageMap">ImageMap</h2>
|
||||
<p>
|
||||
Single images can be also used as maps. This can be useful for examples, debugging purposes or other
|
||||
use-cases when there are no different tiles required or available.
|
||||
</p>
|
||||
<canvas id="imageMapCanvas"> </canvas>
|
||||
<script></script>
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Script">
|
||||
;(function () {
|
||||
// Create the mapapp.
|
||||
let app = (window.ImageMapApp = new MapApp({
|
||||
let app = window.ImageMapApp = new MapApp({
|
||||
view: imageMapCanvas,
|
||||
coordsLogging: true,
|
||||
width: 512,
|
||||
height: 512
|
||||
}))
|
||||
})
|
||||
|
||||
const mapTexture = "../assets/maps/wikimedia-world-robinson/2000px-BlankMap-World.png"
|
||||
|
||||
|
||||
|
||||
const mapTexture = '../assets/maps/wikimedia-world-robinson/2000px-BlankMap-World.png'
|
||||
|
||||
// The images used by the image map need to be loaded beforehand.
|
||||
// Therefore this loading step is required.
|
||||
app.loadSprites([mapTexture], (sprites) => spritesLoaded(sprites), {
|
||||
app.loadSprites([mapTexture], sprites => spritesLoaded(sprites), {
|
||||
resolutionDependent: false
|
||||
})
|
||||
|
||||
spritesLoaded = (sprites) => {
|
||||
|
||||
// Create a projection.
|
||||
const projection = new Projection.Robinson(10)
|
||||
|
||||
@ -107,13 +127,19 @@
|
||||
// Create the map
|
||||
let imageMap = new ImageMap(sprites.get(mapTexture), mapProjection)
|
||||
|
||||
|
||||
// Add the map to the app.
|
||||
app.addMap('europe', imageMap)
|
||||
app.addMap("europe", imageMap)
|
||||
|
||||
|
||||
// Run the app when at least one map is set.
|
||||
app.setup().run()
|
||||
}
|
||||
|
||||
|
||||
|
||||
})()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 554 KiB |
@ -1,163 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark-mode">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>MapApp</title>
|
||||
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>MapApp</title>
|
||||
|
||||
<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="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.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'>
|
||||
|
||||
<style>
|
||||
.controls {
|
||||
display: flex;
|
||||
<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>MapApp</h1>
|
||||
<p>
|
||||
This class extends the PIXIApp to simplify the process of rendering
|
||||
Maps in the canvas. For that reason, it contains useful functions
|
||||
for an easier handling of maps in the canvas.
|
||||
</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}"
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
}
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>MapApp
|
||||
</h1>
|
||||
<p>
|
||||
This class extends the PIXIApp to simplify the process of rendering Maps in the canvas. For that reason, it
|
||||
contains useful functions for an easier handling of maps in the canvas.
|
||||
</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}"
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
</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 }
|
||||
}
|
||||
})
|
||||
|
||||
// You may define a focus point ...
|
||||
let focus = capitals.paris
|
||||
function ready(sprites) {
|
||||
|
||||
// ... and a zoom level.
|
||||
let zoom = 1
|
||||
const cover = true
|
||||
|
||||
// Name has to be app (like all other PIXIApps).
|
||||
const app = (window.app = new MapApp({
|
||||
focus,
|
||||
zoom,
|
||||
view: canvas,
|
||||
// When resources are loaded, the ImageMap can be instantiated.
|
||||
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||
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
|
||||
maxScale: 1,
|
||||
cover
|
||||
})
|
||||
|
||||
// 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 }
|
||||
}
|
||||
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)
|
||||
|
||||
function ready(sprites) {
|
||||
const cover = true
|
||||
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)
|
||||
|
||||
// When resources are loaded, the ImageMap can be instantiated.
|
||||
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||
coordsLogging: true,
|
||||
maxScale: 1,
|
||||
cover
|
||||
// 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)
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
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>
|
||||
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>
|
||||
|
Before Width: | Height: | Size: 1.8 MiB |
@ -37,7 +37,7 @@
|
||||
</head>
|
||||
|
||||
<body onload='Doctest.run()'>
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>MapProjection</h1>
|
||||
<h1>MapProjection</h1>
|
||||
<p>The map projection calculates is responsible for transforming map coordinates to pixel coordinates and backwards.</p>
|
||||
|
||||
<h2>Static Squared World Map</h2>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 MiB |
@ -30,7 +30,7 @@
|
||||
</head>
|
||||
|
||||
<body onload='Doctest.run()'>
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>Maps</h1>
|
||||
<h1>Maps</h1>
|
||||
<p>Maps represent a geographical image in a PIXI.Application. Preferably in a MapApp to have more convenient methods
|
||||
to
|
||||
handle the maps.</p>
|
||||
|
||||
@ -1,164 +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>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>MapViewport</title>
|
||||
|
||||
<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="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.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'>
|
||||
|
||||
<style>
|
||||
.controls {
|
||||
display: flex;
|
||||
<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}"
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
}
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a
|
||||
><a href="index.html">maps.</a>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}"
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
</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 }
|
||||
}
|
||||
})
|
||||
|
||||
// You may define a focus point ...
|
||||
let focus = capitals.paris
|
||||
function ready(sprites) {
|
||||
|
||||
// ... and a zoom level.
|
||||
let zoom = 1
|
||||
const cover = true
|
||||
|
||||
// Name has to be app (like all other PIXIApps).
|
||||
const app = (window.app = new MapApp({
|
||||
focus,
|
||||
zoom,
|
||||
view: canvas,
|
||||
// When resources are loaded, the ImageMap can be instantiated.
|
||||
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||
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
|
||||
maxScale: 1,
|
||||
cover
|
||||
})
|
||||
|
||||
// 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 }
|
||||
}
|
||||
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)
|
||||
|
||||
function ready(sprites) {
|
||||
const cover = true
|
||||
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)
|
||||
|
||||
// When resources are loaded, the ImageMap can be instantiated.
|
||||
let imageMap = new ImageMap(sprites.get(europe), europeData, {
|
||||
coordsLogging: true,
|
||||
maxScale: 1,
|
||||
cover
|
||||
// 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)
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
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>
|
||||
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>
|
||||
|
Before Width: | Height: | Size: 1.8 MiB |
@ -1,277 +1,304 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark-mode">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Overlay</title>
|
||||
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Overlay</title>
|
||||
|
||||
<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>
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="../../../assets/icons/map.png" />
|
||||
<script src="../../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<style>
|
||||
.inline-showcase {
|
||||
display: flex;
|
||||
}
|
||||
<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'>
|
||||
|
||||
.map-example {
|
||||
display: inline-block;
|
||||
width: 256px;
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1 class="title">
|
||||
<a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>Overlay
|
||||
</h1>
|
||||
<!-- <a href="../../../" class="Documentation"></a> -->
|
||||
<p class="description">The overlayclass creates a convenient way to create and design complex map overlays.</p>
|
||||
<canvas id="view" class="center"> </canvas>
|
||||
<script>
|
||||
let app = new MapApp({
|
||||
view,
|
||||
width: 512,
|
||||
height: 512,
|
||||
coordsLogging: true
|
||||
})
|
||||
var osmworld = '../assets/maps/osm/0/0/0.png'
|
||||
let worlOSMData = new MapProjection(new Projection.Mercator())
|
||||
<link rel="shortcut icon" type="image/x-icon" href="../../../assets/icons/map.png">
|
||||
|
||||
function setupMap(textures) {
|
||||
// Create the map!
|
||||
let map = new ImageMap(new PIXI.Sprite(textures.get(osmworld)), worlOSMData)
|
||||
|
||||
// Setup the map in the mapapp.
|
||||
app.setMap('osm', map)
|
||||
app.setup().run()
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.inline-showcase {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Overlay Data">
|
||||
/**
|
||||
* To create an overlay you just need to create a JSON file.
|
||||
* The styles defined in the styles are cascading, meaning that
|
||||
* the styles can be defined on the top level, or directly at the
|
||||
* single items. If the style is not defined in the item, the top-level style will be used.
|
||||
* If the top-level style is not defined either, the default style is applied.
|
||||
*
|
||||
* The structure of an overlay file is as follows:
|
||||
*
|
||||
* {
|
||||
* //COMMENT: Top-Level
|
||||
*
|
||||
* //COMMENT: Frequently used properties are:
|
||||
* size: 500,
|
||||
* color: 0xFF00FF,
|
||||
* fillAlpha:0.5
|
||||
*
|
||||
* icon: 'path/to/icon.png'
|
||||
* iconColor: 0xFFFFFF,
|
||||
* "items": [
|
||||
* //COMMENT: Items are defined in the items array.
|
||||
* {
|
||||
* location: {
|
||||
* //COMMENT: Location must be defined.
|
||||
* x: LAT_VALUE,
|
||||
* y: LNG_VALUE
|
||||
* }
|
||||
* },{
|
||||
* color: 0xFF0000,
|
||||
* location: {
|
||||
* //COMMENT: Location must be defined.
|
||||
* x: LAT_VALUE,
|
||||
* y: LNG_VALUE
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
.map-example {
|
||||
display: inline-block;
|
||||
width: 256px;
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
let exampleOverlayJSON = {
|
||||
icon: '../../../assets/icons/place.png',
|
||||
iconColor: '0x35aaea',
|
||||
iconAnchor: { x: 0.5, y: 1 },
|
||||
size: 5,
|
||||
scale: 0.2,
|
||||
disabledColor: 0x000000,
|
||||
disabledIconColor: 0xcccccc,
|
||||
disabledScale: 0.5,
|
||||
color: '0x3FA7EE',
|
||||
items: [
|
||||
{
|
||||
name: 'Custom Icon',
|
||||
fontWeight: 'bold',
|
||||
icon: '../../../assets/icons/beenhere.png',
|
||||
iconColor: 0x00ff00,
|
||||
iconAlpha: 0.5,
|
||||
size: 0,
|
||||
labelVerticalAlignment: 'underneath',
|
||||
label: 'Abidjan',
|
||||
location: {
|
||||
x: 5.34947,
|
||||
y: -4.006472
|
||||
},
|
||||
information: 'Here a custom icon is used. It overrides the icon setting in the global section.'
|
||||
<body onload="Doctest.run()">
|
||||
<h1 class="title">Overlay</h1>
|
||||
<!-- <a href="../../../" class="Documentation"></a> -->
|
||||
<p class="description">
|
||||
The overlayclass creates a convenient way to create and design
|
||||
complex map overlays.
|
||||
</p>
|
||||
<canvas id="view" class="center"> </canvas>
|
||||
<script>
|
||||
let app = new MapApp({
|
||||
view,
|
||||
width: 512,
|
||||
height: 512,
|
||||
coordsLogging: true
|
||||
})
|
||||
var osmworld = '../assets/maps/osm/0/0/0.png'
|
||||
let worlOSMData = new MapProjection(new Projection.Mercator())
|
||||
|
||||
|
||||
function setupMap(textures) {
|
||||
|
||||
// Create the map!
|
||||
let map = new ImageMap(
|
||||
new PIXI.Sprite(textures.get(osmworld)),
|
||||
worlOSMData
|
||||
)
|
||||
|
||||
// Setup the map in the mapapp.
|
||||
app.setMap('osm', map)
|
||||
app.setup().run()
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script class="doctest" data-collapsible data-collapsed data-title="Overlay Data">
|
||||
|
||||
/**
|
||||
* To create an overlay you just need to create a JSON file.
|
||||
* The styles defined in the styles are cascading, meaning that
|
||||
* the styles can be defined on the top level, or directly at the
|
||||
* single items. If the style is not defined in the item, the top-level style will be used.
|
||||
* If the top-level style is not defined either, the default style is applied.
|
||||
*
|
||||
* The structure of an overlay file is as follows:
|
||||
*
|
||||
* {
|
||||
* //COMMENT: Top-Level
|
||||
*
|
||||
* //COMMENT: Frequently used properties are:
|
||||
* size: 500,
|
||||
* color: 0xFF00FF,
|
||||
* fillAlpha:0.5
|
||||
*
|
||||
* icon: 'path/to/icon.png'
|
||||
* iconColor: 0xFFFFFF,
|
||||
* "items": [
|
||||
* //COMMENT: Items are defined in the items array.
|
||||
* {
|
||||
* location: {
|
||||
* //COMMENT: Location must be defined.
|
||||
* x: LAT_VALUE,
|
||||
* y: LNG_VALUE
|
||||
* }
|
||||
* },{
|
||||
* color: 0xFF0000,
|
||||
* location: {
|
||||
* //COMMENT: Location must be defined.
|
||||
* x: LAT_VALUE,
|
||||
* y: LNG_VALUE
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
|
||||
let exampleOverlayJSON = {
|
||||
icon: '../../../assets/icons/place.png',
|
||||
iconColor: "0x35aaea",
|
||||
iconAnchor: { x: 0.5, y: 1 },
|
||||
size: 5,
|
||||
scale: 0.2,
|
||||
disabledColor: 0x000000,
|
||||
disabledIconColor: 0xCCCCCC,
|
||||
disabledScale: 0.5,
|
||||
color: '0x3FA7EE',
|
||||
items: [
|
||||
{
|
||||
name: 'Custom Icon',
|
||||
fontWeight: "bold",
|
||||
icon: '../../../assets/icons/beenhere.png',
|
||||
iconColor: 0x00ff00,
|
||||
iconAlpha: 0.5,
|
||||
size: 0,
|
||||
labelVerticalAlignment: "underneath",
|
||||
label: 'Abidjan',
|
||||
location: {
|
||||
x: 5.34947,
|
||||
y: -4.006472
|
||||
},
|
||||
{
|
||||
name: 'Berlin',
|
||||
label: 'enabled',
|
||||
disabledLabel: 'disabled',
|
||||
location: {
|
||||
x: 52.52543,
|
||||
y: 13.385291
|
||||
},
|
||||
information: '... ist die Bundeshauptstadt der Bundesrepublik Deutschland.',
|
||||
enabled: false
|
||||
information:
|
||||
'Here a custom icon is used. It overrides the icon setting in the global section.'
|
||||
},
|
||||
{
|
||||
name: 'Berlin',
|
||||
label: "enabled",
|
||||
disabledLabel: "disabled",
|
||||
location: {
|
||||
x: 52.52543,
|
||||
y: 13.385291
|
||||
},
|
||||
{
|
||||
name: 'Canberra',
|
||||
information:
|
||||
'... ist die Bundeshauptstadt der Bundesrepublik Deutschland.',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
name: 'Canberra',
|
||||
|
||||
location: {
|
||||
x: -35.282025,
|
||||
y: 149.128648
|
||||
},
|
||||
information: '... ist die Hauptstadt und achtgrößte Stadt Australiens.'
|
||||
location: {
|
||||
x: -35.282025,
|
||||
y: 149.128648
|
||||
},
|
||||
{
|
||||
name: 'Kapstadt',
|
||||
information:
|
||||
'... ist die Hauptstadt und achtgrößte Stadt Australiens.'
|
||||
},
|
||||
{
|
||||
name: 'Kapstadt',
|
||||
|
||||
location: {
|
||||
x: -33.925448,
|
||||
y: 18.416962
|
||||
},
|
||||
information: `This item adjusts it's size according to the map.`
|
||||
location: {
|
||||
x: -33.925448,
|
||||
y: 18.416962
|
||||
},
|
||||
{
|
||||
name: 'Moskau',
|
||||
information:
|
||||
`This item adjusts it's size according to the map.`
|
||||
},
|
||||
{
|
||||
name: 'Moskau',
|
||||
|
||||
location: {
|
||||
x: 55.750892,
|
||||
y: 37.622799
|
||||
},
|
||||
information:
|
||||
'... die kosmopolitische Hauptstadt Russlands, liegt im Westen des Landes und wird von der Moskwa durchflossen.'
|
||||
location: {
|
||||
x: 55.750892,
|
||||
y: 37.622799
|
||||
},
|
||||
{
|
||||
name: 'Washington, D.C.',
|
||||
information:
|
||||
'... die kosmopolitische Hauptstadt Russlands, liegt im Westen des Landes und wird von der Moskwa durchflossen.'
|
||||
},
|
||||
{
|
||||
name: 'Washington, D.C.',
|
||||
|
||||
location: {
|
||||
x: 38.89565,
|
||||
y: -77.031407
|
||||
},
|
||||
information:
|
||||
'... ist die Hauptstadt der USA und eine kompakte Stadt am Potomac River, die an die Bundesstaaten Maryland und Virginia grenzt.'
|
||||
location: {
|
||||
x: 38.89565,
|
||||
y: -77.031407
|
||||
},
|
||||
{
|
||||
name: 'Rio de Janeiro',
|
||||
information:
|
||||
'... ist die Hauptstadt der USA und eine kompakte Stadt am Potomac River, die an die Bundesstaaten Maryland und Virginia grenzt.'
|
||||
},
|
||||
{
|
||||
name: 'Rio de Janeiro',
|
||||
|
||||
location: {
|
||||
x: -22.8714,
|
||||
y: -43.28049
|
||||
},
|
||||
information: '... ist eine ausgedehnte brasilianische Küstenmetropole. '
|
||||
location: {
|
||||
x: -22.8714,
|
||||
y: -43.28049
|
||||
},
|
||||
{
|
||||
name: 'Tokio',
|
||||
type: 'factory',
|
||||
label: 'factory',
|
||||
location: {
|
||||
x: 35.696278,
|
||||
y: 139.731366
|
||||
},
|
||||
information:
|
||||
'... ist eine Global City in der Kantō-Region im Osten der japanischen Hauptinsel Honshū.'
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
information:
|
||||
'... ist eine ausgedehnte brasilianische Küstenmetropole. '
|
||||
},
|
||||
{
|
||||
name: 'Tokio',
|
||||
type: "factory",
|
||||
label: "factory",
|
||||
location: {
|
||||
x: 35.696278,
|
||||
y: 139.731366
|
||||
},
|
||||
information:
|
||||
'... ist eine Global City in der Kantō-Region im Osten der japanischen Hauptinsel Honshū.'
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<script class="doctest" data-collapsible data-title="Overlay">
|
||||
let overlay = new Overlay(exampleOverlayJSON)
|
||||
<script class="doctest" data-collapsible data-title="Overlay">
|
||||
|
||||
/**
|
||||
* Textures should be loaded using the app's texture loader.
|
||||
* With the findTexture method all required Textures within the
|
||||
* overlays are loaded.
|
||||
*/
|
||||
let overlayTextures = overlay.findAllTextures()
|
||||
let overlay = new Overlay(exampleOverlayJSON)
|
||||
|
||||
let list = [osmworld].concat(overlayTextures)
|
||||
app.loadTextures(list, (textures) => texturesLoaded(textures), {
|
||||
resolutionDependent: false
|
||||
})
|
||||
/**
|
||||
* Textures should be loaded using the app's texture loader.
|
||||
* With the findTexture method all required Textures within the
|
||||
* overlays are loaded.
|
||||
*/
|
||||
let overlayTextures = overlay.findAllTextures()
|
||||
|
||||
function texturesLoaded(textures) {
|
||||
/** When all textures are loaded .... */
|
||||
setupMap(textures)
|
||||
let list = [osmworld].concat(overlayTextures)
|
||||
app.loadTextures(list, textures => texturesLoaded(textures), {
|
||||
resolutionDependent: false
|
||||
})
|
||||
|
||||
//Retrieve all overlay textures.
|
||||
overlay.selectTextures(textures)
|
||||
function texturesLoaded(textures) {
|
||||
|
||||
// Just some Helpers for the Popups.
|
||||
let popup = null
|
||||
let cleaner = null
|
||||
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'
|
||||
/** When all textures are loaded .... */
|
||||
setupMap(textures)
|
||||
|
||||
let geographics = new GeoPoint(item.location)
|
||||
//Retrieve all overlay textures.
|
||||
overlay.selectTextures(textures)
|
||||
|
||||
geographics.drawHandler.add((graphics) => {
|
||||
graphics.beginFill(item.color, item.fillAlpha)
|
||||
graphics.drawRect(0, 0, 10, 10)
|
||||
})
|
||||
// Just some Helpers for the Popups.
|
||||
let popup = null
|
||||
let cleaner = null
|
||||
const vanishingTime = 1000
|
||||
|
||||
let text = new PIXI.Text(item.name, { fontSize: 5 })
|
||||
geographics.graphics.addChild(text)
|
||||
// Factories must return a geographics object.
|
||||
Overlay.createFactory("factory", (item) => {
|
||||
|
||||
return geographics
|
||||
// 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)
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* The actual PIXI elements are created when the overlay.create() is called.
|
||||
* This returns an GeoLayer which can be directly put onto the map's Maplayer (or any other GeoLayer).
|
||||
*
|
||||
* INFO: MapLayer and GeoLayer are specialized container for PIXI. They are meant to
|
||||
* place PIXI Elements according to their world-coordinates (lat/lng position), instead
|
||||
* of actual pixel values.
|
||||
*
|
||||
*/
|
||||
let text = new PIXI.Text(item.name, {fontSize: 5})
|
||||
geographics.graphics.addChild(text)
|
||||
|
||||
let exampleOverlayGeoLayer = overlay.create()
|
||||
|
||||
// When placed on the mapLayer, the PIXI Graphic elements, that
|
||||
// reside inside GeoGraphic Objects are placed automatically at the
|
||||
// correct coordinates of the map.
|
||||
app.mapLayer.addLayer(exampleOverlayGeoLayer)
|
||||
return geographics
|
||||
})
|
||||
|
||||
// Just a helper function that clears the popups and removes
|
||||
// a remaining cleaner timeout.
|
||||
function clearPopup() {
|
||||
if (popup) {
|
||||
popup.parent.removeChild(popup)
|
||||
popup = null
|
||||
}
|
||||
/**
|
||||
*
|
||||
* The actual PIXI elements are created when the overlay.create() is called.
|
||||
* This returns an GeoLayer which can be directly put onto the map's Maplayer (or any other GeoLayer).
|
||||
*
|
||||
* INFO: MapLayer and GeoLayer are specialized container for PIXI. They are meant to
|
||||
* place PIXI Elements according to their world-coordinates (lat/lng position), instead
|
||||
* of actual pixel values.
|
||||
*
|
||||
*/
|
||||
|
||||
if (cleaner != null) {
|
||||
clearTimeout(cleaner)
|
||||
}
|
||||
let exampleOverlayGeoLayer = overlay.create()
|
||||
|
||||
// When placed on the mapLayer, the PIXI Graphic elements, that
|
||||
// reside inside GeoGraphic Objects are placed automatically at the
|
||||
// correct coordinates of the map.
|
||||
app.mapLayer.addLayer(exampleOverlayGeoLayer)
|
||||
|
||||
|
||||
// Just a helper function that clears the popups and removes
|
||||
// a remaining cleaner timeout.
|
||||
function clearPopup() {
|
||||
if (popup) {
|
||||
popup.parent.removeChild(popup)
|
||||
popup = null
|
||||
}
|
||||
|
||||
if (cleaner != null) {
|
||||
clearTimeout(cleaner)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script></script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 718 KiB |
@ -25,7 +25,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>Scatter</h1>
|
||||
<h1>Scatter</h1>
|
||||
<p>The Scatter in Tüsch specifies some classes to make them more suitable for Map applications.</p>
|
||||
|
||||
<h2>CoverScatter</h2>
|
||||
|
||||
|
Before Width: | Height: | Size: 268 KiB |
@ -1,146 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Utils</title>
|
||||
<link rel="stylesheet" href="../../../lib/3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../../css/doctest.css" />
|
||||
<script src="../../../lib/3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../../dist/iwmlib.js"></script>
|
||||
<script src="../../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="all.js"></script>
|
||||
<!doctype html>
|
||||
<html lang='en'>
|
||||
|
||||
<style>
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<title>Utils</title>
|
||||
<link rel='stylesheet' href='../iwmlib/lib/3rdparty/highlight/styles/default.css'>
|
||||
<link rel='stylesheet' href='../iwmlib/lib/../css/doctest.css'>
|
||||
<script src='../iwmlib/lib/3rdparty/highlight/highlight.pack.js'></script>
|
||||
<script src='../iwmlib/lib/3rdparty/all.js'></script>
|
||||
<script src='../iwmlib/lib/all.js'></script>
|
||||
<script src='../iwmlib/lib/pixi/all.js'></script>
|
||||
<script src="all.js"></script>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../../index.html">lib.</a><a href="../index.html">pixi.</a><a href="index.html">maps.</a>Utils</h1>
|
||||
<p>Some utility functionalities for the Tuesch.</p>
|
||||
<style>
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<h2>Event Handler</h2>
|
||||
<p>
|
||||
The event handler class generalizes a common design principle in javascript. When an event occurs, that is
|
||||
of relevance for other objects, then this event should be sent out to all objects, that are interested in
|
||||
that event. Objects interested in that event, subscribe the event handler and get notified via a callback
|
||||
function.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
let result = []
|
||||
function a() {
|
||||
result.push('a')
|
||||
}
|
||||
function b() {
|
||||
result.push('b')
|
||||
}
|
||||
function c() {
|
||||
result.push('c')
|
||||
}
|
||||
function d() {
|
||||
result.push('d')
|
||||
}
|
||||
function e() {
|
||||
result.push('e')
|
||||
}
|
||||
function f() {
|
||||
result.push('f')
|
||||
}
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Utils</h1>
|
||||
<p>Some utility functionalities for the Tuesch.</p>
|
||||
|
||||
//Init and call.
|
||||
let eventHandler = new EventHandler('manual', { listeners: [a, b] })
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), ['a', 'b'].join(','))
|
||||
result = []
|
||||
<h2>Event Handler</h2>
|
||||
<p>
|
||||
The event handler class generalizes a common design principle in javascript. When an event occurs, that is of relevance for
|
||||
other objects, then this event should be sent out to all objects, that are interested in that event. Objects interested
|
||||
in that event, subscribe the event handler and get notified via a callback function.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
let result = []
|
||||
function a() { result.push("a") }
|
||||
function b() { result.push("b") }
|
||||
function c() { result.push("c") }
|
||||
function d() { result.push("d") }
|
||||
function e() { result.push("e") }
|
||||
function f() { result.push("f") }
|
||||
|
||||
// Add single
|
||||
eventHandler.add(c)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), ['a', 'b', 'c'].join(','))
|
||||
result = []
|
||||
//Init and call.
|
||||
let eventHandler = new EventHandler("manual", { listeners: [a, b] })
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), ["a", "b"].join(","))
|
||||
result = []
|
||||
|
||||
// Add multiple
|
||||
eventHandler.addMultiple(d, e, f)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), ['a', 'b', 'c', 'd', 'e', 'f'].join(','))
|
||||
result = []
|
||||
// Add single
|
||||
eventHandler.add(c)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), ["a", "b", "c"].join(","))
|
||||
result = []
|
||||
|
||||
//Remove inbetween
|
||||
eventHandler.remove(c)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), ['a', 'b', 'd', 'e', 'f'].join(','))
|
||||
result = []
|
||||
// Add multiple
|
||||
eventHandler.addMultiple(d, e, f)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), ["a", "b", "c", "d", "e", "f"].join(","))
|
||||
result = []
|
||||
|
||||
// Remove first
|
||||
eventHandler.remove(a)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), ['b', 'd', 'e', 'f'].join(','))
|
||||
result = []
|
||||
//Remove inbetween
|
||||
eventHandler.remove(c)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), ["a", "b", "d", "e", "f"].join(","))
|
||||
result = []
|
||||
|
||||
// Remove all remaining elements.
|
||||
eventHandler.empty()
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(','), [].join(','))
|
||||
result = []
|
||||
</script>
|
||||
// Remove first
|
||||
eventHandler.remove(a)
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), ["b", "d", "e", "f"].join(","))
|
||||
result = []
|
||||
|
||||
<h2>DomUtils</h2>
|
||||
// Remove all remaining elements.
|
||||
eventHandler.empty()
|
||||
eventHandler.call()
|
||||
Doctest.expect(result.join(","), [].join(","))
|
||||
result = []
|
||||
|
||||
Utility functions that help handling the DOM.
|
||||
|
||||
<h3>positionOnElement(element, position)</h3>
|
||||
Function that returns the global position for a normalized position.
|
||||
|
||||
<div
|
||||
id="positionOnElementBox"
|
||||
class="box"
|
||||
style="
|
||||
width: 512px;
|
||||
height: 256px;
|
||||
border: 1px solid black;
|
||||
box-sizing: border-box;
|
||||
transform: rotate(30deg);
|
||||
margin: 100px;
|
||||
"
|
||||
></div>
|
||||
</script>
|
||||
|
||||
<script class="doctest">
|
||||
let target = document.getElementById('positionOnElementBox')
|
||||
<h2>DomUtils</h2>
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
let positions = [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[1, 0],
|
||||
[0.5, 0.5],
|
||||
[0.2, 0.2],
|
||||
[0.2, 0.8],
|
||||
[0.8, 0.2],
|
||||
[0.8, 0.8]
|
||||
]
|
||||
Utility functions that help handling the DOM.
|
||||
|
||||
positions.forEach((position) => {
|
||||
position = { x: position[0], y: position[1] }
|
||||
let transformedPosition = DomUtils.positionOnElement(target, position)
|
||||
let dot = document.createElement('div')
|
||||
const size = 10
|
||||
<h3>positionOnElement(element, position)</h3>
|
||||
Function that returns the global position for a normalized position.
|
||||
|
||||
Object.assign(dot.style, {
|
||||
width: size + 'px',
|
||||
height: size + 'px',
|
||||
top: target.offsetTop + target.offsetHeight / 2 + transformedPosition.y - size / 2 + 'px',
|
||||
left: target.offsetLeft + target.offsetWidth / 2 + transformedPosition.x - size / 2 + 'px',
|
||||
position: 'absolute',
|
||||
backgroundColor: 'green',
|
||||
borderRadius: '50%'
|
||||
})
|
||||
<div id="positionOnElementBox" class="box" style="width: 512px;height:256px;border: 1px solid black; box-sizing: border-box; transform: rotate(30deg); margin:100px;"></div>
|
||||
|
||||
document.body.appendChild(dot)
|
||||
<script class="doctest">
|
||||
|
||||
|
||||
let target = document.getElementById("positionOnElementBox")
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
|
||||
let positions = [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[1, 0],
|
||||
[0.5,0.5],
|
||||
[0.2, 0.2],
|
||||
[0.2, 0.8],
|
||||
[0.8, 0.2],
|
||||
[0.8, 0.8],
|
||||
]
|
||||
|
||||
positions.forEach(position => {
|
||||
position = { x: position[0], y: position[1] }
|
||||
let transformedPosition = DomUtils.positionOnElement(target, position)
|
||||
let dot = document.createElement("div");
|
||||
const size = 10;
|
||||
|
||||
|
||||
Object.assign(dot.style, {
|
||||
width: size + "px",
|
||||
height: size + "px",
|
||||
top: target.offsetTop + target.offsetHeight / 2 + transformedPosition.y -size/2+ "px",
|
||||
left: target.offsetLeft + target.offsetWidth / 2 + transformedPosition.x -size/2 + "px",
|
||||
position: "absolute",
|
||||
backgroundColor: "green",
|
||||
borderRadius: "50%"
|
||||
})
|
||||
|
||||
|
||||
document.body.appendChild(dot)
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1,81 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Message</title>
|
||||
<title>PIXI Message</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Message</h1>
|
||||
<p>
|
||||
A message box is a timed popup window. By default, the message window appears in the upper right corner and
|
||||
disappears after 5 seconds.
|
||||
</p>
|
||||
<p><a href="../../doc/out/Message.html">JavaScript API</a></p>
|
||||
<p>Let's look at some message examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Two buttons which start message windows.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Message</h1>
|
||||
<p>
|
||||
A message box is a timed popup window. By default, the message window appears in the upper right corner and disappears after 5 seconds.
|
||||
</p>
|
||||
<p><a href="../../doc/out/Message.html">JavaScript API</a></p>
|
||||
<p>Let's look at some message examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Two buttons which start message windows.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250
|
||||
}).setup().run()
|
||||
|
||||
let button1 = new Button({
|
||||
x: 0,
|
||||
label: 'Default message',
|
||||
action: (e) => {
|
||||
const message = new Message({
|
||||
app: app,
|
||||
header: 'Dies ist die Überschrift',
|
||||
content: 'Und dies ist der Text der Meldung.'
|
||||
})
|
||||
app.scene.addChild(message)
|
||||
}
|
||||
})
|
||||
let button1 = new Button({
|
||||
x: 0,
|
||||
label: 'Default message',
|
||||
action: e => {
|
||||
const message = new Message({
|
||||
app: app,
|
||||
header: 'Dies ist die Überschrift',
|
||||
content: 'Und dies ist der Text der Meldung.'
|
||||
})
|
||||
app.scene.addChild(message)
|
||||
}
|
||||
})
|
||||
|
||||
let button2 = new Button({
|
||||
x: 170,
|
||||
label: 'Bottom-centered message',
|
||||
action: (e) => {
|
||||
const message = new Message({
|
||||
app: app,
|
||||
content: 'Diese Nachricht hat nur einen Text.',
|
||||
autoClose: false,
|
||||
closeButton: true,
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom'
|
||||
})
|
||||
app.scene.addChild(message)
|
||||
}
|
||||
})
|
||||
let button2 = new Button({
|
||||
x: 170,
|
||||
label: 'Bottom-centered message',
|
||||
action: e => {
|
||||
const message = new Message({
|
||||
app: app,
|
||||
content: 'Diese Nachricht hat nur einen Text.',
|
||||
autoClose: false,
|
||||
closeButton: true,
|
||||
align: 'center',
|
||||
verticalAlign: 'bottom'
|
||||
})
|
||||
app.scene.addChild(message)
|
||||
}
|
||||
})
|
||||
|
||||
let button3 = new Button({
|
||||
x: 0,
|
||||
y: 60,
|
||||
label: 'Message from PixiApp',
|
||||
action: (e) => {
|
||||
let message = app.message({
|
||||
content: 'Diese Nachricht verschwindet gleich wieder.'
|
||||
})
|
||||
}
|
||||
})
|
||||
let button3 = new Button({
|
||||
x: 0,
|
||||
y: 60,
|
||||
label: 'Message from PixiApp',
|
||||
action: e => {
|
||||
let message = app.message({
|
||||
content: 'Diese Nachricht verschwindet gleich wieder.'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(button1, button2)
|
||||
app.scene.addChild(button3)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(button1, button2)
|
||||
app.scene.addChild(button3)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -66,7 +66,7 @@ export default class Message extends InteractivePopup {
|
||||
verticalAlign: 'top', // top, middle, bottom
|
||||
duration: 5,
|
||||
autoClose: true,
|
||||
closeDuration: theme.fast,
|
||||
closeDuration: theme.fast
|
||||
},
|
||||
opts
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 486 KiB |
@ -1,175 +1,169 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Modal</title>
|
||||
<title>PIXI Modal</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Modal</h1>
|
||||
<p>
|
||||
In user interface design for computer applications, a modal window is a graphical control element
|
||||
subordinate to an application's main window. It creates a mode that disables the main window, but keeps it
|
||||
visible with the modal window as a child window in front of it. Users must interact with the modal window
|
||||
before they can return to the parent application. This avoids interrupting the workflow on the main window.
|
||||
Modal windows are sometimes called heavy windows or modal dialogs because they often display a dialog box.
|
||||
</p>
|
||||
<p>Let's look at some modal examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Some buttons whichs starts different modal dialogs.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
backgroundColor: 0xaa2211,
|
||||
theme: 'light'
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Modal</h1>
|
||||
<p>
|
||||
In user interface design for computer applications, a modal window is a graphical control element subordinate to an application's main window. It creates a mode that disables the main window, but keeps it visible with the modal window as a child window in front of it. Users must interact with the modal window before they can return to the parent application. This avoids interrupting the workflow on the main window. Modal windows are sometimes called heavy windows or modal dialogs because they often display a dialog box.
|
||||
</p>
|
||||
<p>Let's look at some modal examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Some buttons whichs starts different modal dialogs.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
backgroundColor: 0xaa2211,
|
||||
theme: 'light'
|
||||
}).setup().run()
|
||||
|
||||
let button1 = new Button({
|
||||
x: 10,
|
||||
y: 10,
|
||||
label: 'Modal',
|
||||
action: (e) => {
|
||||
const modal = new Modal({ app: app })
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button1 = new Button({
|
||||
x: 10,
|
||||
y: 10,
|
||||
label: 'Modal',
|
||||
action: e => {
|
||||
const modal = new Modal({app: app})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button2 = new Button({
|
||||
x: 100,
|
||||
y: 10,
|
||||
label: 'Modal mit Inhalt',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
closeOnBackground: false,
|
||||
backgroundFillAlpha: 0.3,
|
||||
header: 'Dies ist die Überschrift',
|
||||
content: 'Und dies ist der Fließtext.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button2 = new Button({
|
||||
x: 100,
|
||||
y: 10,
|
||||
label: 'Modal mit Inhalt',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
closeOnBackground: false,
|
||||
backgroundFillAlpha: .3,
|
||||
header: 'Dies ist die Überschrift',
|
||||
content: 'Und dies ist der Fließtext.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button3 = new Button({
|
||||
x: 270,
|
||||
y: 10,
|
||||
label: 'Modal mit Fließtext',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
maxWidth: 400,
|
||||
header: 'Modal mit langem Fließtext',
|
||||
content:
|
||||
'Die Relativitätstheorie befasst sich mit der Struktur von Raum und Zeit sowie mit dem Wesen der Gravitation. Sie besteht aus zwei maßgeblich von Albert Einstein geschaffenen physikalischen Theorien, der 1905 veröffentlichten speziellen Relativitätstheorie und der 1916 abgeschlossenen allgemeinen Relativitätstheorie. Die spezielle Relativitätstheorie beschreibt das Verhalten von Raum und Zeit aus der Sicht von Beobachtern, die sich relativ zueinander bewegen, und die damit verbundenen Phänomene.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button3 = new Button({
|
||||
x: 270,
|
||||
y: 10,
|
||||
label: 'Modal mit Fließtext',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
maxWidth: 400,
|
||||
header: 'Modal mit langem Fließtext',
|
||||
content: 'Die Relativitätstheorie befasst sich mit der Struktur von Raum und Zeit sowie mit dem Wesen der Gravitation. Sie besteht aus zwei maßgeblich von Albert Einstein geschaffenen physikalischen Theorien, der 1905 veröffentlichten speziellen Relativitätstheorie und der 1916 abgeschlossenen allgemeinen Relativitätstheorie. Die spezielle Relativitätstheorie beschreibt das Verhalten von Raum und Zeit aus der Sicht von Beobachtern, die sich relativ zueinander bewegen, und die damit verbundenen Phänomene.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button4 = new Button({
|
||||
x: 470,
|
||||
y: 10,
|
||||
label: 'Modal nur Fließtext',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
maxWidth: 600,
|
||||
content:
|
||||
'Die Relativitätstheorie befasst sich mit der Struktur von Raum und Zeit sowie mit dem Wesen der Gravitation. Sie besteht aus zwei maßgeblich von Albert Einstein geschaffenen physikalischen Theorien, der 1905 veröffentlichten speziellen Relativitätstheorie und der 1916 abgeschlossenen allgemeinen Relativitätstheorie. Die spezielle Relativitätstheorie beschreibt das Verhalten von Raum und Zeit aus der Sicht von Beobachtern, die sich relativ zueinander bewegen, und die damit verbundenen Phänomene.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button4 = new Button({
|
||||
x: 470,
|
||||
y: 10,
|
||||
label: 'Modal nur Fließtext',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
maxWidth: 600,
|
||||
content: 'Die Relativitätstheorie befasst sich mit der Struktur von Raum und Zeit sowie mit dem Wesen der Gravitation. Sie besteht aus zwei maßgeblich von Albert Einstein geschaffenen physikalischen Theorien, der 1905 veröffentlichten speziellen Relativitätstheorie und der 1916 abgeschlossenen allgemeinen Relativitätstheorie. Die spezielle Relativitätstheorie beschreibt das Verhalten von Raum und Zeit aus der Sicht von Beobachtern, die sich relativ zueinander bewegen, und die damit verbundenen Phänomene.'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button5 = new Button({
|
||||
x: 10,
|
||||
y: 70,
|
||||
label: 'Modal mit Button',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
header: 'Modal mit Button',
|
||||
content: 'Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.',
|
||||
button: { label: 'OK', action: () => modal.hide() },
|
||||
minWidth: 450,
|
||||
maxWidth: 450,
|
||||
closeButton: false
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button5 = new Button({
|
||||
x: 10,
|
||||
y: 70,
|
||||
label: 'Modal mit Button',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
header: 'Modal mit Button',
|
||||
content: 'Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.',
|
||||
button: {label: 'OK', action: () => modal.hide()},
|
||||
minWidth: 450,
|
||||
maxWidth: 450,
|
||||
closeButton: false
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button6 = new Button({
|
||||
x: 190,
|
||||
y: 70,
|
||||
label: 'Modal mit ButtonGroup',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
header: 'Modal mit ButtonGroup',
|
||||
content:
|
||||
'Seit die Mathematiker über die Relativitätstheorie hergefallen sind, verstehe ich sie selbst nicht mehr.',
|
||||
buttonGroup: {
|
||||
buttons: [{ label: 'Abbrechen', action: (e) => modal.hide() }, { label: 'Anwenden' }]
|
||||
},
|
||||
minWidth: 450,
|
||||
maxWidth: 450,
|
||||
closeButton: false
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button6 = new Button({
|
||||
x: 190,
|
||||
y: 70,
|
||||
label: 'Modal mit ButtonGroup',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
header: 'Modal mit ButtonGroup',
|
||||
content: 'Seit die Mathematiker über die Relativitätstheorie hergefallen sind, verstehe ich sie selbst nicht mehr.',
|
||||
buttonGroup: {
|
||||
buttons: [
|
||||
{label: 'Abbrechen', action: e => modal.hide()},
|
||||
{label: 'Anwenden'}
|
||||
]
|
||||
},
|
||||
minWidth: 450,
|
||||
maxWidth: 450,
|
||||
closeButton: false
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let img = PIXI.Sprite.from('./assets/modal-1.jpg')
|
||||
img.scale.set(0.2, 0.2)
|
||||
let img = PIXI.Sprite.from('./assets/modal-1.jpg')
|
||||
img.scale.set(.2, .2)
|
||||
|
||||
let button7 = new Button({
|
||||
x: 420,
|
||||
y: 70,
|
||||
label: 'Modal mit Foto',
|
||||
action: (e) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
minWidth: 0,
|
||||
padding: 0,
|
||||
content: img,
|
||||
closeButton: false,
|
||||
closeOnPopup: true
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let button7 = new Button({
|
||||
x: 420,
|
||||
y: 70,
|
||||
label: 'Modal mit Foto',
|
||||
action: e => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
minWidth: 0,
|
||||
padding: 0,
|
||||
content: img,
|
||||
closeButton: false,
|
||||
closeOnPopup: true
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
let button8 = new Button({
|
||||
x: 10,
|
||||
y: 130,
|
||||
label: 'App Modal',
|
||||
action: (e) => {
|
||||
let modal = app.modal({
|
||||
header: 'Modal aus App gestartet',
|
||||
content: 'Die größte Erfindung des menschlichen Geistes? - Die Zinseszinsen!',
|
||||
minWidth: 80
|
||||
})
|
||||
}
|
||||
})
|
||||
let button8 = new Button({
|
||||
x: 10,
|
||||
y: 130,
|
||||
label: 'App Modal',
|
||||
action: e => {
|
||||
let modal = app.modal({
|
||||
header: 'Modal aus App gestartet',
|
||||
content: 'Die größte Erfindung des menschlichen Geistes? - Die Zinseszinsen!',
|
||||
minWidth: 80
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(button1, button2, button3, button4)
|
||||
app.scene.addChild(button5, button6, button7)
|
||||
app.scene.addChild(button8)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(button1, button2, button3, button4)
|
||||
app.scene.addChild(button5, button6, button7)
|
||||
app.scene.addChild(button8)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -55,7 +55,7 @@ export default class Modal extends PIXI.Container {
|
||||
backgroundFill: theme.background,
|
||||
backgroundFillAlpha: 0.6,
|
||||
closeOnBackground: true,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -87,7 +87,7 @@ export default class Modal extends PIXI.Container {
|
||||
// interaction
|
||||
//-----------------
|
||||
this.interactive = true
|
||||
this.on('added', (e) => {
|
||||
this.on('added', e => {
|
||||
if (this.visible) {
|
||||
this.show()
|
||||
}
|
||||
@ -101,7 +101,7 @@ export default class Modal extends PIXI.Container {
|
||||
|
||||
if (this.opts.closeOnBackground) {
|
||||
background.interactive = true
|
||||
background.on('pointerup', (e) => {
|
||||
background.on('pointerup', e => {
|
||||
this.hide()
|
||||
})
|
||||
}
|
||||
@ -112,7 +112,7 @@ export default class Modal extends PIXI.Container {
|
||||
visible: true,
|
||||
onHidden: () => {
|
||||
this.hide()
|
||||
},
|
||||
}
|
||||
})
|
||||
let popup = new InteractivePopup(popupOpts)
|
||||
this.popup = popup
|
||||
@ -153,7 +153,7 @@ export default class Modal extends PIXI.Container {
|
||||
show() {
|
||||
TweenLite.to(this, this.theme.fast, {
|
||||
alpha: 1,
|
||||
onStart: () => (this.visible = true),
|
||||
onStart: () => (this.visible = true)
|
||||
})
|
||||
|
||||
return this
|
||||
@ -167,7 +167,7 @@ export default class Modal extends PIXI.Container {
|
||||
hide() {
|
||||
TweenLite.to(this, this.theme.fast, {
|
||||
alpha: 0,
|
||||
onComplete: () => (this.visible = false),
|
||||
onComplete: () => (this.visible = false)
|
||||
})
|
||||
|
||||
return this
|
||||
|
||||
|
Before Width: | Height: | Size: 581 KiB |
@ -1,55 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Popover</h1>
|
||||
<p>
|
||||
Add small overlay content, like those found in iOS, to any element for housing secondary information. The
|
||||
Popover plugin is similar to tooltips; it is a pop-up box that appears when the user clicks or touches an
|
||||
element. The difference is that the popover can contain much more content.
|
||||
</p>
|
||||
<p>Let's look at an example of a popover:</p>
|
||||
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
autoResize: false,
|
||||
width: 850,
|
||||
height: 450
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()" >
|
||||
<h1>Popover</h1>
|
||||
<p>
|
||||
Add small overlay content, like those found in iOS, to any element for housing secondary information.
|
||||
The Popover plugin is similar to tooltips; it is a pop-up box that appears when the user clicks or
|
||||
touches an element. The difference is that the popover can contain much more content.
|
||||
</p>
|
||||
<p>Let's look at an example of a popover:</p>
|
||||
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
<script class="doctest">
|
||||
|
||||
let popover1 = new Popover({ title: 'Popover title', text: 'This is the popover text.', x: 150, y: 130 })
|
||||
app.scene.addChild(popover1)
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
autoResize: false,
|
||||
width: 850, height: 450
|
||||
}).setup().run()
|
||||
|
||||
let popover2 = new Popover({
|
||||
text: 'This is another popover text. It has more words than the first one, some line breaks, \n\nbut no title :-(',
|
||||
x: 50,
|
||||
y: 230,
|
||||
placement: 'right',
|
||||
width: 180
|
||||
})
|
||||
app.scene.addChild(popover2)
|
||||
let popover1 = new Popover({title: "Popover title", text: "This is the popover text.", x: 150, y: 130})
|
||||
app.scene.addChild(popover1)
|
||||
|
||||
let popover3 = new Popover({
|
||||
title: 'Popover title 3. This title has many words but the Popover has no text...',
|
||||
x: 650,
|
||||
y: 70,
|
||||
placement: 'left'
|
||||
})
|
||||
app.scene.addChild(popover3)
|
||||
let popover2 = new Popover({text: "This is another popover text. It has more words than the first one, some line breaks, \n\nbut no title :-(", x: 50, y: 230, placement: "right", width: 180})
|
||||
app.scene.addChild(popover2)
|
||||
|
||||
const text4 = `
|
||||
let popover3 = new Popover({title: "Popover title 3. This title has many words but the Popover has no text...", x: 650, y: 70, placement: "left"})
|
||||
app.scene.addChild(popover3)
|
||||
|
||||
const text4 = `
|
||||
Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas Böses
|
||||
getan hätte, wurde er eines Morgens verhaftet. »Wie ein Hund!« sagte er,
|
||||
es war, als sollte die Scham ihn überleben. Als Gregor Samsa eines Morgens
|
||||
@ -62,38 +49,29 @@ und überblickte mit einem gewissermaßen bewundernden Blick den ihm doch
|
||||
wohlbekannten Apparat.
|
||||
`
|
||||
|
||||
let popover4 = new Popover({
|
||||
title: 'Popover title 4',
|
||||
text: text4,
|
||||
x: 650,
|
||||
y: 120,
|
||||
width: 380,
|
||||
placement: 'bottom',
|
||||
titleStyle: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 40,
|
||||
fontStyle: 'italic',
|
||||
fontWeight: 'bold',
|
||||
fill: ['#6b6acf', '#d7626c'], // gradient
|
||||
stroke: '#393879',
|
||||
strokeThickness: 6,
|
||||
dropShadow: true,
|
||||
dropShadowColor: '#e7bc51',
|
||||
dropShadowBlur: 4,
|
||||
dropShadowAngle: Math.PI / 6,
|
||||
dropShadowDistance: 3,
|
||||
wordWrap: true,
|
||||
wordWrapWidth: 440
|
||||
},
|
||||
textStyle: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 10,
|
||||
fill: '#76a9c9',
|
||||
strokeThickness: 5,
|
||||
wordWrap: true
|
||||
}
|
||||
})
|
||||
app.scene.addChild(popover4)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
let popover4 = new Popover({title: "Popover title 4", text: text4, x: 650, y: 120, width: 380, placement: "bottom", titleStyle: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 40,
|
||||
fontStyle: 'italic',
|
||||
fontWeight: 'bold',
|
||||
fill: ['#6b6acf', '#d7626c'], // gradient
|
||||
stroke: '#393879',
|
||||
strokeThickness: 6,
|
||||
dropShadow: true,
|
||||
dropShadowColor: '#e7bc51',
|
||||
dropShadowBlur: 4,
|
||||
dropShadowAngle: Math.PI / 6,
|
||||
dropShadowDistance: 3,
|
||||
wordWrap: true,
|
||||
wordWrapWidth: 440
|
||||
}, textStyle: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 10,
|
||||
fill: "#76a9c9",
|
||||
strokeThickness: 5,
|
||||
wordWrap: true
|
||||
}})
|
||||
app.scene.addChild(popover4)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -10,7 +10,7 @@ export default class Popover extends PIXI.Graphics {
|
||||
placement = 'top',
|
||||
width = 250,
|
||||
titleStyle = {},
|
||||
textStyle = { fontSize: '1.6em' },
|
||||
textStyle = { fontSize: '1.6em' }
|
||||
} = {}) {
|
||||
super()
|
||||
|
||||
@ -22,7 +22,7 @@ export default class Popover extends PIXI.Graphics {
|
||||
placement,
|
||||
width,
|
||||
titleStyle,
|
||||
textStyle,
|
||||
textStyle
|
||||
}
|
||||
|
||||
this.padding = 12
|
||||
@ -33,7 +33,7 @@ export default class Popover extends PIXI.Graphics {
|
||||
stroke: '#f6f6f6',
|
||||
strokeThickness: 3,
|
||||
wordWrap: true,
|
||||
wordWrapWidth: width - this.padding * 2,
|
||||
wordWrapWidth: width - this.padding * 2
|
||||
}
|
||||
|
||||
this.titleTextStyle = new PIXI.TextStyle(Object.assign({}, style, titleStyle))
|
||||
|
||||
|
Before Width: | Height: | Size: 981 KiB |
@ -1,83 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Popup</title>
|
||||
<title>PIXI Popup</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Popup</h1>
|
||||
<p>
|
||||
This class represents a popup window that can be used to display an arbitrary view. The popup window is a
|
||||
floating container that appears on top of the current activity.
|
||||
</p>
|
||||
<p>Let's look at some popup examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Three popups and a button which opens a popup.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
backgroundColor: 0xcccccc
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Popup</h1>
|
||||
<p>
|
||||
This class represents a popup window that can be used to display an arbitrary view. The popup window is a floating container that appears on top of the current activity.
|
||||
</p>
|
||||
<p>Let's look at some popup examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Three popups and a button which opens a popup.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
backgroundColor: 0xcccccc
|
||||
}).setup().run()
|
||||
|
||||
let popup1 = new Popup({
|
||||
x: 20,
|
||||
y: 20,
|
||||
header: 'Popup'
|
||||
})
|
||||
let popup1 = new Popup({
|
||||
x: 20,
|
||||
y: 20,
|
||||
header: 'Popup'
|
||||
})
|
||||
|
||||
let popup2 = new Popup({
|
||||
x: 140,
|
||||
y: 30,
|
||||
padding: 20,
|
||||
header: 'Popup',
|
||||
content: 'Man kann die Erfahrung nicht\nfrüh genug machen, wie\nentbehrlich man in der\nWelt ist.',
|
||||
headerStyle: { fill: 0xaa3322 },
|
||||
textStyle: { fill: 0x5544ee, fontSize: 10 }
|
||||
})
|
||||
let popup2 = new Popup({
|
||||
x: 140,
|
||||
y: 30,
|
||||
padding: 20,
|
||||
header: 'Popup',
|
||||
content: 'Man kann die Erfahrung nicht\nfrüh genug machen, wie\nentbehrlich man in der\nWelt ist.',
|
||||
headerStyle: {fill: 0xaa3322},
|
||||
textStyle: {fill: 0x5544ee, fontSize: 10}
|
||||
})
|
||||
|
||||
let popup3 = new Popup({
|
||||
x: 330,
|
||||
y: 20,
|
||||
content:
|
||||
'Man sollte alle Tage wenigstens ein kleines Lied hören, ein gutes Gedicht lesen,\nein treffliches Gemälde sehen und, wenn es möglich zu machen wäre,\neinige vernünftige Worte sprechen.'
|
||||
})
|
||||
let popup3 = new Popup({
|
||||
x: 330,
|
||||
y: 20,
|
||||
content: 'Man sollte alle Tage wenigstens ein kleines Lied hören, ein gutes Gedicht lesen,\nein treffliches Gemälde sehen und, wenn es möglich zu machen wäre,\neinige vernünftige Worte sprechen.'
|
||||
})
|
||||
|
||||
let button1 = new Button({
|
||||
x: 20,
|
||||
y: 160,
|
||||
icon: 'speaker_notes',
|
||||
action: () => {
|
||||
app.scene.addChild(
|
||||
new Popup({
|
||||
x: 100,
|
||||
y: 100,
|
||||
closeButton: true,
|
||||
header: 'Die Kunst ist eine Vermittlerin des Unaussprechlichen.',
|
||||
stroke: 0x336699,
|
||||
strokeWidth: 3
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
let button1 = new Button({
|
||||
x: 20,
|
||||
y: 160,
|
||||
icon: 'speaker_notes',
|
||||
action: () => {
|
||||
app.scene.addChild(new Popup({
|
||||
x: 100,
|
||||
y: 100,
|
||||
closeButton: true,
|
||||
header: 'Die Kunst ist eine Vermittlerin des Unaussprechlichen.',
|
||||
stroke: 0x336699,
|
||||
strokeWidth: 3
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(popup1, popup2, popup3)
|
||||
app.scene.addChild(button1)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(popup1, popup2, popup3)
|
||||
app.scene.addChild(button1)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -29,7 +29,7 @@ export class InteractivePopup extends AbstractPopup {
|
||||
closeOnPopup: false,
|
||||
closeButton: true,
|
||||
button: null,
|
||||
buttonGroup: null,
|
||||
buttonGroup: null
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -62,7 +62,7 @@ export class InteractivePopup extends AbstractPopup {
|
||||
|
||||
// interaction
|
||||
//-----------------
|
||||
this.on('pointerup', (e) => {
|
||||
this.on('pointerup', e => {
|
||||
if (this.opts.closeOnPopup) {
|
||||
this.hide()
|
||||
} else {
|
||||
@ -95,7 +95,7 @@ export class InteractivePopup extends AbstractPopup {
|
||||
|
||||
closeButton.interactive = true
|
||||
closeButton.buttonMode = true
|
||||
closeButton.on('pointerdown', (e) => {
|
||||
closeButton.on('pointerdown', e => {
|
||||
this.hide()
|
||||
})
|
||||
|
||||
@ -228,7 +228,7 @@ export default class Popup extends InteractivePopup {
|
||||
{
|
||||
closeButton: false,
|
||||
minWidth: 0,
|
||||
minHeight: 0,
|
||||
minHeight: 0
|
||||
},
|
||||
opts
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 561 KiB |
@ -1,135 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI PopupMenu</title>
|
||||
<title>PIXI PopupMenu</title>
|
||||
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>PopupMenu</h1>
|
||||
<p>
|
||||
A popup menu is a menu in a graphical user interface (GUI) that appears upon user interaction, such as a
|
||||
click or touch operation. A context menu offers a limited set of choices that are available in the current
|
||||
state, or context, of the application to which the menu belongs. Usually the available choices are actions
|
||||
related to the selected object.
|
||||
</p>
|
||||
<p>Let's look at some popup menu examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Some buttons whichs open popup menues.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>PopupMenu</h1>
|
||||
<p>
|
||||
A popup menu is a menu in a graphical user interface (GUI) that appears upon user interaction, such as a click or touch operation. A context menu offers a limited set of choices that are available in the current state, or context, of the application to which the menu belongs. Usually the available choices are actions related to the selected object.
|
||||
</p>
|
||||
<p>Let's look at some popup menu examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Some buttons whichs open popup menues.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250
|
||||
}).setup().run()
|
||||
|
||||
app.loadSprites(
|
||||
[
|
||||
'./assets/popupmenu-1.jpg',
|
||||
'./assets/popupmenu-2.jpg',
|
||||
'./assets/popupmenu-3.jpg',
|
||||
'./assets/popupmenu-4.jpg',
|
||||
'./assets/popupmenu-5.jpg'
|
||||
],
|
||||
(sprites) => {
|
||||
const buttonGroup1 = new ButtonGroup({
|
||||
buttons: [
|
||||
{
|
||||
icon: 'looks_1',
|
||||
action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{ label: 'Speichern', action: () => alert('Gespeichert') },
|
||||
{ label: 'Editieren', action: () => alert('Editiert') },
|
||||
{ label: 'Löschen', action: () => alert('Gelöscht'), disabled: true }
|
||||
]
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'looks_2',
|
||||
action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
closeButton: true,
|
||||
closeOnPopup: false,
|
||||
closeOnAction: true,
|
||||
items: [
|
||||
{ label: 'Option 1' },
|
||||
{ label: 'Option 2' },
|
||||
{ label: 'Option 3', action: () => {} },
|
||||
{ label: 'Option 4', action: () => {} },
|
||||
{ label: 'Option 5' },
|
||||
{ label: 'Option 6' }
|
||||
]
|
||||
})
|
||||
popupmenu.x = 400
|
||||
app.scene.addChild(popupmenu)
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'looks_3',
|
||||
action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{ label: 'Option 01', textStyle: { fill: 0x637a38, fontSize: 14 } },
|
||||
{ label: 'Option 02', textStyle: { fill: 0x8ca351, fontSize: 14 } },
|
||||
{ label: 'Option 03', textStyle: { fill: 0xb5d16a, fontSize: 14 } },
|
||||
{ label: 'Option 04', textStyle: { fill: 0xcedc9c, fontSize: 14 } },
|
||||
{ label: 'Option 05', textStyle: { fill: 0x8c6e31, fontSize: 14 } },
|
||||
{ label: 'Option 06', textStyle: { fill: 0xbda038, fontSize: 14 } },
|
||||
{ label: 'Option 07', textStyle: { fill: 0xe7bc51, fontSize: 14 } },
|
||||
{ label: 'Option 08', textStyle: { fill: 0xe7cc94, fontSize: 14 } },
|
||||
{ label: 'Option 09', textStyle: { fill: 0x843d39, fontSize: 14 } },
|
||||
{ label: 'Option 10', textStyle: { fill: 0xae4a4a, fontSize: 14 } },
|
||||
{ label: 'Option 11', textStyle: { fill: 0xd7626c, fontSize: 14 } },
|
||||
{ label: 'Option 12', textStyle: { fill: 0xe8979c, fontSize: 14 } }
|
||||
],
|
||||
x: 155,
|
||||
margin: 2
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: 'looks_4',
|
||||
action: () => {
|
||||
sprites.forEach((sprite) => sprite.scale.set(0.33, 0.33))
|
||||
app.loadSprites([
|
||||
'./assets/popupmenu-1.jpg',
|
||||
'./assets/popupmenu-2.jpg',
|
||||
'./assets/popupmenu-3.jpg',
|
||||
'./assets/popupmenu-4.jpg',
|
||||
'./assets/popupmenu-5.jpg'
|
||||
], sprites => {
|
||||
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{ content: sprites.get('./assets/popupmenu-1.jpg') },
|
||||
{ content: sprites.get('./assets/popupmenu-2.jpg') },
|
||||
{ content: sprites.get('./assets/popupmenu-3.jpg') },
|
||||
{ content: sprites.get('./assets/popupmenu-4.jpg') },
|
||||
{ content: sprites.get('./assets/popupmenu-5.jpg') }
|
||||
],
|
||||
x: 220,
|
||||
margin: 2,
|
||||
padding: 2
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const buttonGroup1 = new ButtonGroup({
|
||||
buttons: [
|
||||
{icon: 'looks_1', action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{label: 'Speichern', action: () => alert('Gespeichert')},
|
||||
{label: 'Editieren', action: () => alert('Editiert')},
|
||||
{label: 'Löschen', action: () => alert('Gelöscht'), disabled: true}
|
||||
]
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}},
|
||||
{icon: 'looks_2', action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
closeButton: true,
|
||||
closeOnPopup: false,
|
||||
closeOnAction: true,
|
||||
items: [
|
||||
{label: 'Option 1'},
|
||||
{label: 'Option 2'},
|
||||
{label: 'Option 3', action: () => {}},
|
||||
{label: 'Option 4', action: () => {}},
|
||||
{label: 'Option 5'},
|
||||
{label: 'Option 6'}
|
||||
]
|
||||
})
|
||||
popupmenu.x = 400
|
||||
app.scene.addChild(popupmenu)
|
||||
}},
|
||||
{icon: 'looks_3', action: () => {
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{label: 'Option 01', textStyle: {fill: 0x637a38, fontSize: 14}},
|
||||
{label: 'Option 02', textStyle: {fill: 0x8ca351, fontSize: 14}},
|
||||
{label: 'Option 03', textStyle: {fill: 0xb5d16a, fontSize: 14}},
|
||||
{label: 'Option 04', textStyle: {fill: 0xcedc9c, fontSize: 14}},
|
||||
{label: 'Option 05', textStyle: {fill: 0x8c6e31, fontSize: 14}},
|
||||
{label: 'Option 06', textStyle: {fill: 0xbda038, fontSize: 14}},
|
||||
{label: 'Option 07', textStyle: {fill: 0xe7bc51, fontSize: 14}},
|
||||
{label: 'Option 08', textStyle: {fill: 0xe7cc94, fontSize: 14}},
|
||||
{label: 'Option 09', textStyle: {fill: 0x843d39, fontSize: 14}},
|
||||
{label: 'Option 10', textStyle: {fill: 0xae4a4a, fontSize: 14}},
|
||||
{label: 'Option 11', textStyle: {fill: 0xd7626c, fontSize: 14}},
|
||||
{label: 'Option 12', textStyle: {fill: 0xe8979c, fontSize: 14}}
|
||||
],
|
||||
x: 155,
|
||||
margin: 2
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}},
|
||||
{icon: 'looks_4', action: () => {
|
||||
|
||||
app.scene.addChild(buttonGroup1)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
sprites.forEach(sprite => sprite.scale.set(.33, .33))
|
||||
|
||||
const popupmenu = new PopupMenu({
|
||||
items: [
|
||||
{content: sprites.get('./assets/popupmenu-1.jpg')},
|
||||
{content: sprites.get('./assets/popupmenu-2.jpg')},
|
||||
{content: sprites.get('./assets/popupmenu-3.jpg')},
|
||||
{content: sprites.get('./assets/popupmenu-4.jpg')},
|
||||
{content: sprites.get('./assets/popupmenu-5.jpg')}
|
||||
],
|
||||
x: 220,
|
||||
margin: 2,
|
||||
padding: 2
|
||||
})
|
||||
app.scene.addChild(popupmenu)
|
||||
}}
|
||||
]
|
||||
})
|
||||
|
||||
app.scene.addChild(buttonGroup1)
|
||||
}, {resolutionDependent: false})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -50,7 +50,7 @@ export default class PopupMenu extends Popup {
|
||||
items: [],
|
||||
margin: theme.margin / 2,
|
||||
textStyle: theme.textStyle,
|
||||
closeOnPopup: true,
|
||||
closeOnPopup: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -88,19 +88,19 @@ export default class PopupMenu extends Popup {
|
||||
object.interactive = true
|
||||
object.buttonMode = true
|
||||
}
|
||||
object.on('pointerover', (e) => {
|
||||
object.on('pointerover', e => {
|
||||
TweenLite.to(object, this.theme.fast, {
|
||||
alpha: 0.83,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
object.on('pointerout', (e) => {
|
||||
object.on('pointerout', e => {
|
||||
TweenLite.to(object, this.theme.fast, {
|
||||
alpha: 1,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
object.on('pointerup', (e) => {
|
||||
object.on('pointerup', e => {
|
||||
item.action.call(object, e, object)
|
||||
if (this.opts.closeOnAction) {
|
||||
this.hide()
|
||||
|
||||
|
Before Width: | Height: | Size: 539 KiB |
@ -1,80 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Progress</title>
|
||||
<title>PIXI Progress</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Progress</h1>
|
||||
<p>A progress bar can be used to show a user how far along he/she is in a process.</p>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Progress</h1>
|
||||
<p>
|
||||
A progress bar can be used to show a user how far along he/she is in a process.
|
||||
</p>
|
||||
|
||||
<h2>Example 1</h2>
|
||||
<p>Let's look at the progress bar example:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: When the page finished loading, a progress bar should overlay the PixiJS application.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<h2>Example 1</h2>
|
||||
<p>Let's look at the progress bar example:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: When the page finished loading, a progress bar should overlay the PixiJS application.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
let progress1 = new Progress({
|
||||
app: app
|
||||
})
|
||||
let progress1 = new Progress({
|
||||
app: app
|
||||
})
|
||||
|
||||
app.scene.addChild(progress1)
|
||||
app.scene.addChild(progress1)
|
||||
|
||||
setTimeout(() => (progress1.progress = 10), 500)
|
||||
setTimeout(() => (progress1.progress = 20), 800)
|
||||
setTimeout(() => (progress1.progress = 50), 900)
|
||||
setTimeout(() => (progress1.progress = 80), 1500)
|
||||
setTimeout(() => (progress1.progress = 100), 1700)
|
||||
</script>
|
||||
setTimeout(() => progress1.progress = 10, 500)
|
||||
setTimeout(() => progress1.progress = 20, 800)
|
||||
setTimeout(() => progress1.progress = 50, 900)
|
||||
setTimeout(() => progress1.progress = 80, 1500)
|
||||
setTimeout(() => progress1.progress = 100, 1700)
|
||||
</script>
|
||||
|
||||
<h2>Example 2</h2>
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: When the page finished loading, a progress bar should overlay the PixiJS application.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
progress: {
|
||||
height: 20,
|
||||
fillActive: 0xe7bc51,
|
||||
margin: 200
|
||||
}
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<h2>Example 2</h2>
|
||||
<canvas id="canvas2" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: When the page finished loading, a progress bar should overlay the PixiJS application.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app2 = new PIXIApp({
|
||||
view: canvas2,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false,
|
||||
progress: {
|
||||
height: 20,
|
||||
fillActive: 0xe7bc51,
|
||||
margin: 200
|
||||
}
|
||||
}).setup().run()
|
||||
|
||||
setTimeout(() => app2.progress(10), 1000)
|
||||
setTimeout(() => app2.progress(30), 2000)
|
||||
setTimeout(() => app2.progress(35), 2300)
|
||||
setTimeout(() => app2.progress(50), 2800)
|
||||
setTimeout(() => app2.progress(60), 3500)
|
||||
setTimeout(() => app2.progress(90), 4500)
|
||||
setTimeout(() => app2.progress(100), 5000)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
setTimeout(() => app2.progress(10), 1000)
|
||||
setTimeout(() => app2.progress(30), 2000)
|
||||
setTimeout(() => app2.progress(35), 2300)
|
||||
setTimeout(() => app2.progress(50), 2800)
|
||||
setTimeout(() => app2.progress(60), 3500)
|
||||
setTimeout(() => app2.progress(90), 4500)
|
||||
setTimeout(() => app2.progress(100), 5000)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -81,7 +81,7 @@ export default class Progress extends PIXI.Container {
|
||||
backgroundFillAlpha: 1,
|
||||
radius: theme.radius,
|
||||
destroyOnComplete: true,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -116,7 +116,7 @@ export default class Progress extends PIXI.Container {
|
||||
setup() {
|
||||
// interaction
|
||||
//-----------------
|
||||
this.on('added', (e) => {
|
||||
this.on('added', e => {
|
||||
this.show()
|
||||
})
|
||||
|
||||
@ -261,7 +261,7 @@ export default class Progress extends PIXI.Container {
|
||||
hide() {
|
||||
TweenLite.to(this, this.theme.fast, {
|
||||
alpha: 0,
|
||||
onComplete: () => (this.visible = false),
|
||||
onComplete: () => (this.visible = false)
|
||||
})
|
||||
|
||||
return this
|
||||
@ -293,10 +293,10 @@ export default class Progress extends PIXI.Container {
|
||||
if (value === 100 && this.opts.destroyOnComplete) {
|
||||
TweenLite.to(this, this.theme.fast, {
|
||||
alpha: 0,
|
||||
onComplete: () => this.destroy({ children: true }),
|
||||
onComplete: () => this.destroy({ children: true })
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 366 KiB |
@ -1,103 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>PIXI Resolution Doctest</title>
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.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>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.6.5/mousetrap.min.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Resolution</h1>
|
||||
<canvas id="canvas"></canvas>
|
||||
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
fpsLogging: true,
|
||||
transparent: false
|
||||
})
|
||||
|
||||
app.setup()
|
||||
app.run()
|
||||
|
||||
const textProps = { fontSize: 72, fill: 0xffffff }
|
||||
|
||||
Mousetrap.bind(['1', '2', '3', '4', '5'], (event, key) => {
|
||||
app.stage.removeChildren()
|
||||
|
||||
let sprite = null
|
||||
let label = null
|
||||
|
||||
if (key === '1') {
|
||||
sprite = PIXI.Sprite.from('resolution/image-4k.jpg')
|
||||
label = `4096 * 2732 ~ 4K`
|
||||
} else if (key === '2') {
|
||||
sprite = PIXI.Sprite.from('resolution/image-8k.jpg')
|
||||
label = `7952 * 5304 ~ 8K`
|
||||
} else if (key === '3') {
|
||||
const texture = PIXI.Texture.from('resolution/video-1k.mp4')
|
||||
texture.baseTexture.resource.source.loop = true
|
||||
sprite = new PIXI.Sprite(texture)
|
||||
label = `1920 * 1080 = 1K`
|
||||
} else if (key === '4') {
|
||||
const texture = PIXI.Texture.from('resolution/video-4k.mp4')
|
||||
texture.baseTexture.resource.source.loop = true
|
||||
sprite = new PIXI.Sprite(texture)
|
||||
label = `3840 * 2160 = 4K`
|
||||
} else if (key === '5') {
|
||||
const texture = PIXI.Texture.from('resolution/video-8k.mp4')
|
||||
texture.baseTexture.resource.source.loop = true
|
||||
sprite = new PIXI.Sprite(texture)
|
||||
label = `7680 * 4320 ~ 8K`
|
||||
}
|
||||
|
||||
app.stage.addChild(sprite)
|
||||
|
||||
// texts
|
||||
//--------------------
|
||||
const shortcuts = new PIXI.Text(`Press 1 - 5 to change Sprites`, textProps)
|
||||
shortcuts.x = 100
|
||||
shortcuts.y = 100
|
||||
|
||||
const width = new PIXI.Text(`Width: ${app.renderer.width}`, textProps)
|
||||
width.x = 100
|
||||
width.y = shortcuts.y + shortcuts.height * 2
|
||||
|
||||
const height = new PIXI.Text(`Height: ${app.renderer.height}`, textProps)
|
||||
height.x = 100
|
||||
height.y = width.y + width.height + 10
|
||||
|
||||
const resolution = new PIXI.Text(`Resolution: ${app.renderer.resolution}`, textProps)
|
||||
resolution.x = 100
|
||||
resolution.y = height.y + height.height + 10
|
||||
|
||||
const devicePixelRatio = new PIXI.Text(`devicePixelRatio: ${window.devicePixelRatio}`, textProps)
|
||||
devicePixelRatio.x = 100
|
||||
devicePixelRatio.y = resolution.y + resolution.height + 10
|
||||
|
||||
const text = new PIXI.Text(label, textProps)
|
||||
text.x = 100
|
||||
text.y = devicePixelRatio.y + devicePixelRatio.height * 2
|
||||
|
||||
app.stage.addChild(shortcuts, width, height, resolution, devicePixelRatio, text)
|
||||
})
|
||||
|
||||
Mousetrap.trigger('1')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 9.9 MiB |
@ -1,138 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>PIXI Scatter Resolution Doctest</title>
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Scatter Resolution</h1>
|
||||
<canvas id="canvas" />
|
||||
<script>
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
roundPixels: true,
|
||||
resolution: 2
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
|
||||
app.loadSprites(
|
||||
[
|
||||
'../examples/front__1_dpi75.png',
|
||||
'../examples/front__1_dpi150.png',
|
||||
'../examples/front__1_dpi300.png',
|
||||
'../examples/front__1_dpi600.png',
|
||||
'../examples/front__1_dpi1200.png'
|
||||
],
|
||||
(sprites) => {
|
||||
app.scatterContainerFront = new ScatterContainer(app.renderer, { app })
|
||||
app.scatterContainerBack = new ScatterContainer(app.renderer, { app })
|
||||
|
||||
app.scene.addChild(app.scatterContainerBack)
|
||||
app.scene.addChild(app.scatterContainerFront)
|
||||
|
||||
let startScale = 0.5
|
||||
|
||||
// sprite1
|
||||
//--------------------
|
||||
let sprite1 = sprites.get('../examples/front__1_dpi75.png')
|
||||
sprite1.interactive = true
|
||||
let scatter1 = new DisplayObjectScatter(sprite1, app.renderer, {
|
||||
x: 20,
|
||||
y: 20,
|
||||
startScale,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
app.scatterContainerBack.addChild(sprite1)
|
||||
|
||||
// sprite2
|
||||
//--------------------
|
||||
let sprite2 = sprites.get('../examples/front__1_dpi150.png')
|
||||
sprite2.interactive = true
|
||||
let scatter2 = new DisplayObjectScatter(sprite2, app.renderer, {
|
||||
x: 320,
|
||||
y: 20,
|
||||
startScale: 0.5 * startScale,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
app.scatterContainerFront.addChild(sprite2)
|
||||
|
||||
// sprite3
|
||||
//--------------------
|
||||
let sprite3 = sprites.get('../examples/front__1_dpi300.png')
|
||||
sprite3.interactive = true
|
||||
let scatter3 = new DisplayObjectScatter(sprite3, app.renderer, {
|
||||
x: 620,
|
||||
y: 20,
|
||||
startScale: 0.25 * startScale,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
app.scatterContainerBack.addChild(sprite3)
|
||||
|
||||
// sprite4
|
||||
//--------------------
|
||||
let sprite4 = sprites.get('../examples/front__1_dpi600.png')
|
||||
sprite4.interactive = true
|
||||
let scatter4 = new DisplayObjectScatter(sprite4, app.renderer, {
|
||||
x: 920,
|
||||
y: 20,
|
||||
startScale: 0.125 * startScale,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
app.scatterContainerFront.addChild(sprite4)
|
||||
|
||||
// sprite5
|
||||
//--------------------
|
||||
let sprite5 = sprites.get('../examples/front__1_dpi1200.png')
|
||||
sprite5.interactive = true
|
||||
let scatter5 = new DisplayObjectScatter(sprite5, app.renderer, {
|
||||
x: 1220,
|
||||
y: 20,
|
||||
startScale: 0.0625 * startScale,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
app.scatterContainerFront.addChild(sprite5)
|
||||
|
||||
// renderTexture
|
||||
//--------------------
|
||||
sprites.forEach((value) => {
|
||||
const matrix = new PIXI.Matrix()
|
||||
matrix.translate(-value.x, -value.y)
|
||||
|
||||
const texture = PIXI.RenderTexture.create({
|
||||
width: value.width,
|
||||
height: value.height,
|
||||
resolution: 2
|
||||
})
|
||||
app.renderer.render(value, texture, true, matrix)
|
||||
|
||||
const sprite = new PIXI.Sprite(texture)
|
||||
sprite.interactive = true
|
||||
|
||||
new DisplayObjectScatter(sprite, app.renderer, {
|
||||
x: value.x,
|
||||
y: 400,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
|
||||
app.scatterContainerFront.addChild(sprite)
|
||||
})
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,92 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>PIXI Scatter Resolution Doctest</title>
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Scatter Resolution 2</h1>
|
||||
<canvas id="canvas2" class="interactive">Canvas not supported</canvas>
|
||||
<script>
|
||||
class ScatterApp extends PIXIApp {
|
||||
setup() {
|
||||
super.setup()
|
||||
// Obey order in which ScatterContainer are created because the
|
||||
// InteractionMapper register event handlers in a first come first serve
|
||||
// order
|
||||
this.scatterContainerFront = new ScatterContainer(this.renderer, { app: this })
|
||||
this.scatterContainerBack = new ScatterContainer(this.renderer, { app: this })
|
||||
|
||||
// Note that the addChild order is different because later children
|
||||
// are placed in front of earlier children.
|
||||
this.scene.addChild(this.scatterContainerBack)
|
||||
this.scene.addChild(this.scatterContainerFront)
|
||||
|
||||
// Add the queen to ScatterContainer one
|
||||
let sprite1 = PIXI.Sprite.from('../examples/test-1280-720.png')
|
||||
sprite1.interactive = true
|
||||
let scatter1 = new DisplayObjectScatter(sprite1, this.renderer, {
|
||||
x: 20,
|
||||
y: 40,
|
||||
startScale: 0.5,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
this.scatterContainerBack.addChild(sprite1)
|
||||
|
||||
// Add the king to ScatterContainer two
|
||||
let sprite2 = PIXI.Sprite.from('../examples/test-1280-720.png')
|
||||
sprite2.interactive = true
|
||||
let scatter2 = new DisplayObjectScatter(sprite2, this.renderer, {
|
||||
x: 280,
|
||||
y: 40,
|
||||
startScale: 1,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
this.scatterContainerFront.addChild(sprite2)
|
||||
|
||||
// Add the queen to ScatterContainer one
|
||||
let sprite3 = PIXI.Sprite.from('../examples/test-800-450.png')
|
||||
sprite3.interactive = true
|
||||
let scatter3 = new DisplayObjectScatter(sprite3, this.renderer, {
|
||||
x: 140,
|
||||
y: 400,
|
||||
startScale: 0.5,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
this.scatterContainerBack.addChild(sprite3)
|
||||
|
||||
// Add the king to ScatterContainer two
|
||||
let sprite4 = PIXI.Sprite.from('../examples/test-800-450.png')
|
||||
sprite4.interactive = true
|
||||
let scatter4 = new DisplayObjectScatter(sprite4, this.renderer, {
|
||||
x: 280,
|
||||
y: 400,
|
||||
startScale: 1,
|
||||
minScale: 0.01,
|
||||
maxScale: 5.0
|
||||
})
|
||||
this.scatterContainerFront.addChild(sprite4)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
const scatterApp = new ScatterApp({
|
||||
view: canvas2,
|
||||
roundPixels: true,
|
||||
antialias: true
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,38 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>PIXI Scatter Doctest</title>
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>PIXI Scatter Doctest</title>
|
||||
<link rel="stylesheet" href=".././3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
<script src=".././3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Scatter</h1>
|
||||
<p>
|
||||
Scatter objects are UI elements that can be rotated, scaled or moved around which typically leads to
|
||||
"scattered" layouts. The PIXI scatter defined here is a specialization of the
|
||||
<a href="../scatter.html">abstract scatter pattern</a>.
|
||||
</p>
|
||||
<p>
|
||||
PIXI scatter are organized in <code>ScatterContainer</code> parent nodes and
|
||||
<code>DisplayObjectScatter</code> child nodes.
|
||||
</p>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
|
||||
<p>
|
||||
Let's look at an example of a PIXI scatter. Since scatter objects are mainly used as main views it is a
|
||||
common use case that the scene itself is used as the <code>ScatterContainer</code>. The
|
||||
<code>DisplayObjectScatter</code> is simply used as a wrapper that makes any interative DisplayObject
|
||||
zoomable, rotatable and translatable.
|
||||
</p>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>
|
||||
Scatter
|
||||
</h1>
|
||||
<p>
|
||||
Scatter objects are UI elements that can be rotated, scaled or moved around which typically leads to "scattered" layouts.
|
||||
The PIXI scatter defined here is a specialization of the
|
||||
<a href="../scatter.html">abstract scatter pattern</a>.
|
||||
</p>
|
||||
<p>PIXI scatter are organized in
|
||||
<code>ScatterContainer</code> parent nodes and
|
||||
<code>DisplayObjectScatter</code> child nodes.
|
||||
<p>Let's look at an example of a PIXI scatter. Since scatter objects are mainly used as main views it is a common use
|
||||
case that the scene itself is used as the
|
||||
<code>ScatterContainer</code>. The
|
||||
<code>DisplayObjectScatter</code> is simply used as a wrapper that makes any interative DisplayObject zoomable, rotatable and translatable.</p>
|
||||
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
<script class="doctest">
|
||||
|
||||
class ScatterApp extends PIXIApp {
|
||||
|
||||
sceneFactory() {
|
||||
return new ScatterContainer(this.renderer, { showBounds: true, showPolygon: true, app: this })
|
||||
}
|
||||
@ -44,13 +45,13 @@
|
||||
for (let key of ['women', 'king']) {
|
||||
let sprite = PIXI.Sprite.from('../examples/' + key + '.jpeg')
|
||||
sprite.interactive = true
|
||||
let scatter = new DisplayObjectScatter(sprite, this.renderer, {
|
||||
x: x,
|
||||
y: y,
|
||||
startScale: 0.25,
|
||||
minScale: 0.2,
|
||||
maxScale: 1
|
||||
})
|
||||
let scatter = new DisplayObjectScatter(sprite, this.renderer,
|
||||
{
|
||||
x: x, y: y,
|
||||
startScale: 0.25,
|
||||
minScale: 0.2,
|
||||
maxScale: 1
|
||||
})
|
||||
this.scene.addChild(sprite)
|
||||
scatter.zoom(0.5, { animate: 1.0 })
|
||||
x += 100
|
||||
@ -68,16 +69,21 @@
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
|
||||
</script>
|
||||
|
||||
<h1>Two ScatterContainers in one canvas-element</h1>
|
||||
<h1>
|
||||
Two ScatterContainers in one canvas-element
|
||||
</h1>
|
||||
<p>
|
||||
You see two ScatterContainers within the same HTML-canvas-element. The Queen is included in the first, the
|
||||
King in the second ScatterContainer. You should interact the two images independently of each other.
|
||||
You see two ScatterContainers within the same HTML-canvas-element. The Queen is included in the first, the King in the second
|
||||
ScatterContainer. You should interact the two images independently of each other.
|
||||
</p>
|
||||
<canvas id="canvas2" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
<script class="doctest">
|
||||
|
||||
class DoubleScatterApp extends PIXIApp {
|
||||
|
||||
setup() {
|
||||
super.setup()
|
||||
// Obey order in which ScatterContainer are created because the
|
||||
@ -97,7 +103,7 @@
|
||||
let scatter1 = new DisplayObjectScatter(sprite1, this.renderer, {
|
||||
x: 20,
|
||||
y: 40,
|
||||
startScale: 0.5
|
||||
startScale: .5
|
||||
})
|
||||
this.scatterContainerBack.addChild(sprite1)
|
||||
|
||||
@ -107,7 +113,7 @@
|
||||
let scatter2 = new DisplayObjectScatter(sprite2, this.renderer, {
|
||||
x: 280,
|
||||
y: 40,
|
||||
startScale: 0.5
|
||||
startScale: .5
|
||||
})
|
||||
this.scatterContainerFront.addChild(sprite2)
|
||||
return this
|
||||
@ -119,31 +125,31 @@
|
||||
autoResize: false,
|
||||
width: 450,
|
||||
height: 250
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
}).setup().run()
|
||||
|
||||
</script>
|
||||
|
||||
<h1>Nested Scatter</h1>
|
||||
<h1>
|
||||
Nested Scatter
|
||||
</h1>
|
||||
<p>
|
||||
Sometimes it can be required, that multiple scatters are nested in one another. E.g. when a map is displayed
|
||||
as scatter and another scatter is displayed on the map.
|
||||
Sometimes it can be required, that multiple scatters are nested in one another. E.g. when a map is displayed as scatter and
|
||||
another scatter is displayed on the map.
|
||||
</p>
|
||||
<canvas id="canvas3" class="grayBorder interactive">Canvas not supported</canvas>
|
||||
<script class="doctest">
|
||||
|
||||
class NestedScatterApp extends PIXIApp {
|
||||
|
||||
sceneFactory() {
|
||||
return new ScatterContainer(this.renderer, {
|
||||
application: this,
|
||||
showBounds: true,
|
||||
showPolygon: true,
|
||||
app: this
|
||||
})
|
||||
return new ScatterContainer(this.renderer, { application: this, showBounds: true, showPolygon: true, app: this })
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup()
|
||||
|
||||
|
||||
|
||||
// Add the queen to ScatterContainer one
|
||||
let woman = PIXI.Sprite.from('../examples/women.jpeg')
|
||||
woman.interactive = true
|
||||
@ -158,30 +164,25 @@
|
||||
let nestedKing = PIXI.Sprite.from('../examples/king.jpeg')
|
||||
nestedKing.interactive = true
|
||||
new DisplayObjectScatter(nestedKing, this.renderer, {
|
||||
x: 20,
|
||||
y: 20,
|
||||
startScale: 0.3
|
||||
x: 20, y: 20, startScale: 0.3
|
||||
})
|
||||
woman.addChild(nestedKing)
|
||||
|
||||
let nestedQueen = PIXI.Sprite.from('../examples/women.jpeg')
|
||||
let nestedQueen = PIXI.Sprite.from('../examples/women.jpeg')
|
||||
nestedQueen.interactive = true
|
||||
new DisplayObjectScatter(nestedQueen, this.renderer, {
|
||||
x: 40,
|
||||
y: 40,
|
||||
startScale: 0.3
|
||||
x: 40, y: 40, startScale: 0.3
|
||||
})
|
||||
woman.addChild(nestedQueen)
|
||||
|
||||
let king = PIXI.Sprite.from('../examples/king.jpeg')
|
||||
king.interactive = true
|
||||
new DisplayObjectScatter(king, this.renderer, {
|
||||
x: 200,
|
||||
y: 20,
|
||||
startScale: 1
|
||||
x: 200, y: 20, startScale: 1
|
||||
})
|
||||
this.scene.addChild(king)
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
@ -191,9 +192,7 @@
|
||||
autoResize: false,
|
||||
width: 450,
|
||||
height: 250
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
}).setup().run()
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
@ -33,7 +33,7 @@ export class ScatterContainer extends PIXI.Graphics {
|
||||
showPolygon = false,
|
||||
showTouches = false,
|
||||
backgroundColor = null,
|
||||
app = window.app,
|
||||
app = window.app
|
||||
} = {}
|
||||
) {
|
||||
super()
|
||||
@ -41,7 +41,7 @@ export class ScatterContainer extends PIXI.Graphics {
|
||||
if (this.container)
|
||||
this.containerDimensions = {
|
||||
x: this.container.width,
|
||||
y: this.container.height,
|
||||
y: this.container.height
|
||||
}
|
||||
this.backgroundWidth = null
|
||||
this.backgroundHeight = null
|
||||
@ -56,7 +56,7 @@ export class ScatterContainer extends PIXI.Graphics {
|
||||
this.backgroundColor = backgroundColor
|
||||
if (showBounds || showTouches || showPolygon) {
|
||||
//console.log("Show TOUCHES!!!")
|
||||
this.app.ticker.add((delta) => this.update(delta), this)
|
||||
this.app.ticker.add(delta => this.update(delta), this)
|
||||
}
|
||||
if (backgroundColor) {
|
||||
this.updateBackground()
|
||||
@ -277,7 +277,7 @@ export class DisplayObjectScatter extends AbstractScatter {
|
||||
overdoScaling = 1.5,
|
||||
onTransform = null,
|
||||
onResize,
|
||||
onThrowFinished = null,
|
||||
onThrowFinished = null
|
||||
} = {}
|
||||
) {
|
||||
// For the simulation of named parameters,
|
||||
@ -300,7 +300,7 @@ export class DisplayObjectScatter extends AbstractScatter {
|
||||
onThrowFinished,
|
||||
rotationDegrees,
|
||||
rotation,
|
||||
onTransform,
|
||||
onTransform
|
||||
})
|
||||
this.onResize = onResize
|
||||
this.displayObject = displayObject
|
||||
@ -325,7 +325,7 @@ export class DisplayObjectScatter extends AbstractScatter {
|
||||
scale: this.scale,
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
rotation: this.rotation,
|
||||
rotation: this.rotation
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 799 KiB |
@ -43,13 +43,13 @@ export default class Scrollbox extends PIXI.Container {
|
||||
underflow: 'top-left',
|
||||
fadeScrollbar: false,
|
||||
fadeWait: 3000,
|
||||
fadeEase: 'easeInOutSine',
|
||||
fadeEase: 'easeInOutSine'
|
||||
},
|
||||
options
|
||||
)
|
||||
this.ease = new PIXI.extras.Ease.list()
|
||||
|
||||
this.on('added', (event) => {
|
||||
this.on('added', event => {
|
||||
this.update()
|
||||
})
|
||||
|
||||
@ -63,7 +63,7 @@ export default class Scrollbox extends PIXI.Container {
|
||||
passiveWheel: this.options.stopPropagation,
|
||||
stopPropagation: this.options.stopPropagation,
|
||||
screenWidth: this.options.boxWidth,
|
||||
screenHeight: this.options.boxHeight,
|
||||
screenHeight: this.options.boxHeight
|
||||
})
|
||||
)
|
||||
this.content.decelerate().on('moved', () => this._drawScrollbars())
|
||||
@ -396,7 +396,10 @@ export default class Scrollbox extends PIXI.Container {
|
||||
* @private
|
||||
*/
|
||||
_drawMask() {
|
||||
this._maskContent.beginFill(0).drawRect(0, 0, this.boxWidth, this.boxHeight).endFill()
|
||||
this._maskContent
|
||||
.beginFill(0)
|
||||
.drawRect(0, 0, this.boxWidth, this.boxHeight)
|
||||
.endFill()
|
||||
this.content.mask = this._maskContent
|
||||
}
|
||||
|
||||
@ -437,7 +440,7 @@ export default class Scrollbox extends PIXI.Container {
|
||||
const time = this.options.fade === true ? 1000 : this.options.fade
|
||||
this.fade = this.ease.to(this.scrollbar, { alpha: 0 }, time, {
|
||||
wait: this.options.fadeWait,
|
||||
ease: this.options.fadeEase,
|
||||
ease: this.options.fadeEase
|
||||
})
|
||||
this.fade.on('each', () => (this.content.dirty = true))
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Scrollview</h1>
|
||||
<h1>Scrollview</h1>
|
||||
<p>A configurable scrollbox designed for pixi.js.</p>
|
||||
<p><strong>Features:</strong></p>
|
||||
<p>
|
||||
|
||||
|
Before Width: | Height: | Size: 559 KiB |
@ -1,104 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Slider</title>
|
||||
<title>PIXI Slider</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Slider</h1>
|
||||
<p>A slider is used whenever a numeric value within a certain range is to be obtained.</p>
|
||||
<p>
|
||||
The <strong>advantage</strong> of a slider over text input is that it becomes impossible for the user to
|
||||
enter a bad value. Any value that they can pick with the slider is valid.
|
||||
</p>
|
||||
<p>Let's look at some slider examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many sliders with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 450,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Slider</h1>
|
||||
<p>A slider is used whenever a numeric value within a certain range is to be obtained.</p>
|
||||
<p>The <strong>advantage</strong> of a slider over text input is that it becomes impossible
|
||||
for the user to enter a bad value. Any value that they can pick with the slider is valid.</p>
|
||||
<p>Let's look at some slider examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many sliders with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 450,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
let slider1 = new Slider({
|
||||
x: 10,
|
||||
y: 20
|
||||
})
|
||||
let slider1 = new Slider({
|
||||
x: 10,
|
||||
y: 20
|
||||
})
|
||||
|
||||
let slider2 = new Slider({
|
||||
x: 10,
|
||||
y: 70,
|
||||
value: 85,
|
||||
tooltip: 'Start value 85',
|
||||
container: app.view
|
||||
})
|
||||
let slider2 = new Slider({
|
||||
x: 10,
|
||||
y: 70,
|
||||
value: 85,
|
||||
tooltip: 'Start value 85',
|
||||
container: app.view
|
||||
})
|
||||
|
||||
let slider3 = new Slider({
|
||||
x: 10,
|
||||
y: 120,
|
||||
min: -1000,
|
||||
max: 2000,
|
||||
value: 300,
|
||||
disabled: true
|
||||
})
|
||||
let slider3 = new Slider({
|
||||
x: 10,
|
||||
y: 120,
|
||||
min: -1000,
|
||||
max: 2000,
|
||||
value: 300,
|
||||
disabled: true
|
||||
})
|
||||
|
||||
let slider4 = new Slider({
|
||||
x: 10,
|
||||
y: 170,
|
||||
value: -20,
|
||||
width: 600,
|
||||
height: 8,
|
||||
fill: 0xda3031,
|
||||
stroke: 0xf9bc2e,
|
||||
strokeWidth: 2,
|
||||
controlStrokeWidth: 4,
|
||||
controlRadius: 24,
|
||||
theme: 'red',
|
||||
tooltip: 'Range: 0 - 100',
|
||||
onStart: (event, slider) => {
|
||||
console.log('Started', event)
|
||||
},
|
||||
onUpdate: (event, slider) => {
|
||||
slider.tooltip.content = slider.value
|
||||
},
|
||||
onComplete: function (event) {
|
||||
console.log('Completed', this)
|
||||
}
|
||||
})
|
||||
let slider4 = new Slider({
|
||||
x: 10,
|
||||
y: 170,
|
||||
value: -20,
|
||||
width: 600,
|
||||
height: 8,
|
||||
fill: 0xda3031,
|
||||
stroke: 0xf9bc2e,
|
||||
strokeWidth: 2,
|
||||
controlStrokeWidth: 4,
|
||||
controlRadius: 24,
|
||||
theme: 'red',
|
||||
tooltip: 'Range: 0 - 100',
|
||||
onStart: (event, slider) => {
|
||||
console.log('Started', event)
|
||||
},
|
||||
onUpdate: (event, slider) => {
|
||||
slider.tooltip.content = slider.value
|
||||
},
|
||||
onComplete: function(event) {
|
||||
console.log('Completed', this)
|
||||
}
|
||||
})
|
||||
|
||||
let button1 = new Button({
|
||||
x: 10,
|
||||
y: 240,
|
||||
label: 'Toggle-slider-button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
action: (e) => {
|
||||
slider5.visible = !slider5.visible
|
||||
}
|
||||
})
|
||||
let button1 = new Button({
|
||||
x: 10,
|
||||
y: 240,
|
||||
label: 'Toggle-slider-button',
|
||||
type: 'checkbox',
|
||||
active: true,
|
||||
action: e => {
|
||||
slider5.visible = !slider5.visible
|
||||
}
|
||||
})
|
||||
|
||||
let slider5 = new Slider({
|
||||
x: 230,
|
||||
y: 250
|
||||
})
|
||||
let slider5 = new Slider({
|
||||
x: 230,
|
||||
y: 250
|
||||
})
|
||||
|
||||
app.scene.addChild(slider1, slider2, slider3, slider4)
|
||||
app.scene.addChild(button1, slider5)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(slider1, slider2, slider3, slider4)
|
||||
app.scene.addChild(button1, slider5)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -119,7 +119,7 @@ export default class Slider extends PIXI.Container {
|
||||
onUpdate: null,
|
||||
onComplete: null,
|
||||
tooltip: null,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -174,7 +174,7 @@ export default class Slider extends PIXI.Container {
|
||||
//-----------------
|
||||
const container = this.opts.container
|
||||
|
||||
this.on('pointermove', (e) => {
|
||||
this.on('pointermove', e => {
|
||||
if (this.control.dragging) {
|
||||
const moveX = this.control.event.data.getLocalPosition(this.control.parent).x
|
||||
this._value = this.pixelToValue(moveX - this.control.delta - this.opts.controlRadius)
|
||||
@ -188,20 +188,20 @@ export default class Slider extends PIXI.Container {
|
||||
})
|
||||
|
||||
if (container instanceof Element) {
|
||||
container.addEventListener('pointerup', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('pointercancel', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('pointerleave', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('pointerout', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('mouseup', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('mousecancel', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('mouseleave', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('mouseout', (e) => this.onEnd(e), false)
|
||||
container.addEventListener('pointerup', e => this.onEnd(e), false)
|
||||
container.addEventListener('pointercancel', e => this.onEnd(e), false)
|
||||
container.addEventListener('pointerleave', e => this.onEnd(e), false)
|
||||
container.addEventListener('pointerout', e => this.onEnd(e), false)
|
||||
container.addEventListener('mouseup', e => this.onEnd(e), false)
|
||||
container.addEventListener('mousecancel', e => this.onEnd(e), false)
|
||||
container.addEventListener('mouseleave', e => this.onEnd(e), false)
|
||||
container.addEventListener('mouseout', e => this.onEnd(e), false)
|
||||
} else {
|
||||
container.interactive = true
|
||||
container.on('pointerup', (e) => this.onEnd(e))
|
||||
container.on('pointercancel', (e) => this.onEnd(e))
|
||||
container.on('pointerleave', (e) => this.onEnd(e))
|
||||
container.on('pointerout', (e) => this.onEnd(e))
|
||||
container.on('pointerup', e => this.onEnd(e))
|
||||
container.on('pointercancel', e => this.onEnd(e))
|
||||
container.on('pointerleave', e => this.onEnd(e))
|
||||
container.on('pointerout', e => this.onEnd(e))
|
||||
}
|
||||
|
||||
// Slider
|
||||
@ -217,7 +217,7 @@ export default class Slider extends PIXI.Container {
|
||||
control.y = this.opts.controlRadius
|
||||
|
||||
// pointerdown on the control for dragndrop
|
||||
control.on('pointerdown', (e) => {
|
||||
control.on('pointerdown', e => {
|
||||
control.event = e
|
||||
control.delta = e.data.getLocalPosition(this.control).x
|
||||
control.dragging = true
|
||||
@ -233,21 +233,21 @@ export default class Slider extends PIXI.Container {
|
||||
|
||||
// interaction
|
||||
//-----------------
|
||||
this.sliderObj.on('pointerover', (e) => {
|
||||
this.sliderObj.on('pointerover', e => {
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 0.83 })
|
||||
})
|
||||
|
||||
this.sliderObj.on('pointerout', (e) => {
|
||||
this.sliderObj.on('pointerout', e => {
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 1 })
|
||||
})
|
||||
|
||||
this.sliderObj.on('pointerdown', (e) => {
|
||||
this.sliderObj.on('pointerdown', e => {
|
||||
this.sliderObj.pointerdowned = true
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 0.7 })
|
||||
})
|
||||
|
||||
// Click on the slider bar
|
||||
this.sliderObj.on('pointerup', (e) => {
|
||||
this.sliderObj.on('pointerup', e => {
|
||||
if (this.sliderObj.pointerdowned) {
|
||||
this.sliderObj.pointerdowned = false
|
||||
const position = e.data.getLocalPosition(this.control.parent)
|
||||
@ -266,7 +266,7 @@ export default class Slider extends PIXI.Container {
|
||||
if (typeof this.opts.tooltip === 'string') {
|
||||
this.tooltip = new Tooltip({
|
||||
object: this,
|
||||
content: this.opts.tooltip,
|
||||
content: this.opts.tooltip
|
||||
})
|
||||
} else {
|
||||
this.opts.tooltip.object = this
|
||||
|
||||
|
Before Width: | Height: | Size: 394 KiB |
@ -1,156 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>PIXI Stylus</title>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<title>PIXI Stylus</title>
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.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>
|
||||
</head>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Stylus</h1>
|
||||
<p>
|
||||
The Stylus class extends the PIXI.Graphics class and allows to draw into a graphics object. Select the pen
|
||||
tool in the following example app and draw into the canvas.
|
||||
</p>
|
||||
<canvas id="canvas" style="border: 1px solid gray; width: 640px; height: 480px" class="interactive"></canvas>
|
||||
<p>What you should see: A blank sytlus canvas.</p>
|
||||
<script class="doctest">
|
||||
class StylusApp extends PIXIApp {
|
||||
sceneFactory() {
|
||||
return new Stylus(this.renderer)
|
||||
}
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
|
||||
setup() {
|
||||
let buttonColor = 0x666666
|
||||
super.setup()
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Stylus</h1>
|
||||
<p>The Stylus class extends the PIXI.Graphics class and allows to draw into
|
||||
a graphics object. Select the pen tool in the following example app and draw into the canvas.
|
||||
</p>
|
||||
<canvas id="canvas" style="border: 1px solid gray; width: 640px; height: 480px;" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: A blank sytlus canvas.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
class StylusApp extends PIXIApp {
|
||||
|
||||
this.tools = new ButtonGroup({
|
||||
type: 'checkbox',
|
||||
margin: 0,
|
||||
x: 16,
|
||||
y: 16,
|
||||
fill: buttonColor,
|
||||
buttons: [
|
||||
{
|
||||
icon: 'edit',
|
||||
iconColorActive: 0xffff00,
|
||||
action: (event, button) => this.toggleEditMode()
|
||||
},
|
||||
{
|
||||
icon: 'undo',
|
||||
action: (event, button) => this.undo(button)
|
||||
},
|
||||
{
|
||||
icon: 'redo',
|
||||
action: (event, button) => this.redo(button)
|
||||
},
|
||||
{
|
||||
icon: 'delete',
|
||||
action: (event, button) => this.clear(button)
|
||||
}
|
||||
]
|
||||
})
|
||||
this.scene.addChild(this.tools)
|
||||
|
||||
let defaults = {
|
||||
icon: 'brightness_1',
|
||||
action: (event, button) => this.selectColor(button),
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0
|
||||
}
|
||||
|
||||
this.palette = new ButtonGroup({
|
||||
type: 'radio',
|
||||
x: 200,
|
||||
y: 16,
|
||||
margin: 0,
|
||||
strokeAlpha: 0,
|
||||
fill: buttonColor,
|
||||
buttons: [
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0x111111,
|
||||
iconColorActive: 0x111111
|
||||
}), // tooltip: "Black",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0xffff00,
|
||||
iconColorActive: 0xffff00
|
||||
}), // tooltip: "Yellow",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0x00ff00,
|
||||
iconColorActive: 0x00ff00
|
||||
}), // tooltip: "Green",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0xff00ff,
|
||||
iconColorActive: 0xff00ff
|
||||
}) // tooltip: "Violet",
|
||||
]
|
||||
})
|
||||
this.scene.addChild(this.palette)
|
||||
this.scene.interactive = false
|
||||
}
|
||||
|
||||
toggleEditMode() {
|
||||
this.scene.interactive = !this.scene.interactive
|
||||
|
||||
console.log('this.scene.interactive')
|
||||
}
|
||||
|
||||
selectColor(button) {
|
||||
this.scene.color = button.opts.iconColor
|
||||
}
|
||||
|
||||
undo(button) {
|
||||
this.scene.undo()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
|
||||
redo(button) {
|
||||
this.scene.redo()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
|
||||
clear(button) {
|
||||
this.scene.clearAll()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
sceneFactory() {
|
||||
return new Stylus(this.renderer)
|
||||
}
|
||||
|
||||
const app = new StylusApp({
|
||||
view: canvas,
|
||||
width: 640,
|
||||
height: 480,
|
||||
autoResize: false
|
||||
})
|
||||
window.app = app
|
||||
app.setup()
|
||||
app.run()
|
||||
</script>
|
||||
<h2>References</h2>
|
||||
<ul>
|
||||
<li><a href="https://mattdesl.svbtle.com/drawing-lines-is-hard">Drawing Lines is Hard</a></li>
|
||||
<li>
|
||||
<a href="http://perfectionkills.com/exploring-canvas-drawing-techniques/"
|
||||
>Exploring Canvas Drawing Techniques</a
|
||||
>
|
||||
</li>
|
||||
<li><a href="https://github.com/mattdesl/polyline-normals">Polyline Normals</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
setup() {
|
||||
let buttonColor = 0x666666
|
||||
super.setup()
|
||||
|
||||
this.tools = new ButtonGroup({
|
||||
type: 'checkbox',
|
||||
margin: 0,
|
||||
x: 16,
|
||||
y: 16,
|
||||
fill: buttonColor,
|
||||
buttons: [{
|
||||
icon: 'edit',
|
||||
iconColorActive: 0xFFFF00,
|
||||
action: (event, button) => this.toggleEditMode()
|
||||
},
|
||||
{
|
||||
icon: 'undo',
|
||||
action: (event, button) => this.undo(button)
|
||||
},
|
||||
{
|
||||
icon: 'redo',
|
||||
action: (event, button) => this.redo(button)
|
||||
},
|
||||
{
|
||||
icon: 'delete',
|
||||
action: (event, button) => this.clear(button)
|
||||
}
|
||||
]
|
||||
})
|
||||
this.scene.addChild(this.tools)
|
||||
|
||||
let defaults = {
|
||||
icon: 'brightness_1',
|
||||
action: (event, button) => this.selectColor(button),
|
||||
fillAlpha: 0,
|
||||
strokeAlpha: 0,
|
||||
fillActiveAlpha: 0,
|
||||
strokeActiveAlpha: 0
|
||||
}
|
||||
|
||||
this.palette = new ButtonGroup({
|
||||
type: "radio",
|
||||
x: 200,
|
||||
y: 16,
|
||||
margin: 0,
|
||||
strokeAlpha: 0,
|
||||
fill: buttonColor,
|
||||
buttons: [
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0x111111,
|
||||
iconColorActive: 0x111111
|
||||
}), // tooltip: "Black",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0xFFFF00,
|
||||
iconColorActive: 0xFFFF00
|
||||
}), // tooltip: "Yellow",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0x00FF00,
|
||||
iconColorActive: 0x00FF00
|
||||
}), // tooltip: "Green",
|
||||
Object.assign({}, defaults, {
|
||||
iconColor: 0xFF00FF,
|
||||
iconColorActive: 0xFF00FF
|
||||
}) // tooltip: "Violet",
|
||||
]
|
||||
})
|
||||
this.scene.addChild(this.palette)
|
||||
this.scene.interactive = false
|
||||
}
|
||||
|
||||
toggleEditMode() {
|
||||
this.scene.interactive = !this.scene.interactive
|
||||
|
||||
console.log("this.scene.interactive")
|
||||
}
|
||||
|
||||
selectColor(button) {
|
||||
this.scene.color = button.opts.iconColor
|
||||
}
|
||||
|
||||
undo(button) {
|
||||
this.scene.undo()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
|
||||
redo(button) {
|
||||
this.scene.redo()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
|
||||
clear(button) {
|
||||
this.scene.clearAll()
|
||||
setTimeout(() => {
|
||||
button.active = false
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
|
||||
const app = new StylusApp({
|
||||
view: canvas,
|
||||
width: 640,
|
||||
height: 480,
|
||||
autoResize: false
|
||||
})
|
||||
window.app = app
|
||||
app.setup()
|
||||
app.run()
|
||||
</script>
|
||||
<h2>
|
||||
References
|
||||
</h2>
|
||||
<ul>
|
||||
<li><a href="https://mattdesl.svbtle.com/drawing-lines-is-hard">Drawing Lines is Hard</a></li>
|
||||
<li><a href="http://perfectionkills.com/exploring-canvas-drawing-techniques/">Exploring Canvas Drawing
|
||||
Techniques</a></li>
|
||||
<li><a href="https://github.com/mattdesl/polyline-normals">Polyline Normals</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
@ -82,7 +82,7 @@ export default class Stylus extends PIXI.Graphics {
|
||||
captureEvents = true,
|
||||
acceptMouseEvents = true,
|
||||
lineWidth = 16,
|
||||
minStrokeLength = 4,
|
||||
minStrokeLength = 4
|
||||
} = {}) {
|
||||
super()
|
||||
this.activePointers = 0
|
||||
@ -164,7 +164,7 @@ export default class Stylus extends PIXI.Graphics {
|
||||
}
|
||||
|
||||
registerEventHandler() {
|
||||
window.addEventListener('keydown', (e) => {
|
||||
window.addEventListener('keydown', e => {
|
||||
switch (e.keyCode) {
|
||||
case 38: // up arrow
|
||||
this.tiltX += 5
|
||||
@ -182,7 +182,7 @@ export default class Stylus extends PIXI.Graphics {
|
||||
if (this.debug) console.log('keydown', e.keyCode, this.tiltX, this.tiltY)
|
||||
})
|
||||
|
||||
this.on('pointerdown', (e) => {
|
||||
this.on('pointerdown', e => {
|
||||
if (this.debug) console.log('pointerdown', e)
|
||||
if (this.eventInside(e)) {
|
||||
this.activePointers += 1
|
||||
@ -192,13 +192,13 @@ export default class Stylus extends PIXI.Graphics {
|
||||
}
|
||||
})
|
||||
|
||||
this.on('pointermove', (e) => {
|
||||
this.on('pointermove', e => {
|
||||
if (Events.isPointerDown(e.data.originalEvent) || this.isStylusPointer(e) || this.isStylusTouch(e)) {
|
||||
if (this.debug) console.log('pointermove', e, this.eventInside(e))
|
||||
if (this.eventInside(e) && this.singlePointer()) this.moveStroke(this.toStroke(e))
|
||||
}
|
||||
})
|
||||
this.on('pointerup', (e) => {
|
||||
this.on('pointerup', e => {
|
||||
if (this.eventInside(e)) {
|
||||
if (this.activePointers > 0) {
|
||||
this.activePointers -= 1
|
||||
@ -207,13 +207,13 @@ export default class Stylus extends PIXI.Graphics {
|
||||
}
|
||||
if (this.debug) console.log('pointerup', this.activePointers)
|
||||
})
|
||||
this.on('pointerleave', (e) => {
|
||||
this.on('pointerleave', e => {
|
||||
if (this.activePointers > 0) {
|
||||
this.activePointers -= 1
|
||||
}
|
||||
this.endStroke(this.toStroke(e))
|
||||
})
|
||||
this.on('pointercancel', (e) => {
|
||||
this.on('pointercancel', e => {
|
||||
if (this.activePointers > 0) {
|
||||
this.activePointers -= 1
|
||||
}
|
||||
@ -277,7 +277,7 @@ export default class Stylus extends PIXI.Graphics {
|
||||
tiltX: this.tiltX,
|
||||
tiltY: this.tiltY,
|
||||
color: this.color,
|
||||
lineWidth: this.tiltToLineWidth(this.tiltY),
|
||||
lineWidth: this.tiltToLineWidth(this.tiltY)
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 410 KiB |
@ -1,143 +1,125 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Switch</title>
|
||||
<title>PIXI Switch</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Switch</h1>
|
||||
<p>A switch is a visual toggle between two mutually exclusive states—on and off.</p>
|
||||
<p>
|
||||
<strong>Consider adjusting a switch’s appearance to match the style of your app.</strong> If it works well
|
||||
in your app, change the colors of a switch in its on and off states or use custom imagery to represent the
|
||||
switch.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Use switches in table rows only.</strong> Switches are intended for use in tables, such as in a list
|
||||
of settings that can be toggled on and off. If you need similar functionality in a toolbar or navigation
|
||||
bar, use a button instead, and provide two distinct icons that communicate the states.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Avoid adding labels to describe the values of a switch.</strong> Switches are either on or off.
|
||||
Providing labels that describe these states is redundant and clutters the interface.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Consider using switches to manage the availability of related interface elements.</strong> Switches
|
||||
often affect other content onscreen. Enabling the Airplane Mode switch in Settings, for example, disables
|
||||
certain other settings, such as Cellular and Personal Hotspot. Disabling the Wi-Fi switch in Settings >
|
||||
Wi-Fi causes available networks and other options to disappear.
|
||||
</p>
|
||||
<p>Let's look at some switch examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many switches with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Switch</h1>
|
||||
<p>A switch is a visual toggle between two mutually exclusive states—on and off.</p>
|
||||
<p><strong>Consider adjusting a switch’s appearance to match the style of your app.</strong> If it works well in your app, change the colors of a switch in its on and off states or use custom imagery to represent the switch.</p>
|
||||
<p><strong>Use switches in table rows only.</strong> Switches are intended for use in tables, such as in a list of settings that can be toggled on and off. If you need similar functionality in a toolbar or navigation bar, use a button instead, and provide two distinct icons that communicate the states.</p>
|
||||
<p><strong>Avoid adding labels to describe the values of a switch.</strong> Switches are either on or off. Providing labels that describe these states is redundant and clutters the interface.</p>
|
||||
<p><strong>Consider using switches to manage the availability of related interface elements.</strong> Switches often affect other content onscreen. Enabling the Airplane Mode switch in Settings, for example, disables certain other settings, such as Cellular and Personal Hotspot. Disabling the Wi-Fi switch in Settings > Wi-Fi causes available networks and other options to disappear.</p>
|
||||
<p>Let's look at some switch examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many switches with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
let switch1 = new Switch({
|
||||
x: 10,
|
||||
y: 20
|
||||
})
|
||||
let switch1 = new Switch({
|
||||
x: 10,
|
||||
y: 20
|
||||
})
|
||||
|
||||
let switch2 = new Switch({
|
||||
x: 90,
|
||||
y: 20,
|
||||
fill: 0xfd355a,
|
||||
fillActive: 0x5954d3,
|
||||
controlFill: 0xfecd2d,
|
||||
controlFillActive: 0xfd413b,
|
||||
strokeActiveWidth: 4,
|
||||
controlStrokeActive: 0x50d968,
|
||||
controlStrokeActiveWidth: 12,
|
||||
controlStrokeActiveAlpha: 0.8,
|
||||
tooltip: 'Dies ist ein Switch'
|
||||
})
|
||||
let switch2 = new Switch({
|
||||
x: 90,
|
||||
y: 20,
|
||||
fill: 0xfd355a,
|
||||
fillActive: 0x5954d3,
|
||||
controlFill: 0xfecd2d,
|
||||
controlFillActive: 0xfd413b,
|
||||
strokeActiveWidth: 4,
|
||||
controlStrokeActive: 0x50d968,
|
||||
controlStrokeActiveWidth: 12,
|
||||
controlStrokeActiveAlpha: .8,
|
||||
tooltip: 'Dies ist ein Switch'
|
||||
})
|
||||
|
||||
let switch3 = new Switch({
|
||||
x: 170,
|
||||
y: 20,
|
||||
width: 100,
|
||||
height: 40,
|
||||
fill: 0xfe9727,
|
||||
fillAlpha: 0.5,
|
||||
fillActive: 0x5954d3,
|
||||
stroke: 0x5ec7f8,
|
||||
strokeWidth: 12,
|
||||
strokeActive: 0xfd355a,
|
||||
strokeActiveWidth: 4,
|
||||
controlFill: 0xfecd2d,
|
||||
controlFillActive: 0xfd413b,
|
||||
controlStroke: 0xfd413b,
|
||||
controlStrokeWidth: 8,
|
||||
controlStrokeActive: 0x50d968,
|
||||
controlStrokeActiveWidth: 16,
|
||||
controlStrokeActiveAlpha: 0.8,
|
||||
controlRadiusActive: 12,
|
||||
duration: 3,
|
||||
durationActive: 1
|
||||
})
|
||||
let switch3 = new Switch({
|
||||
x: 170,
|
||||
y: 20,
|
||||
width: 100,
|
||||
height: 40,
|
||||
fill: 0xfe9727,
|
||||
fillAlpha: .5,
|
||||
fillActive: 0x5954d3,
|
||||
stroke: 0x5ec7f8,
|
||||
strokeWidth: 12,
|
||||
strokeActive: 0xfd355a,
|
||||
strokeActiveWidth: 4,
|
||||
controlFill: 0xfecd2d,
|
||||
controlFillActive: 0xfd413b,
|
||||
controlStroke: 0xfd413b,
|
||||
controlStrokeWidth: 8,
|
||||
controlStrokeActive: 0x50d968,
|
||||
controlStrokeActiveWidth: 16,
|
||||
controlStrokeActiveAlpha: .8,
|
||||
controlRadiusActive: 12,
|
||||
duration: 3,
|
||||
durationActive: 1
|
||||
})
|
||||
|
||||
let switch4 = new Switch({
|
||||
x: 10,
|
||||
y: 90,
|
||||
active: true
|
||||
})
|
||||
let switch4 = new Switch({
|
||||
x: 10,
|
||||
y: 90,
|
||||
active: true
|
||||
})
|
||||
|
||||
let switch5 = new Switch({
|
||||
x: 90,
|
||||
y: 90,
|
||||
disabled: true
|
||||
})
|
||||
let switch5 = new Switch({
|
||||
x: 90,
|
||||
y: 90,
|
||||
disabled: true
|
||||
})
|
||||
|
||||
let switch6 = new Switch({
|
||||
x: 170,
|
||||
y: 90,
|
||||
active: true,
|
||||
disabled: true
|
||||
})
|
||||
let switch6 = new Switch({
|
||||
x: 170,
|
||||
y: 90,
|
||||
active: true,
|
||||
disabled: true
|
||||
})
|
||||
|
||||
let switch7 = new Switch({
|
||||
x: 250,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 10,
|
||||
fill: 0xffffff,
|
||||
fillActive: 0xffffff,
|
||||
duration: 0.2,
|
||||
durationActive: 0.1,
|
||||
controlFill: 0x00ff00,
|
||||
controlFillActive: 0xff0000,
|
||||
controlRadius: 15,
|
||||
controlRadiusActive: 12,
|
||||
controlStroke: 0x00aa00,
|
||||
controlStrokeWidth: 3,
|
||||
controlStrokeActive: 0xaa0000,
|
||||
controlStrokeActiveWidth: 2,
|
||||
tooltip: {
|
||||
container: app.scene,
|
||||
content: 'Das Gesetz ist der Freund des Schwachen.'
|
||||
}
|
||||
})
|
||||
let switch7 = new Switch({
|
||||
x: 250,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 10,
|
||||
fill: 0xffffff,
|
||||
fillActive: 0xffffff,
|
||||
duration: .2,
|
||||
durationActive: .1,
|
||||
controlFill: 0x00ff00,
|
||||
controlFillActive: 0xff0000,
|
||||
controlRadius: 15,
|
||||
controlRadiusActive: 12,
|
||||
controlStroke: 0x00aa00,
|
||||
controlStrokeWidth: 3,
|
||||
controlStrokeActive: 0xaa0000,
|
||||
controlStrokeActiveWidth: 2,
|
||||
tooltip: {
|
||||
container: app.scene,
|
||||
content: 'Das Gesetz ist der Freund des Schwachen.'
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(switch1, switch2, switch3)
|
||||
app.scene.addChild(switch4, switch5, switch6, switch7)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(switch1, switch2, switch3)
|
||||
app.scene.addChild(switch4, switch5, switch6, switch7)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -147,7 +147,7 @@ export default class Switch extends PIXI.Container {
|
||||
beforeAction: null,
|
||||
afterAction: null,
|
||||
tooltip: null,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -188,7 +188,7 @@ export default class Switch extends PIXI.Container {
|
||||
controlStroke: this.opts.controlStroke,
|
||||
controlStrokeWidth: this.opts.controlStrokeWidth,
|
||||
controlStrokeAlpha: this.opts.controlStrokeAlpha,
|
||||
controlRadius: this.opts.controlRadius,
|
||||
controlRadius: this.opts.controlRadius
|
||||
}
|
||||
|
||||
// setup
|
||||
@ -228,19 +228,19 @@ export default class Switch extends PIXI.Container {
|
||||
|
||||
// interaction
|
||||
//-----------------
|
||||
this.switchObj.on('pointerover', (e) => {
|
||||
this.switchObj.on('pointerover', e => {
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 0.83 })
|
||||
})
|
||||
|
||||
this.switchObj.on('pointerout', (e) => {
|
||||
this.switchObj.on('pointerout', e => {
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 1 })
|
||||
})
|
||||
|
||||
this.switchObj.on('pointerdown', (e) => {
|
||||
this.switchObj.on('pointerdown', e => {
|
||||
TweenLite.to(this.control, this.theme.fast, { alpha: 0.7 })
|
||||
})
|
||||
|
||||
this.switchObj.on('pointerup', (e) => {
|
||||
this.switchObj.on('pointerup', e => {
|
||||
if (this.opts.beforeAction) {
|
||||
this.opts.beforeAction.call(this, e, this)
|
||||
}
|
||||
@ -278,7 +278,7 @@ export default class Switch extends PIXI.Container {
|
||||
if (typeof this.opts.tooltip === 'string') {
|
||||
this.tooltip = new Tooltip({
|
||||
object: this,
|
||||
content: this.opts.tooltip,
|
||||
content: this.opts.tooltip
|
||||
})
|
||||
} else {
|
||||
this.opts.tooltip.object = this
|
||||
@ -416,7 +416,7 @@ export default class Switch extends PIXI.Container {
|
||||
stroke: this.opts.strokeActive,
|
||||
controlFill: this.opts.controlFillActive,
|
||||
controlStroke: this.opts.controlStrokeActive,
|
||||
format: 'number',
|
||||
format: 'number'
|
||||
},
|
||||
fillAlpha: this.opts.fillActiveAlpha,
|
||||
strokeWidth: this.opts.strokeActiveWidth,
|
||||
@ -426,11 +426,11 @@ export default class Switch extends PIXI.Container {
|
||||
controlStrokeAlpha: this.opts.controlStrokeActiveAlpha,
|
||||
controlRadius: this.opts.controlRadiusActive,
|
||||
onUpdate: () => this.drawAnimated(),
|
||||
onComplete: () => this.draw(),
|
||||
onComplete: () => this.draw()
|
||||
})
|
||||
} else {
|
||||
TweenLite.to(this.control, this.opts.durationActive, {
|
||||
x: this.xInactive,
|
||||
x: this.xInactive
|
||||
})
|
||||
TweenLite.to(this.tempAnimated, this.opts.durationActive, {
|
||||
colorProps: {
|
||||
@ -438,7 +438,7 @@ export default class Switch extends PIXI.Container {
|
||||
stroke: this.opts.stroke,
|
||||
controlFill: this.opts.controlFill,
|
||||
controlStroke: this.opts.controlStroke,
|
||||
format: 'number',
|
||||
format: 'number'
|
||||
},
|
||||
fillAlpha: this.opts.fillAlpha,
|
||||
strokeWidth: this.opts.strokeWidth,
|
||||
@ -448,7 +448,7 @@ export default class Switch extends PIXI.Container {
|
||||
controlStrokeAlpha: this.opts.controlStrokeAlpha,
|
||||
controlRadius: this.opts.controlRadius,
|
||||
onUpdate: () => this.drawAnimated(),
|
||||
onComplete: () => this.draw(),
|
||||
onComplete: () => this.draw()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 647 KiB |
@ -121,7 +121,7 @@ export class RecorderTools extends PIXI.Container {
|
||||
// Since this delegate might shadow another delegate, we mus avoid
|
||||
// capturing PointerEvents.
|
||||
this.delegate = new InteractionMapper(container, this, {
|
||||
capturePointerEvents: false,
|
||||
capturePointerEvents: false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1,166 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Text</title>
|
||||
<title>PIXI Text</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
|
||||
<script src="../3rdparty/d3.min.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Text</h1>
|
||||
<p>
|
||||
The tooltip or infotip or a hint is a common graphical user interface element. It is used in conjunction
|
||||
with a cursor, usually a pointer. The user hovers the pointer over an item, without clicking it, and a
|
||||
tooltip may appear—a small "hover box" with information about the item being hovered over.[1][2] Tooltips do
|
||||
not usually appear on mobile operating systems, because there is no cursor (though tooltips may be displayed
|
||||
when using a mouse).
|
||||
</p>
|
||||
<p>Let's look at some tooltip examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Ten colored circles with different tooltips.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 500,
|
||||
transparent: false,
|
||||
backgroundColor: 0x2c2d2b
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../3rdparty/d3.min.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Text</h1>
|
||||
<p>
|
||||
The tooltip or infotip or a hint is a common graphical user interface element. It is used in conjunction with a cursor, usually a pointer. The user hovers the pointer over an item, without clicking it, and a tooltip may appear—a small "hover box" with information about the item being hovered over.[1][2] Tooltips do not usually appear on mobile operating systems, because there is no cursor (though tooltips may be displayed when using a mouse).
|
||||
</p>
|
||||
<p>Let's look at some tooltip examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Ten colored circles with different tooltips.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 500,
|
||||
transparent: false,
|
||||
backgroundColor: 0x2c2d2b
|
||||
}).setup().run()
|
||||
|
||||
const container = new PIXI.Graphics()
|
||||
container.beginFill(0x58595b, 1)
|
||||
container.drawRect(0, 0, 700, 300)
|
||||
container.pivot.set(container.width / 2, container.height / 2)
|
||||
container.position.set(450, 250)
|
||||
app.scene.addChild(container)
|
||||
const container = new PIXI.Graphics()
|
||||
container.beginFill(0x58595b, 1)
|
||||
container.drawRect(0, 0, 700, 300)
|
||||
container.pivot.set(container.width / 2, container.height / 2)
|
||||
container.position.set(450, 250)
|
||||
app.scene.addChild(container)
|
||||
|
||||
const sixthWidth = container.width / 6
|
||||
const halfHeight = container.height / 2
|
||||
const sixthWidth = container.width / 6
|
||||
const halfHeight = container.height / 2
|
||||
|
||||
app.loadSprites(
|
||||
['./assets/stuttgart-library.jpg', './assets/Arial.fnt'],
|
||||
(sprites) => {
|
||||
// PIXI.Text
|
||||
//--------------------
|
||||
const text = new PIXI.Text('Bibliothek\nStuttgart', { fontSize: 50 })
|
||||
text.x = sixthWidth
|
||||
text.y = halfHeight
|
||||
text.pivot.set(text.width / 2, text.height / 2)
|
||||
container.addChild(text)
|
||||
app.loadSprites([
|
||||
'./assets/stuttgart-library.jpg',
|
||||
'./assets/Arial.fnt'
|
||||
], sprites => {
|
||||
|
||||
// PIXI.BitmapText
|
||||
//--------------------
|
||||
const bitmapText = new PIXI.BitmapText('Bibliothek\nStuttgart', {
|
||||
font: '50px Arial',
|
||||
align: 'left'
|
||||
})
|
||||
bitmapText.x = sixthWidth * 3
|
||||
bitmapText.y = halfHeight
|
||||
bitmapText.pivot.set(bitmapText.width / 2, bitmapText.height / 2)
|
||||
container.addChild(bitmapText)
|
||||
// PIXI.Text
|
||||
//--------------------
|
||||
const text = new PIXI.Text('Bibliothek\nStuttgart', {fontSize: 50})
|
||||
text.x = sixthWidth
|
||||
text.y = halfHeight
|
||||
text.pivot.set(text.width / 2, text.height / 2)
|
||||
container.addChild(text)
|
||||
|
||||
// PIXI.Sprite
|
||||
//--------------------
|
||||
const sprite = sprites.get('./assets/stuttgart-library.jpg')
|
||||
sprite.scale.set(0.05, 0.05)
|
||||
sprite.x = sixthWidth * 5
|
||||
sprite.y = halfHeight
|
||||
sprite.anchor.set(0.5, 0.5)
|
||||
container.addChild(sprite)
|
||||
// PIXI.BitmapText
|
||||
//--------------------
|
||||
const bitmapText = new PIXI.BitmapText('Bibliothek\nStuttgart', {
|
||||
font: '50px Arial',
|
||||
align: 'left'
|
||||
})
|
||||
bitmapText.x = sixthWidth * 3
|
||||
bitmapText.y = halfHeight
|
||||
bitmapText.pivot.set(bitmapText.width / 2, bitmapText.height / 2)
|
||||
container.addChild(bitmapText)
|
||||
|
||||
// Scale
|
||||
//--------------------
|
||||
const scaleContainer = d3.scaleLinear().domain([0, 50, 100]).range([0.05, 1, 50])
|
||||
const scaleTexts = d3.scaleLinear().domain([0, 50, 100]).range([0.1, 1, 10])
|
||||
const scaleSprite = d3.scaleLinear().domain([0, 50, 100]).range([0.005, 0.05, 0.5])
|
||||
// PIXI.Sprite
|
||||
//--------------------
|
||||
const sprite = sprites.get('./assets/stuttgart-library.jpg')
|
||||
sprite.scale.set(.05, .05)
|
||||
sprite.x = sixthWidth * 5
|
||||
sprite.y = halfHeight
|
||||
sprite.anchor.set(.5, .5)
|
||||
container.addChild(sprite)
|
||||
|
||||
// Sliders
|
||||
//--------------------
|
||||
const sliderContainer = new Slider({
|
||||
value: 50,
|
||||
width: 500,
|
||||
tooltip: 'Scale Container',
|
||||
container: app.view,
|
||||
onUpdate: function () {
|
||||
const value = scaleContainer(this.value)
|
||||
container.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderContainer.x = app.size.width / 2 - sliderContainer.width / 2
|
||||
sliderContainer.y = 10
|
||||
app.scene.addChild(sliderContainer)
|
||||
// Scale
|
||||
//--------------------
|
||||
const scaleContainer = d3.scaleLinear().domain([0, 50, 100]).range([.05, 1, 50])
|
||||
const scaleTexts = d3.scaleLinear().domain([0, 50, 100]).range([.1, 1, 10])
|
||||
const scaleSprite = d3.scaleLinear().domain([0, 50, 100]).range([.005, .05, .5])
|
||||
|
||||
const sliderContainerAll = new Slider({
|
||||
value: 50,
|
||||
width: 500,
|
||||
tooltip: 'Scale Container All',
|
||||
container: app.view,
|
||||
onUpdate: function () {
|
||||
const value = scaleContainer(this.value)
|
||||
container.scale.set(value, value)
|
||||
// Sliders
|
||||
//--------------------
|
||||
const sliderContainer = new Slider({
|
||||
value: 50,
|
||||
width: 500,
|
||||
tooltip: 'Scale Container',
|
||||
container: app.view,
|
||||
onUpdate: function() {
|
||||
const value = scaleContainer(this.value)
|
||||
container.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderContainer.x = app.size.width / 2 - sliderContainer.width / 2
|
||||
sliderContainer.y = 10
|
||||
app.scene.addChild(sliderContainer)
|
||||
|
||||
text.scale.set(1 / value, 1 / value)
|
||||
bitmapText.scale.set(1 / value, 1 / value)
|
||||
}
|
||||
})
|
||||
sliderContainerAll.x = app.size.width / 2 - sliderContainerAll.width / 2
|
||||
sliderContainerAll.y = 55
|
||||
app.scene.addChild(sliderContainerAll)
|
||||
const sliderContainerAll = new Slider({
|
||||
value: 50,
|
||||
width: 500,
|
||||
tooltip: 'Scale Container All',
|
||||
container: app.view,
|
||||
onUpdate: function() {
|
||||
const value = scaleContainer(this.value)
|
||||
container.scale.set(value, value)
|
||||
|
||||
const sliderText = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.Text',
|
||||
container: app.view,
|
||||
onUpdate: function () {
|
||||
const value = scaleTexts(this.value)
|
||||
text.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderText.x = app.size.width / 6 - sliderText.width / 2
|
||||
sliderText.y = app.size.height - 10 - sliderText.height
|
||||
app.scene.addChild(sliderText)
|
||||
text.scale.set(1 / value, 1 / value)
|
||||
bitmapText.scale.set(1 / value, 1 / value)
|
||||
}
|
||||
})
|
||||
sliderContainerAll.x = app.size.width / 2 - sliderContainerAll.width / 2
|
||||
sliderContainerAll.y = 55
|
||||
app.scene.addChild(sliderContainerAll)
|
||||
|
||||
const sliderBitmapText = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.extras.BitmapText',
|
||||
container: app.view,
|
||||
onUpdate: function () {
|
||||
const value = scaleTexts(this.value)
|
||||
bitmapText.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderBitmapText.x = (app.size.width / 6) * 3 - sliderBitmapText.width / 2
|
||||
sliderBitmapText.y = app.size.height - 10 - sliderBitmapText.height
|
||||
app.scene.addChild(sliderBitmapText)
|
||||
const sliderText = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.Text',
|
||||
container: app.view,
|
||||
onUpdate: function() {
|
||||
const value = scaleTexts(this.value)
|
||||
text.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderText.x = app.size.width / 6 - sliderText.width / 2
|
||||
sliderText.y = app.size.height - 10 - sliderText.height
|
||||
app.scene.addChild(sliderText)
|
||||
|
||||
const sliderSprite = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.Sprite',
|
||||
container: app.view,
|
||||
onUpdate: function () {
|
||||
const value = scaleSprite(this.value)
|
||||
sprite.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderSprite.x = (app.size.width / 6) * 5 - sliderSprite.width / 2
|
||||
sliderSprite.y = app.size.height - 10 - sliderSprite.height
|
||||
app.scene.addChild(sliderSprite)
|
||||
},
|
||||
{ resolutionDependent: false }
|
||||
)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
const sliderBitmapText = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.extras.BitmapText',
|
||||
container: app.view,
|
||||
onUpdate: function() {
|
||||
const value = scaleTexts(this.value)
|
||||
bitmapText.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderBitmapText.x = app.size.width / 6 * 3 - sliderBitmapText.width / 2
|
||||
sliderBitmapText.y = app.size.height - 10 - sliderBitmapText.height
|
||||
app.scene.addChild(sliderBitmapText)
|
||||
|
||||
const sliderSprite = new Slider({
|
||||
value: 50,
|
||||
tooltip: 'Scale PIXI.Sprite',
|
||||
container: app.view,
|
||||
onUpdate: function() {
|
||||
const value = scaleSprite(this.value)
|
||||
sprite.scale.set(value, value)
|
||||
}
|
||||
})
|
||||
sliderSprite.x = app.size.width / 6 * 5 - sliderSprite.width / 2
|
||||
sliderSprite.y = app.size.height - 10 - sliderSprite.height
|
||||
app.scene.addChild(sliderSprite)
|
||||
|
||||
}, {resolutionDependent: false})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
Before Width: | Height: | Size: 568 KiB |
@ -1,45 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Text</title>
|
||||
<title>PIXI Text</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Text</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms,
|
||||
dialogs, and more with support for multiple sizes, states, and more. Buttons will appear pressed when
|
||||
active. Make buttons look inactive by setting the disabled state to true. To allow changing the state
|
||||
between active/inactive, set the button type to "checkbox".
|
||||
</p>
|
||||
<p><a href="../../doc/out/Text.html">JavaScript API</a></p>
|
||||
<p>Let's look at some text examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many texts with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 600,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Text</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms, dialogs,
|
||||
and more with support for multiple sizes, states, and more. Buttons will appear pressed when active. Make
|
||||
buttons look inactive by setting the disabled state to true. To allow changing the state between active/inactive, set
|
||||
the button type to "checkbox".
|
||||
</p>
|
||||
<p><a href="../../doc/out/Text.html">JavaScript API</a></p>
|
||||
<p>Let's look at some text examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many texts with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 600,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
const text1 = new Text({ x: 10, y: 10 })
|
||||
const text1 = new Text({x: 10, y: 10})
|
||||
|
||||
app.scene.addChild(text1)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(text1)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -150,7 +150,7 @@ export default class Text extends PIXI.Container {
|
||||
verticalAlign: 'middle',
|
||||
tooltip: null,
|
||||
badge: null,
|
||||
visible: true,
|
||||
visible: true
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -171,7 +171,7 @@ export default class Text extends PIXI.Container {
|
||||
strokeAlpha: 0,
|
||||
strokeActiveAlpha: 0,
|
||||
fillAlpha: 0,
|
||||
fillActiveAlpha: 0,
|
||||
fillActiveAlpha: 0
|
||||
})
|
||||
}
|
||||
|
||||
@ -243,15 +243,15 @@ export default class Text extends PIXI.Container {
|
||||
|
||||
// interaction
|
||||
//-----------------
|
||||
this.button.on('pointerover', (e) => {
|
||||
this.button.on('pointerover', e => {
|
||||
this.capture(e)
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.83,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
this.button.on('pointermove', (e) => {
|
||||
this.button.on('pointermove', e => {
|
||||
this.capture(e)
|
||||
})
|
||||
|
||||
@ -262,17 +262,17 @@ export default class Text extends PIXI.Container {
|
||||
this.button.on('scroll', this.onEnd.bind(this))
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.button.on('pointerdown', (e) => {
|
||||
this.button.on('pointerdown', e => {
|
||||
//this.capture(e)
|
||||
this.__start.x = e.data.global.x
|
||||
this.__start.y = e.data.global.y
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.7,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
this.button.on('pointerup', (e) => {
|
||||
this.button.on('pointerup', e => {
|
||||
this.capture(e)
|
||||
|
||||
const distance = Points.distance(e.data.global, this.__start)
|
||||
@ -288,7 +288,7 @@ export default class Text extends PIXI.Container {
|
||||
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 0.83,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
|
||||
if (this.opts.type === 'checkbox') {
|
||||
@ -315,7 +315,7 @@ export default class Text extends PIXI.Container {
|
||||
if (typeof this.opts.tooltip === 'string') {
|
||||
this.tooltip = new Tooltip({
|
||||
object: this,
|
||||
content: this.opts.tooltip,
|
||||
content: this.opts.tooltip
|
||||
})
|
||||
} else {
|
||||
this.opts.tooltip = Object.assign({}, { object: this }, this.opts.tooltip)
|
||||
@ -332,7 +332,7 @@ export default class Text extends PIXI.Container {
|
||||
align: 'right',
|
||||
verticalAlign: 'top',
|
||||
offsetLeft: 0,
|
||||
offsetTop: 0,
|
||||
offsetTop: 0
|
||||
}
|
||||
)
|
||||
if (typeof this.opts.badge === 'string') {
|
||||
@ -708,7 +708,7 @@ export default class Text extends PIXI.Container {
|
||||
this.capture(event)
|
||||
TweenLite.to([this.button, this.content], this.theme.fast, {
|
||||
alpha: 1,
|
||||
overwrite: 'none',
|
||||
overwrite: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 242 KiB |
@ -1,118 +1,123 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>PIXI Theme</title>
|
||||
<title>PIXI Theme</title>
|
||||
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css" />
|
||||
<link rel="stylesheet" href="../../css/doctest.css" />
|
||||
<link rel="stylesheet" href="../3rdparty/highlight/styles/default.css">
|
||||
<link rel="stylesheet" href="../../css/doctest.css">
|
||||
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
<script src="../3rdparty/highlight/highlight.pack.js"></script>
|
||||
<script src="../../dist/iwmlib.3rdparty.js"></script>
|
||||
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1><a href="../index.html">lib.</a><a href="index.html">pixi.</a>Theme</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms,
|
||||
dialogs, and more with support for multiple sizes, states, and more. Buttons will appear pressed when
|
||||
active. Make buttons look inactive by setting the disabled state to true. To allow changing the state
|
||||
between active/inactive, set the button type to "checkbox".
|
||||
</p>
|
||||
<p>Let's look at some button examples:</p>
|
||||
<br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>What you should see: Many buttons with very different styling and behaviour.</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
})
|
||||
.setup()
|
||||
.run()
|
||||
<script src="../../dist/iwmlib.js"></script>
|
||||
<script src="../../dist/iwmlib.pixi.js"></script>
|
||||
</head>
|
||||
<body onload="Doctest.run()">
|
||||
<h1>Theme</h1>
|
||||
<p>
|
||||
The Button class defines a clickable/touchable button. Use custom button styles for actions in forms, dialogs,
|
||||
and more with support for multiple sizes, states, and more. Buttons will appear pressed when active. Make
|
||||
buttons look inactive by setting the disabled state to true. To allow changing the state between active/inactive, set
|
||||
the button type to "checkbox".
|
||||
</p>
|
||||
<p>Let's look at some button examples:</p><br />
|
||||
<canvas id="canvas" class="interactive"></canvas>
|
||||
<p>
|
||||
What you should see: Many buttons with very different styling and behaviour.
|
||||
</p>
|
||||
<script class="doctest">
|
||||
const app = new PIXIApp({
|
||||
view: canvas,
|
||||
width: 900,
|
||||
height: 250,
|
||||
transparent: false
|
||||
}).setup().run()
|
||||
|
||||
let buttonDark = new Button({
|
||||
x: 10,
|
||||
y: 10,
|
||||
label: 'Button with theme dark',
|
||||
type: 'checkbox'
|
||||
})
|
||||
let buttonDark = new Button({
|
||||
x: 10,
|
||||
y: 10,
|
||||
label: 'Button with theme dark',
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
let buttonGroupLight = new ButtonGroup({
|
||||
x: 230,
|
||||
y: 10,
|
||||
theme: 'light',
|
||||
buttons: [{ label: 'Button with', active: true }, { label: 'theme light' }],
|
||||
type: 'checkbox'
|
||||
})
|
||||
let buttonGroupLight = new ButtonGroup({
|
||||
x: 230,
|
||||
y: 10,
|
||||
theme: 'light',
|
||||
buttons: [
|
||||
{label: 'Button with', active: true},
|
||||
{label: 'theme light'}
|
||||
],
|
||||
type: 'checkbox'
|
||||
})
|
||||
|
||||
let buttonGroupRed = new ButtonGroup({
|
||||
x: 480,
|
||||
y: 10,
|
||||
theme: 'red',
|
||||
margin: 0,
|
||||
buttons: [{ label: 'Button with', active: true }, { label: 'theme red' }],
|
||||
type: 'radio'
|
||||
})
|
||||
let buttonGroupRed = new ButtonGroup({
|
||||
x: 480,
|
||||
y: 10,
|
||||
theme: 'red',
|
||||
margin: 0,
|
||||
buttons: [
|
||||
{label: 'Button with', active: true},
|
||||
{label: 'theme red'}
|
||||
],
|
||||
type: 'radio'
|
||||
})
|
||||
|
||||
let switchDark = new Switch({
|
||||
x: 10,
|
||||
y: 90
|
||||
})
|
||||
let switchDark = new Switch({
|
||||
x: 10,
|
||||
y: 90
|
||||
})
|
||||
|
||||
let switchLight = new Switch({
|
||||
x: 80,
|
||||
y: 90,
|
||||
theme: 'light'
|
||||
})
|
||||
let switchLight = new Switch({
|
||||
x: 80,
|
||||
y: 90,
|
||||
theme: 'light'
|
||||
})
|
||||
|
||||
let switchRed = new Switch({
|
||||
x: 150,
|
||||
y: 90,
|
||||
theme: 'red'
|
||||
})
|
||||
let switchRed = new Switch({
|
||||
x: 150,
|
||||
y: 90,
|
||||
theme: 'red'
|
||||
})
|
||||
|
||||
let yellowTheme = new Theme({
|
||||
fill: 0xfecd2d,
|
||||
fillActive: 0xfe9727,
|
||||
strokeActive: 0xfecd2d,
|
||||
strokeActiveWidth: 4,
|
||||
textStyle: {
|
||||
fill: 0x5ec7f8
|
||||
},
|
||||
textStyleActive: {
|
||||
fill: 0x5954d3
|
||||
},
|
||||
textStyleLarge: {
|
||||
fontSize: 36
|
||||
}
|
||||
})
|
||||
let yellowTheme = new Theme({
|
||||
fill: 0xfecd2d,
|
||||
fillActive: 0xfe9727,
|
||||
strokeActive: 0xfecd2d,
|
||||
strokeActiveWidth: 4,
|
||||
textStyle: {
|
||||
fill: 0x5ec7f8
|
||||
},
|
||||
textStyleActive: {
|
||||
fill: 0x5954d3
|
||||
},
|
||||
textStyleLarge: {
|
||||
fontSize: 36
|
||||
}
|
||||
})
|
||||
|
||||
let buttonYellow = new Button({
|
||||
x: 10,
|
||||
y: 160,
|
||||
theme: yellowTheme,
|
||||
label: 'Button with theme yellow',
|
||||
type: 'checkbox',
|
||||
action: (event) => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
theme: yellowTheme,
|
||||
header: 'Theme',
|
||||
content: 'Yellow'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
let buttonYellow = new Button({
|
||||
x: 10,
|
||||
y: 160,
|
||||
theme: yellowTheme,
|
||||
label: 'Button with theme yellow',
|
||||
type: 'checkbox',
|
||||
action: event => {
|
||||
const modal = new Modal({
|
||||
app: app,
|
||||
theme: yellowTheme,
|
||||
header: 'Theme',
|
||||
content: 'Yellow'
|
||||
})
|
||||
app.scene.addChild(modal)
|
||||
}
|
||||
})
|
||||
|
||||
app.scene.addChild(buttonDark, buttonGroupLight, buttonGroupRed)
|
||||
app.scene.addChild(switchDark, switchLight, switchRed)
|
||||
app.scene.addChild(buttonYellow)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
app.scene.addChild(buttonDark, buttonGroupLight, buttonGroupRed)
|
||||
app.scene.addChild(switchDark, switchLight, switchRed)
|
||||
app.scene.addChild(buttonYellow)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -112,7 +112,7 @@ export default class Theme {
|
||||
textActiveAlpha: 1,
|
||||
iconColor: color2,
|
||||
iconColorActive: colorPrimary,
|
||||
background: color1,
|
||||
background: color1
|
||||
},
|
||||
opts
|
||||
)
|
||||
@ -129,7 +129,7 @@ export default class Theme {
|
||||
stroke: color1,
|
||||
strokeThickness: 0,
|
||||
miterLimit: 1,
|
||||
lineJoin: 'round',
|
||||
lineJoin: 'round'
|
||||
},
|
||||
this.opts.textStyle
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 53 KiB |