From 3ae1ae6c45c941d47f00258c58c10878b6edb1cc Mon Sep 17 00:00:00 2001 From: lorp Date: Mon, 20 May 2024 22:18:23 +0100 Subject: [PATCH] Simplify styling of mappings --- src/fencer.html | 8 ++++- src/fencer.js | 83 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/fencer.html b/src/fencer.html index a443f91..02f7bc6 100644 --- a/src/fencer.html +++ b/src/fencer.html @@ -11,6 +11,7 @@ font-family: IBM Plex Sans; font-size: 16px; --currentLocationColor:#077bf6; + --mappingcolor: #093; } body { @@ -93,7 +94,12 @@ } .input { - color: #c91616; + color: #093; +/*} color: #c91616;*/ +} + +.mapping { + color: var(--mappingcolor); } .mappings textarea.xml { diff --git a/src/fencer.js b/src/fencer.js index a5cb4cd..462daa4 100644 --- a/src/fencer.js +++ b/src/fencer.js @@ -3,13 +3,15 @@ import { SamsaFont, SamsaInstance, SamsaBuffer } from "./samsa-core/samsa-core.js"; // import samsa-core https://github.com/Lorp/samsa-core import { VariationModel } from "./fontra-src-client-core/var-model.js"; // import Fontra var-model https://github.com/googlefonts/fontra -const svgArrowHandleRadius = 15; +const svgArrowHandleRadius = 12; const svgArrowHandleRadiusRoot2 = svgArrowHandleRadius * 1/Math.sqrt(2); -const svgCurrentLocationRadius = 10; +const svgCurrentLocationRadius = 7; const svgArrowLineWidth = 2; const svgArrowHead = ``; const svgArrowTail = ``; +const svgMapping = ``; const svgCurrentLocation = ``; +const instanceColor = "#f00"; const GLOBAL = { svgElWidth: 400, @@ -454,7 +456,6 @@ function loadFontFromArrayBuffer (arrayBuffer, options={}) { // updates updateMappingsSliders(GLOBAL.draggingIndex); mappingsChanged(); - //updateMappingsSVG(); updateMappingsXML(); updateRenders(); } @@ -498,7 +499,6 @@ function loadFontFromArrayBuffer (arrayBuffer, options={}) { // redraw the mappings SVG // - TODO: decide if we need to update the mappingsView array mappingsChanged(); - //updateMappingsSVG(); } @@ -528,7 +528,6 @@ function loadFontFromArrayBuffer (arrayBuffer, options={}) { // draw mappings SVG mappingsChanged(0); - //updateMappingsSVG(); updateRenders(); } @@ -965,9 +964,29 @@ function mappingsChanged(mode) { const locations = [GLOBAL.current, ...GLOBAL.instances]; [...locations, ...gridLocations].forEach(location => instantiateLocation(sf, location)); + // returns true or false, depending on whether the two user locations are equal + // - true if loc0 and loc1 are equal when simple-normalized + // - false if loc0 and loc1 are not equal when simple-normalized + // - axisIds is an optional array of axes to check (default is to check all axes) + // - loc0 and loc1 are arrays of equal length + function locationsAreEqual(loc0, loc1, axisIds) { + if (loc0.length !== loc1.length) + return false; + + if (!axisIds) + axisIds = [...Array(loc0.length).keys()]; + + let equal = true; + for (let a=0; a { + GLOBAL.instances.forEach(location => { + const [svgX0, svgY0] = svgCoordsFromAxisCoords(location[0]); + const [svgX1, svgY1] = svgCoordsFromAxisCoords(location[1]); const elInstance0 = SVG("g"), elInstance1 = SVG("g"); elInstance0.innerHTML = svgCurrentLocation; - elInstance0.setPosition(svgCoordsFromAxisCoords(instance[0])); - elInstance0.style.color = "red"; + elInstance0.setPosition([svgX0, svgY0]); + elInstance0.style.opacity = 0.9; + elInstance0.style.color = instanceColor; elInstance1.innerHTML = svgCurrentLocation; - elInstance1.setPosition(svgCoordsFromAxisCoords(instance[1])); + elInstance1.setPosition([svgX1, svgY1]); elInstance1.style.opacity = 0.4; - elInstance1.style.color = "red"; - + elInstance1.style.color = instanceColor; + GLOBAL.svgEl.append(elInstance1, elInstance0); + + // are the input and output equal in this projection? (need to allow for normalization rounding) + if (locationsAreEqual(location[0], location[1], visibleAxisIds)) { + GLOBAL.svgEl.append(elInstance0); + } + else { + GLOBAL.svgEl.append(elInstance1, elInstance0, svgArrow({x1: svgX0, y1: svgY0, x2: svgX1, y2: svgY1, tipLen: 7, tipWid: 7, strokeWidth: 1, color: instanceColor})); // add an arrow + } }); // draw the mappings @@ -1020,8 +1049,8 @@ function mappingsChanged(mode) { elInput.classList.add("input", "location"); elOutput.classList.add("output", "location"); - elInput.innerHTML = svgArrowTail; - elOutput.innerHTML = svgArrowHead; + elInput.innerHTML = svgMapping // svgArrowTail; + elOutput.innerHTML = svgMapping // svgArrowHead; elInput.onmousedown = mappingMouseDown; elOutput.onmousedown = mappingMouseDown; @@ -1033,10 +1062,13 @@ function mappingsChanged(mode) { const svgCoordsTo = svgCoordsFromAxisCoords(mapping[1]); elInput.setPosition(svgCoordsFrom); + elInput.style.opacity = 0.4; elOutput.setPosition(svgCoordsTo); + elOutput.style.opacity = 0.4; // draw the arrow - const arrowSvg = svgArrow({index: m, x1: svgCoordsFrom[0], y1: svgCoordsFrom[1], x2: svgCoordsTo[0], y2: svgCoordsTo[1]}); + const arrowSvg = svgArrow({index: m, x1: svgCoordsFrom[0], y1: svgCoordsFrom[1], x2: svgCoordsTo[0], y2: svgCoordsTo[1], tipLen: 7, tipWid: 7, strokeWidth: 2}); + arrowSvg.classList.add("mapping"); // add them all to the SVG element GLOBAL.svgEl.append(arrowSvg, elInput, elOutput); @@ -1047,19 +1079,26 @@ function mappingsChanged(mode) { // - render #1 first since it may be underneath #0 (which needs mouse events) const elCurrent0 = SVG("g"), elCurrent1 = SVG("g"); + const svgCoordsFrom = svgCoordsFromAxisCoords(GLOBAL.current[0]); + const svgCoordsTo = svgCoordsFromAxisCoords(GLOBAL.current[1]); + elCurrent0.innerHTML = svgCurrentLocation; - elCurrent0.setPosition(svgCoordsFromAxisCoords(GLOBAL.current[0])); + elCurrent0.setPosition(svgCoordsFrom); + elCurrent0.style.opacity = 0.9; elCurrent0.classList.add("current", "location"); elCurrent0.style.color = "var(--currentLocationColor)"; elCurrent0.dataset.index = -1; elCurrent0.onmousedown = mappingMouseDown; elCurrent1.innerHTML = svgCurrentLocation; - elCurrent1.setPosition(svgCoordsFromAxisCoords(GLOBAL.current[1])); + elCurrent1.setPosition(svgCoordsTo); elCurrent1.style.opacity = 0.4; elCurrent1.style.color = "var(--currentLocationColor)"; - GLOBAL.svgEl.append(elCurrent1, elCurrent0); // order is important, since we must be able to click on the [0] version if they overlap + // draw the arrow + const arrowSvg = svgArrow({index: -1, x1: svgCoordsFrom[0], y1: svgCoordsFrom[1], x2: svgCoordsTo[0], y2: svgCoordsTo[1], tipLen: 7, tipWid: 7, strokeWidth: 1, color: "var(--currentLocationColor)"}); + + GLOBAL.svgEl.append(elCurrent1, elCurrent0, arrowSvg); // order is important, since we must be able to click on the [0] version if they overlap }