331 lines
9.4 KiB
JavaScript
Raw Normal View History

2017-09-10 21:23:04 +08:00
export const drawRect = function (elem, rectData) {
2017-09-14 20:35:00 +08:00
const rectElem = elem.append('rect')
2017-04-11 22:14:25 +08:00
rectElem.attr('x', rectData.x)
rectElem.attr('y', rectData.y)
rectElem.attr('fill', rectData.fill)
rectElem.attr('stroke', rectData.stroke)
rectElem.attr('width', rectData.width)
rectElem.attr('height', rectData.height)
rectElem.attr('rx', rectData.rx)
rectElem.attr('ry', rectData.ry)
if (typeof rectData.class !== 'undefined') {
rectElem.attr('class', rectData.class)
}
return rectElem
}
2017-09-10 21:23:04 +08:00
export const drawText = function (elem, textData, width) {
2017-04-16 23:48:36 +08:00
// Remove and ignore br:s
2017-09-14 20:35:00 +08:00
const nText = textData.text.replace(/<br\/?>/ig, ' ')
2017-04-11 22:14:25 +08:00
2017-09-14 20:35:00 +08:00
const textElem = elem.append('text')
2017-04-11 22:14:25 +08:00
textElem.attr('x', textData.x)
textElem.attr('y', textData.y)
textElem.style('text-anchor', textData.anchor)
textElem.attr('fill', textData.fill)
if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class)
}
2017-09-14 20:35:00 +08:00
const span = textElem.append('tspan')
2017-04-11 22:14:25 +08:00
span.attr('x', textData.x + textData.textMargin * 2)
span.attr('fill', textData.fill)
span.text(nText)
if (typeof textElem.textwrap !== 'undefined') {
textElem.textwrap({
x: textData.x, // bounding box is 300 pixels from the left
y: textData.y, // bounding box is 400 pixels from the top
width: width, // bounding box is 500 pixels across
height: 1800 // bounding box is 600 pixels tall
}, textData.textMargin)
}
return textElem
}
2014-12-20 09:18:12 +01:00
2017-09-10 21:23:04 +08:00
export const drawLabel = function (elem, txtObject) {
2017-04-11 22:14:25 +08:00
function genPoints (x, y, width, height, cut) {
return x + ',' + y + ' ' +
2017-04-16 23:48:36 +08:00
(x + width) + ',' + y + ' ' +
(x + width) + ',' + (y + height - cut) + ' ' +
(x + width - cut * 1.2) + ',' + (y + height) + ' ' +
(x) + ',' + (y + height)
2017-04-11 22:14:25 +08:00
}
2017-09-14 20:35:00 +08:00
const polygon = elem.append('polygon')
2017-04-11 22:14:25 +08:00
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7))
2017-04-22 21:24:21 +08:00
polygon.attr('class', 'labelBox')
2017-04-11 22:14:25 +08:00
txtObject.y = txtObject.y + txtObject.labelMargin
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin
2017-09-10 21:23:04 +08:00
drawText(elem, txtObject)
2017-04-11 22:14:25 +08:00
}
2017-09-14 20:35:00 +08:00
let actorCnt = -1
2015-01-05 13:41:32 +01:00
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors
* @param description The text in the box
*/
2017-09-10 21:23:04 +08:00
export const drawActor = function (elem, left, verticalPos, description, conf) {
2017-09-14 20:35:00 +08:00
const center = left + (conf.width / 2)
const g = elem.append('g')
2017-04-11 22:14:25 +08:00
if (verticalPos === 0) {
actorCnt++
g.append('line')
2017-04-16 23:48:36 +08:00
.attr('id', 'actor' + actorCnt)
.attr('x1', center)
.attr('y1', 5)
.attr('x2', center)
.attr('y2', 2000)
.attr('class', 'actor-line')
.attr('stroke-width', '0.5px')
.attr('stroke', '#999')
2017-04-11 22:14:25 +08:00
}
2017-09-14 20:35:00 +08:00
const rect = getNoteRect()
2017-04-11 22:14:25 +08:00
rect.x = left
rect.y = verticalPos
rect.fill = '#eaeaea'
rect.width = conf.width
rect.height = conf.height
rect.class = 'actor'
rect.rx = 3
rect.ry = 3
2017-09-10 21:23:04 +08:00
drawRect(g, rect)
2017-04-11 22:14:25 +08:00
_drawTextCandidateFunc(conf)(description, g,
2017-04-16 23:48:36 +08:00
rect.x, rect.y, rect.width, rect.height, { 'class': 'actor' })
2017-04-11 22:14:25 +08:00
}
2017-09-10 21:23:04 +08:00
export const anchorElement = function (elem) {
2017-04-11 22:14:25 +08:00
return elem.append('g')
}
2016-03-08 10:40:52 +01:00
/**
* Draws an actor in the diagram with the attaced line
2016-03-11 16:44:45 +01:00
* @param elem - element to append activation rect
* @param bounds - activation box bounds
* @param verticalPos - precise y cooridnate of bottom activation box edge
2016-03-08 10:40:52 +01:00
*/
2017-09-10 21:23:04 +08:00
export const drawActivation = function (elem, bounds, verticalPos) {
2017-09-14 20:35:00 +08:00
const rect = getNoteRect()
const g = bounds.anchored
2017-04-11 22:14:25 +08:00
rect.x = bounds.startx
rect.y = bounds.starty
rect.fill = '#f4f4f4'
rect.width = bounds.stopx - bounds.startx
rect.height = verticalPos - bounds.starty
2017-09-10 21:23:04 +08:00
drawRect(g, rect)
2017-04-11 22:14:25 +08:00
}
2016-03-08 10:40:52 +01:00
2015-01-05 14:41:00 +01:00
/**
* Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor
* @param pos The position if the actor in the list of actors
* @param description The text in the box
*/
2017-09-10 21:23:04 +08:00
export const drawLoop = function (elem, bounds, labelText, conf) {
2017-09-14 20:35:00 +08:00
const g = elem.append('g')
const drawLoopLine = function (startx, starty, stopx, stopy) {
2017-04-11 22:14:25 +08:00
return g.append('line')
2017-04-16 23:48:36 +08:00
.attr('x1', startx)
.attr('y1', starty)
.attr('x2', stopx)
.attr('y2', stopy)
.attr('class', 'loopLine')
2017-04-11 22:14:25 +08:00
}
drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty)
drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy)
drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy)
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy)
if (typeof bounds.sections !== 'undefined') {
bounds.sections.forEach(function (item) {
drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3')
})
}
2017-09-14 20:35:00 +08:00
let txt = getTextObj()
2017-04-11 22:14:25 +08:00
txt.text = labelText
txt.x = bounds.startx
txt.y = bounds.starty
txt.labelMargin = 1.5 * 10 // This is the small box that says "loop"
2018-03-06 14:37:27 +08:00
txt.class = 'labelText' // Its size & position are fixed.
2017-04-11 22:14:25 +08:00
2017-09-10 21:23:04 +08:00
drawLabel(g, txt)
2017-04-11 22:14:25 +08:00
2017-09-10 21:23:04 +08:00
txt = getTextObj()
2017-04-11 22:14:25 +08:00
txt.text = '[ ' + bounds.title + ' ]'
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2
txt.y = bounds.starty + 1.5 * conf.boxMargin
txt.anchor = 'middle'
txt.class = 'loopText'
2017-09-10 21:23:04 +08:00
drawText(g, txt)
2017-04-11 22:14:25 +08:00
if (typeof bounds.sectionTitles !== 'undefined') {
bounds.sectionTitles.forEach(function (item, idx) {
if (item !== '') {
txt.text = '[ ' + item + ' ]'
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin
2017-09-10 21:23:04 +08:00
drawText(g, txt)
2017-04-11 22:14:25 +08:00
}
})
}
}
2015-01-05 14:41:00 +01:00
2015-01-05 13:41:32 +01:00
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
2017-09-10 21:23:04 +08:00
export const insertArrowHead = function (elem) {
2017-04-11 22:14:25 +08:00
elem.append('defs').append('marker')
2017-04-16 23:48:36 +08:00
.attr('id', 'arrowhead')
.attr('refX', 5)
.attr('refY', 2)
.attr('markerWidth', 6)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0,0 V 4 L6,2 Z') // this is actual shape for arrowhead
2017-04-11 22:14:25 +08:00
}
2015-01-05 13:41:32 +01:00
/**
* Setup arrow head and define the marker. The result is appended to the svg.
*/
2017-09-10 21:23:04 +08:00
export const insertArrowCrossHead = function (elem) {
2017-09-14 20:35:00 +08:00
const defs = elem.append('defs')
const marker = defs.append('marker')
2017-04-16 23:48:36 +08:00
.attr('id', 'crosshead')
.attr('markerWidth', 15)
.attr('markerHeight', 8)
.attr('orient', 'auto')
.attr('refX', 16)
.attr('refY', 4)
// The arrow
2017-04-11 22:14:25 +08:00
marker.append('path')
2017-04-16 23:48:36 +08:00
.attr('fill', 'black')
.attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0'))
.attr('stroke-width', '1px')
.attr('d', 'M 9,2 V 6 L16,4 Z')
2017-04-16 23:48:36 +08:00
// The cross
2017-04-11 22:14:25 +08:00
marker.append('path')
2017-04-16 23:48:36 +08:00
.attr('fill', 'none')
.attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0'))
.attr('stroke-width', '1px')
.attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7')
// this is actual shape for arrowhead
2017-04-11 22:14:25 +08:00
}
2017-09-10 21:23:04 +08:00
export const getTextObj = function () {
2017-09-14 20:35:00 +08:00
const txt = {
2017-04-11 22:14:25 +08:00
x: 0,
y: 0,
'fill': 'black',
'text-anchor': 'start',
style: '#666',
width: 100,
height: 100,
textMargin: 0,
rx: 0,
ry: 0
}
return txt
}
2017-09-10 21:23:04 +08:00
export const getNoteRect = function () {
2017-09-14 20:35:00 +08:00
const rect = {
2017-04-11 22:14:25 +08:00
x: 0,
y: 0,
fill: '#EDF2AE',
stroke: '#666',
width: 100,
anchor: 'start',
height: 100,
rx: 0,
ry: 0
}
return rect
}
2017-09-14 20:35:00 +08:00
const _drawTextCandidateFunc = (function () {
2017-04-11 22:14:25 +08:00
function byText (content, g, x, y, width, height, textAttrs) {
2017-09-14 20:35:00 +08:00
const text = g.append('text')
2017-04-16 23:48:36 +08:00
.attr('x', x + width / 2).attr('y', y + height / 2 + 5)
.style('text-anchor', 'middle')
.text(content)
2017-04-11 22:14:25 +08:00
_setTextAttrs(text, textAttrs)
}
2017-04-11 22:14:25 +08:00
function byTspan (content, g, x, y, width, height, textAttrs) {
2017-09-14 20:35:00 +08:00
const text = g.append('text')
2017-04-16 23:48:36 +08:00
.attr('x', x + width / 2).attr('y', y)
.style('text-anchor', 'middle')
2017-04-11 22:14:25 +08:00
text.append('tspan')
2017-04-16 23:48:36 +08:00
.attr('x', x + width / 2).attr('dy', '0')
.text(content)
2017-04-11 22:14:25 +08:00
if (typeof (text.textwrap) !== 'undefined') {
text.textwrap({ // d3textwrap
x: x + width / 2, y: y, width: width, height: height
}, 0)
2017-04-16 23:48:36 +08:00
// vertical aligment after d3textwrap expans tspan to multiple tspans
2017-09-14 20:35:00 +08:00
let tspans = text.selectAll('tspan')
2017-04-11 22:14:25 +08:00
if (tspans.length > 0 && tspans[0].length > 0) {
tspans = tspans[0]
2017-04-16 23:48:36 +08:00
// set y of <text> to the mid y of the first line
2017-04-11 22:14:25 +08:00
text.attr('y', y + (height / 2.0 - text[0][0].getBBox().height * (1 - 1.0 / tspans.length) / 2.0))
2017-04-16 23:48:36 +08:00
.attr('dominant-baseline', 'central')
.attr('alignment-baseline', 'central')
2017-04-11 22:14:25 +08:00
}
2016-12-17 18:03:11 -05:00
}
2017-04-11 22:14:25 +08:00
_setTextAttrs(text, textAttrs)
}
2017-04-11 22:14:25 +08:00
function byFo (content, g, x, y, width, height, textAttrs) {
2017-09-14 20:35:00 +08:00
const s = g.append('switch')
const f = s.append('foreignObject')
2017-04-16 23:48:36 +08:00
.attr('x', x).attr('y', y)
.attr('width', width).attr('height', height)
2017-09-14 20:35:00 +08:00
const text = f.append('div').style('display', 'table')
2017-04-16 23:48:36 +08:00
.style('height', '100%').style('width', '100%')
2017-04-11 22:14:25 +08:00
text.append('div').style('display', 'table-cell')
2017-04-16 23:48:36 +08:00
.style('text-align', 'center').style('vertical-align', 'middle')
.text(content)
2017-04-11 22:14:25 +08:00
byTspan(content, s, x, y, width, height, textAttrs)
_setTextAttrs(text, textAttrs)
}
2017-04-11 22:14:25 +08:00
function _setTextAttrs (toText, fromTextAttrsDict) {
2017-09-14 20:35:00 +08:00
for (const key in fromTextAttrsDict) {
2017-04-11 22:14:25 +08:00
if (fromTextAttrsDict.hasOwnProperty(key)) {
toText.attr(key, fromTextAttrsDict[key])
2016-12-17 18:03:11 -05:00
}
}
2017-04-11 22:14:25 +08:00
}
2017-04-11 22:14:25 +08:00
return function (conf) {
return conf.textPlacement === 'fo' ? byFo : (
2017-04-16 23:48:36 +08:00
conf.textPlacement === 'old' ? byText : byTspan)
2017-04-11 22:14:25 +08:00
}
})()
2017-09-10 22:03:10 +08:00
export default {
drawRect,
drawText,
drawLabel,
drawActor,
anchorElement,
drawActivation,
drawLoop,
insertArrowHead,
insertArrowCrossHead,
getTextObj,
getNoteRect
}