User-tuned defaults, label-size floor 1, cluster glow removed
- Defaults per user: nodeSize 2, edgeWidth 1, arrowLength 2, labelSize 2 (labelZoom 0.5 stays — reads as the "1x" they confirmed good). - Label size slider floor 3 -> 1 so the default 2 is not the smallest value; sanitize clamp widened to match. - Cluster hull glow (layered low-alpha fills) removed for now: it read as jagged up close (straight-line hull approximation at high zoom) and does not belong until the layout settles. The solid viewer-relative border and the inverse-gated region labels stay. HULL_FILL_LAYERS constant deleted; hullShapes cache carries only the stroke path now. - Saved render-settings.json reset so the new defaults apply on next load. EOF
This commit is contained in:
@@ -129,14 +129,10 @@ const PICKING_PAD = 10;
|
||||
/** Click vs drag threshold: pointer travel under this many px is a click. */
|
||||
const CLICK_SLOP = 4;
|
||||
|
||||
/** Cluster hull styling: layered low-alpha fills approximate the soft
|
||||
* translucent tint (a canvas blur filter rasterizes on the GPU per call
|
||||
* — the original coil-whine driver; never bring ctx.filter back). */
|
||||
const HULL_FILL_LAYERS = [
|
||||
[24, 0.025],
|
||||
[19, 0.04],
|
||||
[14, 0.06],
|
||||
] as const;
|
||||
/** Cluster hull styling: a SOLID viewer-relative border only. The layered
|
||||
* low-alpha fills (the "glow") were removed on user request — they read
|
||||
* as jagged up close (straight-line hull approximation) and are better
|
||||
* revisited once the layout settles. */
|
||||
const HULL_STROKE_PAD = 14;
|
||||
const HULL_CORNER_RADIUS = 9;
|
||||
const REGION_LABEL_SIZE = 14;
|
||||
@@ -355,7 +351,6 @@ export class GraphCanvasRenderer {
|
||||
private shaftsPath: Path2D = new Path2D();
|
||||
private headsPath: Path2D = new Path2D();
|
||||
private hullShapes: {
|
||||
fill: Path2D[];
|
||||
stroke: Path2D;
|
||||
label: string | null;
|
||||
cx: number; // world centroid
|
||||
@@ -699,8 +694,7 @@ export class GraphCanvasRenderer {
|
||||
this.headsPath = heads;
|
||||
|
||||
// Cluster hulls: convex hull of member positions (world = raw data
|
||||
// coordinates — no projection at all), three offset fill layers,
|
||||
// and a SOLID boundary path.
|
||||
// coordinates — no projection at all) and a SOLID boundary path.
|
||||
this.hullShapes = [];
|
||||
for (const cluster of data.clusters) {
|
||||
const pts: Pt[] = [];
|
||||
@@ -711,16 +705,11 @@ export class GraphCanvasRenderer {
|
||||
}
|
||||
const hull = convexHull(pts);
|
||||
if (hull.length < 3) continue;
|
||||
const fills = HULL_FILL_LAYERS.map(([pad]) => {
|
||||
const path = new Path2D();
|
||||
traceRoundedPath(path, offsetPolygon(hull, pad * s), HULL_CORNER_RADIUS * s);
|
||||
return path;
|
||||
});
|
||||
const stroke = new Path2D();
|
||||
traceRoundedPath(stroke, offsetPolygon(hull, HULL_STROKE_PAD * s), HULL_CORNER_RADIUS * s);
|
||||
const cx = pts.reduce((sum, p) => sum + p.x, 0) / pts.length;
|
||||
const cy = pts.reduce((sum, p) => sum + p.y, 0) / pts.length;
|
||||
this.hullShapes.push({ fill: fills, stroke, label: cluster.label || null, cx, cy, hue: clusterHue(cluster.id) });
|
||||
this.hullShapes.push({ stroke, label: cluster.label || null, cx, cy, hue: clusterHue(cluster.id) });
|
||||
}
|
||||
|
||||
// Label wrapping: measureText once per node per geometry build,
|
||||
@@ -765,13 +754,9 @@ export class GraphCanvasRenderer {
|
||||
const regionAlpha = 1 - nodeAlpha;
|
||||
const { nodeR, glowOuter } = this.world;
|
||||
|
||||
// 1–2. Cluster hulls: cached world paths — soft layered fills, then
|
||||
// a SOLID viewer-relative hairline border (dashes dropped for now).
|
||||
// 1. Cluster hulls: cached world paths — SOLID viewer-relative
|
||||
// hairline border only (no fill glow, removed for now).
|
||||
for (const hs of this.hullShapes) {
|
||||
for (let i = 0; i < hs.fill.length; i++) {
|
||||
ctx.fillStyle = `hsla(${hs.hue}, 65%, 60%, ${HULL_FILL_LAYERS[i]![1]})`;
|
||||
ctx.fill(hs.fill[i]!);
|
||||
}
|
||||
ctx.strokeStyle = `hsla(${hs.hue}, 65%, 62%, 0.5)`;
|
||||
ctx.lineWidth = 1.5 / k; // constant screen px
|
||||
ctx.stroke(hs.stroke);
|
||||
|
||||
@@ -524,7 +524,7 @@ export function GraphView() {
|
||||
/>
|
||||
<SettingSlider
|
||||
label="Label size"
|
||||
min={3}
|
||||
min={1}
|
||||
max={24}
|
||||
step={0.5}
|
||||
value={settings.labelSize}
|
||||
|
||||
@@ -34,11 +34,11 @@ export interface GraphRenderSettings {
|
||||
// were calibrated in the screen-fixed era, so everything rendered ~2x
|
||||
// too big once sizes started scaling with the graph.
|
||||
export const DEFAULT_RENDER_SETTINGS: GraphRenderSettings = {
|
||||
nodeSize: 4,
|
||||
nodeSize: 2,
|
||||
edgeWidth: 1,
|
||||
arrowLength: 4,
|
||||
arrowLength: 2,
|
||||
labelZoom: 0.5,
|
||||
labelSize: 7,
|
||||
labelSize: 2,
|
||||
clusterLabels: true,
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ export function sanitizeRenderSettings(raw: unknown): GraphRenderSettings {
|
||||
arrowLength: num(r.arrowLength, DEFAULT_RENDER_SETTINGS.arrowLength, 1, 15),
|
||||
// Range matches the log slider's span [LABEL_ZOOM_MIN, LABEL_ZOOM_MAX].
|
||||
labelZoom: num(r.labelZoom, DEFAULT_RENDER_SETTINGS.labelZoom, 0.0625, 4),
|
||||
labelSize: num(r.labelSize, DEFAULT_RENDER_SETTINGS.labelSize, 3, 24),
|
||||
labelSize: num(r.labelSize, DEFAULT_RENDER_SETTINGS.labelSize, 1, 24),
|
||||
clusterLabels:
|
||||
typeof r.clusterLabels === "boolean" ? r.clusterLabels : DEFAULT_RENDER_SETTINGS.clusterLabels,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user