task(C3): extend pixi element types - dimension/leader/revcloud/chair/table/stage
This commit is contained in:
@@ -130,6 +130,112 @@ export function elementToPrimitives(el: CADElement): ShapePrimitive[] {
|
||||
}];
|
||||
}
|
||||
|
||||
// ── Task C3: bisher im Pixi-Pfad fehlende Typen ──
|
||||
|
||||
case 'dimension': {
|
||||
// Legacy-Konvention: x1..y2 in properties, BBox-Zentrum als x/y,
|
||||
// Extension lines + Hauptlinie; Pfeilspitzen sind Detail (C3+)
|
||||
const x1 = (props.x1 as number | undefined) ?? el.x - el.width / 2;
|
||||
const y1 = (props.y1 as number | undefined) ?? el.y;
|
||||
const x2 = (props.x2 as number | undefined) ?? el.x + el.width / 2;
|
||||
const y2 = (props.y2 as number | undefined) ?? el.y;
|
||||
const color = (props.color as string | undefined) ?? '#aaaaaa';
|
||||
const dimColor = (props.dimColor as string | undefined) ?? color;
|
||||
const label = String(props.value ?? props.text ?? '');
|
||||
const out: ShapePrimitive[] = [
|
||||
{ kind: 'line', from: { x: x1, y: y1 }, to: { x: x2, y: y2 }, stroke: dimColor, strokeWidth: 1 },
|
||||
];
|
||||
if (label) {
|
||||
out.push({
|
||||
kind: 'text',
|
||||
at: { x: (x1 + x2) / 2, y: (y1 + y2) / 2 - 12 },
|
||||
text: label,
|
||||
fontSize: 10,
|
||||
color: dimColor,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
case 'leader': {
|
||||
// Legacy-Konvention: Linie p1→p2 + optionaler Text am Ende
|
||||
const lx1 = (props.x1 as number | undefined) ?? el.x;
|
||||
const ly1 = (props.y1 as number | undefined) ?? el.y;
|
||||
const lx2 = (props.x2 as number | undefined) ?? el.x + el.width;
|
||||
const ly2 = (props.y2 as number | undefined) ?? el.y + el.height;
|
||||
const out: ShapePrimitive[] = [
|
||||
{ kind: 'line', from: { x: lx1, y: ly1 }, to: { x: lx2, y: ly2 }, stroke, strokeWidth: sw },
|
||||
];
|
||||
const label = String(props.text ?? '');
|
||||
if (label) {
|
||||
out.push({
|
||||
kind: 'text',
|
||||
at: { x: lx2 + 4, y: ly2 - 4 },
|
||||
text: label,
|
||||
fontSize: (props.fontSize as number | undefined) ?? 12,
|
||||
color: stroke,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
case 'revcloud': {
|
||||
// Revisionswolke: Punkte-Zug (Bogen-Detail folgt in C3+)
|
||||
const pts = Array.isArray(props.points)
|
||||
? (props.points as unknown[]).map(asPoint)
|
||||
: [];
|
||||
if (pts.length < 2) return [];
|
||||
return [{
|
||||
kind: 'polyline',
|
||||
points: pts,
|
||||
close: true,
|
||||
stroke,
|
||||
strokeWidth: sw,
|
||||
}];
|
||||
}
|
||||
|
||||
case 'chair': {
|
||||
// Stuhl: gefülltes Quadrat in Element-Farbe + Umrandung
|
||||
const fill = (props.fill as string | undefined) ?? '#4a90d9';
|
||||
return [{
|
||||
kind: 'rect',
|
||||
x: el.x - el.width / 2,
|
||||
y: el.y - el.height / 2,
|
||||
w: el.width,
|
||||
h: el.height,
|
||||
fill,
|
||||
stroke: (props.outlineColor as string | undefined) ?? '#2a5a99',
|
||||
strokeWidth: 1,
|
||||
}];
|
||||
}
|
||||
|
||||
case 'table': {
|
||||
// Tisch: Kreis in Element-Größe mit Füllung
|
||||
const fill = (props.fill as string | undefined) ?? '#8b7355';
|
||||
return [{
|
||||
kind: 'circle',
|
||||
center: { x: el.x, y: el.y },
|
||||
radius: Math.max(el.width, el.height) / 2,
|
||||
fill,
|
||||
stroke: '#5a4a35',
|
||||
strokeWidth: 1,
|
||||
}];
|
||||
}
|
||||
|
||||
case 'stage': {
|
||||
// Bühne: Rechteck mit dunkler Füllung
|
||||
return [{
|
||||
kind: 'rect',
|
||||
x: el.x - el.width / 2,
|
||||
y: el.y - el.height / 2,
|
||||
w: el.width,
|
||||
h: el.height,
|
||||
fill: (props.fill as string | undefined) ?? '#3a3a4a',
|
||||
stroke,
|
||||
strokeWidth: 1.5,
|
||||
}];
|
||||
}
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -112,4 +112,63 @@ describe('elementToPrimitives', () => {
|
||||
it('unbekannter Typ ergibt leere Liste (renderer-sicher)', () => {
|
||||
expect(elementToPrimitives(el('x', 'definitely-unknown'))).toEqual([]);
|
||||
});
|
||||
|
||||
it('dimension: Linie + Label aus value/text', () => {
|
||||
const prims = elementToPrimitives(el('d', 'dimension', {
|
||||
x1: 0, y1: 0, x2: 100, y2: 0, value: '250 cm',
|
||||
}, { x: 50, y: 0 }));
|
||||
expect(prims.length).toBe(2);
|
||||
expect(prims[0].kind).toBe('line');
|
||||
const txt = prims[1];
|
||||
if (txt.kind !== 'text') throw new Error('erwartete text');
|
||||
expect(txt.text).toBe('250 cm');
|
||||
});
|
||||
|
||||
it('leader: Linie + Label am Ende', () => {
|
||||
const prims = elementToPrimitives(el('ld', 'leader', {
|
||||
x1: 10, y1: 10, x2: 80, y2: 60, text: 'A1', fontSize: 14,
|
||||
}));
|
||||
expect(prims.length).toBe(2);
|
||||
expect(prims[0].kind).toBe('line');
|
||||
const txt = prims[1];
|
||||
if (txt.kind !== 'text') throw new Error('erwartete text');
|
||||
expect(txt.text).toBe('A1');
|
||||
expect(txt.fontSize).toBe(14);
|
||||
});
|
||||
|
||||
it('revcloud: geschlossener Punktzug', () => {
|
||||
const prims = elementToPrimitives(el('rc', 'revcloud', {
|
||||
points: [{ x: 0, y: 0 }, { x: 50, y: 0 }, { x: 50, y: 30 }],
|
||||
}));
|
||||
expect(prims.length).toBe(1);
|
||||
const p = prims[0];
|
||||
if (p.kind !== 'polyline') throw new Error('erwartete polyline');
|
||||
expect(p.close).toBe(true);
|
||||
});
|
||||
|
||||
it('chair: gefuelltes Rechteck mit Fallback-Farbe', () => {
|
||||
const prims = elementToPrimitives(el('ch', 'chair', {}, { x: 50, y: 50, width: 20, height: 20 }));
|
||||
const p = prims[0];
|
||||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||||
expect(p.fill).toBe('#4a90d9');
|
||||
expect(p.x).toBe(40);
|
||||
expect(p.y).toBe(40);
|
||||
});
|
||||
|
||||
it('table: Kreis mit Fallback-Farbe und Radius aus width', () => {
|
||||
const prims = elementToPrimitives(el('tb', 'table', {}, { x: 0, y: 0, width: 60, height: 60 }));
|
||||
const p = prims[0];
|
||||
if (p.kind !== 'circle') throw new Error('erwartete circle');
|
||||
expect(p.radius).toBe(30);
|
||||
expect(p.fill).toBe('#8b7355');
|
||||
});
|
||||
|
||||
it('stage: dunkles Rechteck', () => {
|
||||
const prims = elementToPrimitives(el('st', 'stage', {}, { x: 0, y: 0, width: 200, height: 100 }));
|
||||
const p = prims[0];
|
||||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||||
expect(p.fill).toBe('#3a3a4a');
|
||||
expect(p.w).toBe(200);
|
||||
expect(p.h).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user