diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml
index 595448c..22f21d2 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.6
+ image: git.baumann.gr/adebaumann/m1730-generator:0.7
imagePullPolicy: Always
ports:
- containerPort: 5000
diff --git a/web/app.py b/web/app.py
index 0c9e15b..6f1c8c6 100644
--- a/web/app.py
+++ b/web/app.py
@@ -1,17 +1,28 @@
import base64
import pathlib
from flask import Flask, render_template, request, Response
+from html import escape
from fontTools.ttLib import TTFont
from fontTools.pens.svgPathPen import SVGPathPen
app = Flask(__name__)
-VERSION = "0.6"
+VERSION = "0.7"
_LOGO_PATH = pathlib.Path(__file__).parent / 'static' / 'logo.png'
_LOGO_B64 = base64.b64encode(_LOGO_PATH.read_bytes()).decode()
_FONT_PATH = pathlib.Path('/usr/local/share/fonts/г/ГОСТ_тип_А.ttf')
+_FONT_B64 = base64.b64encode(_FONT_PATH.read_bytes()).decode()
+_FONT_FACE = (
+ ''
+)
+
_FONT_OBJ = TTFont(str(_FONT_PATH))
_GLYPH_SET = _FONT_OBJ.getGlyphSet()
_CMAP = _FONT_OBJ.getBestCmap()
@@ -19,10 +30,10 @@ _HMTX = _FONT_OBJ['hmtx'].metrics
_UPM = _FONT_OBJ['head'].unitsPerEm
# SVG absolute coordinate constants (1 user unit = 1 mm)
-ZERO_X = 60.844130
-MAX_X = 180.251230
-BAR_Y = 107.54670
-SCALE_LEN = MAX_X - ZERO_X # 119.4071 mm
+ZERO_X = 60.844130
+MAX_X = 180.251230
+BAR_Y = 107.54670
+SCALE_LEN = MAX_X - ZERO_X # 119.4071 mm
BIG_H = 5.0895
SMALL_H = 2.6683
@@ -44,10 +55,8 @@ def _fmt(v: float) -> str:
def _text_to_paths(text, x, y, font_size, anchor='start', fill='#1a1a1a', wrap_transform=None):
- """Convert a text string to SVG elements using glyph outlines."""
s = font_size / _UPM
- # Compute total advance width for centering
if anchor == 'middle':
total_w = sum(
_HMTX.get(_CMAP.get(ord(ch)), (0, 0))[0] * s
@@ -75,7 +84,7 @@ def _text_to_paths(text, x, y, font_size, anchor='start', fill='#1a1a1a', wrap_t
return inner
-def generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, label_count):
+def generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, label_count, use_paths=True):
big_interval = SCALE_LEN / big_ticks
big_xs = [ZERO_X + i * big_interval for i in range(big_ticks + 1)]
@@ -87,23 +96,37 @@ def generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, la
'']
return '\n'.join(parts)
@@ -144,15 +170,16 @@ def index():
@app.route('/generate', methods=['POST'])
def generate():
- unit = request.form.get('unit', '%')
- min_val = float(request.form.get('min', 0))
- max_val = float(request.form.get('max', 100))
+ unit = request.form.get('unit', '%')
+ min_val = float(request.form.get('min', 0))
+ max_val = float(request.form.get('max', 100))
range_label = request.form.get('range_label', '5mA')
- big_ticks = max(1, min(50, int(request.form.get('big_ticks', 10))))
+ big_ticks = max(1, min(50, int(request.form.get('big_ticks', 10))))
small_ticks = max(0, min(20, int(request.form.get('small_ticks', 4))))
label_count = max(2, int(request.form.get('label_count', 6)))
+ use_paths = request.form.get('output_mode', 'paths') == 'paths'
- svg = generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, label_count)
+ svg = generate_svg(unit, min_val, max_val, range_label, big_ticks, small_ticks, label_count, use_paths)
return Response(svg, mimetype='image/svg+xml')
diff --git a/web/templates/index.html b/web/templates/index.html
index 3115a5e..96187c2 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -131,12 +131,42 @@
.field input:focus { border-color: var(--accent); }
+ /* ── Mode toggle ── */
+ .mode-toggle {
+ display: inline-flex;
+ border: 1px solid var(--rule);
+ border-radius: 1px;
+ overflow: hidden;
+ }
+
+ .mode-btn {
+ font-family: var(--f-mono);
+ font-size: 0.72rem;
+ padding: 0.35rem 0.85rem;
+ border: none;
+ background: var(--white);
+ color: var(--muted);
+ cursor: pointer;
+ transition: background 0.12s, color 0.12s;
+ line-height: 1;
+ }
+
+ .mode-btn + .mode-btn {
+ border-left: 1px solid var(--rule);
+ }
+
+ .mode-btn.active {
+ background: var(--ink);
+ color: var(--white);
+ }
+
/* ── Actions ── */
.actions {
display: flex;
gap: 0.75rem;
align-items: center;
padding-top: 1.75rem;
+ flex-wrap: wrap;
}
.btn {
@@ -220,6 +250,17 @@
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; }
}
+
+ .version-tag {
+ position: fixed;
+ bottom: 0.75rem;
+ right: 1rem;
+ font-family: var(--f-mono);
+ font-size: 0.65rem;
+ color: var(--rule);
+ pointer-events: none;
+ user-select: none;
+ }
@@ -284,6 +325,16 @@
+
+
+
+
+
+
Glyphs as outlines — no font required
+
+
@@ -295,6 +346,8 @@
+ v{{ version }}
+