From f716d1a8344053f3774280be3e6e93b195c180ef Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 13 Nov 2023 15:22:42 +0300 Subject: [PATCH 01/29] Rotary-like control for angles --- .../client/web-components/rotary-control.js | 108 ++++++++++++++++++ src/fontra/client/web-components/ui-form.js | 29 +++++ .../views/editor/panel-selection-info.js | 2 +- 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/fontra/client/web-components/rotary-control.js diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js new file mode 100644 index 000000000..6172b1383 --- /dev/null +++ b/src/fontra/client/web-components/rotary-control.js @@ -0,0 +1,108 @@ +import * as html from "../core/html-utils.js"; +import { subVectors } from "../core/vector.js"; + +export class RotaryControl extends html.UnlitElement { + static styles = ` + .knob { + width: 5rem; + height: 5rem; + border-radius: 50%; + margin: 0.3rem; + background: #e3e3e3; + position: relative; + } + + .thumb { + width: 0.2rem; + height: 100%; + left: 50%; + position: absolute; + margin-left: -0.1rem; + background: #d7d7d7; + } + + .dot { + width: 0.2rem; + height: 0.2rem; + background: black; + border-radius: 50%; + margin-top: 5px; + background: #d92020; + } + `; + + constructor() { + super(); + this.onChangeCallback = () => {}; + } + + set value(value) { + this._value = value; + if (this.thumb) { + this.thumb.style.transform = `rotate(${this.value}deg)`; + } + } + + get value() { + return this._value; + } + + render() { + return (this.knob = html.div( + { + class: "knob", + onmousedown: (event) => { + this.startAngle = this.value; + const origin = originOfElement(this.knob); + const target = { x: event.clientX, y: event.clientY }; + const sub = subVectors(target, origin); + const deg = toDegrees(Math.atan2(sub.y, sub.x)); + this.angleWhenDragStart = deg; + }, + onmouseup: (event) => { + this.startAngle = undefined; + this.angleWhenDragStart = undefined; + }, + onmousemove: (event) => { + if (this.startAngle === undefined) { + return; + } + const origin = originOfElement(this.knob); + const target = { x: event.clientX, y: event.clientY }; + const sub = subVectors(target, origin); + const deg = toDegrees(Math.atan2(sub.y, sub.x)); + const diff = deg - this.angleWhenDragStart; + this.value = this.startAngle + diff; + this.onChangeCallback(this.value); + }, + }, + [ + (this.thumb = html.div( + { + class: "thumb", + style: `transform: rotate(${this.value}deg);`, + }, + [ + html.div({ + class: "dot", + }), + ] + )), + ] + )); + } +} + +function originOfElement(element) { + const boundingClientRect = element.getBoundingClientRect(); + return { + x: boundingClientRect.x + boundingClientRect.width / 2, + y: boundingClientRect.y + boundingClientRect.height / 2, + }; +} + +function toDegrees(radians) { + return (radians * 180) / Math.PI; +} + +customElements.define("rotary-control", RotaryControl); diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 7eee9b8fa..40e7fc05c 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -3,6 +3,7 @@ import { SimpleElement } from "../core/html-utils.js"; import { QueueIterator } from "../core/queue-iterator.js"; import { hyphenatedToCamelCase } from "../core/utils.js"; import { RangeSlider } from "/web-components/range-slider.js"; +import { RotaryControl } from "/web-components/rotary-control.js"; export class Form extends SimpleElement { static styles = ` @@ -186,6 +187,34 @@ export class Form extends SimpleElement { valueElement.appendChild(inputElement); } + _addEditAngle(valueElement, fieldItem) { + const inputElement = document.createElement("input"); + inputElement.type = "number"; + inputElement.value = fieldItem.value; + + inputElement.min = 0; + inputElement.max = 360; + inputElement.step = "any"; + + inputElement.disabled = fieldItem.disabled; + inputElement.onchange = (event) => { + let value = parseFloat(inputElement.value); + this._fieldChanging(fieldItem.key, value); + }; + this._fieldGetters[fieldItem.key] = () => inputElement.value; + this._fieldSetters[fieldItem.key] = (value) => (inputElement.value = value); + valueElement.appendChild(inputElement); + valueElement.appendChild( + html.createDomElement("rotary-control", { + value: fieldItem.value, + onChangeCallback: (value) => { + inputElement.value = value; + this._fieldChanging(fieldItem.key, value); + }, + }) + ); + } + _addEditNumberSlider(valueElement, fieldItem) { const rangeElement = new RangeSlider(); rangeElement.value = fieldItem.value; diff --git a/src/fontra/views/editor/panel-selection-info.js b/src/fontra/views/editor/panel-selection-info.js index 5437164a3..f92124ad3 100644 --- a/src/fontra/views/editor/panel-selection-info.js +++ b/src/fontra/views/editor/panel-selection-info.js @@ -226,7 +226,7 @@ export default class SelectionInfoPanel extends Panel { ]) { const value = component.transformation[key]; formContents.push({ - type: "edit-number", + type: key === "rotation" ? "edit-angle" : "edit-number", key: componentKey("transformation", key), label: key, value: value, From 922e6906c16a42c94f301404455ce2a36a17e313 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Tue, 14 Nov 2023 14:30:05 +0300 Subject: [PATCH 02/29] Update knob style --- .../client/web-components/rotary-control.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 6172b1383..e56333132 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -13,21 +13,23 @@ export class RotaryControl extends html.UnlitElement { } .thumb { - width: 0.2rem; - height: 100%; + width: 0.4rem; + height: 90%; left: 50%; position: absolute; - margin-left: -0.1rem; - background: #d7d7d7; + margin-left: -0.2rem; + background: #ccc; + top: 5%; + border-radius: 10px; } .dot { - width: 0.2rem; - height: 0.2rem; - background: black; + width: 0.3rem; + height: 0.3rem; border-radius: 50%; - margin-top: 5px; - background: #d92020; + margin-top: 0.05rem; + background: #d23737; + margin-left: 0.05rem; } `; From d1caa6852d5401d71d0b9c15ea63a31da6f3f4ba Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Tue, 14 Nov 2023 15:47:15 +0300 Subject: [PATCH 03/29] Rotary control improvements, Add demo panel for rotary control --- .../client/web-components/rotary-control.js | 137 +++++++++++------- src/fontra/views/editor/editor.js | 12 ++ 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index e56333132..1c2e789f8 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -3,33 +3,44 @@ import { subVectors } from "../core/vector.js"; export class RotaryControl extends html.UnlitElement { static styles = ` + :host { + --knob-size: 2rem; + --thumb-width: 0.2rem; + } + .knob { - width: 5rem; - height: 5rem; + width: var(--knob-size); + height: var(--knob-size); border-radius: 50%; - margin: 0.3rem; background: #e3e3e3; position: relative; } .thumb { - width: 0.4rem; - height: 90%; + width: var(--thumb-width); + height: var(--knob-size); left: 50%; position: absolute; - margin-left: -0.2rem; + margin-left: calc((var(--thumb-width) / 2) * -1); background: #ccc; - top: 5%; border-radius: 10px; } .dot { - width: 0.3rem; - height: 0.3rem; + width: var(--thumb-width); + height: var(--thumb-width); border-radius: 50%; - margin-top: 0.05rem; background: #d23737; - margin-left: 0.05rem; + } + + .rotary-control { + display: flex; + gap: 0.4rem; + margin: 0.2rem; + } + + .number-input { + width: 4rem; } `; @@ -43,6 +54,9 @@ export class RotaryControl extends html.UnlitElement { if (this.thumb) { this.thumb.style.transform = `rotate(${this.value}deg)`; } + if (this.numberInput) { + this.numberInput.value = this.value; + } } get value() { @@ -50,48 +64,65 @@ export class RotaryControl extends html.UnlitElement { } render() { - return (this.knob = html.div( - { - class: "knob", - onmousedown: (event) => { - this.startAngle = this.value; - const origin = originOfElement(this.knob); - const target = { x: event.clientX, y: event.clientY }; - const sub = subVectors(target, origin); - const deg = toDegrees(Math.atan2(sub.y, sub.x)); - this.angleWhenDragStart = deg; - }, - onmouseup: (event) => { - this.startAngle = undefined; - this.angleWhenDragStart = undefined; - }, - onmousemove: (event) => { - if (this.startAngle === undefined) { - return; + return html.div({ class: "rotary-control" }, [ + (this.numberInput = html.input({ + class: "number-input", + type: "number", + step: "any", + required: "required", + min: 0, + max: 360, + value: this.value, + onchange: (event) => { + if (event.target.reportValidity()) { + this.value = event.target.valueAsNumber; } - const origin = originOfElement(this.knob); - const target = { x: event.clientX, y: event.clientY }; - const sub = subVectors(target, origin); - const deg = toDegrees(Math.atan2(sub.y, sub.x)); - const diff = deg - this.angleWhenDragStart; - this.value = this.startAngle + diff; - this.onChangeCallback(this.value); }, - }, - [ - (this.thumb = html.div( - { - class: "thumb", - style: `transform: rotate(${this.value}deg);`, + })), + (this.knob = html.div( + { + class: "knob", + onmousedown: (event) => { + this.startAngle = this.value; + const origin = originOfElement(this.knob); + const target = { x: event.clientX, y: event.clientY }; + const deg = angle(origin, target); + this.angleWhenDragStart = deg; + }, + onmouseup: (event) => { + this.startAngle = undefined; + this.angleWhenDragStart = undefined; + }, + onmousemove: (event) => { + if (this.startAngle === undefined) { + return; + } + const origin = originOfElement(this.knob); + const target = { x: event.clientX, y: event.clientY }; + const diff = angle(origin, target) - this.angleWhenDragStart; + let value = this.startAngle + diff; + if (value < 0) { + value = 270 + (90 + value); + } + this.value = value; + this.onChangeCallback(this.value); }, - [ - html.div({ - class: "dot", - }), - ] - )), - ] - )); + }, + [ + (this.thumb = html.div( + { + class: "thumb", + style: `transform: rotate(${this.value}deg);`, + }, + [ + html.div({ + class: "dot", + }), + ] + )), + ] + )), + ]); } } @@ -107,4 +138,10 @@ function toDegrees(radians) { return (radians * 180) / Math.PI; } +function angle(origin, target) { + const sub = subVectors(target, origin); + const deg = toDegrees(Math.atan2(sub.y, sub.x)); + return deg; +} + customElements.define("rotary-control", RotaryControl); diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 536b8622e..960cb7b5d 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -62,6 +62,7 @@ import { themeController } from "/core/theme-settings.js"; import { MenuItemDivider, showMenu } from "/web-components/menu-panel.js"; import { dialog, dialogSetup } from "/web-components/modal-dialog.js"; import { parsePluginBasePath } from "/web-components/plugin-manager.js"; +import { RotaryControl } from "/web-components/rotary-control.js"; import DesignspaceNavigationPanel from "./panel-designspace-navigation.js"; import GlyphSearchPanel from "./panel-glyph-search.js"; @@ -76,6 +77,16 @@ const MIN_CANVAS_SPACE = 200; const PASTE_BEHAVIOR_REPLACE = "replace"; const PASTE_BEHAVIOR_ADD = "add"; +class RotaryControlDemoPanel extends Panel { + identifier = "rotary-control-demo"; + iconPath = "/images/info.svg"; + + getContentElement() { + return html.div({}, [html.createDomElement("rotary-control", { value: 0 })]); + } +} +customElements.define("panel-rotary-control", RotaryControlDemoPanel); + export class EditorController { static async fromWebSocket() { const pathItems = window.location.pathname.split("/").slice(3); @@ -474,6 +485,7 @@ export class EditorController { this.addSidebarPanel(new UserSettingsPanel(this), "left"); this.addSidebarPanel(new ReferenceFontPanel(this), "left"); this.addSidebarPanel(new SelectionInfoPanel(this), "right"); + this.addSidebarPanel(new RotaryControlDemoPanel(this), "right"); // Upon reload, the "animating" class may still be set (why?), so remove it for (const sidebarContainer of document.querySelectorAll(".sidebar-container")) { From 3aeecddfcddf5093230deb7d1250c49b5c960224 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Tue, 14 Nov 2023 20:18:59 +0300 Subject: [PATCH 04/29] Implement wheel for knob, fix minus degree glitch --- .../client/web-components/rotary-control.js | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 1c2e789f8..cff08a405 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -1,11 +1,12 @@ import * as html from "../core/html-utils.js"; +import { round } from "../core/utils.js"; import { subVectors } from "../core/vector.js"; export class RotaryControl extends html.UnlitElement { static styles = ` :host { --knob-size: 2rem; - --thumb-width: 0.2rem; + --thumb-size: calc(var(--knob-size) / 5); } .knob { @@ -13,24 +14,16 @@ export class RotaryControl extends html.UnlitElement { height: var(--knob-size); border-radius: 50%; background: #e3e3e3; - position: relative; + display: flex; + justify-content: center; } .thumb { - width: var(--thumb-width); - height: var(--knob-size); - left: 50%; - position: absolute; - margin-left: calc((var(--thumb-width) / 2) * -1); - background: #ccc; - border-radius: 10px; - } - - .dot { - width: var(--thumb-width); - height: var(--thumb-width); + width: var(--thumb-size); + height: var(--thumb-size); + background: rgb(89, 89, 89); border-radius: 50%; - background: #d23737; + margin-top: calc(var(--knob-size) / 8); } .rotary-control { @@ -40,19 +33,41 @@ export class RotaryControl extends html.UnlitElement { } .number-input { - width: 4rem; + width: 5rem; } `; constructor() { super(); this.onChangeCallback = () => {}; + + document.body.addEventListener("mousemove", (event) => { + if (this.startAngle === undefined) { + return; + } + const origin = originOfElement(this.knob); + const target = { x: event.clientX, y: event.clientY }; + const diff = angle(origin, target) - this.angleWhenDragStart; + let value = this.startAngle + diff; + this.value = round(value); + this.onChangeCallback(this.value); + }); + + document.body.addEventListener("mouseup", () => { + this.startAngle = undefined; + this.angleWhenDragStart = undefined; + }); } set value(value) { + if (value < 0) { + // minus 90 degrees should be considered as 270 + value = 360 + value; + } + value = value % 360; this._value = value; - if (this.thumb) { - this.thumb.style.transform = `rotate(${this.value}deg)`; + if (this.knob) { + this.knob.style.transform = `rotate(${this.value}deg)`; } if (this.numberInput) { this.numberInput.value = this.value; @@ -81,7 +96,15 @@ export class RotaryControl extends html.UnlitElement { })), (this.knob = html.div( { + onwheel: (event) => { + const delta = + Math.abs(event.deltaX) > Math.abs(event.deltaY) + ? -1 * event.deltaX + : event.deltaY; + this.value = this.value + delta; + }, class: "knob", + style: `transform: rotate(${this.value}deg);`, onmousedown: (event) => { this.startAngle = this.value; const origin = originOfElement(this.knob); @@ -89,38 +112,8 @@ export class RotaryControl extends html.UnlitElement { const deg = angle(origin, target); this.angleWhenDragStart = deg; }, - onmouseup: (event) => { - this.startAngle = undefined; - this.angleWhenDragStart = undefined; - }, - onmousemove: (event) => { - if (this.startAngle === undefined) { - return; - } - const origin = originOfElement(this.knob); - const target = { x: event.clientX, y: event.clientY }; - const diff = angle(origin, target) - this.angleWhenDragStart; - let value = this.startAngle + diff; - if (value < 0) { - value = 270 + (90 + value); - } - this.value = value; - this.onChangeCallback(this.value); - }, }, - [ - (this.thumb = html.div( - { - class: "thumb", - style: `transform: rotate(${this.value}deg);`, - }, - [ - html.div({ - class: "dot", - }), - ] - )), - ] + [html.div({ class: "thumb" })] )), ]); } @@ -139,8 +132,15 @@ function toDegrees(radians) { } function angle(origin, target) { - const sub = subVectors(target, origin); - const deg = toDegrees(Math.atan2(sub.y, sub.x)); + const vec = subVectors(target, origin); + let deg = toDegrees(Math.atan2(vec.y, vec.x)); + + // the north of the target should be 0 + deg += 90; + + if (deg < 0) { + deg = 270 + (90 + deg); + } return deg; } From 74698ed8435e82a2070e82817e008fb3d3d78d8c Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Tue, 14 Nov 2023 20:36:23 +0300 Subject: [PATCH 05/29] Delete number input in rotary control --- .../client/web-components/rotary-control.js | 24 ++----------------- src/fontra/client/web-components/ui-form.js | 18 +++++++------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index cff08a405..bc9e849cc 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -5,7 +5,7 @@ import { subVectors } from "../core/vector.js"; export class RotaryControl extends html.UnlitElement { static styles = ` :host { - --knob-size: 2rem; + --knob-size: 1.4rem; --thumb-size: calc(var(--knob-size) / 5); } @@ -31,10 +31,6 @@ export class RotaryControl extends html.UnlitElement { gap: 0.4rem; margin: 0.2rem; } - - .number-input { - width: 5rem; - } `; constructor() { @@ -69,9 +65,6 @@ export class RotaryControl extends html.UnlitElement { if (this.knob) { this.knob.style.transform = `rotate(${this.value}deg)`; } - if (this.numberInput) { - this.numberInput.value = this.value; - } } get value() { @@ -80,20 +73,6 @@ export class RotaryControl extends html.UnlitElement { render() { return html.div({ class: "rotary-control" }, [ - (this.numberInput = html.input({ - class: "number-input", - type: "number", - step: "any", - required: "required", - min: 0, - max: 360, - value: this.value, - onchange: (event) => { - if (event.target.reportValidity()) { - this.value = event.target.valueAsNumber; - } - }, - })), (this.knob = html.div( { onwheel: (event) => { @@ -102,6 +81,7 @@ export class RotaryControl extends html.UnlitElement { ? -1 * event.deltaX : event.deltaY; this.value = this.value + delta; + this.onChangeCallback(this.value); }, class: "knob", style: `transform: rotate(${this.value}deg);`, diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 40e7fc05c..d15dc4efe 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -203,15 +203,17 @@ export class Form extends SimpleElement { }; this._fieldGetters[fieldItem.key] = () => inputElement.value; this._fieldSetters[fieldItem.key] = (value) => (inputElement.value = value); - valueElement.appendChild(inputElement); valueElement.appendChild( - html.createDomElement("rotary-control", { - value: fieldItem.value, - onChangeCallback: (value) => { - inputElement.value = value; - this._fieldChanging(fieldItem.key, value); - }, - }) + html.div({ style: "display: flex" }, [ + inputElement, + html.createDomElement("rotary-control", { + value: fieldItem.value, + onChangeCallback: (value) => { + inputElement.value = value; + this._fieldChanging(fieldItem.key, value); + }, + }), + ]) ); } From 2f0e4f8e874c92b3d85f420e63d69fe955216558 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Wed, 15 Nov 2023 17:34:48 +0300 Subject: [PATCH 06/29] Rotary control should dispatch values between -180, 180 --- .../client/web-components/rotary-control.js | 13 +++++++---- src/fontra/client/web-components/ui-form.js | 23 +++++++++---------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index bc9e849cc..3a412530c 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -46,7 +46,7 @@ export class RotaryControl extends html.UnlitElement { const diff = angle(origin, target) - this.angleWhenDragStart; let value = this.startAngle + diff; this.value = round(value); - this.onChangeCallback(this.value); + this.dispatch(this.value); }); document.body.addEventListener("mouseup", () => { @@ -57,7 +57,6 @@ export class RotaryControl extends html.UnlitElement { set value(value) { if (value < 0) { - // minus 90 degrees should be considered as 270 value = 360 + value; } value = value % 360; @@ -71,6 +70,13 @@ export class RotaryControl extends html.UnlitElement { return this._value; } + dispatch(value) { + if (value > 180) { + value -= 360; + } + this.onChangeCallback(value); + } + render() { return html.div({ class: "rotary-control" }, [ (this.knob = html.div( @@ -81,7 +87,7 @@ export class RotaryControl extends html.UnlitElement { ? -1 * event.deltaX : event.deltaY; this.value = this.value + delta; - this.onChangeCallback(this.value); + this.dispatch(this.value); }, class: "knob", style: `transform: rotate(${this.value}deg);`, @@ -115,7 +121,6 @@ function angle(origin, target) { const vec = subVectors(target, origin); let deg = toDegrees(Math.atan2(vec.y, vec.x)); - // the north of the target should be 0 deg += 90; if (deg < 0) { diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index d15dc4efe..4779f3e42 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -192,28 +192,27 @@ export class Form extends SimpleElement { inputElement.type = "number"; inputElement.value = fieldItem.value; - inputElement.min = 0; - inputElement.max = 360; inputElement.step = "any"; inputElement.disabled = fieldItem.disabled; inputElement.onchange = (event) => { let value = parseFloat(inputElement.value); this._fieldChanging(fieldItem.key, value); + rotaryControl.value = value; }; + + const rotaryControl = html.createDomElement("rotary-control", { + value: fieldItem.value, + onChangeCallback: (value) => { + inputElement.value = value; + this._fieldChanging(fieldItem.key, value); + }, + }); + this._fieldGetters[fieldItem.key] = () => inputElement.value; this._fieldSetters[fieldItem.key] = (value) => (inputElement.value = value); valueElement.appendChild( - html.div({ style: "display: flex" }, [ - inputElement, - html.createDomElement("rotary-control", { - value: fieldItem.value, - onChangeCallback: (value) => { - inputElement.value = value; - this._fieldChanging(fieldItem.key, value); - }, - }), - ]) + html.div({ style: "display: flex" }, [inputElement, rotaryControl]) ); } From 33605b71c5589897f5e0ce6b75c3e7c3970b63ac Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 21:34:30 +0300 Subject: [PATCH 07/29] Handle mousemove event in an overlay, delete atan function, use distance instead --- .../client/web-components/rotary-control.js | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 3a412530c..a6e4c69b9 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -1,6 +1,6 @@ import * as html from "../core/html-utils.js"; import { round } from "../core/utils.js"; -import { subVectors } from "../core/vector.js"; +import { distance, subVectors } from "../core/vector.js"; export class RotaryControl extends html.UnlitElement { static styles = ` @@ -31,35 +31,27 @@ export class RotaryControl extends html.UnlitElement { gap: 0.4rem; margin: 0.2rem; } + + .overlay { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1; + } `; constructor() { super(); this.onChangeCallback = () => {}; - - document.body.addEventListener("mousemove", (event) => { - if (this.startAngle === undefined) { - return; - } - const origin = originOfElement(this.knob); - const target = { x: event.clientX, y: event.clientY }; - const diff = angle(origin, target) - this.angleWhenDragStart; - let value = this.startAngle + diff; - this.value = round(value); - this.dispatch(this.value); - }); - - document.body.addEventListener("mouseup", () => { - this.startAngle = undefined; - this.angleWhenDragStart = undefined; - }); } set value(value) { + value %= 360; if (value < 0) { value = 360 + value; } - value = value % 360; this._value = value; if (this.knob) { this.knob.style.transform = `rotate(${this.value}deg)`; @@ -71,12 +63,47 @@ export class RotaryControl extends html.UnlitElement { } dispatch(value) { + value %= 360; if (value > 180) { value -= 360; } this.onChangeCallback(value); } + attachOverlay() { + const overlay = html.div( + { + class: "overlay", + onmouseup: () => { + this.coordinatesDragBegin = undefined; + this.angleWhenDragStart = undefined; + this.shadowRoot.removeChild(overlay); + }, + onmousemove: (event) => { + if (this.coordinatesDragBegin === undefined) { + return; + } + const diff = distance(this.coordinatesDragBegin, { + x: event.clientX, + y: event.clientY, + }); + let value = this.angleWhenDragStart + diff; + if ( + event.clientX < this.coordinatesDragBegin.x || + event.clientY < this.coordinatesDragBegin.y + ) { + value *= -1; + } + this.value = round(value); + this.dispatch(this.value); + }, + }, + [] + ); + this.overlay = overlay; + this.shadowRoot.appendChild(overlay); + } + render() { return html.div({ class: "rotary-control" }, [ (this.knob = html.div( @@ -92,11 +119,10 @@ export class RotaryControl extends html.UnlitElement { class: "knob", style: `transform: rotate(${this.value}deg);`, onmousedown: (event) => { - this.startAngle = this.value; - const origin = originOfElement(this.knob); - const target = { x: event.clientX, y: event.clientY }; - const deg = angle(origin, target); - this.angleWhenDragStart = deg; + this.coordinatesDragBegin = { x: event.clientX, y: event.clientY }; + this.angleWhenDragStart = this.value; + event.preventDefault(); + this.attachOverlay(); }, }, [html.div({ class: "thumb" })] @@ -117,16 +143,4 @@ function toDegrees(radians) { return (radians * 180) / Math.PI; } -function angle(origin, target) { - const vec = subVectors(target, origin); - let deg = toDegrees(Math.atan2(vec.y, vec.x)); - - deg += 90; - - if (deg < 0) { - deg = 270 + (90 + deg); - } - return deg; -} - customElements.define("rotary-control", RotaryControl); From b79b1cab5a7ca64e1c3f41caed95fbe0728a8c75 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 21:37:00 +0300 Subject: [PATCH 08/29] Delete not necessary modus --- src/fontra/client/web-components/rotary-control.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index a6e4c69b9..ac4c619c4 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -63,7 +63,6 @@ export class RotaryControl extends html.UnlitElement { } dispatch(value) { - value %= 360; if (value > 180) { value -= 360; } From 0f5b5e550d008c6b2282629e60b8e8475d5511c3 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 21:37:52 +0300 Subject: [PATCH 09/29] Delete unused functions --- src/fontra/client/web-components/rotary-control.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index ac4c619c4..935791780 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -130,16 +130,4 @@ export class RotaryControl extends html.UnlitElement { } } -function originOfElement(element) { - const boundingClientRect = element.getBoundingClientRect(); - return { - x: boundingClientRect.x + boundingClientRect.width / 2, - y: boundingClientRect.y + boundingClientRect.height / 2, - }; -} - -function toDegrees(radians) { - return (radians * 180) / Math.PI; -} - customElements.define("rotary-control", RotaryControl); From 4d4310fdaac62507e928451f5a462ecd91fcd2e0 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 21:43:35 +0300 Subject: [PATCH 10/29] Dispatch oppositewise angle --- src/fontra/client/web-components/rotary-control.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 935791780..95886a202 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -66,7 +66,7 @@ export class RotaryControl extends html.UnlitElement { if (value > 180) { value -= 360; } - this.onChangeCallback(value); + this.onChangeCallback(value * -1); } attachOverlay() { @@ -88,8 +88,8 @@ export class RotaryControl extends html.UnlitElement { }); let value = this.angleWhenDragStart + diff; if ( - event.clientX < this.coordinatesDragBegin.x || - event.clientY < this.coordinatesDragBegin.y + event.clientX < this.coordinatesDragBegin.x + // || event.clientY < this.coordinatesDragBegin.y ) { value *= -1; } From 56956c446f3f88e3dba8bc82915021a2142119fe Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 21:55:45 +0300 Subject: [PATCH 11/29] Delete trigonometric conversions --- .../client/web-components/rotary-control.js | 28 +++++-------------- src/fontra/client/web-components/ui-form.js | 4 +-- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 95886a202..fababaf0e 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -1,6 +1,5 @@ import * as html from "../core/html-utils.js"; import { round } from "../core/utils.js"; -import { distance, subVectors } from "../core/vector.js"; export class RotaryControl extends html.UnlitElement { static styles = ` @@ -48,10 +47,6 @@ export class RotaryControl extends html.UnlitElement { } set value(value) { - value %= 360; - if (value < 0) { - value = 360 + value; - } this._value = value; if (this.knob) { this.knob.style.transform = `rotate(${this.value}deg)`; @@ -63,10 +58,7 @@ export class RotaryControl extends html.UnlitElement { } dispatch(value) { - if (value > 180) { - value -= 360; - } - this.onChangeCallback(value * -1); + this.onChangeCallback(value); } attachOverlay() { @@ -82,18 +74,12 @@ export class RotaryControl extends html.UnlitElement { if (this.coordinatesDragBegin === undefined) { return; } - const diff = distance(this.coordinatesDragBegin, { - x: event.clientX, - y: event.clientY, - }); - let value = this.angleWhenDragStart + diff; - if ( - event.clientX < this.coordinatesDragBegin.x - // || event.clientY < this.coordinatesDragBegin.y - ) { - value *= -1; - } - this.value = round(value); + const diffX = event.clientX - this.coordinatesDragBegin.x; + const diffY = event.clientY - this.coordinatesDragBegin.y; + let value = + this.angleWhenDragStart + + (Math.abs(diffX) > Math.abs(diffY) ? diffX : diffY); + this.value = value; this.dispatch(this.value); }, }, diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 4779f3e42..4b5b25d8b 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -204,8 +204,8 @@ export class Form extends SimpleElement { const rotaryControl = html.createDomElement("rotary-control", { value: fieldItem.value, onChangeCallback: (value) => { - inputElement.value = value; - this._fieldChanging(fieldItem.key, value); + inputElement.value = value * -1; + this._fieldChanging(fieldItem.key, value * -1); }, }); From fa554a584bff0a99d996204f76eddbefa3b22433 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 17 Nov 2023 22:02:36 +0300 Subject: [PATCH 12/29] Let -> const --- src/fontra/client/web-components/rotary-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index fababaf0e..87c7c586e 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -76,7 +76,7 @@ export class RotaryControl extends html.UnlitElement { } const diffX = event.clientX - this.coordinatesDragBegin.x; const diffY = event.clientY - this.coordinatesDragBegin.y; - let value = + const value = this.angleWhenDragStart + (Math.abs(diffX) > Math.abs(diffY) ? diffX : diffY); this.value = value; From 06efd310d6422d78c15195ff37e0c959c4133028 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 20 Nov 2023 17:51:14 +0300 Subject: [PATCH 13/29] Add dragBegin dragEnd to the dispatched event --- .../client/web-components/rotary-control.js | 24 +++++++++++++++---- src/fontra/client/web-components/ui-form.js | 8 ++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 87c7c586e..01c206dc8 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -1,5 +1,4 @@ import * as html from "../core/html-utils.js"; -import { round } from "../core/utils.js"; export class RotaryControl extends html.UnlitElement { static styles = ` @@ -57,8 +56,20 @@ export class RotaryControl extends html.UnlitElement { return this._value; } - dispatch(value) { - this.onChangeCallback(value); + dispatch() { + const event = { value: this.value }; + + if (this.dragBegin) { + event.dragBegin = true; + this.dragBegin = false; + } + + if (this.dragEnd) { + event.dragEnd = true; + this.dragEnd = false; + } + + this.onChangeCallback(event); } attachOverlay() { @@ -69,6 +80,8 @@ export class RotaryControl extends html.UnlitElement { this.coordinatesDragBegin = undefined; this.angleWhenDragStart = undefined; this.shadowRoot.removeChild(overlay); + this.dragEnd = true; + this.dispatch(); }, onmousemove: (event) => { if (this.coordinatesDragBegin === undefined) { @@ -80,7 +93,7 @@ export class RotaryControl extends html.UnlitElement { this.angleWhenDragStart + (Math.abs(diffX) > Math.abs(diffY) ? diffX : diffY); this.value = value; - this.dispatch(this.value); + this.dispatch(); }, }, [] @@ -99,13 +112,14 @@ export class RotaryControl extends html.UnlitElement { ? -1 * event.deltaX : event.deltaY; this.value = this.value + delta; - this.dispatch(this.value); + this.dispatch(); }, class: "knob", style: `transform: rotate(${this.value}deg);`, onmousedown: (event) => { this.coordinatesDragBegin = { x: event.clientX, y: event.clientY }; this.angleWhenDragStart = this.value; + this.dragBegin = true; event.preventDefault(); this.attachOverlay(); }, diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 4b5b25d8b..eabd89462 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -203,9 +203,11 @@ export class Form extends SimpleElement { const rotaryControl = html.createDomElement("rotary-control", { value: fieldItem.value, - onChangeCallback: (value) => { - inputElement.value = value * -1; - this._fieldChanging(fieldItem.key, value * -1); + onChangeCallback: (event) => { + const value = event.value * -1; + inputElement.value = value; + this._fieldChanging(fieldItem.key, value); + console.log(event); }, }); From 128004b832141b2370a158d5f2d12471f9dcd1c4 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Wed, 29 Nov 2023 14:41:21 +0300 Subject: [PATCH 14/29] Delete onwheel, use dispatchEvent for continuous changes --- .../client/web-components/rotary-control.js | 8 ------- src/fontra/client/web-components/ui-form.js | 21 +++++++++++++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 01c206dc8..90cd32e15 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -106,14 +106,6 @@ export class RotaryControl extends html.UnlitElement { return html.div({ class: "rotary-control" }, [ (this.knob = html.div( { - onwheel: (event) => { - const delta = - Math.abs(event.deltaX) > Math.abs(event.deltaY) - ? -1 * event.deltaX - : event.deltaY; - this.value = this.value + delta; - this.dispatch(); - }, class: "knob", style: `transform: rotate(${this.value}deg);`, onmousedown: (event) => { diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index eabd89462..c673db15b 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -3,7 +3,7 @@ import { SimpleElement } from "../core/html-utils.js"; import { QueueIterator } from "../core/queue-iterator.js"; import { hyphenatedToCamelCase } from "../core/utils.js"; import { RangeSlider } from "/web-components/range-slider.js"; -import { RotaryControl } from "/web-components/rotary-control.js"; +import "/web-components/rotary-control.js"; export class Form extends SimpleElement { static styles = ` @@ -200,14 +200,27 @@ export class Form extends SimpleElement { this._fieldChanging(fieldItem.key, value); rotaryControl.value = value; }; - + let valueStream; const rotaryControl = html.createDomElement("rotary-control", { value: fieldItem.value, onChangeCallback: (event) => { const value = event.value * -1; inputElement.value = value; - this._fieldChanging(fieldItem.key, value); - console.log(event); + if (event.dragBegin) { + valueStream = new QueueIterator(5, true); + this._fieldChanging(fieldItem.key, value, valueStream); + } + if (valueStream) { + valueStream.put(value); + this._dispatchEvent("doChange", { key: fieldItem.key, value: value }); + if (event.dragEnd) { + valueStream.done(); + valueStream = undefined; + this._dispatchEvent("endChange", { key: fieldItem.key }); + } + } else { + this._fieldChanging(fieldItem.key, value, undefined); + } }, }); From 6df491354b5eed62c988bda289e0ec50c33d4cea Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Wed, 29 Nov 2023 15:01:55 +0300 Subject: [PATCH 15/29] Use html.input --- src/fontra/client/web-components/ui-form.js | 23 ++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index c673db15b..8132c0318 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -188,18 +188,17 @@ export class Form extends SimpleElement { } _addEditAngle(valueElement, fieldItem) { - const inputElement = document.createElement("input"); - inputElement.type = "number"; - inputElement.value = fieldItem.value; - - inputElement.step = "any"; - - inputElement.disabled = fieldItem.disabled; - inputElement.onchange = (event) => { - let value = parseFloat(inputElement.value); - this._fieldChanging(fieldItem.key, value); - rotaryControl.value = value; - }; + const inputElement = html.input({ + type: "number", + value: fieldItem.value, + step: "any", + disabled: fieldItem.disabled, + onchange: () => { + let value = parseFloat(inputElement.value); + this._fieldChanging(fieldItem.key, value); + rotaryControl.value = value; + }, + }); let valueStream; const rotaryControl = html.createDomElement("rotary-control", { value: fieldItem.value, From aabda3df297964b266214f179d239f783d9993a9 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 22 Dec 2023 22:37:03 +0300 Subject: [PATCH 16/29] Delete RotaryControlDemoPanel --- src/fontra/views/editor/editor.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 960cb7b5d..5263a1d1d 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -77,16 +77,6 @@ const MIN_CANVAS_SPACE = 200; const PASTE_BEHAVIOR_REPLACE = "replace"; const PASTE_BEHAVIOR_ADD = "add"; -class RotaryControlDemoPanel extends Panel { - identifier = "rotary-control-demo"; - iconPath = "/images/info.svg"; - - getContentElement() { - return html.div({}, [html.createDomElement("rotary-control", { value: 0 })]); - } -} -customElements.define("panel-rotary-control", RotaryControlDemoPanel); - export class EditorController { static async fromWebSocket() { const pathItems = window.location.pathname.split("/").slice(3); @@ -485,7 +475,6 @@ export class EditorController { this.addSidebarPanel(new UserSettingsPanel(this), "left"); this.addSidebarPanel(new ReferenceFontPanel(this), "left"); this.addSidebarPanel(new SelectionInfoPanel(this), "right"); - this.addSidebarPanel(new RotaryControlDemoPanel(this), "right"); // Upon reload, the "animating" class may still be set (why?), so remove it for (const sidebarContainer of document.querySelectorAll(".sidebar-container")) { From c4372effd29099dec5cda24e617a2b5870481778 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 13:12:47 +0300 Subject: [PATCH 17/29] Revert "Delete RotaryControlDemoPanel" This reverts commit aabda3df297964b266214f179d239f783d9993a9. --- src/fontra/views/editor/editor.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 5263a1d1d..960cb7b5d 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -77,6 +77,16 @@ const MIN_CANVAS_SPACE = 200; const PASTE_BEHAVIOR_REPLACE = "replace"; const PASTE_BEHAVIOR_ADD = "add"; +class RotaryControlDemoPanel extends Panel { + identifier = "rotary-control-demo"; + iconPath = "/images/info.svg"; + + getContentElement() { + return html.div({}, [html.createDomElement("rotary-control", { value: 0 })]); + } +} +customElements.define("panel-rotary-control", RotaryControlDemoPanel); + export class EditorController { static async fromWebSocket() { const pathItems = window.location.pathname.split("/").slice(3); @@ -475,6 +485,7 @@ export class EditorController { this.addSidebarPanel(new UserSettingsPanel(this), "left"); this.addSidebarPanel(new ReferenceFontPanel(this), "left"); this.addSidebarPanel(new SelectionInfoPanel(this), "right"); + this.addSidebarPanel(new RotaryControlDemoPanel(this), "right"); // Upon reload, the "animating" class may still be set (why?), so remove it for (const sidebarContainer of document.querySelectorAll(".sidebar-container")) { From d2fe75a8e8e6915d08ba6fa2d7eff679231e7463 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 13:26:45 +0300 Subject: [PATCH 18/29] Angle in number input should be opposite side in knob --- src/fontra/client/web-components/ui-form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 8132c0318..833553b75 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -196,7 +196,7 @@ export class Form extends SimpleElement { onchange: () => { let value = parseFloat(inputElement.value); this._fieldChanging(fieldItem.key, value); - rotaryControl.value = value; + rotaryControl.value = value * -1; }, }); let valueStream; From 186d384f8ac2657769309e7555627fc1cb9a2245 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 13:50:37 +0300 Subject: [PATCH 19/29] Dragging the thumb up should adjust opposite side --- src/fontra/client/web-components/rotary-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 90cd32e15..2bf1a8c21 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -91,7 +91,7 @@ export class RotaryControl extends html.UnlitElement { const diffY = event.clientY - this.coordinatesDragBegin.y; const value = this.angleWhenDragStart + - (Math.abs(diffX) > Math.abs(diffY) ? diffX : diffY); + (Math.abs(diffX) > Math.abs(diffY) ? diffX : -diffY); this.value = value; this.dispatch(); }, From 9b8754c26abb8c416af8a988e5e85146bae874aa Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Fri, 22 Dec 2023 22:37:03 +0300 Subject: [PATCH 20/29] Delete RotaryControlDemoPanel --- src/fontra/views/editor/editor.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 960cb7b5d..5263a1d1d 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -77,16 +77,6 @@ const MIN_CANVAS_SPACE = 200; const PASTE_BEHAVIOR_REPLACE = "replace"; const PASTE_BEHAVIOR_ADD = "add"; -class RotaryControlDemoPanel extends Panel { - identifier = "rotary-control-demo"; - iconPath = "/images/info.svg"; - - getContentElement() { - return html.div({}, [html.createDomElement("rotary-control", { value: 0 })]); - } -} -customElements.define("panel-rotary-control", RotaryControlDemoPanel); - export class EditorController { static async fromWebSocket() { const pathItems = window.location.pathname.split("/").slice(3); @@ -485,7 +475,6 @@ export class EditorController { this.addSidebarPanel(new UserSettingsPanel(this), "left"); this.addSidebarPanel(new ReferenceFontPanel(this), "left"); this.addSidebarPanel(new SelectionInfoPanel(this), "right"); - this.addSidebarPanel(new RotaryControlDemoPanel(this), "right"); // Upon reload, the "animating" class may still be set (why?), so remove it for (const sidebarContainer of document.querySelectorAll(".sidebar-container")) { From b3f9d964d33b804ca81b6c2ff68b3e4040236f28 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 15:35:50 +0300 Subject: [PATCH 21/29] Cache rotation axis if the difference exceeds a threshold --- .../client/web-components/rotary-control.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 2bf1a8c21..edd980ea8 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -81,6 +81,7 @@ export class RotaryControl extends html.UnlitElement { this.angleWhenDragStart = undefined; this.shadowRoot.removeChild(overlay); this.dragEnd = true; + delete this.cachedRotationAxis; this.dispatch(); }, onmousemove: (event) => { @@ -89,9 +90,23 @@ export class RotaryControl extends html.UnlitElement { } const diffX = event.clientX - this.coordinatesDragBegin.x; const diffY = event.clientY - this.coordinatesDragBegin.y; + + let rotationAxis = this.cachedRotationAxis; + + if (!rotationAxis) { + if (Math.abs(diffX) > Math.abs(diffY)) { + rotationAxis = "x"; + } else { + rotationAxis = "y"; + } + } + + if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) { + this.cachedRotationAxis = rotationAxis; + } + const value = - this.angleWhenDragStart + - (Math.abs(diffX) > Math.abs(diffY) ? diffX : -diffY); + this.angleWhenDragStart + (rotationAxis === "x" ? diffX : -diffY); this.value = value; this.dispatch(); }, From f2153aadf09c46570de7310ae128f2d0d429d0cf Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 16:17:18 +0300 Subject: [PATCH 22/29] Revert "Cache rotation axis if the difference exceeds a threshold" This reverts commit b3f9d964d33b804ca81b6c2ff68b3e4040236f28. --- .../client/web-components/rotary-control.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index edd980ea8..2bf1a8c21 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -81,7 +81,6 @@ export class RotaryControl extends html.UnlitElement { this.angleWhenDragStart = undefined; this.shadowRoot.removeChild(overlay); this.dragEnd = true; - delete this.cachedRotationAxis; this.dispatch(); }, onmousemove: (event) => { @@ -90,23 +89,9 @@ export class RotaryControl extends html.UnlitElement { } const diffX = event.clientX - this.coordinatesDragBegin.x; const diffY = event.clientY - this.coordinatesDragBegin.y; - - let rotationAxis = this.cachedRotationAxis; - - if (!rotationAxis) { - if (Math.abs(diffX) > Math.abs(diffY)) { - rotationAxis = "x"; - } else { - rotationAxis = "y"; - } - } - - if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) { - this.cachedRotationAxis = rotationAxis; - } - const value = - this.angleWhenDragStart + (rotationAxis === "x" ? diffX : -diffY); + this.angleWhenDragStart + + (Math.abs(diffX) > Math.abs(diffY) ? diffX : -diffY); this.value = value; this.dispatch(); }, From 0ae3bef670eee41adf8ed8e577f5cdbc932808fc Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 16:18:58 +0300 Subject: [PATCH 23/29] Adjust the angle only in vertical movement --- src/fontra/client/web-components/rotary-control.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 2bf1a8c21..40805ee61 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -87,11 +87,8 @@ export class RotaryControl extends html.UnlitElement { if (this.coordinatesDragBegin === undefined) { return; } - const diffX = event.clientX - this.coordinatesDragBegin.x; - const diffY = event.clientY - this.coordinatesDragBegin.y; const value = - this.angleWhenDragStart + - (Math.abs(diffX) > Math.abs(diffY) ? diffX : -diffY); + this.angleWhenDragStart + (this.coordinatesDragBegin.y - event.clientY); this.value = value; this.dispatch(); }, From 5c00ad7e37388dc5ae2c075498af90ef331b5afd Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 16:22:57 +0300 Subject: [PATCH 24/29] Keep only clientY when drag begin --- src/fontra/client/web-components/rotary-control.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index 40805ee61..c06646683 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -77,18 +77,18 @@ export class RotaryControl extends html.UnlitElement { { class: "overlay", onmouseup: () => { - this.coordinatesDragBegin = undefined; + this.positionDragBegin = undefined; this.angleWhenDragStart = undefined; this.shadowRoot.removeChild(overlay); this.dragEnd = true; this.dispatch(); }, onmousemove: (event) => { - if (this.coordinatesDragBegin === undefined) { + if (this.positionDragBegin === undefined) { return; } const value = - this.angleWhenDragStart + (this.coordinatesDragBegin.y - event.clientY); + this.angleWhenDragStart + (this.positionDragBegin - event.clientY); this.value = value; this.dispatch(); }, @@ -106,7 +106,7 @@ export class RotaryControl extends html.UnlitElement { class: "knob", style: `transform: rotate(${this.value}deg);`, onmousedown: (event) => { - this.coordinatesDragBegin = { x: event.clientX, y: event.clientY }; + this.positionDragBegin = event.clientY; this.angleWhenDragStart = this.value; this.dragBegin = true; event.preventDefault(); From 1a01fd89e8d46aefd9b45be25454c0ae75fea329 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 25 Dec 2023 16:32:12 +0300 Subject: [PATCH 25/29] Deleted rotary control import in editor.js --- src/fontra/views/editor/editor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 5263a1d1d..536b8622e 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -62,7 +62,6 @@ import { themeController } from "/core/theme-settings.js"; import { MenuItemDivider, showMenu } from "/web-components/menu-panel.js"; import { dialog, dialogSetup } from "/web-components/modal-dialog.js"; import { parsePluginBasePath } from "/web-components/plugin-manager.js"; -import { RotaryControl } from "/web-components/rotary-control.js"; import DesignspaceNavigationPanel from "./panel-designspace-navigation.js"; import GlyphSearchPanel from "./panel-glyph-search.js"; From e54acb850464e9f3b1f2db5319c5bcbf1e8d1350 Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Wed, 27 Dec 2023 02:05:34 +0300 Subject: [PATCH 26/29] Delete vertical margin of the knob --- src/fontra/client/web-components/rotary-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index c06646683..f37b6a560 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -27,7 +27,7 @@ export class RotaryControl extends html.UnlitElement { .rotary-control { display: flex; gap: 0.4rem; - margin: 0.2rem; + margin: 0 0.2rem; } .overlay { From 455f1a2a18930dae42cbbdce6f308fe4c2e9528b Mon Sep 17 00:00:00 2001 From: Fatih Erikli Date: Mon, 1 Jan 2024 08:58:54 +0300 Subject: [PATCH 27/29] Delete .thumb child, use :before pseudo selector instead --- src/fontra/client/web-components/rotary-control.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fontra/client/web-components/rotary-control.js b/src/fontra/client/web-components/rotary-control.js index f37b6a560..329b9194a 100644 --- a/src/fontra/client/web-components/rotary-control.js +++ b/src/fontra/client/web-components/rotary-control.js @@ -16,7 +16,8 @@ export class RotaryControl extends html.UnlitElement { justify-content: center; } - .thumb { + .knob:before { + content: ""; width: var(--thumb-size); height: var(--thumb-size); background: rgb(89, 89, 89); @@ -113,7 +114,7 @@ export class RotaryControl extends html.UnlitElement { this.attachOverlay(); }, }, - [html.div({ class: "thumb" })] + [] )), ]); } From 5e765f47d605218d9c9a99e19ba99531dbc6edff Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 2 Jan 2024 09:51:34 +0100 Subject: [PATCH 28/29] Use eplicit closure for the rotary changes; style tweak --- src/fontra/client/web-components/ui-form.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 833553b75..2e3dcf307 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -199,16 +199,21 @@ export class Form extends SimpleElement { rotaryControl.value = value * -1; }, }); - let valueStream; const rotaryControl = html.createDomElement("rotary-control", { value: fieldItem.value, - onChangeCallback: (event) => { + }); + { + // Rotary change closure + let valueStream; + + rotaryControl.onChangeCallback = (event) => { const value = event.value * -1; inputElement.value = value; if (event.dragBegin) { valueStream = new QueueIterator(5, true); this._fieldChanging(fieldItem.key, value, valueStream); } + if (valueStream) { valueStream.put(value); this._dispatchEvent("doChange", { key: fieldItem.key, value: value }); @@ -220,13 +225,13 @@ export class Form extends SimpleElement { } else { this._fieldChanging(fieldItem.key, value, undefined); } - }, - }); + }; + } this._fieldGetters[fieldItem.key] = () => inputElement.value; this._fieldSetters[fieldItem.key] = (value) => (inputElement.value = value); valueElement.appendChild( - html.div({ style: "display: flex" }, [inputElement, rotaryControl]) + html.div({ style: "display: flex; gap: 0.15rem;" }, [inputElement, rotaryControl]) ); } From 07e7146f50c85d8215dfa3453ea21a0454d2ce83 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 2 Jan 2024 09:52:18 +0100 Subject: [PATCH 29/29] simplify --- src/fontra/client/web-components/ui-form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/ui-form.js b/src/fontra/client/web-components/ui-form.js index 2e3dcf307..ef85ec384 100644 --- a/src/fontra/client/web-components/ui-form.js +++ b/src/fontra/client/web-components/ui-form.js @@ -207,7 +207,7 @@ export class Form extends SimpleElement { let valueStream; rotaryControl.onChangeCallback = (event) => { - const value = event.value * -1; + const value = -event.value; inputElement.value = value; if (event.dragBegin) { valueStream = new QueueIterator(5, true);