Render self connections and wavy lines in vaguely sketch style [#18]

This commit is contained in:
David Evans 2018-01-13 14:06:26 +00:00
parent d1bab06bcc
commit f24933e5a1
5 changed files with 426 additions and 166 deletions

View File

@ -3104,7 +3104,130 @@ define('svg/SVGTextBlock',['./SVGUtilities'], (svg) => {
return SVGTextBlock; return SVGTextBlock;
}); });
define('svg/SVGShapes',['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock) => { define('svg/PatternedLine',[],() => {
'use strict';
return class PatternedLine {
constructor(pattern = null, phase = 0) {
this.pattern = pattern;
this.dw = pattern && pattern.partWidth;
this.points = [];
this.phase = phase;
this.x = null;
this.y = null;
this.disconnect = 0;
}
_nextDelta() {
return this.pattern.getDelta(this.phase ++);
}
_link() {
if(this.disconnect === 2) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
}
}
cap() {
if(this.disconnect > 0) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
}
return this;
}
move(x, y) {
this.cap();
this.x = x;
this.y = y;
this.disconnect = 2;
return this;
}
line(x, y) {
if(this.pattern) {
const len = Math.sqrt(
(x - this.x) * (x - this.x) +
(y - this.y) * (y - this.y)
);
const dx1 = (x - this.x) / len;
const dy1 = (y - this.y) / len;
const dx2 = -dy1;
const dy2 = dx1;
for(let pos = 0; pos + this.dw <= len; pos += this.dw) {
const delta = this._nextDelta();
this.points.push(
(this.x + pos * dx1 + delta * dx2) + ' ' +
(this.y + pos * dy1 + delta * dy2)
);
}
this.disconnect = 1;
} else {
this._link();
this.disconnect = 2;
}
this.x = x;
this.y = y;
return this;
}
arc(cx, cy, theta) {
const radius = Math.sqrt(
(cx - this.x) * (cx - this.x) +
(cy - this.y) * (cy - this.y)
);
const theta1 = Math.atan2(cx - this.x, cy - this.y);
const nextX = cx + Math.sin(theta1 + theta) * radius;
const nextY = cy - Math.cos(theta1 + theta) * radius;
if(this.pattern) {
const dir = (theta < 0 ? 1 : -1);
const dt = this.dw / radius;
for(let t = theta1; t + dt <= theta1 + theta; t += dt) {
const delta = this._nextDelta() * dir;
this.points.push(
(cx + Math.sin(t) * (radius + delta)) + ' ' +
(cy - Math.cos(t) * (radius + delta))
);
}
this.disconnect = 1;
} else {
this.points.push(
this.x + ' ' + this.y +
'A' + radius + ' ' + radius + ' 0 ' +
((theta < 0) ? '0 ' : '1 ') +
'1 ' +
nextX + ' ' + nextY
);
this.disconnect = 0;
}
this.x = nextX;
this.y = nextY;
return this;
}
asPath() {
this._link();
return 'M' + this.points.join('L');
}
};
});
define('svg/SVGShapes',[
'./SVGUtilities',
'./SVGTextBlock',
'./PatternedLine',
], (
svg,
SVGTextBlock,
PatternedLine
) => {
'use strict'; 'use strict';
function renderBox(attrs, position) { function renderBox(attrs, position) {
@ -3218,6 +3341,7 @@ define('svg/SVGShapes',['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock)
renderNote, renderNote,
renderBoxedText, renderBoxedText,
TextBlock: SVGTextBlock, TextBlock: SVGTextBlock,
PatternedLine,
}; };
}); });
@ -5218,122 +5342,13 @@ define('sequence/Exporter',[],() => {
}; };
}); });
define('svg/PatternedLine',[],() => { define('sequence/themes/BaseTheme',[
'use strict'; 'svg/SVGUtilities',
'svg/SVGShapes',
return class PatternedLine { ], (
constructor(pattern = null, phase = 0) { svg,
this.pattern = pattern; SVGShapes
this.dw = pattern && pattern.partWidth; ) => {
this.points = [];
this.phase = phase;
this.x = null;
this.y = null;
this.disconnect = 0;
}
_nextDelta() {
return this.pattern.getDelta(this.phase ++);
}
_link() {
if(this.disconnect === 2) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
}
}
cap() {
if(this.disconnect > 0) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
}
return this;
}
move(x, y) {
this.cap();
this.x = x;
this.y = y;
this.disconnect = 2;
return this;
}
line(x, y) {
if(this.pattern) {
const len = Math.sqrt(
(x - this.x) * (x - this.x) +
(y - this.y) * (y - this.y)
);
const dx1 = (x - this.x) / len;
const dy1 = (y - this.y) / len;
const dx2 = -dy1;
const dy2 = dx1;
for(let pos = 0; pos + this.dw <= len; pos += this.dw) {
const delta = this._nextDelta();
this.points.push(
(this.x + pos * dx1 + delta * dx2) + ' ' +
(this.y + pos * dy1 + delta * dy2)
);
}
this.disconnect = 1;
} else {
this._link();
this.disconnect = 2;
}
this.x = x;
this.y = y;
return this;
}
arc(cx, cy, theta) {
const radius = Math.sqrt(
(cx - this.x) * (cx - this.x) +
(cy - this.y) * (cy - this.y)
);
const theta1 = Math.atan2(cx - this.x, cy - this.y);
const nextX = cx + Math.sin(theta1 + theta) * radius;
const nextY = cy - Math.cos(theta1 + theta) * radius;
if(this.pattern) {
const dir = (theta < 0 ? 1 : -1);
const dt = this.dw / radius;
for(let t = theta1; t + dt <= theta1 + theta; t += dt) {
const delta = this._nextDelta() * dir;
this.points.push(
(cx + Math.sin(t) * (radius + delta)) + ' ' +
(cy - Math.cos(t) * (radius + delta))
);
}
this.disconnect = 1;
} else {
this.points.push(
this.x + ' ' + this.y +
'A' + radius + ' ' + radius + ' 0 ' +
((theta < 0) ? '0 ' : '1 ') +
'1 ' +
nextX + ' ' + nextY
);
this.disconnect = 0;
}
this.x = nextX;
this.y = nextY;
return this;
}
asPath() {
this._link();
return 'M' + this.points.join('L');
}
};
});
define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
'use strict'; 'use strict';
function deepCopy(o) { function deepCopy(o) {
@ -5446,16 +5461,20 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (s
BaseTheme.WavePattern = class WavePattern { BaseTheme.WavePattern = class WavePattern {
constructor(width, height) { constructor(width, height) {
this.deltas = [ if(Array.isArray(height)) {
0, this.deltas = height;
-height * 2 / 3, } else {
-height, this.deltas = [
-height * 2 / 3, 0,
0, -height * 2 / 3,
height * 2 / 3, -height,
height, -height * 2 / 3,
height * 2 / 3, 0,
]; height * 2 / 3,
height,
height * 2 / 3,
];
}
this.partWidth = width / this.deltas.length; this.partWidth = width / this.deltas.length;
} }
@ -5467,7 +5486,7 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (s
BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => { BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => {
return { return {
shape: svg.make('path', Object.assign({ shape: svg.make('path', Object.assign({
d: new PatternedLine(pattern) d: new SVGShapes.PatternedLine(pattern)
.move(x1 + dx1, y) .move(x1 + dx1, y)
.line(x2 + dx2, y) .line(x2 + dx2, y)
.cap() .cap()
@ -5485,7 +5504,7 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (s
) => { ) => {
return { return {
shape: svg.make('path', Object.assign({ shape: svg.make('path', Object.assign({
d: new PatternedLine(pattern) d: new SVGShapes.PatternedLine(pattern)
.move(xL + dx1, y1) .move(xL + dx1, y1)
.line(xR, y1) .line(xR, y1)
.arc(xR, (y1 + y2) / 2, Math.PI) .arc(xR, (y1 + y2) / 2, Math.PI)
@ -6588,8 +6607,6 @@ define('sequence/themes/Sketch',[
'stroke-linecap': 'round', 'stroke-linecap': 'round',
}; };
const WAVE = new BaseTheme.WavePattern(6, 0.5);
const SETTINGS = { const SETTINGS = {
titleMargin: 10, titleMargin: 10,
outerMargin: 5, outerMargin: 5,
@ -6641,7 +6658,7 @@ define('sequence/themes/Sketch',[
'fill': 'none', 'fill': 'none',
}, PENCIL), }, PENCIL),
renderFlat: null, renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, null), renderRev: null,
}, },
'dash': { 'dash': {
attrs: Object.assign({ attrs: Object.assign({
@ -6649,7 +6666,7 @@ define('sequence/themes/Sketch',[
'stroke-dasharray': '4, 2', 'stroke-dasharray': '4, 2',
}, PENCIL), }, PENCIL),
renderFlat: null, renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, null), renderRev: null,
}, },
'wave': { 'wave': {
attrs: Object.assign({ attrs: Object.assign({
@ -6657,8 +6674,8 @@ define('sequence/themes/Sketch',[
'stroke-linejoin': 'round', 'stroke-linejoin': 'round',
'stroke-linecap': 'round', 'stroke-linecap': 'round',
}, PENCIL), }, PENCIL),
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE), renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE), renderRev: null,
}, },
}, },
arrow: { arrow: {
@ -6849,6 +6866,31 @@ define('sequence/themes/Sketch',[
const RIGHT = {}; const RIGHT = {};
const LEFT = {}; const LEFT = {};
class SketchWavePattern extends BaseTheme.WavePattern {
constructor(width, handedness) {
const heights = [
+0.0,
-0.3,
-0.6,
-0.75,
-0.45,
+0.0,
+0.45,
+0.75,
+0.6,
+0.3,
];
if(handedness !== RIGHT) {
heights.reverse();
}
super(6, heights);
}
getDelta(p) {
return super.getDelta(p) + Math.sin(p * 0.03) * 0.5;
}
}
class SketchTheme extends BaseTheme { class SketchTheme extends BaseTheme {
constructor(handedness = RIGHT) { constructor(handedness = RIGHT) {
super({ super({
@ -6866,29 +6908,49 @@ define('sequence/themes/Sketch',[
this.handedness = -1; this.handedness = -1;
} }
this.random = new Random(); this.random = new Random();
this.wave = new SketchWavePattern(4, handedness);
this._assignFunctions(); this._assignCapFunctions();
this._assignConnectFunctions();
this._assignNoteFunctions();
this._assignBlockFunctions();
} }
_assignFunctions() { _assignCapFunctions() {
this.renderBar = this.renderBar.bind(this); this.renderBar = this.renderBar.bind(this);
this.renderBox = this.renderBox.bind(this); this.renderBox = this.renderBox.bind(this);
this.renderArrowHead = this.renderArrowHead.bind(this);
this.renderFlatConnector = this.renderFlatConnector.bind(this);
this.renderTag = this.renderTag.bind(this);
this.agentCap.cross.render = this.renderCross.bind(this); this.agentCap.cross.render = this.renderCross.bind(this);
this.agentCap.bar.render = this.renderBar; this.agentCap.bar.render = this.renderBar;
this.agentCap.box.boxRenderer = this.renderBox; this.agentCap.box.boxRenderer = this.renderBox;
}
_assignConnectFunctions() {
this.renderArrowHead = this.renderArrowHead.bind(this);
this.renderFlatConnector = this.renderFlatConnector.bind(this);
this.renderRevConnector = this.renderRevConnector.bind(this);
this.connect.arrow.single.render = this.renderArrowHead; this.connect.arrow.single.render = this.renderArrowHead;
this.connect.arrow.double.render = this.renderArrowHead; this.connect.arrow.double.render = this.renderArrowHead;
this.connect.line.solid.renderFlat = this.renderFlatConnector; this.connect.line.solid.renderFlat = this.renderFlatConnector;
this.connect.line.solid.renderRev = this.renderRevConnector;
this.connect.line.dash.renderFlat = this.renderFlatConnector; this.connect.line.dash.renderFlat = this.renderFlatConnector;
this.connect.line.dash.renderRev = this.renderRevConnector;
this.connect.line.wave.renderFlat =
this.renderFlatConnectorWave.bind(this);
this.connect.line.wave.renderRev =
this.renderRevConnectorWave.bind(this);
}
_assignNoteFunctions() {
this.notes.note.boxRenderer = this.renderNote.bind(this); this.notes.note.boxRenderer = this.renderNote.bind(this);
this.notes.state.boxRenderer = this.renderState.bind(this); this.notes.state.boxRenderer = this.renderState.bind(this);
}
_assignBlockFunctions() {
this.renderTag = this.renderTag.bind(this);
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this); this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
this.blocks[''].boxRenderer = this.renderBlock.bind(this); this.blocks[''].boxRenderer = this.renderBlock.bind(this);
this.blocks.ref.section.mode.boxRenderer = this.renderTag; this.blocks.ref.section.mode.boxRenderer = this.renderTag;
@ -7088,6 +7150,74 @@ define('sequence/themes/Sketch',[
}; };
} }
renderRevConnector(attrs, {xL, dx1, dx2, y1, y2, xR}) {
const variance = Math.min((xR - xL) * 0.06, 3);
const overshoot = Math.min((xR - xL) * 0.5, 6);
const p1x = xL + dx1 + this.vary(variance, -1);
const p1y = y1 + this.vary(variance, -1);
const b1x = xR - overshoot * this.vary(0.2, 1);
const b1y = y1 - this.vary(1, 2);
const p2x = xR;
const p2y = y1 + this.vary(1, 1);
const b2x = xR;
const b2y = y2 + this.vary(2);
const p3x = xL + dx2 + this.vary(variance, -1);
const p3y = y2 + this.vary(variance, -1);
return {
shape: svg.make('path', Object.assign({
d: (
'M' + p1x + ' ' + p1y +
'C' + p1x + ' ' + p1y +
',' + b1x + ' ' + b1y +
',' + p2x + ' ' + p2y +
'S' + b2x + ' ' + b2y +
',' + p3x + ' ' + p3y
),
}, attrs)),
p1: {x: p1x - dx1, y: p1y},
p2: {x: p3x - dx2, y: p3y},
};
}
renderFlatConnectorWave(attrs, {x1, dx1, x2, dx2, y}) {
const x1v = x1 + this.vary(0.3);
const x2v = x2 + this.vary(0.3);
const y1v = y + this.vary(1);
const y2v = y + this.vary(1);
return {
shape: svg.make('path', Object.assign({
d: new SVGShapes.PatternedLine(this.wave)
.move(x1v + dx1, y1v)
.line(x2v + dx2, y2v)
.cap()
.asPath(),
}, attrs)),
p1: {x: x1v, y: y1v},
p2: {x: x2v, y: y2v},
};
}
renderRevConnectorWave(attrs, {xL, dx1, dx2, y1, y2, xR}) {
const x1v = xL + this.vary(0.3);
const x2v = xL + this.vary(0.3);
const y1v = y1 + this.vary(1);
const y2v = y2 + this.vary(1);
return {
shape: svg.make('path', Object.assign({
d: new SVGShapes.PatternedLine(this.wave)
.move(x1v + dx1, y1v)
.line(xR, y1)
.arc(xR, (y1 + y2) / 2, Math.PI)
.line(x2v + dx2, y2v)
.cap()
.asPath(),
}, attrs)),
p1: {x: x1v, y: y1v},
p2: {x: x2v, y: y2v},
};
}
renderArrowHead(attrs, {x, y, dx, dy}) { renderArrowHead(attrs, {x, y, dx, dy}) {
const w = dx * this.vary(0.2, 1); const w = dx * this.vary(0.2, 1);
const h = dy * this.vary(0.3, 1); const h = dy * this.vary(0.3, 1);

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,10 @@
define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => { define([
'svg/SVGUtilities',
'svg/SVGShapes',
], (
svg,
SVGShapes
) => {
'use strict'; 'use strict';
function deepCopy(o) { function deepCopy(o) {
@ -111,16 +117,20 @@ define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
BaseTheme.WavePattern = class WavePattern { BaseTheme.WavePattern = class WavePattern {
constructor(width, height) { constructor(width, height) {
this.deltas = [ if(Array.isArray(height)) {
0, this.deltas = height;
-height * 2 / 3, } else {
-height, this.deltas = [
-height * 2 / 3, 0,
0, -height * 2 / 3,
height * 2 / 3, -height,
height, -height * 2 / 3,
height * 2 / 3, 0,
]; height * 2 / 3,
height,
height * 2 / 3,
];
}
this.partWidth = width / this.deltas.length; this.partWidth = width / this.deltas.length;
} }
@ -132,7 +142,7 @@ define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => { BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => {
return { return {
shape: svg.make('path', Object.assign({ shape: svg.make('path', Object.assign({
d: new PatternedLine(pattern) d: new SVGShapes.PatternedLine(pattern)
.move(x1 + dx1, y) .move(x1 + dx1, y)
.line(x2 + dx2, y) .line(x2 + dx2, y)
.cap() .cap()
@ -150,7 +160,7 @@ define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
) => { ) => {
return { return {
shape: svg.make('path', Object.assign({ shape: svg.make('path', Object.assign({
d: new PatternedLine(pattern) d: new SVGShapes.PatternedLine(pattern)
.move(xL + dx1, y1) .move(xL + dx1, y1)
.line(xR, y1) .line(xR, y1)
.arc(xR, (y1 + y2) / 2, Math.PI) .arc(xR, (y1 + y2) / 2, Math.PI)

View File

@ -30,8 +30,6 @@ define([
'stroke-linecap': 'round', 'stroke-linecap': 'round',
}; };
const WAVE = new BaseTheme.WavePattern(6, 0.5);
const SETTINGS = { const SETTINGS = {
titleMargin: 10, titleMargin: 10,
outerMargin: 5, outerMargin: 5,
@ -83,7 +81,7 @@ define([
'fill': 'none', 'fill': 'none',
}, PENCIL), }, PENCIL),
renderFlat: null, renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, null), renderRev: null,
}, },
'dash': { 'dash': {
attrs: Object.assign({ attrs: Object.assign({
@ -91,7 +89,7 @@ define([
'stroke-dasharray': '4, 2', 'stroke-dasharray': '4, 2',
}, PENCIL), }, PENCIL),
renderFlat: null, renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, null), renderRev: null,
}, },
'wave': { 'wave': {
attrs: Object.assign({ attrs: Object.assign({
@ -99,8 +97,8 @@ define([
'stroke-linejoin': 'round', 'stroke-linejoin': 'round',
'stroke-linecap': 'round', 'stroke-linecap': 'round',
}, PENCIL), }, PENCIL),
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE), renderFlat: null,
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE), renderRev: null,
}, },
}, },
arrow: { arrow: {
@ -291,6 +289,31 @@ define([
const RIGHT = {}; const RIGHT = {};
const LEFT = {}; const LEFT = {};
class SketchWavePattern extends BaseTheme.WavePattern {
constructor(width, handedness) {
const heights = [
+0.0,
-0.3,
-0.6,
-0.75,
-0.45,
+0.0,
+0.45,
+0.75,
+0.6,
+0.3,
];
if(handedness !== RIGHT) {
heights.reverse();
}
super(6, heights);
}
getDelta(p) {
return super.getDelta(p) + Math.sin(p * 0.03) * 0.5;
}
}
class SketchTheme extends BaseTheme { class SketchTheme extends BaseTheme {
constructor(handedness = RIGHT) { constructor(handedness = RIGHT) {
super({ super({
@ -308,29 +331,49 @@ define([
this.handedness = -1; this.handedness = -1;
} }
this.random = new Random(); this.random = new Random();
this.wave = new SketchWavePattern(4, handedness);
this._assignFunctions(); this._assignCapFunctions();
this._assignConnectFunctions();
this._assignNoteFunctions();
this._assignBlockFunctions();
} }
_assignFunctions() { _assignCapFunctions() {
this.renderBar = this.renderBar.bind(this); this.renderBar = this.renderBar.bind(this);
this.renderBox = this.renderBox.bind(this); this.renderBox = this.renderBox.bind(this);
this.renderArrowHead = this.renderArrowHead.bind(this);
this.renderFlatConnector = this.renderFlatConnector.bind(this);
this.renderTag = this.renderTag.bind(this);
this.agentCap.cross.render = this.renderCross.bind(this); this.agentCap.cross.render = this.renderCross.bind(this);
this.agentCap.bar.render = this.renderBar; this.agentCap.bar.render = this.renderBar;
this.agentCap.box.boxRenderer = this.renderBox; this.agentCap.box.boxRenderer = this.renderBox;
}
_assignConnectFunctions() {
this.renderArrowHead = this.renderArrowHead.bind(this);
this.renderFlatConnector = this.renderFlatConnector.bind(this);
this.renderRevConnector = this.renderRevConnector.bind(this);
this.connect.arrow.single.render = this.renderArrowHead; this.connect.arrow.single.render = this.renderArrowHead;
this.connect.arrow.double.render = this.renderArrowHead; this.connect.arrow.double.render = this.renderArrowHead;
this.connect.line.solid.renderFlat = this.renderFlatConnector; this.connect.line.solid.renderFlat = this.renderFlatConnector;
this.connect.line.solid.renderRev = this.renderRevConnector;
this.connect.line.dash.renderFlat = this.renderFlatConnector; this.connect.line.dash.renderFlat = this.renderFlatConnector;
this.connect.line.dash.renderRev = this.renderRevConnector;
this.connect.line.wave.renderFlat =
this.renderFlatConnectorWave.bind(this);
this.connect.line.wave.renderRev =
this.renderRevConnectorWave.bind(this);
}
_assignNoteFunctions() {
this.notes.note.boxRenderer = this.renderNote.bind(this); this.notes.note.boxRenderer = this.renderNote.bind(this);
this.notes.state.boxRenderer = this.renderState.bind(this); this.notes.state.boxRenderer = this.renderState.bind(this);
}
_assignBlockFunctions() {
this.renderTag = this.renderTag.bind(this);
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this); this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
this.blocks[''].boxRenderer = this.renderBlock.bind(this); this.blocks[''].boxRenderer = this.renderBlock.bind(this);
this.blocks.ref.section.mode.boxRenderer = this.renderTag; this.blocks.ref.section.mode.boxRenderer = this.renderTag;
@ -530,6 +573,74 @@ define([
}; };
} }
renderRevConnector(attrs, {xL, dx1, dx2, y1, y2, xR}) {
const variance = Math.min((xR - xL) * 0.06, 3);
const overshoot = Math.min((xR - xL) * 0.5, 6);
const p1x = xL + dx1 + this.vary(variance, -1);
const p1y = y1 + this.vary(variance, -1);
const b1x = xR - overshoot * this.vary(0.2, 1);
const b1y = y1 - this.vary(1, 2);
const p2x = xR;
const p2y = y1 + this.vary(1, 1);
const b2x = xR;
const b2y = y2 + this.vary(2);
const p3x = xL + dx2 + this.vary(variance, -1);
const p3y = y2 + this.vary(variance, -1);
return {
shape: svg.make('path', Object.assign({
d: (
'M' + p1x + ' ' + p1y +
'C' + p1x + ' ' + p1y +
',' + b1x + ' ' + b1y +
',' + p2x + ' ' + p2y +
'S' + b2x + ' ' + b2y +
',' + p3x + ' ' + p3y
),
}, attrs)),
p1: {x: p1x - dx1, y: p1y},
p2: {x: p3x - dx2, y: p3y},
};
}
renderFlatConnectorWave(attrs, {x1, dx1, x2, dx2, y}) {
const x1v = x1 + this.vary(0.3);
const x2v = x2 + this.vary(0.3);
const y1v = y + this.vary(1);
const y2v = y + this.vary(1);
return {
shape: svg.make('path', Object.assign({
d: new SVGShapes.PatternedLine(this.wave)
.move(x1v + dx1, y1v)
.line(x2v + dx2, y2v)
.cap()
.asPath(),
}, attrs)),
p1: {x: x1v, y: y1v},
p2: {x: x2v, y: y2v},
};
}
renderRevConnectorWave(attrs, {xL, dx1, dx2, y1, y2, xR}) {
const x1v = xL + this.vary(0.3);
const x2v = xL + this.vary(0.3);
const y1v = y1 + this.vary(1);
const y2v = y2 + this.vary(1);
return {
shape: svg.make('path', Object.assign({
d: new SVGShapes.PatternedLine(this.wave)
.move(x1v + dx1, y1v)
.line(xR, y1)
.arc(xR, (y1 + y2) / 2, Math.PI)
.line(x2v + dx2, y2v)
.cap()
.asPath(),
}, attrs)),
p1: {x: x1v, y: y1v},
p2: {x: x2v, y: y2v},
};
}
renderArrowHead(attrs, {x, y, dx, dy}) { renderArrowHead(attrs, {x, y, dx, dy}) {
const w = dx * this.vary(0.2, 1); const w = dx * this.vary(0.2, 1);
const h = dy * this.vary(0.3, 1); const h = dy * this.vary(0.3, 1);

View File

@ -1,4 +1,12 @@
define(['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock) => { define([
'./SVGUtilities',
'./SVGTextBlock',
'./PatternedLine',
], (
svg,
SVGTextBlock,
PatternedLine
) => {
'use strict'; 'use strict';
function renderBox(attrs, position) { function renderBox(attrs, position) {
@ -112,5 +120,6 @@ define(['./SVGUtilities', './SVGTextBlock'], (svg, SVGTextBlock) => {
renderNote, renderNote,
renderBoxedText, renderBoxedText,
TextBlock: SVGTextBlock, TextBlock: SVGTextBlock,
PatternedLine,
}; };
}); });