const C = {
textbox: 'textbox',
funnybox: 'funnybox',
nosize: 'nosize',
nowidth: 'nowidth',
notificationSpecParsed: 'notificationSpecParsed',
rightAngleLine: 'right-angle-line',
}
registerParser(C.textbox, parserTextbox)
registerLayoutProducer(C.textbox, layoutTextbox)
registerRenderer(C.textbox, renderTextbox)
registerParser(C.funnybox, parserFunnybox)
registerParser(C.nosize, parserNosize)
registerRenderer(C.nosize, renderNosize)
registerParser(C.nowidth, parserNowidth)
registerParser(C.rightAngleLine, parserRightAngleLine)
registerLayoutProducer(C.rightAngleLine, layoutRightAngleLine)
registerRenderer(C.rightAngleLine, renderRightAngleLine)
addListener(C.notificationSpecParsed, specParsed)
function parserTextbox(line, inputFile, variables, settings) {
const {key, tokens, contentLines, content} = parseKeyContent(line, inputFile, 3, variables, true)
const params = {}
let width = settings['text-width']
let height = settings['text-height']
if (tokens[0] !== undefined
&& tokens[1] !== undefined
&& (!isNaN(tokens[0]) || tokens[0] === 'fill')
&& (!isNaN(tokens[1]) || tokens[1] === 'fill')) {
width = fillOrFloat(Util.extractParams(tokens[0], params, 'fillWidth'), inputFile, true)
height = fillOrFloat(Util.extractParams(tokens[1], params, 'fillHeight'), inputFile, true)
let firstLineArr = contentLines[0].split(' ')
let count = 0
while (true) {
// Remove the size tokens from contentLines
let token = firstLineArr.shift()
if (token != '') {
count++
}
if (count === 2) {
break
}
}
contentLines[0] = firstLineArr.join(' ')
}
return {
key,
type: C.textbox,
width: fillOrFloat(Util.extractParams(tokens[0], params, 'fillWidth'), inputFile, true),
height: fillOrFloat(Util.extractParams(tokens[1], params, 'fillHeight'), inputFile, true),
params,
text: contentLines,
}
}
function layoutTextbox(obj, position) {
const {colX, rowY, colWidth, rowHeight} = position
const x1 = colX + colWidth / 2 - obj.width / 2
const y1 = rowY + rowHeight / 2 - obj.height / 2
return {
cx: x1 + obj.width / 2,
cy: y1 + obj.height / 2,
width: obj.width,
height: obj.height,
x1: x1,
y1: y1,
}
}
function renderTextbox(obj, sizeAndPosition, styleBlock, svgBlock, context, styleData) {
let {x1, y1, width, height} = sizeAndPosition
let buf = ``
buf += renderText(obj, sizeAndPosition, styleBlock, svgBlock, context, styleData)
return buf
}
function renderText(obj, sizeAndPosition, styleBlock, svgBlock, context, styleData) {
let {cx, cy, width, height, gridAlign} = sizeAndPosition
styleBlock = applyTextAlignment(gridAlign, styleData)
let x = cx
let y = cy
if (sizeAndPosition.gridAlign.horizontal === 'left') {
x -= width / 2
} else if (sizeAndPosition.gridAlign.horizontal === 'right') {
x += width / 2
}
if (sizeAndPosition.gridAlign.vertical === 'top') {
y -= height / 2
} else if (sizeAndPosition.gridAlign.vertical === 'bottom') {
y += height / 2
}
let lineHeight = 1.2
let dy = 0
if (sizeAndPosition.gridAlign.vertical === 'middle') {
dy = round(-1 * lineHeight / 2 * (obj.text.length - 1))
} else if (sizeAndPosition.gridAlign.vertical === 'bottom') {
dy = round(-1 * lineHeight * (obj.text.length - 1))
}
// Any styles defined will override default class
let buf = ``
for (var line of obj.text) {
const safe = Util.htmlEntities(line.trim())
buf += `${safe}`
dy = lineHeight
}
buf += ``
return buf
}
function applyTextAlignment(gridAlign, styleData) {
let alignClass
if (gridAlign.vertical === 'top') {
alignClass = `-pln-diagram-at`
} else if (gridAlign.vertical === 'bottom') {
alignClass = `-pln-diagram-ab`
} else if (gridAlign.vertical === 'middle') {
alignClass = `-pln-diagram-am`
}
if (gridAlign.horizontal === 'left') {
alignClass += ` -pln-diagram-al`
} else if (gridAlign.horizontal === 'right') {
alignClass += ` -pln-diagram-ar`
} else if (gridAlign.horizontal === 'center') {
alignClass += ` -pln-diagram-ac`
}
let classesBuf = ''
for (var c of styleData.classes) {
classesBuf += ' ' + c
}
let styleBuf = ''
if (styleData.style !== '') {
styleBuf = ` style="${styleData.style}"`
}
return ` class="${alignClass}${classesBuf}"${styleBuf}`
}
function parserFunnybox(line, inputFile, variables, settings) {
const {key, tokens, contentLines, content} = parseKeyContent(line, inputFile, 3, variables, true)
return {
key,
type: C.funnybox,
}
}
function parserNosize(line, inputFile, variables, settings) {
const {key, tokens, contentLines, content} = parseKeyContent(line, inputFile, 3, variables, true)
return {
key,
width: 1,
type: C.nosize,
}
}
function renderNosize(obj, sizeAndPosition, styleBlock, svgBlock) {
let {x1, y1, width, height} = sizeAndPosition
let buf = ``
return buf
}
function parserNowidth(line, inputFile, variables, settings) {
const {key, tokens, contentLines, content} = parseKeyContent(line, inputFile, 3, variables, true)
return {
key,
height: 1,
type: C.nosize,
}
}
function parserRightAngleLine(line, inputFile, variables) {
const {key, tokens} = parseKeyContent(line, inputFile, 2, variables, true)
const params = {
fillWidth: [0, 1],
fillHeight: [0, 1],
}
return {
key,
type: C.rightAngleLine,
width: 'fill',
height: 'fill',
params
}
}
function layoutRightAngleLine(obj, position) {
const {colX, rowY, colWidth, rowHeight} = position
const pathHeadUp = 'l 5 0 l -5 -15 l -5 15 z'
const pathHeadDown = 'l 5 0 l -5 15 l -5 -15 z'
const pathHeadLeft = 'l 0 5 l -15 -5 l 15 -5 z'
const pathHeadRight = 'l 0 5 l 15 -5 l -15 -5 z'
let pathHead
let x1 = position.box.from.x
let y1 = position.box.from.y
let x2 = position.box.to.x
let y2 = position.box.to.y
let dx1 = 0
let dy1 = 0
let dx2 = 0
let dy2 = 0
if (position.box.to.handleV === 'bottom') {
y2 += 16
pathHead = pathHeadUp
dx1 = x2 - x1
dy2 = y2 - y1
} else if (position.box.to.handleV === 'top') {
y2 -= 16
pathHead = pathHeadDown
dx1 = x2 - x1
dy2 = y2 - y1
} else if (position.box.to.handleH === 'left') {
x2 -= 16
pathHead = pathHeadRight
dy1 = y2 - y1
dx2 = x2 - x1
} else if (position.box.to.handleH === 'right') {
x2 += 16
pathHead = pathHeadLeft
dy1 = y2 - y1
dx2 = x2 - x1
}
let path = `m ${x1} ${y1} l ${dx1} ${dy1} l ${dx2} ${dy2}`
pathHead = `m ${x2} ${y2} ${pathHead}`
return {
path,
pathHead,
}
}
function renderRightAngleLine(obj, sizeAndPosition, styleBlock, svgBlock) {
const {cx, cy} = sizeAndPosition
const x1 = cx - obj.width / 2
const y1 = cy - obj.height / 2
let pathHeadStyle = ` class="${obj.key}-head"`
const pathSpec = `M ${round(x1)},${round(y1)} ${sizeAndPosition.path}`
let buf = ``
const headPathSpec = `M ${round(x1)},${round(y1)} ${sizeAndPosition.pathHead}`
buf += ``
return buf
}
function specParsed(spec) {
spec.globalStyles['.test-spec-parsed'] = `text-anchor: start;`
}