Render self connections and wavy lines in vaguely sketch style [#18]
This commit is contained in:
parent
d1bab06bcc
commit
f24933e5a1
|
@ -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,6 +5461,9 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (s
|
||||||
|
|
||||||
BaseTheme.WavePattern = class WavePattern {
|
BaseTheme.WavePattern = class WavePattern {
|
||||||
constructor(width, height) {
|
constructor(width, height) {
|
||||||
|
if(Array.isArray(height)) {
|
||||||
|
this.deltas = height;
|
||||||
|
} else {
|
||||||
this.deltas = [
|
this.deltas = [
|
||||||
0,
|
0,
|
||||||
-height * 2 / 3,
|
-height * 2 / 3,
|
||||||
|
@ -5456,6 +5474,7 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities', 'svg/PatternedLine'], (s
|
||||||
height,
|
height,
|
||||||
height * 2 / 3,
|
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
|
@ -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,6 +117,9 @@ define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
|
||||||
|
|
||||||
BaseTheme.WavePattern = class WavePattern {
|
BaseTheme.WavePattern = class WavePattern {
|
||||||
constructor(width, height) {
|
constructor(width, height) {
|
||||||
|
if(Array.isArray(height)) {
|
||||||
|
this.deltas = height;
|
||||||
|
} else {
|
||||||
this.deltas = [
|
this.deltas = [
|
||||||
0,
|
0,
|
||||||
-height * 2 / 3,
|
-height * 2 / 3,
|
||||||
|
@ -121,6 +130,7 @@ define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
|
||||||
height,
|
height,
|
||||||
height * 2 / 3,
|
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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue