diff --git a/dist/iwmlib.js b/dist/iwmlib.js index 8fa529d..c858c55 100644 --- a/dist/iwmlib.js +++ b/dist/iwmlib.js @@ -1545,14 +1545,34 @@ } + /* eslint-disable no-undef */ + /* eslint-disable no-console */ + /* eslint-disable no-unused-vars */ let ipc = null; + let logMessages = new Set(); + let logHandlers = { + log: console.log, + warn: console.warn, + error: console.error + }; try { ipc = require('electron').ipcRenderer; - } catch (e) {} + 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.'); + } /** Basic class for app specific logging requirements. * Can be used to implement persistent logging in electron apps. + * Uses a logMessage cache to prevent error overflows. This is + * needed since errors may occur very frequently + * (e.g. display update loops at 60fps, programmatic loops, ...). + * + * The logging handlers can be overwritten by calling the static + * setup method. */ class Logging { @@ -1560,13 +1580,38 @@ * @param {*} message */ static log(message) { + logHandlers.log(message); + } - if (ipc) { - ipc.send('log', message); - } else { - console.log(message); + /** + * Static warn function. + * Emits each warning only once per session. + * @param {*} message + */ + static warn(message) { + if (!logMessages.has(message)) { + logMessages.add(message); + logHandlers.warn(message); } } + + /** + * Static error function. + * Emits each error message only once per session. + * @param {*} message + */ + static error(message) { + if (!logMessages.has(message)) { + logMessages.add(message); + logHandlers.error(message); + } + } + + static setup({log=console.log, warn=console.warn, error=console.error} = {}) { + logHandlers.log = log; + logHandlers.warn = warn; + logHandlers.error = error; + } } /* globals Hammer, propagating */ diff --git a/dist/iwmlib.pixi.js b/dist/iwmlib.pixi.js index e86ef66..d208ec2 100644 --- a/dist/iwmlib.pixi.js +++ b/dist/iwmlib.pixi.js @@ -4709,28 +4709,73 @@ // } } + /* eslint-disable no-undef */ + /* eslint-disable no-console */ + /* eslint-disable no-unused-vars */ let ipc = null; + let logMessages = new Set(); + let logHandlers = { + log: console.log, + warn: console.warn, + error: console.error + }; try { ipc = require('electron').ipcRenderer; - } catch (e) {} + 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.'); + } /** Basic class for app specific logging requirements. * Can be used to implement persistent logging in electron apps. + * Uses a logMessage cache to prevent error overflows. This is + * needed since errors may occur very frequently + * (e.g. display update loops at 60fps, programmatic loops, ...). + * + * The logging handlers can be overwritten by calling the static + * setup method. */ - class Logging { + class Logging$1 { /** Static log function. * @param {*} message */ static log(message) { + logHandlers.log(message); + } - if (ipc) { - ipc.send('log', message); - } else { - console.log(message); + /** + * Static warn function. + * Emits each warning only once per session. + * @param {*} message + */ + static warn(message) { + if (!logMessages.has(message)) { + logMessages.add(message); + logHandlers.warn(message); } } + + /** + * Static error function. + * Emits each error message only once per session. + * @param {*} message + */ + static error(message) { + if (!logMessages.has(message)) { + logMessages.add(message); + logHandlers.error(message); + } + } + + static setup({log=console.log, warn=console.warn, error=console.error} = {}) { + logHandlers.log = log; + logHandlers.warn = warn; + logHandlers.error = error; + } } /* globals Hammer, propagating */ @@ -5676,7 +5721,7 @@ let size = this.interaction.current.size; let limit = this.logInteractionsAbove; if (size > limit) { - Logging.log(`Number of interactions ${size} exceeds ${limit}`); + Logging$1.log(`Number of interactions ${size} exceeds ${limit}`); } } @@ -7805,10 +7850,12 @@ /* 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 = []; + const lateTextures = new Map(); + let lastSweepTime = 0; + let sweepInterval = 2000.0; /** The current Tile implementation simply uses PIXI.Sprites. * @@ -7833,43 +7880,6 @@ 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) - } */ - - /** - * 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) - } */ - - /** * Returns true iff the url is pending * @@ -8001,14 +8011,60 @@ return null } + /** + * Specialized renderWebGL to avoid freezing system + * + * @param {*} renderer + * @memberof Tile + */ + renderWebGL(renderer) { + try { + super.renderWebGL(renderer); + } + catch (e) { + // We want persistent logging here + Logging.error("Error in Tile.renderWebGL: " + e.message); + } + } + + /** + * Removes lately arrived texture if they have not been touched in the meanwhile. + * + * @static + * @memberof Tile + */ + static sweepLateTextures() { + let now = performance.now(); + if (now > lastSweepTime + sweepInterval) { + lastSweepTime = now; + let count = 0; + for (let [url, texture] of lateTextures.entries()) { + if (texture) { + let base = texture.baseTexture; + if (base != null && base.touched == 0) { + texture.destroy(true); + //console.info("Sweeping ", url) + count += 1; + lateTextures.delete(url); + } + } + } + if (count > 0) + console.log("Sweeping textures", count); + } + } + /** * 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); + lateTextures.set(url, texture); + //console.warn("Tile.lateTexture") + // We cannot destroy the texture since we got errors in t.renderWebGL. + // Perhaps we can destroy unsed textures later on + Tile.sweepLateTextures(); } static printInfos() { @@ -11811,6 +11867,10 @@ return ['decade', 'year', 'month', 'day', 'hour', 'minute', 'second'] } + static get largeTickSize() { + return 4.2 + } + get minWidth() { return 10 } @@ -11885,7 +11945,7 @@ return date.toLocaleDateString('de', format) } - draw(timeline, range, width, height, available, format, nextFormat, level) { + draw(timeline, range, width, height, available, format, nextFormat, level, extraTicks=false) { let first = null; let last = null; let keyedFormat = (format) ? format[this.formatKey] : null; @@ -11893,7 +11953,6 @@ let redundant = (nextFormat) ? this.formatKey in nextFormat : false; let fullyRedundant = keyedFormat != null && keyedFormat == keyedNextFormat; let y = timeline.getY(); - for (let { start, end } of this.iterRanges(range)) { let x = timeline.toX(start); let xx = x; @@ -11902,11 +11961,10 @@ let key = this.dateKey(start); let text = this.toLocaleString(start, format); let align = 'center'; - let downTick = false; if (nextFormat) { yy = y + timeline.tickLabelOffset(-1, 1); align = 'left'; - timeline.drawTick(x, 4.2); + timeline.drawTick(x, Ticks.largeTickSize); let nextX = timeline.toX(end) - 100; if (x < 0 && nextX > -100 && !redundant) { xx = Math.min(4, nextX); @@ -11914,20 +11972,18 @@ else { xx -= 2; } - downTick = true; } else if (level > 0) { xx = x + available / 2; } - else { - downTick = true; - } + if (!fullyRedundant) { timeline.ensureLabel(key, text, { x: xx, y: yy, align }, FontInfo.small); } - if (downTick) timeline.drawTick(x, -1); + if (extraTicks) + timeline.drawTick(x, -level); } if (timeline.visibleRange(start, end)) { if (first == null) @@ -11939,6 +11995,15 @@ return null return { start: first, end: last } } + + drawExtra(timeline, range, size) { + for (let { start } of this.iterRanges(range)) { + if (timeline.visibleDate(start)) { + let x = timeline.toX(start); + timeline.drawTick(x, -size); + } + } + } } class DecadeTicks extends Ticks { @@ -12125,15 +12190,34 @@ visible.push(ticks); } let level = 0; + let ranges = []; for (let ticks of visible) { if (range == null) - return + continue range = ticks.draw(timeline, range, width, height, availables.get(ticks), formats.get(ticks), nextFormats.get(ticks), level); + if (range) { + ranges.push({ticks, range}); + } level += 1; } + + let extraLevel = ranges.length - 1; + let extraStart = extraLevel; + for(let {ticks, range} of ranges) { + ticks.drawExtra(timeline, range, extraLevel); + extraLevel -= 1; + if (extraLevel <= 0) { + continue + } + } + + timeline.drawTick(start, Ticks.largeTickSize); + timeline.drawTick(start, -extraStart); + timeline.drawTick(end, Ticks.largeTickSize); + timeline.drawTick(end, -extraStart); } } diff --git a/lib/logging.html b/lib/logging.html index 955418a..3c117a9 100644 --- a/lib/logging.html +++ b/lib/logging.html @@ -8,15 +8,26 @@ - +

Logging

-

Store informations of your app permanently.

+

Store informations of your app permanently or use app specific logging functions.

+

You can overwrite the log, warn, and error handler by using Logging.setup with + app specific functions.

+ \ No newline at end of file diff --git a/lib/logging.js b/lib/logging.js index cefb05d..3a0555e 100644 --- a/lib/logging.js +++ b/lib/logging.js @@ -1,10 +1,21 @@ +/* eslint-disable no-undef */ +/* eslint-disable no-console */ +/* eslint-disable no-unused-vars */ let ipc = null let logMessages = new Set() +let logHandlers = { + log: console.log, + warn: console.warn, + error: console.error +} try { ipc = require('electron').ipcRenderer + 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.") + console.log('Cannot use electron logging.') } /** Basic class for app specific logging requirements. @@ -12,6 +23,9 @@ try { * Uses a logMessage cache to prevent error overflows. This is * needed since errors may occur very frequently * (e.g. display update loops at 60fps, programmatic loops, ...). + * + * The logging handlers can be overwritten by calling the static + * setup method. */ export default class Logging { @@ -19,12 +33,7 @@ export default class Logging { * @param {*} message */ static log(message) { - - if (ipc) { - ipc.send('log', message) - } else { - console.log(message) - } + logHandlers.log(message) } /** @@ -35,11 +44,7 @@ export default class Logging { static warn(message) { if (!logMessages.has(message)) { logMessages.add(message) - if (ipc) { - ipc.send('warn', message) - } else { - console.warn(message) - } + logHandlers.warn(message) } } @@ -51,11 +56,13 @@ export default class Logging { static error(message) { if (!logMessages.has(message)) { logMessages.add(message) - if (ipc) { - ipc.send('error', message) - } else { - console.error(message) - } + logHandlers.error(message) } } + + static setup({log=console.log, warn=console.warn, error=console.error} = {}) { + logHandlers.log = log + logHandlers.warn = warn + logHandlers.error = error + } }