18 Commits

Author SHA1 Message Date
Uwe Oestermeier fa25d13469 Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-04 09:35:00 +02:00
Uwe Oestermeier 4c08359394 Added active flag to avoid transform of inactive deepzoom images. 2019-06-04 09:34:50 +02:00
mhalfmann b5400c8223 fixed resize function 2019-06-04 08:43:07 +02:00
Manfred Knobloch 5a336e8d40 regenerated pngs 2019-06-03 11:41:18 +02:00
Manfred Knobloch 2d1a6b1b7f Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-03 11:39:54 +02:00
Manfred Knobloch 636e2e439c typo fixed 2019-06-03 11:39:33 +02:00
Sebastian Kupke b208592e3a Version 1.0.12. 2019-06-03 10:53:33 +02:00
Uwe Oestermeier 95d1941545 Disabled debug flag. 2019-06-03 10:49:56 +02:00
Uwe Oestermeier 086dfff19e Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib 2019-06-03 10:24:36 +02:00
Uwe Oestermeier 0442df4287 Reverting getBounds to bound to avoid excessive loading of tiles. 2019-06-03 10:24:10 +02:00
Manfred Knobloch e3d167bd7f concluded merge 2019-06-03 09:46:24 +02:00
Manfred Knobloch da5ed78558 added fs-extra to have ensure-dir for non existing dirs 2019-06-03 09:42:45 +02:00
Uwe Oestermeier 0c46c4e656 Fixed minor problems. 2019-06-03 08:55:33 +02:00
Uwe Oestermeier 304818dc13 Fixed typos. 2019-06-01 12:40:01 +02:00
Uwe Oestermeier 05ecd0b048 Fixed minor bugs 2019-06-01 12:31:38 +02:00
Uwe Oestermeier 895ec55a46 Added support for keeping a limited set of tile textures. 2019-06-01 09:56:29 +02:00
Uwe Oestermeier 67c6a6c95c Correct version number 2019-05-31 16:21:50 +02:00
Uwe Oestermeier 107529f844 Added warning to Tile.destroy 2019-05-31 16:10:46 +02:00
21 changed files with 551 additions and 1002 deletions
+10 -3
View File
@@ -7,7 +7,8 @@
*/ */
const puppeteer = require('puppeteer'); const puppeteer = require('puppeteer');
const fs = require("fs") const fs_bare = require("fs") // required for fs-extra
const fs = require("fs-extra")
const path = require("path") const path = require("path")
const start_dir = process.cwd() const start_dir = process.cwd()
const start_file = path.join(start_dir,"lib","index.html") const start_file = path.join(start_dir,"lib","index.html")
@@ -39,18 +40,24 @@ async function makeScreenshot(href){
page.once("load",logPageEvent) page.once("load",logPageEvent)
await page.goto(href) await page.goto(href)
href = href.replace("file:///","")
const fname = path.parse(href).name const fname = path.parse(href).name
let fpath
if (fname != "index"){ if (fname != "index"){
image_url = href.replace(fname + ".html" ,"thumbnails/" + fname + ".png") image_url = href.replace(fname + ".html" ,"thumbnails/" + fname + ".png")
fpath = href.replace(fname + ".html", "thumbnails")
} }
else{ else{
image_url = href.replace(fname + ".html" ,"thumbnail.png") image_url = href.replace(fname + ".html" ,"thumbnail.png")
fpath = href.replace(fname + ".html", "")
} }
image_url = image_url.replace("file:///","") // image_url = image_url.replace("file:///","")
// fpath = fpath.replace("file:///","")
page.removeAllListeners() page.removeAllListeners()
fs.ensureDir(fpath)
await page.screenshot({path: image_url}); await page.screenshot({path: image_url});
await browser.close(); await browser.close();
} }
+83 -83
View File
@@ -92733,86 +92733,86 @@ module.exports = function (_Plugin) {
},{}]},{},[13]); },{}]},{},[13]);
/*jslint plusplus: true, vars: true, indent: 2 */ /*jslint plusplus: true, vars: true, indent: 2 */
/* convertPointFromPageToNode.js from /* convertPointFromPageToNode.js from
<script src="https://gist.github.com/Yaffle/1145197.js"></script> <script src="https://gist.github.com/Yaffle/1145197.js"></script>
convertPointFromPageToNode(element, event.pageX, event.pageY) -> {x, y} convertPointFromPageToNode(element, event.pageX, event.pageY) -> {x, y}
returns coordinate in element's local coordinate system (works properly returns coordinate in element's local coordinate system (works properly
with css transforms without perspective projection) with css transforms without perspective projection)
convertPointFromNodeToPage(element, offsetX, offsetY) -> {x, y} convertPointFromNodeToPage(element, offsetX, offsetY) -> {x, y}
returns coordinate in window's coordinate system (works properly with returns coordinate in window's coordinate system (works properly with
css transforms without perspective projection) css transforms without perspective projection)
*/ */
(function () { (function () {
'use strict' '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) { function Point(x, y, z) {
this.x = x this.x = x
this.y = y this.y = y
this.z = z this.z = z
} }
Point.prototype.transformBy = function (matrix) { Point.prototype.transformBy = function (matrix) {
var tmp = matrix.multiply(I.translate(this.x, this.y, this.z)) var tmp = matrix.multiply(I.translate(this.x, this.y, this.z))
return new Point(tmp.m41, tmp.m42, tmp.m43) return new Point(tmp.m41, tmp.m42, tmp.m43)
} }
function createMatrix(transform) { function createMatrix(transform) {
try { try {
return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform) return (typeof(WebKitCSSMatrix) == 'undefined') ? new DOMMatrix(transform) : new WebKitCSSMatrix(transform)
} catch(e) { } catch(e) {
console.warn(transform) console.warn(transform)
console.warn(e.toString()) console.warn(e.toString())
return I return I
} }
} }
function getTransformationMatrix(element) { function getTransformationMatrix(element) {
var transformationMatrix = I var transformationMatrix = I
var x = element var x = element
while (x != undefined && x !== x.ownerDocument.documentElement) { while (x != undefined && x !== x.ownerDocument.documentElement) {
var computedStyle = window.getComputedStyle(x, undefined) var computedStyle = window.getComputedStyle(x, undefined)
var transform = computedStyle.transform || 'none' var transform = computedStyle.transform || 'none'
var c = transform === 'none' ? I : createMatrix(transform) var c = transform === 'none' ? I : createMatrix(transform)
transformationMatrix = c.multiply(transformationMatrix) transformationMatrix = c.multiply(transformationMatrix)
x = x.parentNode x = x.parentNode
} }
var w = element.offsetWidth var w = element.offsetWidth
var h = element.offsetHeight var h = element.offsetHeight
var i = 4 var i = 4
var left = +Infinity var left = +Infinity
var top = +Infinity var top = +Infinity
while (--i >= 0) { while (--i >= 0) {
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h,
0).transformBy(transformationMatrix) 0).transformBy(transformationMatrix)
if (p.x < left) { if (p.x < left) {
left = p.x left = p.x
} }
if (p.y < top) { if (p.y < top) {
top = p.y top = p.y
} }
} }
var rect = element.getBoundingClientRect() var rect = element.getBoundingClientRect()
transformationMatrix = I.translate(window.pageXOffset + rect.left - left, transformationMatrix = I.translate(window.pageXOffset + rect.left - left,
window.pageYOffset + rect.top - top, 0) window.pageYOffset + rect.top - top, 0)
.multiply(transformationMatrix) .multiply(transformationMatrix)
return transformationMatrix return transformationMatrix
} }
window.convertPointFromPageToNode = function (element, pageX, pageY) { window.convertPointFromPageToNode = function (element, pageX, pageY) {
return new Point(pageX, pageY, 0).transformBy( return new Point(pageX, pageY, 0).transformBy(
getTransformationMatrix(element).inverse()) getTransformationMatrix(element).inverse())
} }
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) { window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
return new Point(offsetX, offsetY, 0).transformBy( return new Point(offsetX, offsetY, 0).transformBy(
getTransformationMatrix(element)) getTransformationMatrix(element))
} }
}()) }())
+12 -5
View File
@@ -2995,11 +2995,16 @@
} }
} }
_throwDeltaTime() {
let t = performance.now();
let dt = t - this.lastframe;
this.lastframe = t;
return dt
}
animateThrow(time) { animateThrow(time) {
if (this.velocity != null) { if (this.velocity != null) {
let t = performance.now(); let dt = this._throwDeltaTime();
let dt = t - this.lastframe;
this.lastframe = t;
// console.log("animateThrow", dt) // console.log("animateThrow", dt)
let next = this.nextVelocity(this.velocity); let next = this.nextVelocity(this.velocity);
let prevLength = Points.length(this.velocity); let prevLength = Points.length(this.velocity);
@@ -3232,7 +3237,9 @@
keepOnStage(velocity, collision = 0.5) { keepOnStage(velocity, collision = 0.5) {
let stagePolygon = this.containerPolygon; let stagePolygon = this.containerPolygon;
if (!stagePolygon) return // UO: since keepOnStage is called in nextVelocity we need to
// ensure a return value
if (!stagePolygon) return { x: 0, y: 0}
let polygon = this.polygon; let polygon = this.polygon;
let bounced = this.bouncing(); let bounced = this.bouncing();
if (bounced) { if (bounced) {
@@ -4251,7 +4258,7 @@
let resizeW = r * Math.cos(Angle.degree2radian(phiCorrected)); let resizeW = r * Math.cos(Angle.degree2radian(phiCorrected));
let resizeH = -r * Math.sin(Angle.degree2radian(phiCorrected)); let resizeH = -r * Math.sin(Angle.degree2radian(phiCorrected));
if (this.element.offsetWidth + resizeW / this.scale > this.width * 0.3 && this.element.offsetHeight + resizeH / this.scale > this.height * 0.3) TweenLite.to(this.element, 0, { width: this.element.offsetWidth + resizeW / this.scale, height: this.element.offsetHeight + resizeH / this.scale }); if ((this.element.offsetWidth + resizeW) / this.scale > this.width * 0.5 / this.scale && (this.element.offsetHeight + resizeH) / this.scale > this.height * 0.3 / this.scale) TweenLite.to(this.element, 0, { width: this.element.offsetWidth + resizeW / this.scale, height: this.element.offsetHeight + resizeH / this.scale });
this.oldX = e.clientX; this.oldX = e.clientX;
this.oldY = e.clientY; this.oldY = e.clientY;
+202 -49
View File
@@ -6159,11 +6159,16 @@
} }
} }
_throwDeltaTime() {
let t = performance.now();
let dt = t - this.lastframe;
this.lastframe = t;
return dt
}
animateThrow(time) { animateThrow(time) {
if (this.velocity != null) { if (this.velocity != null) {
let t = performance.now(); let dt = this._throwDeltaTime();
let dt = t - this.lastframe;
this.lastframe = t;
// console.log("animateThrow", dt) // console.log("animateThrow", dt)
let next = this.nextVelocity(this.velocity); let next = this.nextVelocity(this.velocity);
let prevLength = Points.length(this.velocity); let prevLength = Points.length(this.velocity);
@@ -6396,7 +6401,9 @@
keepOnStage(velocity, collision = 0.5) { keepOnStage(velocity, collision = 0.5) {
let stagePolygon = this.containerPolygon; let stagePolygon = this.containerPolygon;
if (!stagePolygon) return // UO: since keepOnStage is called in nextVelocity we need to
// ensure a return value
if (!stagePolygon) return { x: 0, y: 0}
let polygon = this.polygon; let polygon = this.polygon;
let bounced = this.bouncing(); let bounced = this.bouncing();
if (bounced) { if (bounced) {
@@ -7794,8 +7801,14 @@
} }
} }
const deepZoomTileCache = new Map(); /* ES Lint */
/* globals PIXI, console*/
const registeredTiles = new Map();
const pendingTiles = new Map();
/** Implements a baseTexture cache. The last textures are kept for reuse */
let keepTextures = 0;
const keptTextures = [];
/** The current Tile implementation simply uses PIXI.Sprites. /** The current Tile implementation simply uses PIXI.Sprites.
* *
@@ -7809,6 +7822,82 @@
this.register(url); this.register(url);
} }
/**
* Static method to enable keeping of base textures
*
* @static
* @param {*} value
* @memberof Tile
*/
static enableKeepTextures(value = 1000) {
keepTextures = value;
}
/**
* Marks the given url as pending. Pending tiles should not be destroyed
*
* @static
* @param {*} url
* @memberof Tile
*/
static schedule(url) {
let count = 0;
if (pendingTiles.has(url)) {
count = pendingTiles.get(url);
}
pendingTiles.set(url, count + 1);
// console.log("Tile.scheduled", url, pendingTiles.size)
}
/**
* Returns true iff the url is pending
*
* @static
* @param {*} url
* @returns
* @memberof Tile
*/
static isPending(url) {
return pendingTiles.has(url) && pendingTiles.get(url) > 0
}
static isObsolete(url) {
if (registeredTiles.has(url) && registeredTiles.get(url) > 0) {
return false
}
return true
}
/**
* Removes the given url from pending urls.
*
* @static
* @param {*} url
* @memberof Tile
*/
static unschedule(url) {
if (pendingTiles.has(url)) {
let count = pendingTiles.get(url);
if (count > 1) {
pendingTiles.set(url, count - 1);
}
else {
pendingTiles.clear(url);
}
}
// console.log("Tile.unscheduled", url, pendingTiles.size)
}
/**
* Loads a tile from image using the PIXI.Texture.fromImage method.
*
* @static
* @param {*} imageId
* @param {*} crossorigin
* @param {*} scaleMode
* @returns
* @memberof Tile
*/
static fromImage(imageId, crossorigin, scaleMode) { static fromImage(imageId, crossorigin, scaleMode) {
return new Tile(PIXI.Texture.fromImage(imageId, crossorigin, scaleMode), imageId) return new Tile(PIXI.Texture.fromImage(imageId, crossorigin, scaleMode), imageId)
} }
@@ -7821,13 +7910,14 @@
* @memberof Tile * @memberof Tile
*/ */
register(url, debug = false) { register(url, debug = false) {
if (deepZoomTileCache.has(url)) { Tile.unschedule(url);
let tiles = deepZoomTileCache.get(url); if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url);
tiles.add(this); tiles.add(this);
if (debug) console.log("Tile.register", url, tiles.size); if (debug) console.log("Tile.register", url, tiles.size);
} }
else { else {
deepZoomTileCache.set(url, new Set([this])); registeredTiles.set(url, new Set([this]));
if (debug) console.log("Tile.register", url, 1); if (debug) console.log("Tile.register", url, 1);
} }
} }
@@ -7839,10 +7929,11 @@
* @memberof Tile * @memberof Tile
*/ */
unregister() { unregister() {
let tiles = deepZoomTileCache.get(this.url); let tiles = registeredTiles.get(this.url);
tiles.delete(this); tiles.delete(this);
if (tiles.size == 0) { if (tiles.size == 0) {
deepZoomTileCache.delete(this.url); registeredTiles.delete(this.url);
return 0
} }
return tiles.size return tiles.size
} }
@@ -7854,19 +7945,83 @@
* @memberof Tile * @memberof Tile
*/ */
destroy(options, debug = false) { destroy(options, debug = false) {
if (this.parent != null) ;
let count = this.unregister(); let count = this.unregister();
if (count <= 0) {
let opts = { children: true, texture: true, baseTexture: true }; if (keepTextures > 0) {
keptTextures.push({ url: this.url, texture: this.texture });
let opts = { children: true, texture: false, baseTexture: false };
if (debug) console.log("Tile.destroy", registeredTiles.size, opts);
super.destroy(opts); super.destroy(opts);
if (debug) console.log("Tile.destroy", deepZoomTileCache.size, opts);
while (keptTextures.length > keepTextures) {
let { url, texture } = keptTextures.shift();
if (Tile.isObsolete(url)) {
texture.destroy(true); // Destroy base as well
if (debug) console.log("Destroying texture and baseTexture", url);
}
}
} }
else { else {
let opts = { children: true, texture: false, baseTexture: false }; // No longer registered and not pending
if (debug) console.log("Tile.destroy", deepZoomTileCache.size, opts); if (count <= 0 && !Tile.isPending(this.url)) {
super.destroy(opts); let opts = { children: true, texture: true, baseTexture: true };
super.destroy(opts);
if (debug) console.log("Tile.destroy", registeredTiles.size, opts);
}
else {
let opts = { children: true, texture: false, baseTexture: false };
if (debug) console.log("Tile.destroy", registeredTiles.size, opts);
super.destroy(opts);
}
if (this.parent != null) {
// UO: Emit warning and remove
console.warn("Destroying tile with parent. Hiding instead");
this.visible = false;
}
} }
} }
/**
* Returns an available texture that can be reused
*
* @param {*} url
* @returns
* @memberof Tile
*/
static textureAvailable(url) {
if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url);
for (let tile of tiles.values()) {
//console.log("Reusing cached texture", tile.parent)
return tile.texture
}
}
return null
}
/**
* Texture received too late. We do not need it.
* @param {*} url
* @param {*} texture
*/
static lateTexture(url, texture) {
let destroyBase = !registeredTiles.has(url);
texture.destroy(destroyBase);
}
static printInfos() {
let references = new Map();
let multiples = 0;
for (let [url, tiles] of registeredTiles.entries()) {
let count = tiles.size;
references.set(url, count);
if (count > 1) {
multiples += 1;
}
}
console.log({ multiples, references });
}
} }
/** /**
@@ -7897,6 +8052,8 @@
schedule(url, col, row) { schedule(url, col, row) {
if (this.loaded.has(url)) return false if (this.loaded.has(url)) return false
if (this.loading.has(url)) return false if (this.loading.has(url)) return false
Tile.schedule(url);
this.map.set(url, [col, row]); this.map.set(url, [col, row]);
this.loading.add(url); this.loading.add(url);
this.loadQueue.push(url); this.loadQueue.push(url);
@@ -7906,6 +8063,7 @@
unschedule(url) { unschedule(url) {
if (this.loaded.has(url)) this.loaded.delete(url); if (this.loaded.has(url)) this.loaded.delete(url);
if (this.loading.has(url)) this.loading.delete(url); if (this.loading.has(url)) this.loading.delete(url);
Tile.unschedule(url);
this.loadQueue = this.loadQueue.filter(item => item != url); this.loadQueue = this.loadQueue.filter(item => item != url);
} }
@@ -7931,9 +8089,14 @@
console.warn("Tile already loaded"); console.warn("Tile already loaded");
tile.unregister(); tile.unregister();
} }
tile = new Tile(texture, url); try {
this.loaded.set(url, tile); tile = new Tile(texture, url);
this.tiles.tileAvailable(tile, col, row, url); this.loaded.set(url, tile);
this.tiles.tileAvailable(tile, col, row, url);
} catch (error) {
console.warn("Tile loading error", error);
}
} }
} }
@@ -7960,16 +8123,13 @@
if (this.loaded.has(url)) return false if (this.loaded.has(url)) return false
if (this.loading.has(url)) return false if (this.loading.has(url)) return false
if (deepZoomTileCache.has(url)) { Tile.schedule(url);
let tiles = deepZoomTileCache.get(url); let reusableTexture = Tile.textureAvailable(url);
for (let tile of tiles.values()) { if (reusableTexture) {
//console.log("Reusing cached texture", tile.parent) if (this.debug) console.log('Texture reusable', reusableTexture);
let texture = tile.texture; this._textureAvailable(url, col, row, reusableTexture);
this._textureAvailable(url, col, row, texture); return false
return false
}
} }
let texture = PIXI.utils.TextureCache[url]; let texture = PIXI.utils.TextureCache[url];
if (texture) { if (texture) {
if (this.debug) console.log('Texture already loaded', texture); if (this.debug) console.log('Texture already loaded', texture);
@@ -8024,8 +8184,8 @@
_onLoaded(loader, resource) { _onLoaded(loader, resource) {
if (this.destroyed) { if (this.destroyed) {
let texture = resource.texture; let texture = resource.texture;
let destroyBase = !deepZoomTileCache.has(resource.url); let url = resource.url;
texture.destroy(destroyBase); Tile.lateTexture(url, texture);
console.warn("Received resource after destroy", texture); console.warn("Received resource after destroy", texture);
return return
} }
@@ -8486,18 +8646,8 @@
return n % 2 == 0 return n % 2 == 0
} }
function printTileCacheInfos() { function printTileCacheInfos() {
let references = new Map(); Tile.printInfos();
let multiples = 0;
for (let [url, tiles] of deepZoomTileCache.entries()) {
let count = tiles.size;
references.set(url, count);
if (count > 1) {
multiples += 1;
}
}
console.log({ multiples, references });
} }
/** /**
* A utility class that holds information typically provided by DZI files, i.e. * A utility class that holds information typically provided by DZI files, i.e.
@@ -8853,6 +9003,7 @@
: 1; : 1;
this.alpha = alpha; this.alpha = alpha;
this.fastLoads = 0; this.fastLoads = 0;
this.active = true;
this.autoLoadTiles = autoLoadTiles; this.autoLoadTiles = autoLoadTiles;
this.minimumLevel = minimumLevel; this.minimumLevel = minimumLevel;
this.quadTrees = new Map(); // url as keys, TileQuadNodes as values this.quadTrees = new Map(); // url as keys, TileQuadNodes as values
@@ -8903,7 +9054,7 @@
this.minimumLevel = deepZoomInfo.baseLevel; this.minimumLevel = deepZoomInfo.baseLevel;
} }
this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel); this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel);
console.log("autoLoadTiles", this.autoLoadTiles); //console.log("autoLoadTiles", this.autoLoadTiles)
if (this.autoLoadTiles) { if (this.autoLoadTiles) {
this.setupTiles(center); this.setupTiles(center);
} }
@@ -9124,7 +9275,7 @@
} }
worldBounds() { worldBounds() {
let viewBounds = this.app.scene.getBounds(); let viewBounds = this.app.scene.bounds; // UO: Never use getBounds()
// Using getBounds extends visible scope after loading tiles and leads // Using getBounds extends visible scope after loading tiles and leads
// to excessive loading // to excessive loading
if (this.world != null) { if (this.world != null) {
@@ -9506,6 +9657,9 @@
* @param {boolean} debug - log debug infos * @param {boolean} debug - log debug infos
*/ */
transformed(event) { transformed(event) {
if (!this.active) {
return
}
let key = this.currentLevel.toString(); let key = this.currentLevel.toString();
let currentTiles = this.tileLayers[key]; let currentTiles = this.tileLayers[key];
if (typeof currentTiles == 'undefined') { if (typeof currentTiles == 'undefined') {
@@ -9528,7 +9682,7 @@
this.ensureTiles(this.currentLevel, event.about); this.ensureTiles(this.currentLevel, event.about);
return return
} }
let level = this.levelForScale(event.scale); let level = this.levelForScale(event.scale);
let newLevel = Math.max(level, this.minimumLevel); let newLevel = Math.max(level, this.minimumLevel);
if (newLevel != this.currentLevel) { if (newLevel != this.currentLevel) {
@@ -9553,6 +9707,7 @@
* @memberof DeepZoomImage * @memberof DeepZoomImage
*/ */
activate() { activate() {
this.active = true;
this.destroyTilesAboveLevel(this.currentLevel); this.destroyTilesAboveLevel(this.currentLevel);
this.ensureTiles(this.currentLevel, null); this.ensureTiles(this.currentLevel, null);
//console.log("Activate Textures!", this.currentLevel) //console.log("Activate Textures!", this.currentLevel)
@@ -9564,16 +9719,14 @@
* @memberof DeepZoomImage * @memberof DeepZoomImage
*/ */
deactivate() { deactivate() {
this.active = false;
this.destroyAllTiles(); this.destroyAllTiles();
Object.keys(this.tileLayers).forEach(key => {
this.destroyTiles(key);
});
this.tileContainer.destroy({ children: true }); this.tileContainer.destroy({ children: true });
printTileCacheInfos(); printTileCacheInfos();
} }
throwFinished() { throwFinished() {
console.log("throwFinished"); //console.log("throwFinished")
let key = this.currentLevel.toString(); let key = this.currentLevel.toString();
let currentTiles = this.tileLayers[key]; let currentTiles = this.tileLayers[key];
if (typeof currentTiles == 'undefined') { if (typeof currentTiles == 'undefined') {
+1 -1
View File
@@ -1864,7 +1864,7 @@ export class DeepZoomImage extends PIXI.Container {
this.minimumLevel = deepZoomInfo.baseLevel this.minimumLevel = deepZoomInfo.baseLevel
} }
this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel) this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel)
console.log("autoLoadTiles", this.autoLoadTiles) //console.log("autoLoadTiles", this.autoLoadTiles)
if (this.autoLoadTiles) { if (this.autoLoadTiles) {
this.setupTiles(center) this.setupTiles(center)
} }
+1 -1
View File
@@ -23,7 +23,7 @@ a single delegate pattern.
<p>The main differences are that <code>PointerEvent</code> are fired for each <p>The main differences are that <code>PointerEvent</code> are fired for each
touch point, whereas the <code>TouchEvent</code> collects multiple touch point, whereas the <code>TouchEvent</code> collects multiple
<code>TouchPoints</code> into a single event. The basic PointMap and Interaction <code>TouchPoints</code> into a single event. The basic PointMap and Interaction
classes unify this behavior by collection all contact points regardless classes unify this behavior by collecting all contact points regardless
of their original mouse, touch, or pointer events.</p> of their original mouse, touch, or pointer events.</p>
<h2> <h2>
Point Maps Point Maps
+1 -1
View File
@@ -101,7 +101,7 @@
minScale: 0, minScale: 0,
maxScale: 50, maxScale: 50,
onTransform: event => { onTransform: event => {
console.log('currentLevel', deepZoomImage1.currentLevel) //console.log('currentLevel', deepZoomImage1.currentLevel)
deepZoomImage1.transformed(event) deepZoomImage1.transformed(event)
} }
}) })
+12 -19
View File
@@ -1,24 +1,14 @@
import { Capabilities } from '../../capabilities.js' import { Capabilities } from '../../capabilities.js'
import { Points } from '../../utils.js' import { Points } from '../../utils.js'
import { deepZoomTileCache } from './tile.js' import Tile from './tile.js'
import { Tiles } from './tiles.js' import { Tiles } from './tiles.js'
function isEven(n) { function isEven(n) {
return n % 2 == 0 return n % 2 == 0
} }
function printTileCacheInfos() { function printTileCacheInfos() {
let references = new Map() Tile.printInfos()
let multiples = 0
for (let [url, tiles] of deepZoomTileCache.entries()) {
let count = tiles.size
references.set(url, count)
if (count > 1) {
multiples += 1
}
}
console.log({ multiples, references })
} }
/** /**
* A utility class that holds information typically provided by DZI files, i.e. * A utility class that holds information typically provided by DZI files, i.e.
@@ -374,6 +364,7 @@ export class DeepZoomImage extends PIXI.Container {
: 1 : 1
this.alpha = alpha this.alpha = alpha
this.fastLoads = 0 this.fastLoads = 0
this.active = true
this.autoLoadTiles = autoLoadTiles this.autoLoadTiles = autoLoadTiles
this.minimumLevel = minimumLevel this.minimumLevel = minimumLevel
this.quadTrees = new Map() // url as keys, TileQuadNodes as values this.quadTrees = new Map() // url as keys, TileQuadNodes as values
@@ -424,7 +415,7 @@ export class DeepZoomImage extends PIXI.Container {
this.minimumLevel = deepZoomInfo.baseLevel this.minimumLevel = deepZoomInfo.baseLevel
} }
this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel) this.currentLevel = Math.max(this.minimumLevel, deepZoomInfo.baseLevel)
console.log("autoLoadTiles", this.autoLoadTiles) //console.log("autoLoadTiles", this.autoLoadTiles)
if (this.autoLoadTiles) { if (this.autoLoadTiles) {
this.setupTiles(center) this.setupTiles(center)
} }
@@ -645,7 +636,7 @@ export class DeepZoomImage extends PIXI.Container {
} }
worldBounds() { worldBounds() {
let viewBounds = this.app.scene.getBounds() let viewBounds = this.app.scene.bounds // UO: Never use getBounds()
// Using getBounds extends visible scope after loading tiles and leads // Using getBounds extends visible scope after loading tiles and leads
// to excessive loading // to excessive loading
if (this.world != null) { if (this.world != null) {
@@ -1027,6 +1018,9 @@ export class DeepZoomImage extends PIXI.Container {
* @param {boolean} debug - log debug infos * @param {boolean} debug - log debug infos
*/ */
transformed(event) { transformed(event) {
if (!this.active) {
return
}
let key = this.currentLevel.toString() let key = this.currentLevel.toString()
let currentTiles = this.tileLayers[key] let currentTiles = this.tileLayers[key]
if (typeof currentTiles == 'undefined') { if (typeof currentTiles == 'undefined') {
@@ -1049,7 +1043,7 @@ export class DeepZoomImage extends PIXI.Container {
this.ensureTiles(this.currentLevel, event.about) this.ensureTiles(this.currentLevel, event.about)
return return
} }
let level = this.levelForScale(event.scale) let level = this.levelForScale(event.scale)
let newLevel = Math.max(level, this.minimumLevel) let newLevel = Math.max(level, this.minimumLevel)
if (newLevel != this.currentLevel) { if (newLevel != this.currentLevel) {
@@ -1074,6 +1068,7 @@ export class DeepZoomImage extends PIXI.Container {
* @memberof DeepZoomImage * @memberof DeepZoomImage
*/ */
activate() { activate() {
this.active = true
this.destroyTilesAboveLevel(this.currentLevel) this.destroyTilesAboveLevel(this.currentLevel)
this.ensureTiles(this.currentLevel, null) this.ensureTiles(this.currentLevel, null)
//console.log("Activate Textures!", this.currentLevel) //console.log("Activate Textures!", this.currentLevel)
@@ -1085,16 +1080,14 @@ export class DeepZoomImage extends PIXI.Container {
* @memberof DeepZoomImage * @memberof DeepZoomImage
*/ */
deactivate() { deactivate() {
this.active = false
this.destroyAllTiles() this.destroyAllTiles()
Object.keys(this.tileLayers).forEach(key => {
this.destroyTiles(key)
})
this.tileContainer.destroy({ children: true }) this.tileContainer.destroy({ children: true })
printTileCacheInfos() printTileCacheInfos()
} }
throwFinished() { throwFinished() {
console.log("throwFinished") //console.log("throwFinished")
let key = this.currentLevel.toString() let key = this.currentLevel.toString()
let currentTiles = this.tileLayers[key] let currentTiles = this.tileLayers[key]
if (typeof currentTiles == 'undefined') { if (typeof currentTiles == 'undefined') {
+20 -15
View File
@@ -1,4 +1,4 @@
import { deepZoomTileCache, Tile } from './tile.js' import Tile from './tile.js'
/** /**
* A Tile Loader component that can be plugged into a Tiles Layer. * A Tile Loader component that can be plugged into a Tiles Layer.
@@ -28,6 +28,8 @@ export class TileLoader {
schedule(url, col, row) { schedule(url, col, row) {
if (this.loaded.has(url)) return false if (this.loaded.has(url)) return false
if (this.loading.has(url)) return false if (this.loading.has(url)) return false
Tile.schedule(url)
this.map.set(url, [col, row]) this.map.set(url, [col, row])
this.loading.add(url) this.loading.add(url)
this.loadQueue.push(url) this.loadQueue.push(url)
@@ -37,6 +39,7 @@ export class TileLoader {
unschedule(url) { unschedule(url) {
if (this.loaded.has(url)) this.loaded.delete(url) if (this.loaded.has(url)) this.loaded.delete(url)
if (this.loading.has(url)) this.loading.delete(url) if (this.loading.has(url)) this.loading.delete(url)
Tile.unschedule(url)
this.loadQueue = this.loadQueue.filter(item => item != url) this.loadQueue = this.loadQueue.filter(item => item != url)
} }
@@ -62,9 +65,14 @@ export class TileLoader {
console.warn("Tile already loaded") console.warn("Tile already loaded")
tile.unregister() tile.unregister()
} }
tile = new Tile(texture, url) try {
this.loaded.set(url, tile) tile = new Tile(texture, url)
this.tiles.tileAvailable(tile, col, row, url) this.loaded.set(url, tile)
this.tiles.tileAvailable(tile, col, row, url)
} catch (error) {
console.warn("Tile loading error", error)
}
} }
} }
@@ -91,16 +99,13 @@ export class PIXITileLoader extends TileLoader {
if (this.loaded.has(url)) return false if (this.loaded.has(url)) return false
if (this.loading.has(url)) return false if (this.loading.has(url)) return false
if (deepZoomTileCache.has(url)) { Tile.schedule(url)
let tiles = deepZoomTileCache.get(url) let reusableTexture = Tile.textureAvailable(url)
for (let tile of tiles.values()) { if (reusableTexture) {
//console.log("Reusing cached texture", tile.parent) if (this.debug) console.log('Texture reusable', reusableTexture)
let texture = tile.texture this._textureAvailable(url, col, row, reusableTexture)
this._textureAvailable(url, col, row, texture) return false
return false
}
} }
let texture = PIXI.utils.TextureCache[url] let texture = PIXI.utils.TextureCache[url]
if (texture) { if (texture) {
if (this.debug) console.log('Texture already loaded', texture) if (this.debug) console.log('Texture already loaded', texture)
@@ -155,8 +160,8 @@ export class PIXITileLoader extends TileLoader {
_onLoaded(loader, resource) { _onLoaded(loader, resource) {
if (this.destroyed) { if (this.destroyed) {
let texture = resource.texture let texture = resource.texture
let destroyBase = !deepZoomTileCache.has(resource.url) let url = resource.url
texture.destroy(destroyBase) Tile.lateTexture(url, texture)
console.warn("Received resource after destroy", texture) console.warn("Received resource after destroy", texture)
return return
} }
+162 -17
View File
@@ -1,19 +1,100 @@
/* ES Lint */
/* globals PIXI, console*/
export const deepZoomTileCache = new Map() const registeredTiles = new Map()
const pendingTiles = new Map()
/** Implements a baseTexture cache. The last textures are kept for reuse */
let keepTextures = 0
const keptTextures = []
/** The current Tile implementation simply uses PIXI.Sprites. /** The current Tile implementation simply uses PIXI.Sprites.
* *
* BTW: PIXI.extras.TilingSprite is not appropriate. It should be used for * BTW: PIXI.extras.TilingSprite is not appropriate. It should be used for
* repeating patterns. * repeating patterns.
**/ **/
export class Tile extends PIXI.Sprite { export default class Tile extends PIXI.Sprite {
constructor(texture, url) { constructor(texture, url) {
super(texture) super(texture)
this.url = url this.url = url
this.register(url) this.register(url)
} }
/**
* Static method to enable keeping of base textures
*
* @static
* @param {*} value
* @memberof Tile
*/
static enableKeepTextures(value = 1000) {
keepTextures = value
}
/**
* Marks the given url as pending. Pending tiles should not be destroyed
*
* @static
* @param {*} url
* @memberof Tile
*/
static schedule(url) {
let count = 0
if (pendingTiles.has(url)) {
count = pendingTiles.get(url)
}
pendingTiles.set(url, count + 1)
// console.log("Tile.scheduled", url, pendingTiles.size)
}
/**
* Returns true iff the url is pending
*
* @static
* @param {*} url
* @returns
* @memberof Tile
*/
static isPending(url) {
return pendingTiles.has(url) && pendingTiles.get(url) > 0
}
static isObsolete(url) {
if (registeredTiles.has(url) && registeredTiles.get(url) > 0) {
return false
}
return true
}
/**
* Removes the given url from pending urls.
*
* @static
* @param {*} url
* @memberof Tile
*/
static unschedule(url) {
if (pendingTiles.has(url)) {
let count = pendingTiles.get(url)
if (count > 1) {
pendingTiles.set(url, count - 1)
}
else {
pendingTiles.clear(url)
}
}
// console.log("Tile.unscheduled", url, pendingTiles.size)
}
/**
* Loads a tile from image using the PIXI.Texture.fromImage method.
*
* @static
* @param {*} imageId
* @param {*} crossorigin
* @param {*} scaleMode
* @returns
* @memberof Tile
*/
static fromImage(imageId, crossorigin, scaleMode) { static fromImage(imageId, crossorigin, scaleMode) {
return new Tile(PIXI.Texture.fromImage(imageId, crossorigin, scaleMode), imageId) return new Tile(PIXI.Texture.fromImage(imageId, crossorigin, scaleMode), imageId)
} }
@@ -26,13 +107,14 @@ export class Tile extends PIXI.Sprite {
* @memberof Tile * @memberof Tile
*/ */
register(url, debug = false) { register(url, debug = false) {
if (deepZoomTileCache.has(url)) { Tile.unschedule(url)
let tiles = deepZoomTileCache.get(url) if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url)
tiles.add(this) tiles.add(this)
if (debug) console.log("Tile.register", url, tiles.size) if (debug) console.log("Tile.register", url, tiles.size)
} }
else { else {
deepZoomTileCache.set(url, new Set([this])) registeredTiles.set(url, new Set([this]))
if (debug) console.log("Tile.register", url, 1) if (debug) console.log("Tile.register", url, 1)
} }
} }
@@ -44,10 +126,11 @@ export class Tile extends PIXI.Sprite {
* @memberof Tile * @memberof Tile
*/ */
unregister() { unregister() {
let tiles = deepZoomTileCache.get(this.url) let tiles = registeredTiles.get(this.url)
tiles.delete(this) tiles.delete(this)
if (tiles.size == 0) { if (tiles.size == 0) {
deepZoomTileCache.delete(this.url) registeredTiles.delete(this.url)
return 0
} }
return tiles.size return tiles.size
} }
@@ -59,19 +142,81 @@ export class Tile extends PIXI.Sprite {
* @memberof Tile * @memberof Tile
*/ */
destroy(options, debug = false) { destroy(options, debug = false) {
if (this.parent != null) {
}
let count = this.unregister() let count = this.unregister()
if (count <= 0) {
let opts = { children: true, texture: true, baseTexture: true } if (keepTextures > 0) {
keptTextures.push({ url: this.url, texture: this.texture })
let opts = { children: true, texture: false, baseTexture: false }
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
super.destroy(opts) super.destroy(opts)
if (debug) console.log("Tile.destroy", deepZoomTileCache.size, opts)
while (keptTextures.length > keepTextures) {
let { url, texture } = keptTextures.shift()
if (Tile.isObsolete(url)) {
texture.destroy(true) // Destroy base as well
if (debug) console.log("Destroying texture and baseTexture", url)
}
}
} }
else { else {
let opts = { children: true, texture: false, baseTexture: false } // No longer registered and not pending
if (debug) console.log("Tile.destroy", deepZoomTileCache.size, opts) if (count <= 0 && !Tile.isPending(this.url)) {
super.destroy(opts) let opts = { children: true, texture: true, baseTexture: true }
super.destroy(opts)
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
}
else {
let opts = { children: true, texture: false, baseTexture: false }
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
super.destroy(opts)
}
if (this.parent != null) {
// UO: Emit warning and remove
console.warn("Destroying tile with parent. Hiding instead")
this.visible = false
}
} }
} }
/**
* Returns an available texture that can be reused
*
* @param {*} url
* @returns
* @memberof Tile
*/
static textureAvailable(url) {
if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url)
for (let tile of tiles.values()) {
//console.log("Reusing cached texture", tile.parent)
return tile.texture
}
}
return null
}
/**
* Texture received too late. We do not need it.
* @param {*} url
* @param {*} texture
*/
static lateTexture(url, texture) {
let destroyBase = !registeredTiles.has(url)
texture.destroy(destroyBase)
}
static printInfos() {
let references = new Map()
let multiples = 0
for (let [url, tiles] of registeredTiles.entries()) {
let count = tiles.size
references.set(url, count)
if (count > 1) {
multiples += 1
}
}
console.log({ multiples, references })
}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

+9 -4
View File
@@ -173,11 +173,16 @@ class Throwable {
} }
} }
_throwDeltaTime() {
let t = performance.now()
let dt = t - this.lastframe
this.lastframe = t
return dt
}
animateThrow(time) { animateThrow(time) {
if (this.velocity != null) { if (this.velocity != null) {
let t = performance.now() let dt = this._throwDeltaTime()
let dt = t - this.lastframe
this.lastframe = t
// console.log("animateThrow", dt) // console.log("animateThrow", dt)
let next = this.nextVelocity(this.velocity) let next = this.nextVelocity(this.velocity)
let prevLength = Points.length(this.velocity) let prevLength = Points.length(this.velocity)
@@ -1434,7 +1439,7 @@ export class DOMScatter extends AbstractScatter {
let resizeW = r * Math.cos(Angle.degree2radian(phiCorrected)) let resizeW = r * Math.cos(Angle.degree2radian(phiCorrected))
let resizeH = -r * Math.sin(Angle.degree2radian(phiCorrected)) let resizeH = -r * Math.sin(Angle.degree2radian(phiCorrected))
if (this.element.offsetWidth + resizeW / this.scale > this.width * 0.3 && this.element.offsetHeight + resizeH / this.scale > this.height * 0.3) TweenLite.to(this.element, 0, { width: this.element.offsetWidth + resizeW / this.scale, height: this.element.offsetHeight + resizeH / this.scale }); if ((this.element.offsetWidth + resizeW) / this.scale > this.width * 0.5 / this.scale && (this.element.offsetHeight + resizeH) / this.scale > this.height * 0.3 / this.scale) TweenLite.to(this.element, 0, { width: this.element.offsetWidth + resizeW / this.scale, height: this.element.offsetHeight + resizeH / this.scale });
this.oldX = e.clientX this.oldX = e.clientX
this.oldY = e.clientY this.oldY = e.clientY
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

+36 -803
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "iwmlib", "name": "iwmlib",
"version": "1.0.8", "version": "1.0.12",
"description": "An Open Source library for multi-touch, WebGL powered applications.", "description": "An Open Source library for multi-touch, WebGL powered applications.",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -28,6 +28,7 @@
"gulp-uglify": "^3.0.2" "gulp-uglify": "^3.0.2"
}, },
"dependencies": { "dependencies": {
"fs-extra": "^8.0.1",
"gsap": "^2.1.3", "gsap": "^2.1.3",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"optimal-select": "^4.0.1", "optimal-select": "^4.0.1",