From cf844d007be74248462378207d90ce6475ed9ce9 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Tue, 14 Jul 2026 23:25:01 +0200 Subject: [PATCH] Add reciprocal (1/x) scale mapping --- k8s/deployment.yaml | 2 +- web/app.py | 15 ++++++++++++++- web/templates/index.html | 5 +++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 89ac4ae..c4f422a 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: m1730-generator - image: git.baumann.gr/adebaumann/m1730-generator:0.81 + image: git.baumann.gr/adebaumann/m1730-generator:0.82 imagePullPolicy: Always ports: - containerPort: 5000 diff --git a/web/app.py b/web/app.py index e2be9a4..d36decc 100644 --- a/web/app.py +++ b/web/app.py @@ -8,7 +8,7 @@ from fontTools.pens.svgPathPen import SVGPathPen app = Flask(__name__) -VERSION = "0.81" +VERSION = "0.82" _LOGO_PATH = pathlib.Path(__file__).parent / 'static' / 'logo.png' _LOGO_B64 = base64.b64encode(_LOGO_PATH.read_bytes()).decode() @@ -362,6 +362,19 @@ def generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, la def major_value(i): return min_val + span * (i / big_ticks) ** 2 + elif scale_type == 'reciprocal': + if min_val <= 0 or max_val <= 0: + raise ValueError("Reciprocal scale requires min and max values greater than 0.") + if max_val <= min_val: + raise ValueError("Reciprocal scale requires max value greater than min.") + k = 1.0 / min_val - 1.0 / max_val # always positive + + def value_to_x(v): + return ZERO_X + SCALE_LEN * (1.0 / v - 1.0 / max_val) / k + + def major_value(i): + return 1.0 / (1.0 / max_val + i / big_ticks * k) + else: span = max_val - min_val diff --git a/web/templates/index.html b/web/templates/index.html index 23cdecd..5199478 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -322,6 +322,8 @@ title="Square-root scale — ticks crowd at the low end; used for RMS current/power meters. Min must be ≥ 0">√ +
@@ -442,6 +444,9 @@ if (!(parseFloat(maxInput.value) > 0)) maxInput.value = '100'; } else if (btn.dataset.scale === 'sqrt') { if (parseFloat(minInput.value) < 0) minInput.value = '0'; + } else if (btn.dataset.scale === 'reciprocal') { + if (!(parseFloat(minInput.value) > 0)) minInput.value = '1'; + if (!(parseFloat(maxInput.value) > parseFloat(minInput.value))) maxInput.value = String(parseFloat(minInput.value) * 10); } } doGenerate();