Render if/else/repeat/ref blocks in sketch style, and improve standard rendering [#18]
This commit is contained in:
parent
531b284afa
commit
bb61d1faf3
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
|
@ -172,6 +172,7 @@ define([
|
|||
textSizer: this.sizer,
|
||||
addSpacing,
|
||||
addSeparation: this.addSeparation,
|
||||
state: this.state,
|
||||
components: this.components,
|
||||
};
|
||||
const component = this.components.get(stage.type);
|
||||
|
@ -240,13 +241,13 @@ define([
|
|||
return;
|
||||
}
|
||||
|
||||
this.theme.drawAgentLine(this.agentLines, {
|
||||
this.agentLines.appendChild(this.theme.renderAgentLine({
|
||||
x: agentInfo.x,
|
||||
y0: agentInfo.latestYStart,
|
||||
y1: toY,
|
||||
width: agentInfo.currentRad * 2,
|
||||
className: 'agent-' + agentInfo.index + '-line',
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
addHighlightObject(line, o) {
|
||||
|
@ -416,6 +417,13 @@ define([
|
|||
this.height = (y1 - y0);
|
||||
}
|
||||
|
||||
_resetState() {
|
||||
this.components.forEach((component) => {
|
||||
component.resetState(this.state);
|
||||
});
|
||||
this.currentY = 0;
|
||||
}
|
||||
|
||||
_reset() {
|
||||
this.knownDefs.clear();
|
||||
this.highlights.clear();
|
||||
|
@ -428,9 +436,7 @@ define([
|
|||
svg.empty(this.actionLabels);
|
||||
this.mask.appendChild(this.maskReveal);
|
||||
this.defs.appendChild(this.mask);
|
||||
this.components.forEach((component) => {
|
||||
component.resetState(this.state);
|
||||
});
|
||||
this._resetState();
|
||||
}
|
||||
|
||||
setHighlight(line = null) {
|
||||
|
@ -475,7 +481,7 @@ define([
|
|||
this.maxX = 0;
|
||||
this.buildAgentInfos(sequence.agents, sequence.stages);
|
||||
|
||||
this.currentY = 0;
|
||||
this._resetState();
|
||||
sequence.stages.forEach(this.renderStage);
|
||||
const bottomY = this.checkAgentRange(['[', ']'], this.currentY);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ define([
|
|||
'./Generator',
|
||||
'./Renderer',
|
||||
'./Exporter',
|
||||
'./themes/BaseTheme',
|
||||
'./themes/Basic',
|
||||
'./themes/Chunky',
|
||||
'./themes/Sketch',
|
||||
|
@ -14,6 +15,7 @@ define([
|
|||
Generator,
|
||||
Renderer,
|
||||
Exporter,
|
||||
BaseTheme,
|
||||
BasicTheme,
|
||||
ChunkyTheme,
|
||||
SketchTheme
|
||||
|
@ -234,6 +236,7 @@ define([
|
|||
Generator,
|
||||
Renderer,
|
||||
Exporter,
|
||||
BaseTheme,
|
||||
themes,
|
||||
addTheme,
|
||||
registerCodeMirrorMode,
|
||||
|
|
|
@ -16,6 +16,7 @@ define(() => {
|
|||
textSizer,
|
||||
addSpacing,
|
||||
addSeparation,
|
||||
state,
|
||||
components,
|
||||
}*/) {
|
||||
}
|
||||
|
@ -27,6 +28,7 @@ define(() => {
|
|||
textSizer,
|
||||
addSpacing,
|
||||
addSeparation,
|
||||
state,
|
||||
components,
|
||||
}*/) {
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ define([
|
|||
|
||||
class BlockSplit extends BaseComponent {
|
||||
separation({left, right, mode, label}, env) {
|
||||
const config = env.theme.block.section;
|
||||
const blockInfo = env.state.blocks.get(left);
|
||||
const config = env.theme.getBlock(blockInfo.mode).section;
|
||||
const width = (
|
||||
env.textSizer.measure(config.mode.labelAttrs, mode).width +
|
||||
config.mode.padding.left +
|
||||
|
@ -32,21 +33,15 @@ define([
|
|||
}
|
||||
|
||||
render({left, right, mode, label}, env, first = false) {
|
||||
const config = env.theme.block;
|
||||
const blockInfo = env.state.blocks.get(left);
|
||||
const config = env.theme.getBlock(blockInfo.mode);
|
||||
const agentInfoL = env.agentInfos.get(left);
|
||||
const agentInfoR = env.agentInfos.get(right);
|
||||
const {hold} = env.state.blocks.get(left);
|
||||
|
||||
let y = env.primaryY;
|
||||
|
||||
if(!first) {
|
||||
y += config.section.padding.bottom;
|
||||
hold.appendChild(svg.make('line', Object.assign({
|
||||
'x1': agentInfoL.x,
|
||||
'y1': y,
|
||||
'x2': agentInfoR.x,
|
||||
'y2': y,
|
||||
}, config.separator.attrs)));
|
||||
}
|
||||
|
||||
const clickable = env.makeRegion();
|
||||
|
@ -56,8 +51,9 @@ define([
|
|||
y,
|
||||
padding: config.section.mode.padding,
|
||||
boxAttrs: config.section.mode.boxAttrs,
|
||||
boxRenderer: config.section.mode.boxRenderer,
|
||||
labelAttrs: config.section.mode.labelAttrs,
|
||||
boxLayer: hold,
|
||||
boxLayer: blockInfo.hold,
|
||||
labelLayer: clickable,
|
||||
SVGTextBlockClass: env.SVGTextBlockClass,
|
||||
});
|
||||
|
@ -83,6 +79,15 @@ define([
|
|||
'fill': 'transparent',
|
||||
}), clickable.firstChild);
|
||||
|
||||
if(!first) {
|
||||
blockInfo.hold.appendChild(config.sepRenderer({
|
||||
'x1': agentInfoL.x,
|
||||
'y1': y,
|
||||
'x2': agentInfoR.x,
|
||||
'y2': y,
|
||||
}));
|
||||
}
|
||||
|
||||
return y + labelHeight + config.section.padding.top;
|
||||
}
|
||||
}
|
||||
|
@ -96,15 +101,31 @@ define([
|
|||
state.blocks.clear();
|
||||
}
|
||||
|
||||
storeBlockInfo(stage, env) {
|
||||
env.state.blocks.set(stage.left, {
|
||||
mode: stage.mode,
|
||||
hold: null,
|
||||
startY: null,
|
||||
});
|
||||
}
|
||||
|
||||
separationPre(stage, env) {
|
||||
this.storeBlockInfo(stage, env);
|
||||
}
|
||||
|
||||
separation(stage, env) {
|
||||
array.mergeSets(env.visibleAgents, [stage.left, stage.right]);
|
||||
super.separation(stage, env);
|
||||
}
|
||||
|
||||
renderPre({left, right}, env) {
|
||||
renderPre(stage, env) {
|
||||
this.storeBlockInfo(stage, env);
|
||||
|
||||
const config = env.theme.getBlock(stage.mode);
|
||||
|
||||
return {
|
||||
agentNames: [left, right],
|
||||
topShift: env.theme.block.margin.top,
|
||||
agentNames: [stage.left, stage.right],
|
||||
topShift: config.margin.top,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -112,11 +133,9 @@ define([
|
|||
const hold = svg.make('g');
|
||||
env.blockLayer.appendChild(hold);
|
||||
|
||||
env.state.blocks.set(stage.left, {
|
||||
hold,
|
||||
mode: stage.mode,
|
||||
startY: env.primaryY,
|
||||
});
|
||||
const blockInfo = env.state.blocks.get(stage.left);
|
||||
blockInfo.hold = hold;
|
||||
blockInfo.startY = env.primaryY;
|
||||
|
||||
return super.render(stage, env, true);
|
||||
}
|
||||
|
@ -128,25 +147,27 @@ define([
|
|||
}
|
||||
|
||||
renderPre({left, right}, env) {
|
||||
const blockInfo = env.state.blocks.get(left);
|
||||
const config = env.theme.getBlock(blockInfo.mode);
|
||||
|
||||
return {
|
||||
agentNames: [left, right],
|
||||
topShift: env.theme.block.section.padding.bottom,
|
||||
topShift: config.section.padding.bottom,
|
||||
};
|
||||
}
|
||||
|
||||
render({left, right}, env) {
|
||||
const config = env.theme.block;
|
||||
|
||||
const blockInfo = env.state.blocks.get(left);
|
||||
const config = env.theme.getBlock(blockInfo.mode);
|
||||
const agentInfoL = env.agentInfos.get(left);
|
||||
const agentInfoR = env.agentInfos.get(right);
|
||||
const {hold, startY, mode} = env.state.blocks.get(left);
|
||||
const configMode = config.modes[mode] || config.modes[''];
|
||||
hold.appendChild(svg.make('rect', Object.assign({
|
||||
'x': agentInfoL.x,
|
||||
'y': startY,
|
||||
'width': agentInfoR.x - agentInfoL.x,
|
||||
'height': env.primaryY - startY,
|
||||
}, configMode.boxAttrs)));
|
||||
|
||||
blockInfo.hold.appendChild(config.boxRenderer({
|
||||
x: agentInfoL.x,
|
||||
y: blockInfo.startY,
|
||||
width: agentInfoR.x - agentInfoL.x,
|
||||
height: env.primaryY - blockInfo.startY,
|
||||
}));
|
||||
|
||||
return env.primaryY + config.margin.bottom + env.theme.actionMargin;
|
||||
}
|
||||
|
|
|
@ -9,19 +9,6 @@ define([
|
|||
) => {
|
||||
'use strict';
|
||||
|
||||
function drawHorizontalArrowHead({x, y, dx, dy, attrs}) {
|
||||
return svg.make(
|
||||
attrs.fill === 'none' ? 'polyline' : 'polygon',
|
||||
Object.assign({
|
||||
'points': (
|
||||
(x + dx) + ' ' + (y - dy) + ' ' +
|
||||
x + ' ' + y + ' ' +
|
||||
(x + dx) + ' ' + (y + dy)
|
||||
),
|
||||
}, attrs)
|
||||
);
|
||||
}
|
||||
|
||||
class Arrowhead {
|
||||
constructor(propName) {
|
||||
this.propName = propName;
|
||||
|
@ -48,13 +35,11 @@ define([
|
|||
|
||||
render(layer, theme, pt, dir) {
|
||||
const config = this.getConfig(theme);
|
||||
const func = config.render || drawHorizontalArrowHead;
|
||||
layer.appendChild(func({
|
||||
layer.appendChild(config.render(config.attrs, {
|
||||
x: pt.x + this.short(theme) * dir,
|
||||
y: pt.y,
|
||||
dx: config.width * dir,
|
||||
dy: config.height / 2,
|
||||
attrs: config.attrs,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
define(['svg/SVGUtilities'], (svg) => {
|
||||
'use strict';
|
||||
|
||||
function deepCopy(o) {
|
||||
if(typeof o !== 'object' || !o) {
|
||||
return o;
|
||||
}
|
||||
const r = {};
|
||||
for(let k in o) {
|
||||
if(o.hasOwnProperty(k)) {
|
||||
r[k] = deepCopy(o[k]);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
class BaseTheme {
|
||||
constructor({name, settings, blocks, notes}) {
|
||||
this.name = name;
|
||||
this.blocks = deepCopy(blocks);
|
||||
this.notes = deepCopy(notes);
|
||||
Object.assign(this, deepCopy(settings));
|
||||
}
|
||||
|
||||
reset() {
|
||||
}
|
||||
|
||||
addDefs() {
|
||||
}
|
||||
|
||||
getBlock(type) {
|
||||
return this.blocks[type] || this.blocks[''];
|
||||
}
|
||||
|
||||
getNote(type) {
|
||||
return this.notes[type] || this.notes[''];
|
||||
}
|
||||
|
||||
renderAgentLine({x, y0, y1, width, className}) {
|
||||
if(width > 0) {
|
||||
return svg.make('rect', Object.assign({
|
||||
'x': x - width / 2,
|
||||
'y': y0,
|
||||
'width': width,
|
||||
'height': y1 - y0,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs));
|
||||
} else {
|
||||
return svg.make('line', Object.assign({
|
||||
'x1': x,
|
||||
'y1': y0,
|
||||
'x2': x,
|
||||
'y2': y1,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseTheme.renderHorizArrowHead = (attrs, {x, y, dx, dy}) => {
|
||||
return svg.make(
|
||||
attrs.fill === 'none' ? 'polyline' : 'polygon',
|
||||
Object.assign({
|
||||
'points': (
|
||||
(x + dx) + ' ' + (y - dy) + ' ' +
|
||||
x + ' ' + y + ' ' +
|
||||
(x + dx) + ' ' + (y + dy)
|
||||
),
|
||||
}, attrs)
|
||||
);
|
||||
};
|
||||
|
||||
BaseTheme.renderTag = (attrs, {x, y, width, height}) => {
|
||||
const {rx, ry} = attrs;
|
||||
const x2 = x + width;
|
||||
const y2 = y + height;
|
||||
|
||||
const line = (
|
||||
'M' + x2 + ' ' + y +
|
||||
'L' + x2 + ' ' + (y2 - ry) +
|
||||
'L' + (x2 - rx) + ' ' + y2 +
|
||||
'L' + x + ' ' + y2
|
||||
);
|
||||
|
||||
const g = svg.make('g');
|
||||
if(attrs.fill !== 'none') {
|
||||
g.appendChild(svg.make('path', Object.assign({
|
||||
'd': line + 'L' + x + ' ' + y,
|
||||
}, attrs, {'stroke': 'none'})));
|
||||
}
|
||||
|
||||
if(attrs.stroke !== 'none') {
|
||||
g.appendChild(svg.make('path', Object.assign({
|
||||
'd': line,
|
||||
}, attrs, {'fill': 'none'})));
|
||||
}
|
||||
|
||||
return g;
|
||||
};
|
||||
|
||||
BaseTheme.renderCross = (attrs, {x, y, radius}) => {
|
||||
return svg.make('path', Object.assign({
|
||||
'd': (
|
||||
'M' + (x - radius) + ' ' + (y - radius) +
|
||||
'l' + (radius * 2) + ' ' + (radius * 2) +
|
||||
'm0 ' + (-radius * 2) +
|
||||
'l' + (-radius * 2) + ' ' + (radius * 2)
|
||||
),
|
||||
}, attrs));
|
||||
};
|
||||
|
||||
return BaseTheme;
|
||||
});
|
|
@ -1,9 +1,9 @@
|
|||
define([
|
||||
'core/ArrayUtilities',
|
||||
'./BaseTheme',
|
||||
'svg/SVGUtilities',
|
||||
'svg/SVGShapes',
|
||||
], (
|
||||
array,
|
||||
BaseTheme,
|
||||
svg,
|
||||
SVGShapes
|
||||
) => {
|
||||
|
@ -43,33 +43,19 @@ define([
|
|||
},
|
||||
cross: {
|
||||
size: 20,
|
||||
render: ({x, y, radius}) => {
|
||||
return svg.make('path', {
|
||||
'd': (
|
||||
'M' + (x - radius) + ' ' + (y - radius) +
|
||||
'l' + (radius * 2) + ' ' + (radius * 2) +
|
||||
'm0 ' + (-radius * 2) +
|
||||
'l' + (-radius * 2) + ' ' + (radius * 2)
|
||||
),
|
||||
render: BaseTheme.renderCross.bind(null, {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
});
|
||||
},
|
||||
}),
|
||||
},
|
||||
bar: {
|
||||
height: 4,
|
||||
render: ({x, y, width, height}) => {
|
||||
return svg.make('rect', {
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
render: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#000000',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
});
|
||||
},
|
||||
}),
|
||||
},
|
||||
fade: {
|
||||
width: 5,
|
||||
|
@ -114,6 +100,7 @@ define([
|
|||
'single': {
|
||||
width: 5,
|
||||
height: 10,
|
||||
render: BaseTheme.renderHorizArrowHead,
|
||||
attrs: {
|
||||
'fill': '#000000',
|
||||
'stroke-width': 0,
|
||||
|
@ -123,6 +110,7 @@ define([
|
|||
'double': {
|
||||
width: 4,
|
||||
height: 6,
|
||||
render: BaseTheme.renderHorizArrowHead,
|
||||
attrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
|
@ -156,32 +144,22 @@ define([
|
|||
},
|
||||
},
|
||||
|
||||
block: {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
titleAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 20,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
modes: {
|
||||
'ref': {
|
||||
boxAttrs: {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
},
|
||||
},
|
||||
'': {
|
||||
boxAttrs: {
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
'stroke-width': 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
section: {
|
||||
};
|
||||
|
||||
const SHARED_BLOCK_SECTION = {
|
||||
padding: {
|
||||
top: 3,
|
||||
bottom: 2,
|
||||
|
@ -193,13 +171,13 @@ define([
|
|||
right: 3,
|
||||
bottom: 0,
|
||||
},
|
||||
boxAttrs: {
|
||||
boxRenderer: BaseTheme.renderTag.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
},
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-weight': 'bold',
|
||||
|
@ -222,29 +200,48 @@ define([
|
|||
'text-anchor': 'left',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const BLOCKS = {
|
||||
'ref': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
separator: {
|
||||
attrs: {
|
||||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
}),
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
},
|
||||
'': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
}),
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
sepRenderer: SVGShapes.renderLine.bind(null, {
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'stroke-dasharray': '4, 2',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
titleAttrs: {
|
||||
const NOTE_ATTRS = {
|
||||
'font-family': FONT,
|
||||
'font-size': 20,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
},
|
||||
};
|
||||
|
||||
const NOTES = {
|
||||
|
@ -255,11 +252,7 @@ define([
|
|||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'note': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
|
@ -274,11 +267,7 @@ define([
|
|||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'state': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
|
@ -291,48 +280,18 @@ define([
|
|||
'rx': 10,
|
||||
'ry': 10,
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
};
|
||||
|
||||
return class BasicTheme {
|
||||
return class BasicTheme extends BaseTheme {
|
||||
constructor() {
|
||||
this.name = 'basic';
|
||||
Object.assign(this, SETTINGS);
|
||||
}
|
||||
|
||||
reset() {
|
||||
}
|
||||
|
||||
addDefs() {
|
||||
}
|
||||
|
||||
getNote(type) {
|
||||
return NOTES[type];
|
||||
}
|
||||
|
||||
drawAgentLine(container, {x, y0, y1, width, className}) {
|
||||
if(width > 0) {
|
||||
container.appendChild(svg.make('rect', Object.assign({
|
||||
'x': x - width / 2,
|
||||
'y': y0,
|
||||
'width': width,
|
||||
'height': y1 - y0,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs)));
|
||||
} else {
|
||||
container.appendChild(svg.make('line', Object.assign({
|
||||
'x1': x,
|
||||
'y1': y0,
|
||||
'x2': x,
|
||||
'y2': y1,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs)));
|
||||
}
|
||||
super({
|
||||
name: 'basic',
|
||||
settings: SETTINGS,
|
||||
blocks: BLOCKS,
|
||||
notes: NOTES,
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
define([
|
||||
'core/ArrayUtilities',
|
||||
'./BaseTheme',
|
||||
'svg/SVGUtilities',
|
||||
'svg/SVGShapes',
|
||||
], (
|
||||
array,
|
||||
BaseTheme,
|
||||
svg,
|
||||
SVGShapes
|
||||
) => {
|
||||
|
@ -46,37 +46,22 @@ define([
|
|||
},
|
||||
cross: {
|
||||
size: 20,
|
||||
render: ({x, y, radius}) => {
|
||||
return svg.make('path', Object.assign({
|
||||
'd': (
|
||||
'M' + (x - radius) + ' ' + (y - radius) +
|
||||
'l' + (radius * 2) + ' ' + (radius * 2) +
|
||||
'm0 ' + (-radius * 2) +
|
||||
'l' + (-radius * 2) + ' ' + (radius * 2)
|
||||
),
|
||||
}, {
|
||||
render: BaseTheme.renderCross.bind(null, {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 3,
|
||||
'stroke-linecap': 'round',
|
||||
}));
|
||||
},
|
||||
}),
|
||||
},
|
||||
bar: {
|
||||
height: 4,
|
||||
render: ({x, y, width, height}) => {
|
||||
return svg.make('rect', {
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
render: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#000000',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 3,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
});
|
||||
},
|
||||
}),
|
||||
},
|
||||
fade: {
|
||||
width: 5,
|
||||
|
@ -121,6 +106,7 @@ define([
|
|||
single: {
|
||||
width: 10,
|
||||
height: 12,
|
||||
render: BaseTheme.renderHorizArrowHead,
|
||||
attrs: {
|
||||
'fill': '#000000',
|
||||
'stroke': '#000000',
|
||||
|
@ -131,6 +117,7 @@ define([
|
|||
double: {
|
||||
width: 10,
|
||||
height: 12,
|
||||
render: BaseTheme.renderHorizArrowHead,
|
||||
attrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
|
@ -165,32 +152,23 @@ define([
|
|||
},
|
||||
},
|
||||
|
||||
block: {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
titleAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-weight': 'bolder',
|
||||
'font-size': 20,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
modes: {
|
||||
'ref': {
|
||||
boxAttrs: {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 4,
|
||||
'rx': 5,
|
||||
'ry': 5,
|
||||
},
|
||||
},
|
||||
'': {
|
||||
boxAttrs: {
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 4,
|
||||
'rx': 5,
|
||||
'ry': 5,
|
||||
'stroke-width': 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
section: {
|
||||
};
|
||||
|
||||
const SHARED_BLOCK_SECTION = {
|
||||
padding: {
|
||||
top: 3,
|
||||
bottom: 4,
|
||||
|
@ -202,13 +180,13 @@ define([
|
|||
right: 5,
|
||||
bottom: 1,
|
||||
},
|
||||
boxAttrs: {
|
||||
boxRenderer: BaseTheme.renderTag.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 2,
|
||||
'rx': 3,
|
||||
'ry': 3,
|
||||
},
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-weight': 'bold',
|
||||
|
@ -231,30 +209,48 @@ define([
|
|||
'text-anchor': 'left',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const BLOCKS = {
|
||||
'ref': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
separator: {
|
||||
attrs: {
|
||||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 4,
|
||||
'rx': 5,
|
||||
'ry': 5,
|
||||
}),
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
},
|
||||
'': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 4,
|
||||
'rx': 5,
|
||||
'ry': 5,
|
||||
}),
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
sepRenderer: SVGShapes.renderLine.bind(null, {
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 2,
|
||||
'stroke-dasharray': '5, 3',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
titleAttrs: {
|
||||
const NOTE_ATTRS = {
|
||||
'font-family': FONT,
|
||||
'font-weight': 'bolder',
|
||||
'font-size': 20,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 3,
|
||||
},
|
||||
};
|
||||
|
||||
const NOTES = {
|
||||
|
@ -265,11 +261,7 @@ define([
|
|||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'note': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
|
@ -285,11 +277,7 @@ define([
|
|||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'state': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
|
@ -302,48 +290,18 @@ define([
|
|||
'rx': 10,
|
||||
'ry': 10,
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
};
|
||||
|
||||
return class ChunkyTheme {
|
||||
return class ChunkyTheme extends BaseTheme {
|
||||
constructor() {
|
||||
this.name = 'chunky';
|
||||
Object.assign(this, SETTINGS);
|
||||
}
|
||||
|
||||
reset() {
|
||||
}
|
||||
|
||||
addDefs() {
|
||||
}
|
||||
|
||||
getNote(type) {
|
||||
return NOTES[type];
|
||||
}
|
||||
|
||||
drawAgentLine(container, {x, y0, y1, width, className}) {
|
||||
if(width > 0) {
|
||||
container.appendChild(svg.make('rect', Object.assign({
|
||||
'x': x - width / 2,
|
||||
'y': y0,
|
||||
'width': width,
|
||||
'height': y1 - y0,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs)));
|
||||
} else {
|
||||
container.appendChild(svg.make('line', Object.assign({
|
||||
'x1': x,
|
||||
'y1': y0,
|
||||
'x2': x,
|
||||
'y2': y1,
|
||||
'class': className,
|
||||
}, this.agentLineAttrs)));
|
||||
}
|
||||
super({
|
||||
name: 'chunky',
|
||||
settings: SETTINGS,
|
||||
blocks: BLOCKS,
|
||||
notes: NOTES,
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
define([
|
||||
'core/ArrayUtilities',
|
||||
'./BaseTheme',
|
||||
'svg/SVGUtilities',
|
||||
'svg/SVGShapes',
|
||||
'./HandleeFontData',
|
||||
], (
|
||||
array,
|
||||
BaseTheme,
|
||||
svg,
|
||||
SVGShapes,
|
||||
Handlee
|
||||
|
@ -13,25 +13,11 @@ define([
|
|||
|
||||
// TODO:
|
||||
// * fade starter/terminator sometimes does not fully cover line
|
||||
// * blocks (if/else/repeat/ref)
|
||||
|
||||
const FONT = Handlee.name;
|
||||
const FONT_FAMILY = '"' + FONT + '",cursive';
|
||||
const LINE_HEIGHT = 1.5;
|
||||
|
||||
function deepCopy(o) {
|
||||
if(typeof o !== 'object' || !o) {
|
||||
return o;
|
||||
}
|
||||
const r = {};
|
||||
for(let k in o) {
|
||||
if(o.hasOwnProperty(k)) {
|
||||
r[k] = deepCopy(o[k]);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
const PENCIL = {
|
||||
'stroke': 'rgba(0,0,0,0.7)',
|
||||
'stroke-width': 0.8,
|
||||
|
@ -39,6 +25,13 @@ define([
|
|||
'stroke-linecap': 'round',
|
||||
};
|
||||
|
||||
const THICK_PENCIL = {
|
||||
'stroke': 'rgba(0,0,0,0.8)',
|
||||
'stroke-width': 1.2,
|
||||
'stroke-linejoin': 'round',
|
||||
'stroke-linecap': 'round',
|
||||
};
|
||||
|
||||
const SETTINGS = {
|
||||
titleMargin: 10,
|
||||
outerMargin: 5,
|
||||
|
@ -154,50 +147,34 @@ define([
|
|||
},
|
||||
},
|
||||
|
||||
block: {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
titleAttrs: {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-size': 20,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
modes: {
|
||||
'ref': {
|
||||
boxAttrs: {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
},
|
||||
},
|
||||
'': {
|
||||
boxAttrs: {
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
'stroke-width': 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
section: {
|
||||
};
|
||||
|
||||
const SHARED_BLOCK_SECTION = {
|
||||
padding: {
|
||||
top: 3,
|
||||
bottom: 2,
|
||||
},
|
||||
mode: {
|
||||
padding: {
|
||||
top: 1,
|
||||
top: 2,
|
||||
left: 3,
|
||||
right: 3,
|
||||
right: 5,
|
||||
bottom: 0,
|
||||
},
|
||||
boxAttrs: {
|
||||
'fill': '#FFFFFF',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
},
|
||||
boxRenderer: null,
|
||||
labelAttrs: {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-weight': 'bold',
|
||||
|
@ -220,29 +197,32 @@ define([
|
|||
'text-anchor': 'left',
|
||||
},
|
||||
},
|
||||
},
|
||||
separator: {
|
||||
attrs: {
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1.5,
|
||||
'stroke-dasharray': '4, 2',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
titleAttrs: {
|
||||
const BLOCKS = {
|
||||
'ref': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
boxRenderer: null,
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
},
|
||||
'': {
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
boxRenderer: null,
|
||||
section: SHARED_BLOCK_SECTION,
|
||||
sepRenderer: null,
|
||||
},
|
||||
};
|
||||
|
||||
const NOTE_ATTRS = {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-size': 20,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
'text-anchor': 'middle',
|
||||
'class': 'title',
|
||||
},
|
||||
|
||||
agentLineAttrs: {
|
||||
'fill': 'none',
|
||||
'stroke': '#000000',
|
||||
'stroke-width': 1,
|
||||
},
|
||||
};
|
||||
|
||||
const NOTES = {
|
||||
|
@ -253,33 +233,21 @@ define([
|
|||
boxRenderer: SVGShapes.renderBox.bind(null, {
|
||||
'fill': '#FFFFFF',
|
||||
}),
|
||||
labelAttrs: {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'note': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
padding: {top: 5, left: 5, right: 10, bottom: 5},
|
||||
overlap: {left: 10, right: 10},
|
||||
boxRenderer: null,
|
||||
labelAttrs: {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
'state': {
|
||||
margin: {top: 0, left: 5, right: 5, bottom: 0},
|
||||
padding: {top: 7, left: 7, right: 7, bottom: 7},
|
||||
overlap: {left: 10, right: 10},
|
||||
boxRenderer: null,
|
||||
labelAttrs: {
|
||||
'font-family': FONT_FAMILY,
|
||||
'font-size': 8,
|
||||
'line-height': LINE_HEIGHT,
|
||||
},
|
||||
labelAttrs: NOTE_ATTRS,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -324,8 +292,15 @@ define([
|
|||
const RIGHT = {};
|
||||
const LEFT = {};
|
||||
|
||||
class SketchTheme {
|
||||
class SketchTheme extends BaseTheme {
|
||||
constructor(handedness = RIGHT) {
|
||||
super({
|
||||
name: '',
|
||||
settings: SETTINGS,
|
||||
blocks: BLOCKS,
|
||||
notes: NOTES,
|
||||
});
|
||||
|
||||
if(handedness === RIGHT) {
|
||||
this.name = 'sketch';
|
||||
this.handedness = 1;
|
||||
|
@ -334,17 +309,31 @@ define([
|
|||
this.handedness = -1;
|
||||
}
|
||||
this.random = new Random();
|
||||
Object.assign(this, deepCopy(SETTINGS));
|
||||
this.notes = deepCopy(NOTES);
|
||||
|
||||
this._assignFunctions();
|
||||
}
|
||||
|
||||
_assignFunctions() {
|
||||
this.renderBar = this.renderBar.bind(this);
|
||||
this.renderBox = this.renderBox.bind(this);
|
||||
this.renderArrowHead = this.renderArrowHead.bind(this);
|
||||
this.renderConnect = this.renderConnect.bind(this);
|
||||
this.renderTag = this.renderTag.bind(this);
|
||||
|
||||
this.agentCap.cross.render = this.renderCross.bind(this);
|
||||
this.agentCap.bar.render = this.renderBar.bind(this);
|
||||
this.agentCap.box.boxRenderer = this.renderBox.bind(this);
|
||||
this.connect.arrow.single.render = this.renderArrowHead.bind(this);
|
||||
this.connect.arrow.double.render = this.renderArrowHead.bind(this);
|
||||
this.connect.line.solid.render = this.renderConnect.bind(this);
|
||||
this.connect.line.dash.render = this.renderConnect.bind(this);
|
||||
this.agentCap.bar.render = this.renderBar;
|
||||
this.agentCap.box.boxRenderer = this.renderBox;
|
||||
this.connect.arrow.single.render = this.renderArrowHead;
|
||||
this.connect.arrow.double.render = this.renderArrowHead;
|
||||
this.connect.line.solid.render = this.renderConnect;
|
||||
this.connect.line.dash.render = this.renderConnect;
|
||||
this.notes.note.boxRenderer = this.renderNote.bind(this);
|
||||
this.notes.state.boxRenderer = this.renderState.bind(this);
|
||||
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
|
||||
this.blocks[''].boxRenderer = this.renderBlock.bind(this);
|
||||
this.blocks.ref.section.mode.boxRenderer = this.renderTag;
|
||||
this.blocks[''].section.mode.boxRenderer = this.renderTag;
|
||||
this.blocks[''].sepRenderer = this.renderSeparator.bind(this);
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
@ -434,11 +423,12 @@ define([
|
|||
const shape = svg.make('path', Object.assign({
|
||||
'd': line.nodes,
|
||||
'fill': 'none',
|
||||
}, PENCIL));
|
||||
'stroke-dasharray': lineOptions.dash ? '6, 5' : 'none',
|
||||
}, lineOptions.thick ? THICK_PENCIL : PENCIL));
|
||||
return shape;
|
||||
}
|
||||
|
||||
renderBox({x, y, width, height}, {fill = null} = {}) {
|
||||
renderBox({x, y, width, height}, {fill = null, thick = false} = {}) {
|
||||
const lT = this.lineNodes(
|
||||
{x, y},
|
||||
{x: x + width, y},
|
||||
|
@ -463,7 +453,7 @@ define([
|
|||
const shape = svg.make('path', Object.assign({
|
||||
'd': lT.nodes + lR.nodes + lB.nodes + lL.nodes,
|
||||
'fill': fill || '#FFFFFF',
|
||||
}, PENCIL));
|
||||
}, thick ? THICK_PENCIL : PENCIL));
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
@ -538,7 +528,7 @@ define([
|
|||
};
|
||||
}
|
||||
|
||||
renderArrowHead({x, y, dx, dy, attrs}) {
|
||||
renderArrowHead(attrs, {x, y, dx, dy}) {
|
||||
const w = dx * (1 + this.vary(0.2));
|
||||
const h = dy * (1 + this.vary(0.3));
|
||||
const l1 = this.lineNodes(
|
||||
|
@ -566,6 +556,60 @@ define([
|
|||
return this.renderBox({x, y, width, height});
|
||||
}
|
||||
|
||||
renderRefBlock({x, y, width, height}) {
|
||||
return this.renderBox(
|
||||
{x, y, width, height},
|
||||
{fill: '#FFFFFF', thick: true}
|
||||
);
|
||||
}
|
||||
|
||||
renderBlock({x, y, width, height}) {
|
||||
return this.renderBox(
|
||||
{x, y, width, height},
|
||||
{fill: 'none', thick: true}
|
||||
);
|
||||
}
|
||||
|
||||
renderTag({x, y, width, height}) {
|
||||
const x2 = x + width;
|
||||
const y2 = y + height;
|
||||
|
||||
const l1 = this.lineNodes(
|
||||
{x: x2 + 3, y},
|
||||
{x: x2 - 2, y: y2},
|
||||
{}
|
||||
);
|
||||
const l2 = this.lineNodes(
|
||||
l1.p2,
|
||||
{x, y: y2 + 1},
|
||||
{var1: 0, move: false}
|
||||
);
|
||||
|
||||
const line = l1.nodes + l2.nodes;
|
||||
|
||||
const g = svg.make('g');
|
||||
|
||||
g.appendChild(svg.make('path', {
|
||||
'd': line + 'L' + x + ' ' + y,
|
||||
'fill': '#FFFFFF',
|
||||
}));
|
||||
|
||||
g.appendChild(svg.make('path', Object.assign({
|
||||
'd': line,
|
||||
'fill': '#FFFFFF',
|
||||
}, PENCIL)));
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
renderSeparator({x1, y1, x2, y2}) {
|
||||
return this.renderLine(
|
||||
{x: x1, y: y1},
|
||||
{x: x2, y: y2},
|
||||
{thick: true, dash: true}
|
||||
);
|
||||
}
|
||||
|
||||
renderBar({x, y, width, height}) {
|
||||
return this.renderBox({x, y, width, height}, {fill: '#000000'});
|
||||
}
|
||||
|
@ -590,11 +634,7 @@ define([
|
|||
}, PENCIL));
|
||||
}
|
||||
|
||||
getNote(type) {
|
||||
return this.notes[type];
|
||||
}
|
||||
|
||||
drawAgentLine(container, {x, y0, y1, width, className}) {
|
||||
renderAgentLine({x, y0, y1, width, className}) {
|
||||
if(width > 0) {
|
||||
const shape = this.renderBox({
|
||||
x: x - width / 2,
|
||||
|
@ -603,7 +643,7 @@ define([
|
|||
height: y1 - y0,
|
||||
}, {fill: 'none'});
|
||||
shape.setAttribute('class', className);
|
||||
container.appendChild(shape);
|
||||
return shape;
|
||||
} else {
|
||||
const shape = this.renderLine(
|
||||
{x, y: y0},
|
||||
|
@ -611,7 +651,7 @@ define([
|
|||
{varY: 0.3}
|
||||
);
|
||||
shape.setAttribute('class', className);
|
||||
container.appendChild(shape);
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ define(['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock) => {
|
|||
return svg.make('rect', Object.assign({}, position, attrs));
|
||||
}
|
||||
|
||||
function renderLine(attrs, position) {
|
||||
return svg.make('line', Object.assign({}, position, attrs));
|
||||
}
|
||||
|
||||
function renderNote(attrs, flickAttrs, position) {
|
||||
const g = svg.make('g');
|
||||
const x0 = position.x;
|
||||
|
@ -104,6 +108,7 @@ define(['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock) => {
|
|||
|
||||
return {
|
||||
renderBox,
|
||||
renderLine,
|
||||
renderNote,
|
||||
renderBoxedText,
|
||||
TextBlock: SVGTextBlock,
|
||||
|
|
Loading…
Reference in New Issue