From 22d1ca351ddb5d90e155a193df08a4dd0d12d0ca Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Sun, 13 Jun 2021 22:59:50 -0500 Subject: [PATCH] List monitors --- src/index.js | 32 +++++----- src/monitor.js | 165 +++++++++++++++++++++++++++++++++++++++++++------ src/style.css | 31 +++++++++- 3 files changed, 193 insertions(+), 35 deletions(-) diff --git a/src/index.js b/src/index.js index d5dbef4..fb44262 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,7 @@ import AudioEngine from 'scratch-audio'; import {BitmapAdapter} from 'scratch-svg-renderer'; import Question from './question'; -import {VariableMonitor} from './monitor'; +import {ListMonitor, VariableMonitor} from './monitor'; import styles from './style.css'; class Scaffolding { @@ -154,22 +154,24 @@ class Scaffolding { } _onmonitorsupdate (monitors) { - // for (const key of this._monitors.keys()) { - // if (!monitors.has(key)) { - // console.log("remove", key); - // const monitor = this._monitors.get(key); - // monitor.destroy(); - // this._monitors.delete(key); - // } - // } - - for (const monitor of monitors.valueSeq()) { - const id = monitor.get('id'); + for (const monitorData of monitors.valueSeq()) { + const id = monitorData.get('id'); if (!this._monitors.has(id)) { - this._monitors.set(id, new VariableMonitor(this, monitor)); + const visible = monitorData.get('visible'); + if (!visible) { + // Would be a waste to make it now + continue; + } + // TODO: add to DOM in same order as appears in list + const mode = monitorData.get('mode'); + if (mode === 'list') { + this._monitors.set(id, new ListMonitor(this, monitorData)); + } else { + this._monitors.set(id, new VariableMonitor(this, monitorData)); + } } - const mon = this._monitors.get(id); - mon.update(monitor); + const monitorObject = this._monitors.get(id); + monitorObject.update(monitorData); } } diff --git a/src/monitor.js b/src/monitor.js index 973a1a4..b527ef8 100644 --- a/src/monitor.js +++ b/src/monitor.js @@ -1,6 +1,6 @@ import styles from './style.css'; -class VariableMonitor { +class Monitor { constructor (parent, monitor) { this.parent = parent; @@ -14,6 +14,37 @@ class VariableMonitor { this.root.className = styles.monitorRoot; this.root.setAttribute('opcode', this.opcode); + this.parent._monitorOverlay.appendChild(this.root); + } + + getLabel () { + let base; + if (Object.keys(this.params).length) { + base = this.params[Object.keys(this.params)[0]]; + } else { + base = this.id; + } + + if (this.spriteName) { + return `${this.spriteName}: ${base}`; + } + return base; + } + + update (monitor) { + // TODO: don't touch if not changed + const x = monitor.get('x'); + const y = monitor.get('y'); + const visible = monitor.get('visible'); + this.root.style.transform = `translate(${x}px, ${y}px)`; + this.root.style.display = visible ? '' : 'none'; + } +} + +class VariableMonitor extends Monitor { + constructor (parent, monitor) { + super(parent, monitor); + this.inner = document.createElement('div'); this.inner.className = styles.monitorInner; @@ -34,33 +65,129 @@ class VariableMonitor { this.parent._monitorOverlay.appendChild(this.root); } - getLabel () { - let base; - if (Object.keys(this.params).length) { - base = this.params[Object.keys(this.params)[0]]; - } else { - base = this.id; - } + update (monitor) { + const value = monitor.get('value'); + this.value.textContent = value; + } +} - if (this.spriteName) { - return `${this.spriteName}: ${base}`; +const ROW_HEIGHT = 20; + +class Row { + constructor () { + this._index = -1; + this._value = ''; + this._visible = true; + + this.root = document.createElement('div'); + this.root.className = styles.monitorRowRoot; + this.indexEl = document.createElement('div'); + this.indexEl.className = styles.monitorRowIndex; + this.valueEl = document.createElement('div'); + this.valueEl.className = styles.monitorRowValue; + this.root.appendChild(this.indexEl); + this.root.appendChild(this.valueEl); + } + + setIndex (index) { + if (this._index !== index) { + this._index = index; + this.root.style.transform = `translateY(${index * ROW_HEIGHT}px)`; + this.indexEl.textContent = index + 1; } - return base; + } + + setValue (value) { + if (this._value !== value) { + this._value = value; + this.valueEl.textContent = value; + } + } + + setVisible (visible) { + if (this._visible !== visible) { + this._visible = visible; + this.root.style.display = visible ? '' : 'none'; + } + } +} + +class ListMonitor extends Monitor { + constructor (parent, monitor) { + super(parent, monitor); + + this.rows = []; + this.scrollTop = 0; + + this.rowsOuter = document.createElement('div'); + this.rowsOuter.className = styles.monitorRowsOuter; + + this.rowsInner = document.createElement('div'); + this.rowsInner.className = styles.monitorRowsInner; + this.rowsInner.addEventListener('scroll', this._onscroll.bind(this)); + + this.endPoint = document.createElement('div'); + this.endPoint.className = styles.monitorRowsEndpoint; + + this.rowsInner.appendChild(this.endPoint); + this.rowsOuter.appendChild(this.rowsInner); + this.root.appendChild(this.rowsOuter); + } + + _onscroll (e) { + this.scrollTop = e.target.scrollTop; + this.updateValue(this.value); + } + + getRow () { + if (this.rows.length) { + return this.rows.pop(); + } + return new Row(); } update (monitor) { - const x = monitor.get('x'); - const y = monitor.get('y'); - const value = monitor.get('value'); - const visible = monitor.get('visible'); + super.update(monitor); - this.root.style.transform = `translate(${x}px, ${y}px)`; - this.value.textContent = value; + this.width = monitor.get('width') || 200; + this.height = monitor.get('height') || 200; + this.root.style.width = `${this.width}px`; + this.root.style.height = `${this.height}px`; - this.root.style.display = visible ? '' : 'none'; + this.value = monitor.get('value'); + this.updateValue(this.value); + } + + updateValue (value) { + this.endPoint.style.transform = `translateY(${value.length * ROW_HEIGHT}px)`; + + let startIndex = Math.floor(this.scrollTop / ROW_HEIGHT) - 5; + if (startIndex < 0) startIndex = 0; + let endIndex = Math.ceil((this.scrollTop + this.height) / ROW_HEIGHT) + 5; + if (endIndex > value.length - 1) endIndex = value.length - 1; + + const rowsNeeded = endIndex - startIndex + 1; + while (this.rows.length < rowsNeeded) { + const row = new Row(); + this.rows.push(row); + this.rowsInner.appendChild(row.root); + } + for (var i = 0; i < rowsNeeded; i++) { + const row = this.rows[i]; + const rowIndex = i + startIndex; + row.setIndex(rowIndex); + row.setValue(value[rowIndex]); + row.setVisible(true); + } + while (i < this.rows.length) { + const row = this.rows[i]; + row.setVisible(false); + i++; + } } } export { - VariableMonitor + VariableMonitor, + ListMonitor }; diff --git a/src/style.css b/src/style.css index 17c0f1c..f405651 100644 --- a/src/style.css +++ b/src/style.css @@ -66,7 +66,6 @@ border: 1px solid hsla(0, 0%, 0%, 0.15); border-radius: 4px; font-size: 12px; - user-select: none; overflow: hidden; } .monitor-inner { @@ -98,3 +97,33 @@ .monitor-root[opcode^="data_"] .monitor-value { background-color: rgb(255, 140, 26); } + +.monitor-rows-outer { + height: 200px; +} +.monitor-rows-inner { + height: 100%; + overflow-y: auto; + position: relative; +} +.monitor-rows-endpoint { + position: absolute; + top: 0; + left: 0; + width: 1px; + height: 1px; + pointer-events: none; +} + +.monitor-row-root { + position: absolute; + top: 0; + left: 0; + display: flex; +} +.monitor-row-index { + +} +.monitor-row-value { + +}