<!DOCTYPE html> <head> <meta charset="utf-8"> <title>Scroll View</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> [dropzone] { background-color: grey; margin: 1px; border-width: 1px; border-style: dashed; } [data-fact-id] { background-color: lightgray; } [data-hint-available] { background-color: yellow } math { display: inline-flex; align-items: center; flex-wrap: wrap; } .lagacySlot { width: 100px; height: 100px; margin: 50px; border-width: 1px; } #rectangle { width: 10px; height: 10px; position: absolute; background-color: red; } </style> </head> <body> <div id="scrollContainer"> <div>No scroll selected</div> <math> <mi>E</mi> <mo>=</mo> <mfenced> <mtable> <mtr> <mtd> <mi dropzone="copy" data-allowed-types="PointFact,AngleFact" data-slot-id="http://mathhub.info/FrameIT/frameworld?Example?A">a</mi> </mtd> <mtd> <mi dropzone="copy" data-slot-id="http://mathhub.info/FrameIT/frameworld?Example?B">b</mi> </mtd> <mtd> <mn>0</mn> </mtd> </mtr> <mtr> <mtd> <mn>0</mn> </mtd> <mtd> <mn>1</mn> </mtd> <mtd> <mn>0</mn> </mtd> </mtr> <mtr> <mtd> <mn>0</mn> </mtd> <mtd> <mn>0</mn> </mtd> <mtd> <mn>1</mn> </mtd> </mtr> </mtable> </math> </div> <button type="button" title="Apply the scroll" onclick="applyScroll('')">Magic</button><br> <p>You can right click on yellow slots to get a hint.</p> </body> <script> /** * @typedef Point * @type {object} * @property {number} x * @property {number} y * @property {number} z */ /** * @property {Point} point * @property {Point} normal * @property {string} s_type * @property {string} label * @property {string|null} _CustomLabel * @property {boolean} hasCustomLabel * @property {number} labelId */ class Fact { /** @property {string} id Fact id */ id = "" /** @property {string} s_type Fact type */ s_type = "" /** @property {string} label used in unity */ label = "" /** @property {string | null} _CustomLabel Custom label */ _CustomLabel = null /** @property {boolean} hasCustomLabel */ hasCustomLabel = false /** @property {number} labelId */ labelId = 0 } class Point { /** @property {number} x */ x = 0 /** @property {number} y */ y = 0 /** @property {number} z */ z = 0 } /** s_type: PointFact, label: A, _CustomLabel: null, hasCustomLabel: false, labelId: 0, point: {x: -1.66086578, y: -0.00494432449, z: -2.17682648}, normal: {x: 0, y: 1, z: 0} */ class PointFact extends Fact { s_type = "PointFact"; /** @property {Point} point */ point = new Point() /** @property {Point} normal */ normal = new Point() } /** * pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact252, pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact254, pid3: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, s_type: AngleFact, label: ∠BDF, _CustomLabel: null, is_right_angle: false, hasCustomLabel: false, labelId: 0 */ class AngleFact extends Fact { s_type = "AngleFact"; pid1 = ""; pid2 = ""; pid3 = ""; is_right_angle = false; } /** * s_type: LineFact, pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact255, pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, dir: [object Object], label: [EF], _CustomLabel: null, hasCustomLabel: false, labelId: 0 */ class LineFact extends Fact { s_type = "LineFact"; pid1 = ""; pid2 = ""; dir = new Point(); } /** * s_type: RayFact, pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact252, dir: [object Object], label: FB, _CustomLabel: null, hasCustomLabel: false, labelId: 0 */ class RayFact extends Fact { s_type = "RayFact"; pid1 = ""; pid2 = ""; dir = new Point(); } /** @param {DragEvent} event */ function dropHandler(event) { event.preventDefault() console.log("dropHandler", event) const data = event.dataTransfer.getData("application/json") //const data = event.dataTransfer.getData("text/plain") console.log(`Droped data: '${event.dataTransfer.types}'`, event.dataTransfer.types) /** @type {Fact} */ const fact = JSON.parse(data) console.warn(`Droped Fact '${fact.label}':`, fact) /** @type {HTMLElement} */ const element = event.target if (element.hasAttribute("data-allowed-types")) { //const allowedTypesStr = element.dataset["allowed-types"] const allowedTypesStr = element.getAttribute("data-allowed-types") const allowedTypes = allowedTypesStr.split(",") if (!allowedTypes.includes(fact.s_type)) { console.warn(`The drop target data-type '${fact.s_type}' is not a member of the allowed types '${allowedTypesStr}'`) return } } element.innerHTML = fact.label element.fact = fact element.dataset.factId = fact.id } /** @param {MouseEvent} event */ function clickHandler(event) { event.preventDefault() console.log("clickHandler") console.log("clickHandler", event) switch (event.button) { case 0: console.log("Left button clicked") event.target.fact = null event.target.dataset.factId = null break case 1: console.log("Middle button clicked") break case 2: console.log("Right button clicked") getHint(event.target.dataset.slotId) break default: console.log("Unknown button clicked") } } /* * register the drag event listeners */ //document.addEventListener("dragstart", ev => printHandler(ev, "DragStartEvent")) //document.addEventListener("dragenter", ev => printHandler(ev, "DragEnterEvent")) //document.addEventListener("drag", ev => printHandler(ev, "DragEvent")) document.addEventListener("dragover", ev => ev.preventDefault()) //document.addEventListener("dragover", ev => printPreventDefaultHandler(ev, "DragOverEvent")) //document.addEventListener("dragleave", ev => printHandler(ev, "DragLeaveEvent")) //document.addEventListener("dragend", ev => printHandler(ev, "DragEndEvent")) // select all dropzones and add drop event listeners //let dropZones = document.querySelectorAll('[dropzone="copy"]') //dropZones.forEach( dropZone => dropZone.addEventListener("drop", ev => dropHandler(ev, "DropEvent")) ) /** select all dropzones and add drop event listeners */ function addDropZoneEventListeners() { console.log("addDropZoneEventListeners") document.querySelectorAll('[dropzone="copy"]') .forEach( dropZone => { dropZone.removeEventListener("drop", dropHandler) dropZone.removeEventListener("click", clickHandler) dropZone.removeEventListener("contextmenu", clickHandler) //dropZone.addEventListener("dragover", ev => ev.preventDefault()) dropZone.addEventListener("drop", dropHandler) dropZone.addEventListener("click", clickHandler) dropZone.addEventListener("contextmenu", clickHandler) }) } //addDropZoneEventListeners() </script> <!--<script src="visualiseCursor.mjs" defer type="module"></script>--> <!--<script> /* mouse and pointer event handling */ const rectangle = document.createElement("div"); rectangle.id = "rectangle"; console.log("appendChild to", document.body) document.body.appendChild(rectangle); function followCursor(event) { const cursorX = event.clientX; const cursorY = event.clientY +5; //console.log(`MouseEvent X: ${cursorX}, Y: ${cursorY}, Event type: ${event.type}`, event); rectangle.style.left = `${cursorX}px`; rectangle.style.top = `${cursorY}px`; } document.addEventListener("mousemove", followCursor); document.addEventListener("pointermove", followCursor); document.addEventListener("mouseover", followCursor); document.addEventListener("pointerover", followCursor); document.addEventListener("mouseout", followCursor); document.addEventListener("pointerout", followCursor); </script>--> </html>