Text elements as a separated class
This commit is contained in:
parent
96efac1e3f
commit
e8140eae88
48
area.js
48
area.js
|
|
@ -471,7 +471,7 @@ var DrawingArea = new Lang.Class({
|
|||
|
||||
if (duplicate) {
|
||||
// deep cloning
|
||||
let copy = new Elements.DrawingElement(JSON.parse(JSON.stringify(this.grabbedElement)));
|
||||
let copy = new this.grabbedElement.constructor(JSON.parse(JSON.stringify(this.grabbedElement)));
|
||||
this.elements.push(copy);
|
||||
this.grabbedElement = copy;
|
||||
}
|
||||
|
|
@ -554,28 +554,32 @@ var DrawingArea = new Lang.Class({
|
|||
this._stopDrawing();
|
||||
});
|
||||
|
||||
this.currentElement = new Elements.DrawingElement ({
|
||||
shape: this.currentTool,
|
||||
color: this.currentColor.to_string(),
|
||||
line: { lineWidth: this.currentLineWidth, lineJoin: this.currentLineJoin, lineCap: this.currentLineCap },
|
||||
dash: { active: this.dashedLine, array: this.dashedLine ? [this.dashArray[0] || this.currentLineWidth, this.dashArray[1] || this.currentLineWidth * 3] : [0, 0] , offset: this.dashOffset },
|
||||
fill: this.fill,
|
||||
fillRule: this.currentFillRule,
|
||||
eraser: eraser,
|
||||
transform: { active: false, center: [0, 0], angle: 0, startAngle: 0, ratio: 1 },
|
||||
points: []
|
||||
});
|
||||
|
||||
if (this.currentTool == Shapes.TEXT) {
|
||||
this.currentElement.fill = false;
|
||||
this.currentElement.font = {
|
||||
family: (this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric]),
|
||||
weight: this.currentFontWeight,
|
||||
style: this.currentFontStyle,
|
||||
stretch: this.currentFontStretch,
|
||||
variant: this.currentFontVariant };
|
||||
this.currentElement.text = _("Text");
|
||||
this.currentElement.textRightAligned = this.currentTextRightAligned;
|
||||
this.currentElement = new Elements.DrawingElement({
|
||||
shape: this.currentTool,
|
||||
color: this.currentColor.to_string(),
|
||||
eraser: eraser,
|
||||
font: {
|
||||
family: (this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric]),
|
||||
weight: this.currentFontWeight,
|
||||
style: this.currentFontStyle,
|
||||
stretch: this.currentFontStretch,
|
||||
variant: this.currentFontVariant },
|
||||
text: _("Text"),
|
||||
textRightAligned: this.currentTextRightAligned,
|
||||
points: []
|
||||
});
|
||||
} else {
|
||||
this.currentElement = new Elements.DrawingElement({
|
||||
shape: this.currentTool,
|
||||
color: this.currentColor.to_string(),
|
||||
eraser: eraser,
|
||||
fill: this.fill,
|
||||
fillRule: this.currentFillRule,
|
||||
line: { lineWidth: this.currentLineWidth, lineJoin: this.currentLineJoin, lineCap: this.currentLineCap },
|
||||
dash: { active: this.dashedLine, array: this.dashedLine ? [this.dashArray[0] || this.currentLineWidth, this.dashArray[1] || this.currentLineWidth * 3] : [0, 0] , offset: this.dashOffset },
|
||||
points: []
|
||||
});
|
||||
}
|
||||
|
||||
this.currentElement.startDrawing(startX, startY);
|
||||
|
|
|
|||
307
elements.js
307
elements.js
|
|
@ -57,10 +57,14 @@ const MIN_TRANSLATION_DISTANCE = 1; // px
|
|||
const MIN_ROTATION_ANGLE = Math.PI / 1000; // rad
|
||||
const MIN_DRAWING_SIZE = 3; // px
|
||||
|
||||
var DrawingElement = function(params) {
|
||||
return params.shape == Shapes.TEXT ? new TextElement(params) : new _DrawingElement(params);
|
||||
};
|
||||
|
||||
// DrawingElement represents a "brushstroke".
|
||||
// It can be converted into a cairo path as well as a svg element.
|
||||
// See DrawingArea._startDrawing() to know its params.
|
||||
var DrawingElement = new Lang.Class({
|
||||
const _DrawingElement = new Lang.Class({
|
||||
Name: 'DrawOnYourScreenDrawingElement',
|
||||
|
||||
_init: function(params) {
|
||||
|
|
@ -69,16 +73,12 @@ var DrawingElement = new Lang.Class({
|
|||
|
||||
// compatibility with json generated by old extension versions
|
||||
|
||||
if (params.fillRule === undefined)
|
||||
this.fillRule = Cairo.FillRule.WINDING;
|
||||
if (params.transformations === undefined)
|
||||
this.transformations = [];
|
||||
if (params.shape == Shapes.TEXT) {
|
||||
if (params.font && params.font.weight === 0)
|
||||
this.font.weight = 400;
|
||||
if (params.font && params.font.weight === 1)
|
||||
this.font.weight = 700;
|
||||
}
|
||||
if (params.font && params.font.weight === 0)
|
||||
this.font.weight = 400;
|
||||
if (params.font && params.font.weight === 1)
|
||||
this.font.weight = 700;
|
||||
|
||||
if (params.transform && params.transform.center) {
|
||||
let angle = (params.transform.angle || 0) + (params.transform.startAngle || 0);
|
||||
|
|
@ -104,10 +104,6 @@ var DrawingElement = new Lang.Class({
|
|||
fillRule: this.fillRule,
|
||||
eraser: this.eraser,
|
||||
transformations: this.transformations,
|
||||
text: this.text,
|
||||
lineIndex: this.lineIndex !== undefined ? this.lineIndex : undefined,
|
||||
textRightAligned: this.textRightAligned,
|
||||
font: this.font,
|
||||
points: this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100])
|
||||
};
|
||||
},
|
||||
|
|
@ -129,9 +125,12 @@ var DrawingElement = new Lang.Class({
|
|||
cr.stroke();
|
||||
}
|
||||
|
||||
cr.setLineCap(this.line.lineCap);
|
||||
cr.setLineJoin(this.line.lineJoin);
|
||||
cr.setLineWidth(this.line.lineWidth);
|
||||
if (this.line) {
|
||||
cr.setLineCap(this.line.lineCap);
|
||||
cr.setLineJoin(this.line.lineJoin);
|
||||
cr.setLineWidth(this.line.lineWidth);
|
||||
}
|
||||
|
||||
if (this.fillRule)
|
||||
cr.setFillRule(this.fillRule);
|
||||
|
||||
|
|
@ -175,6 +174,12 @@ var DrawingElement = new Lang.Class({
|
|||
}
|
||||
});
|
||||
|
||||
this._drawCairo(cr, params);
|
||||
|
||||
cr.identityMatrix();
|
||||
},
|
||||
|
||||
_drawCairo: function(cr, params) {
|
||||
let [points, shape] = [this.points, this.shape];
|
||||
|
||||
if (shape == Shapes.LINE && points.length == 3) {
|
||||
|
|
@ -218,51 +223,10 @@ var DrawingElement = new Lang.Class({
|
|||
if (shape == Shapes.POLYGON)
|
||||
cr.closePath();
|
||||
|
||||
} else if (shape == Shapes.TEXT && points.length == 2) {
|
||||
let layout = PangoCairo.create_layout(cr);
|
||||
let fontSize = Math.abs(points[1][1] - points[0][1]) * Pango.SCALE;
|
||||
let fontDescription = new Pango.FontDescription();
|
||||
fontDescription.set_absolute_size(fontSize);
|
||||
['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => {
|
||||
if (this.font[attribute] !== undefined)
|
||||
try {
|
||||
fontDescription[`set_${attribute}`](this.font[attribute]);
|
||||
} catch(e) {}
|
||||
});
|
||||
layout.set_font_description(fontDescription);
|
||||
layout.set_text(this.text, -1);
|
||||
this.textWidth = layout.get_pixel_size()[0];
|
||||
cr.moveTo(points[1][0] - (this.textRightAligned ? this.textWidth : 0), Math.max(points[0][1],points[1][1]) - layout.get_baseline() / Pango.SCALE);
|
||||
layout.set_text(this.text, -1);
|
||||
PangoCairo.show_layout(cr, layout);
|
||||
|
||||
if (params.showTextCursor) {
|
||||
let cursorPosition = this.cursorPosition == -1 ? this.text.length : this.cursorPosition;
|
||||
layout.set_text(this.text.slice(0, cursorPosition), -1);
|
||||
let width = layout.get_pixel_size()[0];
|
||||
cr.rectangle(points[1][0] - (this.textRightAligned ? this.textWidth : 0) + width, Math.max(points[0][1],points[1][1]),
|
||||
Math.abs(points[1][1] - points[0][1]) / 25, - Math.abs(points[1][1] - points[0][1]));
|
||||
cr.fill();
|
||||
}
|
||||
|
||||
if (params.showTextRectangle || params.drawTextRectangle) {
|
||||
cr.rectangle(points[1][0] - (this.textRightAligned ? this.textWidth : 0), Math.max(points[0][1], points[1][1]),
|
||||
this.textWidth, - Math.abs(points[1][1] - points[0][1]));
|
||||
if (params.showTextRectangle)
|
||||
setDummyStroke(cr);
|
||||
else
|
||||
// Only draw the rectangle to find the element, not to show it.
|
||||
cr.setLineWidth(0);
|
||||
}
|
||||
}
|
||||
|
||||
cr.identityMatrix();
|
||||
},
|
||||
|
||||
getContainsPoint: function(cr, x, y) {
|
||||
if (this.shape == Shapes.TEXT)
|
||||
return cr.inFill(x, y);
|
||||
|
||||
cr.save();
|
||||
cr.setLineWidth(Math.max(this.line.lineWidth, 25));
|
||||
cr.setDash([], 0);
|
||||
|
|
@ -274,33 +238,6 @@ var DrawingElement = new Lang.Class({
|
|||
},
|
||||
|
||||
buildSVG: function(bgColor) {
|
||||
let row = "\n ";
|
||||
let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]);
|
||||
let color = this.eraser ? bgColor : this.color;
|
||||
let fill = this.fill && !this.isStraightLine;
|
||||
let attributes = '';
|
||||
|
||||
if (fill) {
|
||||
attributes = `fill="${color}"`;
|
||||
if (this.fillRule)
|
||||
attributes += ` fill-rule="${FillRuleNames[this.fillRule].toLowerCase()}"`;
|
||||
} else {
|
||||
attributes = `fill="none"`;
|
||||
}
|
||||
|
||||
if (this.line && this.line.lineWidth) {
|
||||
attributes += ` stroke="${color}"` +
|
||||
` stroke-width="${this.line.lineWidth}"`;
|
||||
if (this.line.lineCap)
|
||||
attributes += ` stroke-linecap="${LineCapNames[this.line.lineCap].toLowerCase()}"`;
|
||||
if (this.line.lineJoin && !this.isStraightLine)
|
||||
attributes += ` stroke-linejoin="${LineJoinNames[this.line.lineJoin].toLowerCase()}"`;
|
||||
if (this.dash && this.dash.active && this.dash.array && this.dash.array[0] && this.dash.array[1])
|
||||
attributes += ` stroke-dasharray="${this.dash.array[0]} ${this.dash.array[1]}" stroke-dashoffset="${this.dash.offset}"`;
|
||||
} else {
|
||||
attributes += ` stroke="none"`;
|
||||
}
|
||||
|
||||
let transAttribute = '';
|
||||
this.transformations.slice(0).reverse().forEach(transformation => {
|
||||
transAttribute += transAttribute ? ' ' : ' transform="';
|
||||
|
|
@ -328,6 +265,37 @@ var DrawingElement = new Lang.Class({
|
|||
});
|
||||
transAttribute += transAttribute ? '"' : '';
|
||||
|
||||
return this._drawSvg(transAttribute);
|
||||
},
|
||||
|
||||
_drawSvg: function(transAttribute) {
|
||||
let row = "\n ";
|
||||
let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]);
|
||||
let color = this.eraser ? bgColor : this.color;
|
||||
let fill = this.fill && !this.isStraightLine;
|
||||
let attributes = '';
|
||||
|
||||
if (fill) {
|
||||
attributes = `fill="${color}"`;
|
||||
if (this.fillRule)
|
||||
attributes += ` fill-rule="${FillRuleNames[this.fillRule].toLowerCase()}"`;
|
||||
} else {
|
||||
attributes = `fill="none"`;
|
||||
}
|
||||
|
||||
if (this.line && this.line.lineWidth) {
|
||||
attributes += ` stroke="${color}"` +
|
||||
` stroke-width="${this.line.lineWidth}"`;
|
||||
if (this.line.lineCap)
|
||||
attributes += ` stroke-linecap="${LineCapNames[this.line.lineCap].toLowerCase()}"`;
|
||||
if (this.line.lineJoin && !this.isStraightLine)
|
||||
attributes += ` stroke-linejoin="${LineJoinNames[this.line.lineJoin].toLowerCase()}"`;
|
||||
if (this.dash && this.dash.active && this.dash.array && this.dash.array[0] && this.dash.array[1])
|
||||
attributes += ` stroke-dasharray="${this.dash.array[0]} ${this.dash.array[1]}" stroke-dashoffset="${this.dash.offset}"`;
|
||||
} else {
|
||||
attributes += ` stroke="none"`;
|
||||
}
|
||||
|
||||
if (this.shape == Shapes.LINE && points.length == 4) {
|
||||
row += `<path ${attributes} d="M${points[0][0]} ${points[0][1]}`;
|
||||
row += ` C ${points[1][0]} ${points[1][1]}, ${points[2][0]} ${points[2][1]}, ${points[3][0]} ${points[3][1]}`;
|
||||
|
|
@ -372,26 +340,6 @@ var DrawingElement = new Lang.Class({
|
|||
row += ` ${points[i][0]},${points[i][1]}`;
|
||||
row += `"${transAttribute}/>`;
|
||||
|
||||
} else if (this.shape == Shapes.TEXT && points.length == 2) {
|
||||
attributes = `fill="${color}" ` +
|
||||
`stroke="transparent" ` +
|
||||
`stroke-opacity="0" ` +
|
||||
`font-size="${Math.abs(points[1][1] - points[0][1])}"`;
|
||||
|
||||
if (this.font.family)
|
||||
attributes += ` font-family="${this.font.family}"`;
|
||||
if (this.font.weight && this.font.weight != Pango.Weight.NORMAL)
|
||||
attributes += ` font-weight="${this.font.weight}"`;
|
||||
if (this.font.style && FontStyleNames[this.font.style])
|
||||
attributes += ` font-style="${FontStyleNames[this.font.style].toLowerCase()}"`;
|
||||
if (FontStretchNames[this.font.stretch] && this.font.stretch != Pango.Stretch.NORMAL)
|
||||
attributes += ` font-stretch="${FontStretchNames[this.font.stretch].toLowerCase()}"`;
|
||||
if (this.font.variant && FontVariantNames[this.font.variant])
|
||||
attributes += ` font-variant="${FontVariantNames[this.font.variant].toLowerCase()}"`;
|
||||
|
||||
// this.textWidth is computed during Cairo building.
|
||||
row += `<text ${attributes} x="${points[1][0] - (this.textRightAligned ? this.textWidth : 0)}" `;
|
||||
row += `y="${Math.max(points[0][1], points[1][1])}"${transAttribute}>${this.text}</text>`;
|
||||
}
|
||||
|
||||
return row;
|
||||
|
|
@ -469,14 +417,6 @@ var DrawingElement = new Lang.Class({
|
|||
} else if (this.shape == Shapes.POLYGON || this.shape == Shapes.POLYLINE) {
|
||||
points[points.length - 1] = [x, y];
|
||||
|
||||
} else if (this.shape == Shapes.TEXT && transform) {
|
||||
if (points.length < 2)
|
||||
return;
|
||||
|
||||
let [slideX, slideY] = [x - points[1][0], y - points[1][1]];
|
||||
points[0] = [points[0][0] + slideX, points[0][1] + slideY];
|
||||
points[1] = [x, y];
|
||||
|
||||
} else {
|
||||
points[1] = [x, y];
|
||||
|
||||
|
|
@ -590,11 +530,6 @@ var DrawingElement = new Lang.Class({
|
|||
}
|
||||
},
|
||||
|
||||
// When rotating grouped lines, lineOffset is used to retrieve the rotation center of the first line.
|
||||
_getLineOffset: function() {
|
||||
return (this.lineIndex || 0) * Math.abs(this.points[1][1] - this.points[0][1]);
|
||||
},
|
||||
|
||||
// The figure rotation center before transformations (original).
|
||||
// this.textWidth is computed during Cairo building.
|
||||
_getOriginalCenter: function() {
|
||||
|
|
@ -603,7 +538,6 @@ var DrawingElement = new Lang.Class({
|
|||
this._originalCenter = this.shape == Shapes.ELLIPSE ? [points[0][0], points[0][1]] :
|
||||
this.shape == Shapes.LINE && points.length == 4 ? getCurveCenter(points[0], points[1], points[2], points[3]) :
|
||||
this.shape == Shapes.LINE && points.length == 3 ? getCurveCenter(points[0], points[0], points[1], points[2]) :
|
||||
this.shape == Shapes.TEXT && this.textWidth ? [points[1][0], Math.max(points[0][1], points[1][1]) - this._getLineOffset()] :
|
||||
points.length >= 3 ? getCentroid(points) :
|
||||
getNaiveCenter(points);
|
||||
}
|
||||
|
|
@ -648,6 +582,139 @@ var DrawingElement = new Lang.Class({
|
|||
}
|
||||
});
|
||||
|
||||
const TextElement = new Lang.Class({
|
||||
Name: 'DrawOnYourScreenTextElement',
|
||||
Extends: _DrawingElement,
|
||||
|
||||
toJSON: function() {
|
||||
return {
|
||||
shape: this.shape,
|
||||
color: this.color,
|
||||
eraser: this.eraser,
|
||||
transformations: this.transformations,
|
||||
text: this.text,
|
||||
lineIndex: this.lineIndex !== undefined ? this.lineIndex : undefined,
|
||||
textRightAligned: this.textRightAligned,
|
||||
font: this.font,
|
||||
points: this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100])
|
||||
};
|
||||
},
|
||||
|
||||
_drawCairo: function(cr, params) {
|
||||
let points = this.points;
|
||||
|
||||
if (points.length == 2) {
|
||||
let layout = PangoCairo.create_layout(cr);
|
||||
let fontSize = Math.abs(points[1][1] - points[0][1]) * Pango.SCALE;
|
||||
let fontDescription = new Pango.FontDescription();
|
||||
fontDescription.set_absolute_size(fontSize);
|
||||
['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => {
|
||||
if (this.font[attribute] !== undefined)
|
||||
try {
|
||||
fontDescription[`set_${attribute}`](this.font[attribute]);
|
||||
} catch(e) {}
|
||||
});
|
||||
layout.set_font_description(fontDescription);
|
||||
layout.set_text(this.text, -1);
|
||||
this.textWidth = layout.get_pixel_size()[0];
|
||||
cr.moveTo(points[1][0] - (this.textRightAligned ? this.textWidth : 0), Math.max(points[0][1],points[1][1]) - layout.get_baseline() / Pango.SCALE);
|
||||
layout.set_text(this.text, -1);
|
||||
PangoCairo.show_layout(cr, layout);
|
||||
|
||||
if (params.showTextCursor) {
|
||||
let cursorPosition = this.cursorPosition == -1 ? this.text.length : this.cursorPosition;
|
||||
layout.set_text(this.text.slice(0, cursorPosition), -1);
|
||||
let width = layout.get_pixel_size()[0];
|
||||
cr.rectangle(points[1][0] - (this.textRightAligned ? this.textWidth : 0) + width, Math.max(points[0][1],points[1][1]),
|
||||
Math.abs(points[1][1] - points[0][1]) / 25, - Math.abs(points[1][1] - points[0][1]));
|
||||
cr.fill();
|
||||
}
|
||||
|
||||
if (params.showTextRectangle || params.drawTextRectangle) {
|
||||
cr.rectangle(points[1][0] - (this.textRightAligned ? this.textWidth : 0), Math.max(points[0][1], points[1][1]),
|
||||
this.textWidth, - Math.abs(points[1][1] - points[0][1]));
|
||||
if (params.showTextRectangle)
|
||||
setDummyStroke(cr);
|
||||
else
|
||||
// Only draw the rectangle to find the element, not to show it.
|
||||
cr.setLineWidth(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getContainsPoint: function(cr, x, y) {
|
||||
return cr.inFill(x, y);
|
||||
},
|
||||
|
||||
_drawSvg: function(transAttribute) {
|
||||
let row = "\n ";
|
||||
let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]);
|
||||
let color = this.eraser ? bgColor : this.color;
|
||||
let attributes = '';
|
||||
|
||||
if (points.length == 2) {
|
||||
attributes = `fill="${color}" ` +
|
||||
`stroke="transparent" ` +
|
||||
`stroke-opacity="0" ` +
|
||||
`font-size="${Math.abs(points[1][1] - points[0][1])}"`;
|
||||
|
||||
if (this.font.family)
|
||||
attributes += ` font-family="${this.font.family}"`;
|
||||
if (this.font.weight && this.font.weight != Pango.Weight.NORMAL)
|
||||
attributes += ` font-weight="${this.font.weight}"`;
|
||||
if (this.font.style && FontStyleNames[this.font.style])
|
||||
attributes += ` font-style="${FontStyleNames[this.font.style].toLowerCase()}"`;
|
||||
if (FontStretchNames[this.font.stretch] && this.font.stretch != Pango.Stretch.NORMAL)
|
||||
attributes += ` font-stretch="${FontStretchNames[this.font.stretch].toLowerCase()}"`;
|
||||
if (this.font.variant && FontVariantNames[this.font.variant])
|
||||
attributes += ` font-variant="${FontVariantNames[this.font.variant].toLowerCase()}"`;
|
||||
|
||||
// this.textWidth is computed during Cairo building.
|
||||
row += `<text ${attributes} x="${points[1][0] - (this.textRightAligned ? this.textWidth : 0)}" `;
|
||||
row += `y="${Math.max(points[0][1], points[1][1])}"${transAttribute}>${this.text}</text>`;
|
||||
}
|
||||
|
||||
return row;
|
||||
},
|
||||
|
||||
updateDrawing: function(x, y, transform) {
|
||||
let points = this.points;
|
||||
if (x == points[points.length - 1][0] && y == points[points.length - 1][1])
|
||||
return;
|
||||
|
||||
transform = transform || this.transformations.length >= 1;
|
||||
|
||||
if (transform) {
|
||||
if (points.length < 2)
|
||||
return;
|
||||
|
||||
let [slideX, slideY] = [x - points[1][0], y - points[1][1]];
|
||||
points[0] = [points[0][0] + slideX, points[0][1] + slideY];
|
||||
points[1] = [x, y];
|
||||
|
||||
} else {
|
||||
points[1] = [x, y];
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
// When rotating grouped lines, lineOffset is used to retrieve the rotation center of the first line.
|
||||
_getLineOffset: function() {
|
||||
return (this.lineIndex || 0) * Math.abs(this.points[1][1] - this.points[0][1]);
|
||||
},
|
||||
|
||||
_getOriginalCenter: function() {
|
||||
if (!this._originalCenter) {
|
||||
let points = this.points;
|
||||
this._originalCenter = this.textWidth ? [points[1][0], Math.max(points[0][1], points[1][1]) - this._getLineOffset()] :
|
||||
points.length >= 3 ? getCentroid(points) :
|
||||
getNaiveCenter(points);
|
||||
}
|
||||
|
||||
return this._originalCenter;
|
||||
},
|
||||
});
|
||||
|
||||
const setDummyStroke = function(cr) {
|
||||
cr.setLineWidth(2);
|
||||
cr.setLineCap(0);
|
||||
|
|
@ -655,10 +722,6 @@ const setDummyStroke = function(cr) {
|
|||
cr.setDash([1, 2], 0);
|
||||
};
|
||||
|
||||
/*
|
||||
Some geometric utils
|
||||
*/
|
||||
|
||||
const getNearness = function(pointA, pointB, distance) {
|
||||
return Math.hypot(pointB[0] - pointA[0], pointB[1] - pointA[1]) < distance;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue