143 lines
4.4 KiB
JavaScript
Executable File
143 lines
4.4 KiB
JavaScript
Executable File
import { ceil, child, classAdd, classDel, positionSet } from '../infrastructure/util.js';
|
|
import { rectTxtSettingsPnlCreate } from './rect-txt-settings.js';
|
|
import { shapeCreate } from './shape-evt-proc.js';
|
|
import { settingsPnlCreate } from './shape-settings.js';
|
|
import { ShapeSmbl } from './shape-smbl.js';
|
|
|
|
/**
|
|
* @param {CanvasElement} canvas
|
|
* @param {RectData} rectData
|
|
*/
|
|
export function rect(canvas, rectData) {
|
|
rectData.w = rectData.w ?? 96;
|
|
rectData.h = rectData.h ?? 48;
|
|
rectData.a = rectData.a ?? (rectData.t ? 1 : 2);
|
|
|
|
const templ = `
|
|
<rect data-key="outer" data-evt-no data-evt-index="2" width="144" height="96" x="-72" y="-48" fill="transparent" stroke="transparent" stroke-width="0" />
|
|
<rect data-key="main" width="96" height="48" x="-48" y="-24" rx="15" ry="15" fill="#1aaee5" stroke="#fff" stroke-width="1" />
|
|
<text data-key="text" y="0" x="${rectTxtXByAlign(rectData)}" style="pointer-events: none;" fill="#fff"> </text>`;
|
|
|
|
const shape = shapeCreate(canvas, rectData, templ,
|
|
{
|
|
right: { dir: 'right', position: { x: 48, y: 0 } },
|
|
left: { dir: 'left', position: { x: -48, y: 0 } },
|
|
bottom: { dir: 'bottom', position: { x: 0, y: 24 } },
|
|
top: { dir: 'top', position: { x: 0, y: -24 } }
|
|
},
|
|
// onTextChange
|
|
txtEl => {
|
|
const textBox = txtEl.getBBox();
|
|
const newWidth = ceil(96, 48, textBox.width + (rectData.t ? 6 : 0)); // 6 px right padding for text shape
|
|
const newHeight = ceil(48, 48, textBox.height);
|
|
|
|
if (rectData.w !== newWidth || rectData.h !== newHeight) {
|
|
rectData.w = newWidth;
|
|
rectData.h = newHeight;
|
|
resize();
|
|
}
|
|
},
|
|
// settingsPnlCreateFn
|
|
rectData.t ? rectTxtSettingsPnlCreate : settingsPnlCreate);
|
|
|
|
classAdd(shape.el, rectData.t ? 'shtxt' : 'shrect');
|
|
|
|
let currentW = rectData.w;
|
|
let currentTxtAlign = rectData.a;
|
|
/** @param {boolean?=} fixTxtAlign */
|
|
function resize(fixTxtAlign) {
|
|
const mainX = rectData.w / -2;
|
|
const mainY = rectData.h / -2;
|
|
const middleX = 0;
|
|
|
|
shape.cons.right.position.x = -mainX;
|
|
shape.cons.left.position.x = mainX;
|
|
shape.cons.bottom.position.y = -mainY;
|
|
shape.cons.bottom.position.x = middleX;
|
|
shape.cons.top.position.y = mainY;
|
|
shape.cons.top.position.x = middleX;
|
|
for (const connectorKey in shape.cons) {
|
|
positionSet(child(shape.el, connectorKey), shape.cons[connectorKey].position);
|
|
}
|
|
|
|
rectSet(shape.el, 'main', rectData.w, rectData.h, mainX, mainY);
|
|
rectSet(shape.el, 'outer', rectData.w + 48, rectData.h + 48, mainX - 24, mainY - 24);
|
|
|
|
// if text align or width changed
|
|
// fix text align
|
|
if (fixTxtAlign || currentTxtAlign !== rectData.a || currentW !== rectData.w) {
|
|
let txtX;
|
|
let posXDelta;
|
|
switch (rectData.a) {
|
|
// text align left
|
|
case 1:
|
|
txtX = mainX + 8;
|
|
posXDelta = (rectData.w - currentW) / 2;
|
|
break;
|
|
case 2:
|
|
txtX = 0;
|
|
posXDelta = 0;
|
|
break;
|
|
// text align right
|
|
case 3:
|
|
txtX = -mainX - 8;
|
|
posXDelta = (rectData.w - currentW) / -2;
|
|
break;
|
|
}
|
|
|
|
const txtEl = child(shape.el, 'text');
|
|
txtEl.x.baseVal[0].value = txtX;
|
|
txtEl.querySelectorAll('tspan').forEach(ss => { ss.x.baseVal[0].value = txtX; });
|
|
|
|
rectData.position.x += posXDelta;
|
|
|
|
classDel(shape.el, `ta-${currentTxtAlign}`);
|
|
classAdd(shape.el, `ta-${rectData.a}`);
|
|
|
|
currentTxtAlign = rectData.a;
|
|
currentW = rectData.w;
|
|
}
|
|
|
|
shape.draw();
|
|
}
|
|
|
|
classAdd(shape.el, `ta-${rectData.a}`);
|
|
if (rectData.w !== 96 || rectData.h !== 48) { resize(true); } else { shape.draw(); }
|
|
|
|
shape.el[ShapeSmbl].draw = resize;
|
|
|
|
return shape.el;
|
|
}
|
|
|
|
/**
|
|
* @param {Element} svgGrp, @param {string} key,
|
|
* @param {number} w, @param {number} h
|
|
* @param {number} x, @param {number} y
|
|
*/
|
|
function rectSet(svgGrp, key, w, h, x, y) {
|
|
/** @type {SVGRectElement} */ const rect = child(svgGrp, key);
|
|
rect.width.baseVal.value = w;
|
|
rect.height.baseVal.value = h;
|
|
rect.x.baseVal.value = x;
|
|
rect.y.baseVal.value = y;
|
|
}
|
|
|
|
/** @param {RectData} rectData */
|
|
const rectTxtXByAlign = rectData => rectData.a === 1
|
|
? -40 // text align keft
|
|
: rectData.a === 2
|
|
? 0 // text align middle
|
|
: 40; // text align right
|
|
|
|
/** @typedef { {x:number, y:number} } Point */
|
|
/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */
|
|
/** @typedef { import('./shape-evt-proc').CanvasData } CanvasData */
|
|
/** @typedef { import('./shape-evt-proc').ConnectorsData } ConnectorsData */
|
|
/**
|
|
@typedef {{
|
|
type:number, position: Point, title?: string, styles?: string[],
|
|
w?:number, h?:number
|
|
t?:boolean,
|
|
a?: 1|2|3
|
|
}} RectData */
|