Simplify and extract wavy line rendering
This commit is contained in:
parent
3553c66c9c
commit
4eb9ec21d6
|
@ -4065,113 +4065,6 @@ define('sequence/components/Connect',[
|
||||||
new Arrowhead('double'),
|
new Arrowhead('double'),
|
||||||
];
|
];
|
||||||
|
|
||||||
function makeWavyLineHeights(height) {
|
|
||||||
return [
|
|
||||||
0,
|
|
||||||
-height * 2 / 3,
|
|
||||||
-height,
|
|
||||||
-height * 2 / 3,
|
|
||||||
0,
|
|
||||||
height * 2 / 3,
|
|
||||||
height,
|
|
||||||
height * 2 / 3,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderFlat({x1, dx1, x2, dx2, y}, attrs) {
|
|
||||||
const ww = attrs['wave-width'];
|
|
||||||
const hh = attrs['wave-height'];
|
|
||||||
|
|
||||||
if(!ww || !hh) {
|
|
||||||
return {
|
|
||||||
shape: svg.make('line', Object.assign({
|
|
||||||
'x1': x1 + dx1,
|
|
||||||
'y1': y,
|
|
||||||
'x2': x2 + dx2,
|
|
||||||
'y2': y,
|
|
||||||
}, attrs)),
|
|
||||||
p1: {x: x1, y},
|
|
||||||
p2: {x: x2, y},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const heights = makeWavyLineHeights(hh);
|
|
||||||
const dw = ww / heights.length;
|
|
||||||
let p = 0;
|
|
||||||
|
|
||||||
let points = '';
|
|
||||||
const xL = Math.min(x1 + dx1, x2 + dx2);
|
|
||||||
const xR = Math.max(x1 + dx1, x2 + dx2);
|
|
||||||
for(let x = xL; x + dw <= xR; x += dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y + heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
points += xR + ' ' + y;
|
|
||||||
return {
|
|
||||||
shape: svg.make('polyline', Object.assign({points}, attrs)),
|
|
||||||
p1: {x: x1, y},
|
|
||||||
p2: {x: x2, y},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderRev({xL, dx1, dx2, y1, y2, xR}, attrs) {
|
|
||||||
const r = (y2 - y1) / 2;
|
|
||||||
const ww = attrs['wave-width'];
|
|
||||||
const hh = attrs['wave-height'];
|
|
||||||
|
|
||||||
if(!ww || !hh) {
|
|
||||||
return {
|
|
||||||
shape: svg.make('path', Object.assign({
|
|
||||||
'd': (
|
|
||||||
'M' + (xL + dx1) + ' ' + y1 +
|
|
||||||
'L' + xR + ' ' + y1 +
|
|
||||||
'A' + r + ' ' + r + ' 0 0 1 ' + xR + ' ' + y2 +
|
|
||||||
'L' + (xL + dx2) + ' ' + y2
|
|
||||||
),
|
|
||||||
}, attrs)),
|
|
||||||
p1: {x: xL, y: y1},
|
|
||||||
p2: {x: xL, y: y2},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const heights = makeWavyLineHeights(hh);
|
|
||||||
const dw = ww / heights.length;
|
|
||||||
let p = 0;
|
|
||||||
|
|
||||||
let points = '';
|
|
||||||
for(let x = xL + dx1; x + dw <= xR; x += dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y1 + heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ym = (y1 + y2) / 2;
|
|
||||||
for(let t = 0; t + dw / r <= Math.PI; t += dw / r) {
|
|
||||||
const h = heights[(p ++) % heights.length];
|
|
||||||
points += (
|
|
||||||
(xR + Math.sin(t) * (r - h)) + ' ' +
|
|
||||||
(ym - Math.cos(t) * (r - h)) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let x = xR; x - dw >= xL + dx2; x -= dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y2 - heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
points += (xL + dx2) + ' ' + y2;
|
|
||||||
return {
|
|
||||||
shape: svg.make('polyline', Object.assign({points}, attrs)),
|
|
||||||
p1: {x: xL, y: y1},
|
|
||||||
p2: {x: xL, y: y2},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Connect extends BaseComponent {
|
class Connect extends BaseComponent {
|
||||||
separation({label, agentNames, options}, env) {
|
separation({label, agentNames, options}, env) {
|
||||||
const config = env.theme.connect;
|
const config = env.theme.connect;
|
||||||
|
@ -4261,14 +4154,14 @@ define('sequence/components/Connect',[
|
||||||
const y1 = y0 + r * 2;
|
const y1 = y0 + r * 2;
|
||||||
|
|
||||||
const line = config.line[options.line];
|
const line = config.line[options.line];
|
||||||
const rendered = (line.renderRev || renderRev)({
|
const rendered = line.renderRev(line.attrs, {
|
||||||
xL: lineX,
|
xL: lineX,
|
||||||
dx1: lArrow.lineGap(env.theme, line.attrs),
|
dx1: lArrow.lineGap(env.theme, line.attrs),
|
||||||
dx2: rArrow.lineGap(env.theme, line.attrs),
|
dx2: rArrow.lineGap(env.theme, line.attrs),
|
||||||
y1: y0,
|
y1: y0,
|
||||||
y2: y1,
|
y2: y1,
|
||||||
xR: x1,
|
xR: x1,
|
||||||
}, line.attrs);
|
});
|
||||||
env.shapeLayer.appendChild(rendered.shape);
|
env.shapeLayer.appendChild(rendered.shape);
|
||||||
|
|
||||||
lArrow.render(env.shapeLayer, env.theme, rendered.p1, 1);
|
lArrow.render(env.shapeLayer, env.theme, rendered.p1, 1);
|
||||||
|
@ -4325,13 +4218,13 @@ define('sequence/components/Connect',[
|
||||||
});
|
});
|
||||||
|
|
||||||
const line = config.line[options.line];
|
const line = config.line[options.line];
|
||||||
const rendered = (line.render || renderFlat)({
|
const rendered = line.renderFlat(line.attrs, {
|
||||||
x1: x0,
|
x1: x0,
|
||||||
dx1: lArrow.lineGap(env.theme, line.attrs) * dir,
|
dx1: lArrow.lineGap(env.theme, line.attrs) * dir,
|
||||||
x2: x1,
|
x2: x1,
|
||||||
dx2: -rArrow.lineGap(env.theme, line.attrs) * dir,
|
dx2: -rArrow.lineGap(env.theme, line.attrs) * dir,
|
||||||
y,
|
y,
|
||||||
}, line.attrs);
|
});
|
||||||
env.shapeLayer.appendChild(rendered.shape);
|
env.shapeLayer.appendChild(rendered.shape);
|
||||||
|
|
||||||
lArrow.render(env.shapeLayer, env.theme, rendered.p1, dir);
|
lArrow.render(env.shapeLayer, env.theme, rendered.p1, dir);
|
||||||
|
@ -5325,7 +5218,122 @@ define('sequence/Exporter',[],() => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
define('sequence/themes/BaseTheme',['svg/SVGUtilities'], (svg) => {
|
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 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_link() {
|
||||||
|
if(this.disconnect) {
|
||||||
|
this.points.push(this.x + ' ' + this.y);
|
||||||
|
this.disconnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextDelta() {
|
||||||
|
return this.pattern.getDelta(this.phase ++);
|
||||||
|
}
|
||||||
|
|
||||||
|
cap() {
|
||||||
|
if(this.x !== null) {
|
||||||
|
this.points.push(this.x + ' ' + this.y);
|
||||||
|
this.x = null;
|
||||||
|
this.y = null;
|
||||||
|
this.disconnect = false;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(x, y) {
|
||||||
|
this.cap();
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.disconnect = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
line(x, y) {
|
||||||
|
this._link();
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.disconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arc(cx, cy, theta) {
|
||||||
|
this._link();
|
||||||
|
|
||||||
|
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);
|
||||||
|
this.x = cx + Math.sin(theta1 + theta) * radius;
|
||||||
|
this.y = 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))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.points.push(
|
||||||
|
(cx + Math.sin(theta1) * radius) + ' ' +
|
||||||
|
(cy - Math.cos(theta1) * radius) +
|
||||||
|
'A' + radius + ' ' + radius + ' 0 ' +
|
||||||
|
((theta < 0) ? '0 ' : '1 ') +
|
||||||
|
'1 ' +
|
||||||
|
this.x + ' ' + this.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -5436,6 +5444,60 @@ define('sequence/themes/BaseTheme',['svg/SVGUtilities'], (svg) => {
|
||||||
}, attrs));
|
}, attrs));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BaseTheme.WavePattern = class WavePattern {
|
||||||
|
constructor(width, height) {
|
||||||
|
this.deltas = [
|
||||||
|
0,
|
||||||
|
-height * 2 / 3,
|
||||||
|
-height,
|
||||||
|
-height * 2 / 3,
|
||||||
|
0,
|
||||||
|
height * 2 / 3,
|
||||||
|
height,
|
||||||
|
height * 2 / 3,
|
||||||
|
];
|
||||||
|
this.partWidth = width / this.deltas.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDelta(p) {
|
||||||
|
return this.deltas[p % this.deltas.length];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => {
|
||||||
|
return {
|
||||||
|
shape: svg.make('path', Object.assign({
|
||||||
|
d: new PatternedLine(pattern)
|
||||||
|
.move(x1 + dx1, y)
|
||||||
|
.line(x2 + dx2, y)
|
||||||
|
.cap()
|
||||||
|
.asPath(),
|
||||||
|
}, attrs)),
|
||||||
|
p1: {x: x1, y},
|
||||||
|
p2: {x: x2, y},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderRevConnector = (
|
||||||
|
pattern,
|
||||||
|
attrs,
|
||||||
|
{xL, dx1, dx2, y1, y2, xR}
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
shape: svg.make('path', Object.assign({
|
||||||
|
d: new PatternedLine(pattern)
|
||||||
|
.move(xL + dx1, y1)
|
||||||
|
.line(xR, y1)
|
||||||
|
.arc(xR, (y1 + y2) / 2, Math.PI)
|
||||||
|
.line(xL + dx2, y2)
|
||||||
|
.cap()
|
||||||
|
.asPath(),
|
||||||
|
}, attrs)),
|
||||||
|
p1: {x: xL, y: y1},
|
||||||
|
p2: {x: xL, y: y2},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return BaseTheme;
|
return BaseTheme;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5453,6 +5515,8 @@ define('sequence/themes/Basic',[
|
||||||
const FONT = 'sans-serif';
|
const FONT = 'sans-serif';
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
|
|
||||||
|
const WAVE = new BaseTheme.WavePattern(6, 0.5);
|
||||||
|
|
||||||
const SETTINGS = {
|
const SETTINGS = {
|
||||||
titleMargin: 10,
|
titleMargin: 10,
|
||||||
outerMargin: 5,
|
outerMargin: 5,
|
||||||
|
@ -5517,6 +5581,8 @@ define('sequence/themes/Basic',[
|
||||||
'stroke': '#000000',
|
'stroke': '#000000',
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -5525,6 +5591,8 @@ define('sequence/themes/Basic',[
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
'stroke-dasharray': '4, 2',
|
'stroke-dasharray': '4, 2',
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -5533,9 +5601,9 @@ define('sequence/themes/Basic',[
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 6,
|
|
||||||
'wave-height': 0.5,
|
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
@ -5752,6 +5820,8 @@ define('sequence/themes/Chunky',[
|
||||||
const FONT = 'sans-serif';
|
const FONT = 'sans-serif';
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
|
|
||||||
|
const WAVE = new BaseTheme.WavePattern(10, 1);
|
||||||
|
|
||||||
const SETTINGS = {
|
const SETTINGS = {
|
||||||
titleMargin: 12,
|
titleMargin: 12,
|
||||||
outerMargin: 5,
|
outerMargin: 5,
|
||||||
|
@ -5822,6 +5892,8 @@ define('sequence/themes/Chunky',[
|
||||||
'stroke': '#000000',
|
'stroke': '#000000',
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -5830,6 +5902,8 @@ define('sequence/themes/Chunky',[
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
'stroke-dasharray': '10, 4',
|
'stroke-dasharray': '10, 4',
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -5838,9 +5912,9 @@ define('sequence/themes/Chunky',[
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 10,
|
|
||||||
'wave-height': 1,
|
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
@ -6514,6 +6588,8 @@ 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,
|
||||||
|
@ -6564,27 +6640,25 @@ define('sequence/themes/Sketch',[
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: null,
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-dasharray': '4, 2',
|
'stroke-dasharray': '4, 2',
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: null,
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 6,
|
|
||||||
'wave-height': 0.5,
|
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
@ -6800,16 +6874,19 @@ define('sequence/themes/Sketch',[
|
||||||
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.renderArrowHead = this.renderArrowHead.bind(this);
|
||||||
this.renderConnect = this.renderConnect.bind(this);
|
this.renderFlatConnector = this.renderFlatConnector.bind(this);
|
||||||
this.renderTag = this.renderTag.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;
|
||||||
|
|
||||||
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.render = this.renderConnect;
|
|
||||||
this.connect.line.dash.render = this.renderConnect;
|
this.connect.line.solid.renderFlat = this.renderFlatConnector;
|
||||||
|
this.connect.line.dash.renderFlat = this.renderFlatConnector;
|
||||||
|
|
||||||
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);
|
||||||
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
|
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
|
||||||
|
@ -6998,7 +7075,7 @@ define('sequence/themes/Sketch',[
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConnect({x1, dx1, x2, dx2, y}, attrs) {
|
renderFlatConnector(attrs, {x1, dx1, x2, dx2, y}) {
|
||||||
const ln = this.lineNodes(
|
const ln = this.lineNodes(
|
||||||
{x: x1 + dx1, y},
|
{x: x1 + dx1, y},
|
||||||
{x: x2 + dx2, y},
|
{x: x2 + dx2, y},
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -118,7 +118,7 @@ defineDescribe('SequenceDiagram', [
|
||||||
|
|
||||||
// Arrow
|
// Arrow
|
||||||
expect(content).toContain(
|
expect(content).toContain(
|
||||||
'<line x1="20.5" y1="26" x2="48.5" y2="26"'
|
'<path d="M20.5 26L48.5 26"'
|
||||||
);
|
);
|
||||||
expect(content).toContain(
|
expect(content).toContain(
|
||||||
'<polygon points="46 21 51 26 46 31"'
|
'<polygon points="46 21 51 26 46 31"'
|
||||||
|
|
|
@ -76,113 +76,6 @@ define([
|
||||||
new Arrowhead('double'),
|
new Arrowhead('double'),
|
||||||
];
|
];
|
||||||
|
|
||||||
function makeWavyLineHeights(height) {
|
|
||||||
return [
|
|
||||||
0,
|
|
||||||
-height * 2 / 3,
|
|
||||||
-height,
|
|
||||||
-height * 2 / 3,
|
|
||||||
0,
|
|
||||||
height * 2 / 3,
|
|
||||||
height,
|
|
||||||
height * 2 / 3,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderFlat({x1, dx1, x2, dx2, y}, attrs) {
|
|
||||||
const ww = attrs['wave-width'];
|
|
||||||
const hh = attrs['wave-height'];
|
|
||||||
|
|
||||||
if(!ww || !hh) {
|
|
||||||
return {
|
|
||||||
shape: svg.make('line', Object.assign({
|
|
||||||
'x1': x1 + dx1,
|
|
||||||
'y1': y,
|
|
||||||
'x2': x2 + dx2,
|
|
||||||
'y2': y,
|
|
||||||
}, attrs)),
|
|
||||||
p1: {x: x1, y},
|
|
||||||
p2: {x: x2, y},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const heights = makeWavyLineHeights(hh);
|
|
||||||
const dw = ww / heights.length;
|
|
||||||
let p = 0;
|
|
||||||
|
|
||||||
let points = '';
|
|
||||||
const xL = Math.min(x1 + dx1, x2 + dx2);
|
|
||||||
const xR = Math.max(x1 + dx1, x2 + dx2);
|
|
||||||
for(let x = xL; x + dw <= xR; x += dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y + heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
points += xR + ' ' + y;
|
|
||||||
return {
|
|
||||||
shape: svg.make('polyline', Object.assign({points}, attrs)),
|
|
||||||
p1: {x: x1, y},
|
|
||||||
p2: {x: x2, y},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderRev({xL, dx1, dx2, y1, y2, xR}, attrs) {
|
|
||||||
const r = (y2 - y1) / 2;
|
|
||||||
const ww = attrs['wave-width'];
|
|
||||||
const hh = attrs['wave-height'];
|
|
||||||
|
|
||||||
if(!ww || !hh) {
|
|
||||||
return {
|
|
||||||
shape: svg.make('path', Object.assign({
|
|
||||||
'd': (
|
|
||||||
'M' + (xL + dx1) + ' ' + y1 +
|
|
||||||
'L' + xR + ' ' + y1 +
|
|
||||||
'A' + r + ' ' + r + ' 0 0 1 ' + xR + ' ' + y2 +
|
|
||||||
'L' + (xL + dx2) + ' ' + y2
|
|
||||||
),
|
|
||||||
}, attrs)),
|
|
||||||
p1: {x: xL, y: y1},
|
|
||||||
p2: {x: xL, y: y2},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const heights = makeWavyLineHeights(hh);
|
|
||||||
const dw = ww / heights.length;
|
|
||||||
let p = 0;
|
|
||||||
|
|
||||||
let points = '';
|
|
||||||
for(let x = xL + dx1; x + dw <= xR; x += dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y1 + heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ym = (y1 + y2) / 2;
|
|
||||||
for(let t = 0; t + dw / r <= Math.PI; t += dw / r) {
|
|
||||||
const h = heights[(p ++) % heights.length];
|
|
||||||
points += (
|
|
||||||
(xR + Math.sin(t) * (r - h)) + ' ' +
|
|
||||||
(ym - Math.cos(t) * (r - h)) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let x = xR; x - dw >= xL + dx2; x -= dw) {
|
|
||||||
points += (
|
|
||||||
x + ' ' +
|
|
||||||
(y2 - heights[(p ++) % heights.length]) + ' '
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
points += (xL + dx2) + ' ' + y2;
|
|
||||||
return {
|
|
||||||
shape: svg.make('polyline', Object.assign({points}, attrs)),
|
|
||||||
p1: {x: xL, y: y1},
|
|
||||||
p2: {x: xL, y: y2},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Connect extends BaseComponent {
|
class Connect extends BaseComponent {
|
||||||
separation({label, agentNames, options}, env) {
|
separation({label, agentNames, options}, env) {
|
||||||
const config = env.theme.connect;
|
const config = env.theme.connect;
|
||||||
|
@ -272,14 +165,14 @@ define([
|
||||||
const y1 = y0 + r * 2;
|
const y1 = y0 + r * 2;
|
||||||
|
|
||||||
const line = config.line[options.line];
|
const line = config.line[options.line];
|
||||||
const rendered = (line.renderRev || renderRev)({
|
const rendered = line.renderRev(line.attrs, {
|
||||||
xL: lineX,
|
xL: lineX,
|
||||||
dx1: lArrow.lineGap(env.theme, line.attrs),
|
dx1: lArrow.lineGap(env.theme, line.attrs),
|
||||||
dx2: rArrow.lineGap(env.theme, line.attrs),
|
dx2: rArrow.lineGap(env.theme, line.attrs),
|
||||||
y1: y0,
|
y1: y0,
|
||||||
y2: y1,
|
y2: y1,
|
||||||
xR: x1,
|
xR: x1,
|
||||||
}, line.attrs);
|
});
|
||||||
env.shapeLayer.appendChild(rendered.shape);
|
env.shapeLayer.appendChild(rendered.shape);
|
||||||
|
|
||||||
lArrow.render(env.shapeLayer, env.theme, rendered.p1, 1);
|
lArrow.render(env.shapeLayer, env.theme, rendered.p1, 1);
|
||||||
|
@ -336,13 +229,13 @@ define([
|
||||||
});
|
});
|
||||||
|
|
||||||
const line = config.line[options.line];
|
const line = config.line[options.line];
|
||||||
const rendered = (line.render || renderFlat)({
|
const rendered = line.renderFlat(line.attrs, {
|
||||||
x1: x0,
|
x1: x0,
|
||||||
dx1: lArrow.lineGap(env.theme, line.attrs) * dir,
|
dx1: lArrow.lineGap(env.theme, line.attrs) * dir,
|
||||||
x2: x1,
|
x2: x1,
|
||||||
dx2: -rArrow.lineGap(env.theme, line.attrs) * dir,
|
dx2: -rArrow.lineGap(env.theme, line.attrs) * dir,
|
||||||
y,
|
y,
|
||||||
}, line.attrs);
|
});
|
||||||
env.shapeLayer.appendChild(rendered.shape);
|
env.shapeLayer.appendChild(rendered.shape);
|
||||||
|
|
||||||
lArrow.render(env.shapeLayer, env.theme, rendered.p1, dir);
|
lArrow.render(env.shapeLayer, env.theme, rendered.p1, dir);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(['svg/SVGUtilities'], (svg) => {
|
define(['svg/SVGUtilities', 'svg/PatternedLine'], (svg, PatternedLine) => {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function deepCopy(o) {
|
function deepCopy(o) {
|
||||||
|
@ -109,5 +109,59 @@ define(['svg/SVGUtilities'], (svg) => {
|
||||||
}, attrs));
|
}, attrs));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BaseTheme.WavePattern = class WavePattern {
|
||||||
|
constructor(width, height) {
|
||||||
|
this.deltas = [
|
||||||
|
0,
|
||||||
|
-height * 2 / 3,
|
||||||
|
-height,
|
||||||
|
-height * 2 / 3,
|
||||||
|
0,
|
||||||
|
height * 2 / 3,
|
||||||
|
height,
|
||||||
|
height * 2 / 3,
|
||||||
|
];
|
||||||
|
this.partWidth = width / this.deltas.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDelta(p) {
|
||||||
|
return this.deltas[p % this.deltas.length];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderFlatConnector = (pattern, attrs, {x1, dx1, x2, dx2, y}) => {
|
||||||
|
return {
|
||||||
|
shape: svg.make('path', Object.assign({
|
||||||
|
d: new PatternedLine(pattern)
|
||||||
|
.move(x1 + dx1, y)
|
||||||
|
.line(x2 + dx2, y)
|
||||||
|
.cap()
|
||||||
|
.asPath(),
|
||||||
|
}, attrs)),
|
||||||
|
p1: {x: x1, y},
|
||||||
|
p2: {x: x2, y},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderRevConnector = (
|
||||||
|
pattern,
|
||||||
|
attrs,
|
||||||
|
{xL, dx1, dx2, y1, y2, xR}
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
shape: svg.make('path', Object.assign({
|
||||||
|
d: new PatternedLine(pattern)
|
||||||
|
.move(xL + dx1, y1)
|
||||||
|
.line(xR, y1)
|
||||||
|
.arc(xR, (y1 + y2) / 2, Math.PI)
|
||||||
|
.line(xL + dx2, y2)
|
||||||
|
.cap()
|
||||||
|
.asPath(),
|
||||||
|
}, attrs)),
|
||||||
|
p1: {x: xL, y: y1},
|
||||||
|
p2: {x: xL, y: y2},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return BaseTheme;
|
return BaseTheme;
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,8 @@ define([
|
||||||
const FONT = 'sans-serif';
|
const FONT = 'sans-serif';
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
|
|
||||||
|
const WAVE = new BaseTheme.WavePattern(6, 0.5);
|
||||||
|
|
||||||
const SETTINGS = {
|
const SETTINGS = {
|
||||||
titleMargin: 10,
|
titleMargin: 10,
|
||||||
outerMargin: 5,
|
outerMargin: 5,
|
||||||
|
@ -76,6 +78,8 @@ define([
|
||||||
'stroke': '#000000',
|
'stroke': '#000000',
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -84,6 +88,8 @@ define([
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
'stroke-dasharray': '4, 2',
|
'stroke-dasharray': '4, 2',
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -92,9 +98,9 @@ define([
|
||||||
'stroke-width': 1,
|
'stroke-width': 1,
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 6,
|
|
||||||
'wave-height': 0.5,
|
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
|
|
@ -12,6 +12,8 @@ define([
|
||||||
const FONT = 'sans-serif';
|
const FONT = 'sans-serif';
|
||||||
const LINE_HEIGHT = 1.3;
|
const LINE_HEIGHT = 1.3;
|
||||||
|
|
||||||
|
const WAVE = new BaseTheme.WavePattern(10, 1);
|
||||||
|
|
||||||
const SETTINGS = {
|
const SETTINGS = {
|
||||||
titleMargin: 12,
|
titleMargin: 12,
|
||||||
outerMargin: 5,
|
outerMargin: 5,
|
||||||
|
@ -82,6 +84,8 @@ define([
|
||||||
'stroke': '#000000',
|
'stroke': '#000000',
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -90,6 +94,8 @@ define([
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
'stroke-dasharray': '10, 4',
|
'stroke-dasharray': '10, 4',
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, null),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -98,9 +104,9 @@ define([
|
||||||
'stroke-width': 3,
|
'stroke-width': 3,
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 10,
|
|
||||||
'wave-height': 1,
|
|
||||||
},
|
},
|
||||||
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
|
|
@ -30,6 +30,8 @@ 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,
|
||||||
|
@ -80,27 +82,25 @@ define([
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: null,
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'dash': {
|
'dash': {
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-dasharray': '4, 2',
|
'stroke-dasharray': '4, 2',
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: null,
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, null),
|
||||||
},
|
},
|
||||||
'wave': {
|
'wave': {
|
||||||
attrs: Object.assign({
|
attrs: Object.assign({
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-linejoin': 'round',
|
'stroke-linejoin': 'round',
|
||||||
'stroke-linecap': 'round',
|
'stroke-linecap': 'round',
|
||||||
'wave-width': 6,
|
|
||||||
'wave-height': 0.5,
|
|
||||||
}, PENCIL),
|
}, PENCIL),
|
||||||
render: null,
|
renderFlat: BaseTheme.renderFlatConnector.bind(null, WAVE),
|
||||||
renderRev: null,
|
renderRev: BaseTheme.renderRevConnector.bind(null, WAVE),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
|
@ -316,16 +316,19 @@ define([
|
||||||
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.renderArrowHead = this.renderArrowHead.bind(this);
|
||||||
this.renderConnect = this.renderConnect.bind(this);
|
this.renderFlatConnector = this.renderFlatConnector.bind(this);
|
||||||
this.renderTag = this.renderTag.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;
|
||||||
|
|
||||||
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.render = this.renderConnect;
|
|
||||||
this.connect.line.dash.render = this.renderConnect;
|
this.connect.line.solid.renderFlat = this.renderFlatConnector;
|
||||||
|
this.connect.line.dash.renderFlat = this.renderFlatConnector;
|
||||||
|
|
||||||
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);
|
||||||
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
|
this.blocks.ref.boxRenderer = this.renderRefBlock.bind(this);
|
||||||
|
@ -514,7 +517,7 @@ define([
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConnect({x1, dx1, x2, dx2, y}, attrs) {
|
renderFlatConnector(attrs, {x1, dx1, x2, dx2, y}) {
|
||||||
const ln = this.lineNodes(
|
const ln = this.lineNodes(
|
||||||
{x: x1 + dx1, y},
|
{x: x1 + dx1, y},
|
||||||
{x: x2 + dx2, y},
|
{x: x2 + dx2, y},
|
||||||
|
|
|
@ -4,6 +4,7 @@ define([
|
||||||
'svg/SVGUtilities_spec',
|
'svg/SVGUtilities_spec',
|
||||||
'svg/SVGTextBlock_spec',
|
'svg/SVGTextBlock_spec',
|
||||||
'svg/SVGShapes_spec',
|
'svg/SVGShapes_spec',
|
||||||
|
'svg/PatternedLine_spec',
|
||||||
'interface/Interface_spec',
|
'interface/Interface_spec',
|
||||||
'sequence/SequenceDiagram_spec',
|
'sequence/SequenceDiagram_spec',
|
||||||
'sequence/Tokeniser_spec',
|
'sequence/Tokeniser_spec',
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
define(() => {
|
||||||
|
'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 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_link() {
|
||||||
|
if(this.disconnect) {
|
||||||
|
this.points.push(this.x + ' ' + this.y);
|
||||||
|
this.disconnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextDelta() {
|
||||||
|
return this.pattern.getDelta(this.phase ++);
|
||||||
|
}
|
||||||
|
|
||||||
|
cap() {
|
||||||
|
if(this.x !== null) {
|
||||||
|
this.points.push(this.x + ' ' + this.y);
|
||||||
|
this.x = null;
|
||||||
|
this.y = null;
|
||||||
|
this.disconnect = false;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(x, y) {
|
||||||
|
this.cap();
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.disconnect = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
line(x, y) {
|
||||||
|
this._link();
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.disconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arc(cx, cy, theta) {
|
||||||
|
this._link();
|
||||||
|
|
||||||
|
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);
|
||||||
|
this.x = cx + Math.sin(theta1 + theta) * radius;
|
||||||
|
this.y = 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))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.points.push(
|
||||||
|
(cx + Math.sin(theta1) * radius) + ' ' +
|
||||||
|
(cy - Math.cos(theta1) * radius) +
|
||||||
|
'A' + radius + ' ' + radius + ' 0 ' +
|
||||||
|
((theta < 0) ? '0 ' : '1 ') +
|
||||||
|
'1 ' +
|
||||||
|
this.x + ' ' + this.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
asPath() {
|
||||||
|
this._link();
|
||||||
|
return 'M' + this.points.join('L');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('unpatterned', () => {
|
||||||
|
describe('line', () => {
|
||||||
|
it('connects points with lines', () => {
|
||||||
|
const ln = new PatternedLine()
|
||||||
|
.move(10, 20)
|
||||||
|
.line(30, 50)
|
||||||
|
.line(1, 2)
|
||||||
|
.cap();
|
||||||
|
|
||||||
|
expect(ln.asPath()).toEqual(
|
||||||
|
'M10 20' +
|
||||||
|
'L30 50' +
|
||||||
|
'L1 2'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue