mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 20:29:00 +00:00
ui(resize): wall handles — half-size wall-with-arrows glyph, grab cursor
Owner request: in the resize tool make the wall-drag handles twice smaller, replace the circle with a 'wall + two opposite arrows' icon, drag cursor. - visible glyph: wall segment with two arrows perpendicular to the edge (the drag directions), rotated per wall orientation; accent ink over a --hp-bg halo, readable on any plan - HIT area unchanged: an invisible circle of the original finger-sized radius keeps touch targets and the HP-1550-04 hit priority over openings (04_handle_wins_hit_test still passes) - cursor: grab on hover, grabbing while dragging (:active) - scale-frame corner handles untouched (classic filled circles, nwse-resize) - docs/RESIZE.md: handle appearance updated
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+30
-9
File diff suppressed because one or more lines are too long
+8
-3
@@ -19,9 +19,14 @@ before — no handles, no new hit areas.
|
||||
## Mechanism A — wall drag
|
||||
|
||||
- Every visible room shows a small handle at the midpoint of every
|
||||
wall (handles for all rooms at once — owner's UX pick; they are
|
||||
finger-sized but unobtrusive, radius derived from `view.w` like
|
||||
`.vacfithandle`).
|
||||
wall (handles for all rooms at once — owner's UX pick). The visible
|
||||
glyph is a compact icon — a wall segment with two arrows pointing
|
||||
perpendicular to it (the directions the wall drags), rotated to the
|
||||
wall's orientation; accent ink over a `--hp-bg` halo. It is half the
|
||||
size of the old circle, but the HIT area is an invisible circle of
|
||||
the original finger-sized radius (derived from `view.w` like
|
||||
`.vacfithandle`), so touch targets did not shrink. Cursor: `grab`,
|
||||
`grabbing` while dragging.
|
||||
- Dragging a handle moves the wall along its outward normal; **both
|
||||
ends of the edge translate together** (the wall stays parallel to
|
||||
itself; adjacent walls stretch/shrink). Works for any polygon
|
||||
|
||||
+15
-2
@@ -2538,19 +2538,32 @@ class HouseplanCard extends LitElement {
|
||||
|
||||
/** Handles of the resize tool: wall midpoints + the scale frame of the selected room. */
|
||||
private _renderResizeLayer(view: { x: number; y: number; w: number; h: number }): TemplateResult {
|
||||
const hr = Math.max(view.w * 0.013, 5); // finger-sized on touch, like .vacfithandle
|
||||
const hr = Math.max(view.w * 0.013, 5); // finger-sized HIT radius on touch, like .vacfithandle
|
||||
// Wall-handle glyph: half the old circle — a wall segment with two arrows
|
||||
// pointing perpendicular to it (the directions the wall can be dragged).
|
||||
// Drawn in local coords (wall along X), rotated per edge at render time.
|
||||
// The invisible circle above keeps the full finger-sized hit area and the
|
||||
// HP-1550-04 hit-test priority over openings.
|
||||
const s = hr / 2, f = (v: number) => v.toFixed(1);
|
||||
const iconD =
|
||||
`M ${f(-0.7 * s)} 0 H ${f(0.7 * s)}` +
|
||||
` M 0 ${f(-0.22 * s)} V ${f(-s)} M ${f(-0.32 * s)} ${f(-0.6 * s)} L 0 ${f(-s)} L ${f(0.32 * s)} ${f(-0.6 * s)}` +
|
||||
` M 0 ${f(0.22 * s)} V ${f(s)} M ${f(-0.32 * s)} ${f(0.6 * s)} L 0 ${f(s)} L ${f(0.32 * s)} ${f(0.6 * s)}`;
|
||||
const parts: TemplateResult[] = [];
|
||||
const rooms = this._rszRooms();
|
||||
for (const r of rooms) {
|
||||
for (let i = 0; i < r.poly.length; i++) {
|
||||
const a = r.poly[i], b = r.poly[(i + 1) % r.poly.length];
|
||||
if (Math.hypot(b[0] - a[0], b[1] - a[1]) < this._gridPitch) continue;
|
||||
parts.push(svg`<circle class="rszhandle" cx="${((a[0] + b[0]) / 2).toFixed(1)}" cy="${((a[1] + b[1]) / 2).toFixed(1)}" r="${hr.toFixed(1)}"
|
||||
const mx = f((a[0] + b[0]) / 2), my = f((a[1] + b[1]) / 2);
|
||||
const ang = f(Math.atan2(b[1] - a[1], b[0] - a[0]) * 180 / Math.PI);
|
||||
parts.push(svg`<circle class="rszhandle" cx="${mx}" cy="${my}" r="${f(hr)}"
|
||||
@pointerdown=${(e: PointerEvent) => this._rszEdgeDown(e, r.id, i)}
|
||||
@pointermove=${(e: PointerEvent) => this._rszMove(e)}
|
||||
@pointerup=${(e: PointerEvent) => this._rszUp(e)}
|
||||
@pointercancel=${(e: PointerEvent) => this._rszPointerCancel(e)}
|
||||
@lostpointercapture=${(e: PointerEvent) => this._rszPointerCancel(e)}></circle>`);
|
||||
parts.push(svg`<g class="rszicon" transform="translate(${mx} ${my}) rotate(${ang})"><path class="rszhalo" d="${iconD}"></path><path class="rszink" d="${iconD}"></path></g>`);
|
||||
}
|
||||
}
|
||||
const sel = this._rszSel ? rooms.find((r) => r.id === this._rszSel) : null;
|
||||
|
||||
+25
-4
@@ -1450,16 +1450,37 @@ export const cardStyles = css`
|
||||
user-select: none;
|
||||
}
|
||||
/* room resize tool (docs/RESIZE.md) */
|
||||
/* wall handle: invisible finger-sized hit circle (HP-1550-04 hit priority
|
||||
kept), the visible glyph lives in the sibling .rszicon */
|
||||
.rszhandle {
|
||||
fill: transparent;
|
||||
stroke: none;
|
||||
pointer-events: all;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
.rszhandle:active { cursor: grabbing; }
|
||||
/* wall-with-arrows glyph: accent ink over a bg halo, readable on any plan */
|
||||
.rszicon { pointer-events: none; }
|
||||
.rszicon path {
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
.rszhalo { stroke: var(--hp-bg); stroke-width: 6; }
|
||||
.rszink { stroke: var(--hp-accent); stroke-width: 2; }
|
||||
.rszhandle:hover + .rszicon .rszink { stroke-width: 3; }
|
||||
/* corner (scale-frame) handles keep the classic filled circle */
|
||||
.rszcorner {
|
||||
fill: var(--hp-bg);
|
||||
stroke: var(--hp-accent);
|
||||
stroke-width: 2;
|
||||
vector-effect: non-scaling-stroke;
|
||||
cursor: move;
|
||||
touch-action: none;
|
||||
cursor: nwse-resize;
|
||||
}
|
||||
.rszhandle:hover { fill: var(--hp-accent); }
|
||||
.rszcorner { cursor: nwse-resize; }
|
||||
.rszcorner:hover { fill: var(--hp-accent); }
|
||||
.rszcorner:active { cursor: nwse-resize; }
|
||||
.rszframe {
|
||||
fill: none;
|
||||
stroke: var(--hp-accent);
|
||||
|
||||
Reference in New Issue
Block a user