js-draw
Version:
Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.
874 lines (858 loc) • 29.7 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _IconProvider_instances, _IconProvider_makeXIcon;
Object.defineProperty(exports, "__esModule", { value: true });
const math_1 = require("@js-draw/math");
const SVGRenderer_1 = __importDefault(require("../rendering/renderers/SVGRenderer"));
const Viewport_1 = __importDefault(require("../Viewport"));
const FreehandLineBuilder_1 = require("../components/builders/FreehandLineBuilder");
const PolylineBuilder_1 = require("../components/builders/PolylineBuilder");
const Eraser_1 = require("../tools/Eraser");
const createElement_1 = require("../util/createElement");
const types_1 = require("../tools/SelectionTool/types");
const svgNamespace = 'http://www.w3.org/2000/svg';
let checkerboardIdCounter = 0;
const makeCheckerboardPattern = () => {
const id = `checkerboard-${checkerboardIdCounter++}`;
const patternElement = (0, createElement_1.createSvgElement)('pattern', {
id: id,
viewBox: '0,0,10,10',
width: '20%',
height: '20%',
patternUnits: 'userSpaceOnUse',
children: (0, createElement_1.createSvgElements)('rect', [
{ x: 0, y: 0, width: 10, height: 10, fill: 'white' },
{ x: 0, y: 0, width: 5, height: 5, fill: 'gray' },
{ x: 5, y: 5, width: 5, height: 5, fill: 'gray' },
]),
});
const patternRef = `url(#${id})`;
return {
patternDefElement: patternElement,
// @deprecated use patternDefElement
get patternDef() {
return patternElement.innerHTML;
},
patternRef,
};
};
const makeRedoIcon = (mirror) => {
const icon = document.createElementNS(svgNamespace, 'svg');
icon.innerHTML = `
<style>
.toolbar-svg-undo-redo-icon {
stroke: var(--icon-color);
stroke-width: 12;
stroke-linejoin: round;
stroke-linecap: round;
fill: none;
transform-origin: center;
}
</style>
`;
const path = document.createElementNS(svgNamespace, 'path');
path.setAttribute('d', 'M20,20 A15,15 0 0 1 70,80 L80,90 L60,70 L65,90 L87,90 L65,80');
path.classList.add('toolbar-svg-undo-redo-icon');
if (mirror) {
path.style.transform = 'scale(-1, 1)';
}
icon.appendChild(path);
icon.setAttribute('viewBox', '0 0 100 100');
return icon;
};
/**
* Provides icons that can be used in the toolbar and other locations.
*
* To customize the icons used by the editor, extend this class and override methods.
*
* @example
* ```ts,runnable
* import * as jsdraw from 'js-draw';
*
* class CustomIconProvider extends jsdraw.IconProvider {
* // Use '☺' instead of the default dropdown symbol.
* public override makeDropdownIcon() {
* const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
* icon.innerHTML = `
* <text x='5' y='55' style='fill: var(--icon-color); font-size: 50pt;'>☺</text>
* `;
* icon.setAttribute('viewBox', '0 0 100 100');
* return icon;
* }
* }
*
* const icons = new CustomIconProvider();
* const editor = new jsdraw.Editor(document.body, {
* // The icon pack to use is specified through the editor's initial
* // configuration object:
* iconProvider: icons,
* });
*
* // Add a toolbar that uses these icons
* jsdraw.makeDropdownToolbar(editor).addDefaults();
* ```
*/
class IconProvider {
constructor() {
_IconProvider_instances.add(this);
}
makeUndoIcon() {
return makeRedoIcon(true);
}
// @returns a redo icon.
makeRedoIcon() {
return makeRedoIcon(false);
}
makeDropdownIcon() {
const icon = this.makeIconFromPath('M5,10 L50,90 L95,10 Z');
icon.setAttribute('viewBox', '-10 -10 110 110');
return icon;
}
makeEraserIcon(eraserSize, mode) {
eraserSize ??= 10;
const scaledSize = eraserSize / 4;
const eraserColor = '#ff70af';
// Draw an eraser-like shape. Created with Inkscape
const icon = (0, createElement_1.createSvgElement)('svg', {
viewBox: '0 0 120 120',
children: [
(0, createElement_1.createSvgElement)('defs', {
children: [
(0, createElement_1.createSvgElement)('linearGradient', {
id: 'dash-pattern',
children: (0, createElement_1.createSvgElements)('stop', [
{ offset: '80%', 'stop-color': eraserColor },
{ offset: '85%', 'stop-color': 'white' },
{ offset: '90%', 'stop-color': eraserColor },
]),
}),
],
}),
(0, createElement_1.createSvgElement)('path', {
fill: mode === Eraser_1.EraserMode.PartialStroke ? 'url(#dash-pattern)' : eraserColor,
stroke: 'black',
transform: 'rotate(41.35)',
d: `
M 52.5 27
C 50 28.9 48.9 31.7 48.9 34.8
L 48.9 39.8
C 48.9 45.3 53.4 49.8 58.9 49.8
L 103.9 49.8
C 105.8 49.8 107.6 49.2 109.1 48.3
L 110.2 ${scaledSize + 49.5} L 159.7 ${scaledSize + 5}
L 157.7 ${-scaledSize + 5.2} L 112.4 ${49.5 - scaledSize}
C 113.4 43.5 113.9 41.7 113.9 39.8
L 113.9 34.8
C 113.9 29.3 109.4 24.8 103.9 24.8
L 58.9 24.8
C 56.5 24.8 54.3 25.7 52.5 27
z
`,
}),
(0, createElement_1.createSvgElement)('rect', {
stroke: '#cc8077',
fill: 'var(--icon-color)',
width: 65,
height: 75,
x: 48.9,
y: -38.7,
transform: 'rotate(41.35)',
}),
],
});
return icon;
}
makeSelectionIcon(mode = types_1.SelectionMode.Rectangle) {
const icon = document.createElementNS(svgNamespace, 'svg');
if (mode === types_1.SelectionMode.Rectangle) {
icon.innerHTML = `
<g>
<rect x="10" y="10" width="70" height="70" fill="pink" stroke="black" stroke-dasharray="32 9"/>
<rect x="75" y="75" width="10" height="10" fill="white" stroke="black"/>
</g>
`;
}
else {
icon.innerHTML = `
<g>
<rect x="10" y="10" width="76" height="76" rx="50" stroke-dasharray="32 9" fill="pink" stroke="black"/>
<rect x="71" y="71" width="10" height="10" fill="white" stroke="black"/>
</g>
`;
}
icon.setAttribute('viewBox', '0 0 100 100');
return icon;
}
makeRotateIcon() {
const icon = document.createElementNS(svgNamespace, 'svg');
icon.innerHTML = `
<defs>
<marker
id="arrow-marker"
viewBox="0 0 10 10"
refX="3" refY="5"
markerWidth="3" markerHeight="3"
orient="auto-start-reverse"
>
<path
d="M0,0 L8,5 L0,10z"
fill="var(--icon-color)"
/>
</marker>
</defs>
<path
marker-start="url(#arrow-marker)"
d="
M20,20
A30,30 0 1 1 80 80
"
fill="none"
stroke="var(--icon-color)"
stroke-width="12"
/>
<path
d="
M80,80
A30,30 0 1 1 20 20
"
fill="none"
stroke="var(--icon-color)"
stroke-width="12"
stroke-dasharray="30 10 20 10 20 10 10"
style="stroke-linecap: butt;"
/>
`;
icon.setAttribute('viewBox', '-5 -5 110 110');
return icon;
}
makeHandToolIcon() {
const fill = 'none';
const strokeColor = 'var(--icon-color)';
const strokeWidth = '3';
// Draw a cursor-like shape
return this.makeIconFromPath(`
m 10,60
5,30
H 90
V 30
C 90,20 75,20 75,30
V 60
20
C 75,10 60,10 60,20
V 60
15
C 60,5 45,5 45,15
V 60
25
C 45,15 30,15 30,25
V 60
75
L 25,60
C 20,45 10,50 10,60
Z
`, fill, strokeColor, strokeWidth);
}
makeTouchPanningIcon() {
const fill = 'none';
const strokeColor = 'var(--icon-color)';
const strokeWidth = '3';
return this.makeIconFromPath(`
M 5,5.5
V 17.2
L 16.25,5.46
Z
m 33.75,0
L 50,17
V 5.5
Z
M 5,40.7
v 11.7
h 11.25
z
M 26,19
C 19.8,19.4 17.65,30.4 21.9,34.8
L 50,70
H 27.5
c -11.25,0 -11.25,17.6 0,17.6
H 61.25
C 94.9,87.8 95,87.6 95,40.7 78.125,23 67,29 55.6,46.5
L 33.1,23
C 30.3125,20.128192 27.9,19 25.830078,19.119756
Z
`, fill, strokeColor, strokeWidth);
}
/** Unused by js-draw. @deprecated */
makeAllDevicePanningIcon() {
const fill = 'none';
const strokeColor = 'var(--icon-color)';
const strokeWidth = '3';
return this.makeIconFromPath(`
M 5 5
L 5 17.5
17.5 5
5 5
z
M 42.5 5
L 55 17.5
55 5
42.5 5
z
M 70 10
L 70 21
61 15
55.5 23
66 30
56 37
61 45
70 39
70 50
80 50
80 39
89 45
95 36
84 30
95 23
89 15
80 21
80 10
70 10
z
M 27.5 26.25
L 27.5 91.25
L 43.75 83.125
L 52 99
L 68 91
L 60 75
L 76.25 66.875
L 27.5 26.25
z
M 5 42.5
L 5 55
L 17.5 55
L 5 42.5
z
`, fill, strokeColor, strokeWidth);
}
makeZoomIcon() {
const icon = document.createElementNS(svgNamespace, 'svg');
icon.setAttribute('viewBox', '0 0 100 100');
const addTextNode = (text, x, y) => {
const textNode = document.createElementNS(svgNamespace, 'text');
textNode.appendChild(document.createTextNode(text));
textNode.setAttribute('x', x.toString());
textNode.setAttribute('y', y.toString());
textNode.style.textAlign = 'center';
textNode.style.textAnchor = 'middle';
textNode.style.fontSize = '55px';
textNode.style.fill = 'var(--icon-color)';
textNode.style.fontFamily = 'monospace';
icon.appendChild(textNode);
};
addTextNode('+', 40, 45);
addTextNode('-', 70, 75);
return icon;
}
makeRotationLockIcon() {
const icon = this.makeIconFromPath(`
M 40.1 25.1
C 32.5 25 27.9 34.1 27.9 34.1
L 25.7 30
L 28 44.7
L 36.6 40.3
L 32.3 38.3
C 33.6 28 38.1 25.2 45.1 31.8
L 49.4 29.6
C 45.9 26.3 42.8 25.1 40.1 25.1
z
M 51.7 34.2
L 43.5 39.1
L 48 40.8
C 47.4 51.1 43.1 54.3 35.7 48.2
L 31.6 50.7
C 45.5 62.1 52.6 44.6 52.6 44.6
L 55.1 48.6
L 51.7 34.2
z
M 56.9 49.9
C 49.8 49.9 49.2 57.3 49.3 60.9
L 47.6 60.9
L 47.6 73.7
L 66.1 73.7
L 66.1 60.9
L 64.4 60.9
C 64.5 57.3 63.9 49.9 56.9 49.9
z
M 56.9 53.5
C 60.8 53.5 61 58.2 60.8 60.9
L 52.9 60.9
C 52.7 58.2 52.9 53.5 56.9 53.5
z
`);
icon.setAttribute('viewBox', '10 10 70 70');
return icon;
}
makeInsertImageIcon() {
return this.makeIconFromPath(`
M 5 10 L 5 90 L 95 90 L 95 10 L 5 10 z
M 10 15 L 90 15 L 90 50 L 70 75 L 40 50 L 10 75 L 10 15 z
M 22.5 25 A 7.5 7.5 0 0 0 15 32.5 A 7.5 7.5 0 0 0 22.5 40 A 7.5 7.5 0 0 0 30 32.5 A 7.5 7.5 0 0 0 22.5 25 z
`);
}
makeUploadFileIcon() {
return this.makeIconFromPath(`
M 48,10 32,34 43,33 42,68
H 54
L 53,33 64,34 Z
M 8,66 V 86 H 88 V 66 H 78 V 76 H 18 V 66 Z
`);
}
makeTextIcon(textStyle) {
const icon = document.createElementNS(svgNamespace, 'svg');
icon.setAttribute('viewBox', '0 0 100 100');
const textNode = document.createElementNS(svgNamespace, 'text');
textNode.appendChild(document.createTextNode('T'));
textNode.style.fontFamily = textStyle.fontFamily;
textNode.style.fontWeight = textStyle.fontWeight ?? '';
textNode.style.fontVariant = textStyle.fontVariant ?? '';
textNode.style.fill = textStyle.renderingStyle.fill.toHexString();
textNode.style.textAnchor = 'middle';
textNode.setAttribute('x', '50');
textNode.setAttribute('y', '75');
textNode.style.fontSize = '65px';
textNode.style.filter = 'drop-shadow(0px 0px 10px var(--shadow-color))';
icon.appendChild(textNode);
return icon;
}
makePenIcon(penStyle) {
// Use a square-root scale to prevent the pen's tip from overflowing.
const strokeSize = Math.round(Math.sqrt(penStyle.thickness) * 4);
const color = penStyle.color;
const rounded = this.isRoundedTipPen(penStyle);
const tipThickness = strokeSize / 2;
const inkTipPath = `
M ${15 - tipThickness},${80 - tipThickness}
${15 - tipThickness},${80 + tipThickness}
30,83
15,65
Z
`;
const trailStartEndY = 80 + tipThickness;
const inkTrailPath = `
m ${15 - tipThickness * 1.1},${trailStartEndY}
c 35,10 55,15 60,30
l ${35 + tipThickness * 1.2},${-10 - tipThickness}
C 80.47,98.32 50.5,${90 + tipThickness} 20,${trailStartEndY} Z
`;
const colorBubblePath = `
M 72.45,35.67
A 10,15 41.8 0 1 55,40.2 10,15 41.8 0 1 57.55,22.3 10,15 41.8 0 1 75,17.8 10,15 41.8 0 1 72.5,35.67
Z
`;
let gripMainPath = 'M 85,-25 25,35 h 10 v 10 h 10 v 10 h 10 v 10 h 10 l -5,10 60,-60 z';
let gripShadow1Path = 'M 25,35 H 35 L 90,-15 85,-25 Z';
let gripShadow2Path = 'M 60,75 65,65 H 55 l 55,-55 10,5 z';
if (rounded) {
gripMainPath = 'M 85,-25 25,35 c 15,0 40,30 35,40 l 60,-60 z';
gripShadow1Path = 'm 25,35 c 3.92361,0.384473 7.644275,0.980572 10,3 l 55,-53 -5,-10 z';
gripShadow2Path = 'M 60,75 C 61,66 59,65 56,59 l 54,-54 10,10 z';
}
const penTipPath = `M 25,35 ${10 - tipThickness / 4},${70 - tipThickness / 2} 20,75 25,85 60,75 70,55 45,25 Z`;
const pencilTipColor = math_1.Color4.fromHex('#f4d7d7');
const tipColor = pencilTipColor.mix(color, tipThickness / 40 - 0.1).toHexString();
const checkerboardPattern = makeCheckerboardPattern();
const colorString = color.toHexString();
const ink = (0, createElement_1.createSvgPaths)({
fill: checkerboardPattern.patternRef,
d: inkTipPath,
}, {
fill: checkerboardPattern.patternRef,
d: inkTrailPath,
}, {
fill: colorString,
d: inkTipPath,
}, {
fill: colorString,
d: inkTrailPath,
});
const penTip = (0, createElement_1.createSvgPaths)({ fill: checkerboardPattern.patternRef, d: penTipPath }, { fill: tipColor, stroke: colorString, d: penTipPath });
const grip = (0, createElement_1.createSvgPaths)({ fill: 'var(--icon-color)', stroke: 'var(--icon-color)', d: gripMainPath },
// Shadows
{ fill: 'rgba(150, 150, 150, 0.3)', d: gripShadow1Path }, { fill: 'rgba(100, 100, 100, 0.2)', d: gripShadow2Path },
// Color bubble
{ fill: checkerboardPattern.patternRef, d: colorBubblePath }, { fill: colorString, d: colorBubblePath });
const icon = document.createElementNS(svgNamespace, 'svg');
icon.setAttribute('viewBox', '0 0 100 100');
const iconMainContent = (0, createElement_1.createSvgElement)('g', {
children: [ink, penTip, grip].flat(),
});
const defs = (0, createElement_1.createSvgElement)('defs', {
children: [checkerboardPattern.patternDefElement],
});
icon.replaceChildren(defs, iconMainContent);
return icon;
}
makeIconFromFactory(penStyle) {
// Increase the thickness we use to generate the icon less with larger actual thicknesses.
// We want the icon to be recognisable with a large range of thicknesses.
const thickness = Math.sqrt(penStyle.thickness) * 3;
const nowTime = performance.now();
const startPoint = {
pos: math_1.Vec2.of(10, 10),
width: thickness,
color: penStyle.color,
time: nowTime - 100,
};
const endPoint = {
pos: math_1.Vec2.of(90, 90),
width: thickness,
color: penStyle.color,
time: nowTime,
};
const viewport = new Viewport_1.default(() => { });
const builder = penStyle.factory(startPoint, viewport);
builder.addPoint(endPoint);
const icon = document.createElementNS(svgNamespace, 'svg');
icon.setAttribute('viewBox', '0 0 100 100');
viewport.updateScreenSize(math_1.Vec2.of(100, 100));
let renderer;
// Any transparency? Include a checkerboard grid.
const includeTransparencyGrid = penStyle.color.a < 1;
if (includeTransparencyGrid) {
const checkerboardPattern = makeCheckerboardPattern();
const defs = document.createElementNS(svgNamespace, 'defs');
defs.appendChild(checkerboardPattern.patternDefElement);
icon.appendChild(defs);
const background = document.createElementNS(svgNamespace, 'g');
icon.appendChild(background);
renderer = new (class extends SVGRenderer_1.default {
constructor() {
super(icon, viewport);
}
addPathToSVG() {
const addedPath = super.addPathToSVG();
if (addedPath) {
// Add a copy of the path on the background
const copy = addedPath.cloneNode(true);
copy.style.zIndex = '-1';
if (copy.hasAttribute('stroke')) {
copy.setAttribute('stroke', checkerboardPattern.patternRef);
}
// Note: Assumes that the component wouldn't normally be both stroked
// and filled.
else if (copy.hasAttribute('fill')) {
copy.setAttribute('fill', checkerboardPattern.patternRef);
}
background.appendChild(copy);
}
return addedPath;
}
})();
}
else {
renderer = new SVGRenderer_1.default(icon, viewport);
}
builder.preview(renderer);
// If only a single path was rendered, try to give it a checkerboard background to
// emphasize transparency. TODO: This is very fragile
const bbox = builder.getBBox();
icon.setAttribute('viewBox', `${bbox.x} ${bbox.y} ${bbox.w} ${bbox.h}`);
return icon;
}
makePipetteIcon(color) {
const icon = document.createElementNS(svgNamespace, 'svg');
const mainGroup = document.createElementNS(svgNamespace, 'g');
mainGroup.style.rotate = '45deg';
mainGroup.style.transformOrigin = 'center';
const pipette = document.createElementNS(svgNamespace, 'g');
pipette.innerHTML = `
<path
style="fill: var(--icon-color); stroke-linecap:round; stroke-linejoin:round;"
d="
m 32,12 v 68
c 0,1 0.5,2 1.33,2.5 1.67,1.15 3.67,2.1 5.17,3.2 1.4,1.1 2.3,2.1 2.5,3.1 0.6,2.1 1,4.6 1,6.2 0,3.7 5.45,4.1 6,0.4 l 0.9,-6.8
c 0.3,-0.9 1.1,-1.9 2.6,-2.9 1.5,-1.1 3.4,-2 5.1,-3.2
C 57.5,82 58,81 58,80
V 12 Z m 20,25 v 41.3
c 0,1.7 -2.5,1.6 -4,2.7 -1,0.76 -2.1,1.5 -3,2.6
C 44,82.5 43.02,81.75 42,81 40.51,79.92 38,80 38,78.34
V 51 Z
"
/>
<rect
style="fill: var(--icon-color);"
width="32"
height="9"
x="29"
y="2"
ry="4.5"
/>
<path
style="fill: var(--icon-color);"
d="m 45,-25 c -5.54,0 -11,4.26 -11,9 V 0 h 22 v -16 c 0,-4.74 -5.46,-9 -11,-9 z"
/>
`;
if (color) {
const checkerboardPattern = makeCheckerboardPattern();
const defs = document.createElementNS(svgNamespace, 'defs');
defs.appendChild(checkerboardPattern.patternDefElement);
icon.appendChild(defs);
const fluidBackground = document.createElementNS(svgNamespace, 'path');
const fluid = document.createElementNS(svgNamespace, 'path');
const fluidPathData = `
M 35,36 H 55 V 78.678012 83 L 45,87 35,83 Z
`;
fluid.setAttribute('d', fluidPathData);
fluidBackground.setAttribute('d', fluidPathData);
fluid.style.fill = color.toHexString();
fluidBackground.style.fill = checkerboardPattern.patternRef;
mainGroup.appendChild(fluidBackground);
mainGroup.appendChild(fluid);
}
mainGroup.appendChild(pipette);
icon.appendChild(mainGroup);
icon.setAttribute('viewBox', '5 -40 140 140');
return icon;
}
makeShapeAutocorrectIcon() {
const fill = 'none';
const strokeColor = 'var(--icon-color)';
return this.makeIconFromPath(`
m 79.129476,33.847107 9.967823,-0.03218 v 55 h -55 l 0.03218,-9.96782
M 71.1,40.8 a 30,30 0 0 1 -30,30 30,30 0 0 1 -30,-30 30,30 0 0 1 30,-30 30,30 0 0 1 30,30 L 71.1,40.8
M 34.1,58.8 v -25 h 25 v 0
`, fill, strokeColor, '7px');
}
makeStrokeSmoothingIcon() {
const fill = 'none';
const strokeColor = 'var(--icon-color)';
return this.makeIconFromPath(`
m 31,83.2 c -50,0 30,-65 -20,-65
M 75,17.3 40,59.7 38.2,77.6 55.5,72.4 90.5,30 Z
`, fill, strokeColor, '7px');
}
makePressureSensitivityIcon() {
const icon = document.createElementNS(svgNamespace, 'svg');
icon.setAttribute('viewBox', '4 -10 100 100');
icon.replaceChildren(...(0, createElement_1.createSvgPaths)({
d: `
M 39.7,77.7
C 39.7,77.7 3.4,78.1 4.2,60 4.7,45.2 33.2,30.5 40,25 55.9,12.1 7.4,4.8 7.4,4.8
c 0,0 40.2,5.5 40.2,15.4
C 47.6,29.1 21.2,35.1 23.9,60 25,70 39.7,77.7 39.7,77.7
Z`,
fill: 'var(--icon-color)',
stroke: 'var(--icon-color)',
'stroke-width': '2px',
}, {
d: 'M 86.4,15.6 101.4,28.8 65,70 47.5,74.6 50,56.7Z',
fill: 'transparent',
stroke: 'var(--icon-color)',
'stroke-width': '6px',
}));
return icon;
}
/** Unused. @deprecated */
makeFormatSelectionIcon() {
return this.makeIconFromPath(`
M 5 10
L 5 20 L 10 20 L 10 15 L 20 15 L 20 40 L 15 40 L 15 45 L 35 45 L 35 40 L 30 40 L 30 15 L 40 15 L 40 20 L 45 20 L 45 15 L 45 10 L 5 10 z
M 90 10 C 90 10 86.5 13.8 86 14 C 86 14 76.2 24.8 76 25 L 60 25 L 60 65 C 75 70 85 70 90 65 L 90 25 L 80 25 L 76.7 25 L 90 10 z
M 60 25 L 55 25 L 50 30 L 60 25 z
M 10 55 L 10 90 L 41 90 L 41 86 L 45 86 L 45 55 L 10 55 z
M 42 87 L 42 93 L 48 93 L 48 87 L 42 87 z
`);
}
makeResizeImageToSelectionIcon() {
return this.makeIconFromPath(`
M 75 5 75 10 90 10 90 25 95 25 95 5 75 5 z
M 15 15 15 30 20 30 20 20 30 20 30 15 15 15 z
M 84 15 82 17 81 16 81 20 85 20 84 19 86 17 84 15 z
M 26 24 24 26 26 28 25 29 29 29 29 25 28 26 26 24 z
M 25 71 26 72 24 74 26 76 28 74 29 75 29 71 25 71 z
M 15 75 15 85 25 85 25 80 20 80 20 75 15 75 z
M 90 75 90 90 75 90 75 95 95 95 95 75 90 75 z
M 81 81 81 85 82 84 84 86 86 84 84 82 85 81 81 81 z
`);
}
/** Renamed to {@link makeResizeImageToSelectionIcon} @deprecated */
makeResizeViewportIcon() {
return this.makeResizeImageToSelectionIcon();
}
makeDuplicateSelectionIcon() {
return this.makeIconFromPath(`
M 45,10 45,55 90,55 90,10 45,10 z
M 10,25 10,90 70,90 70,60 40,60 40,25 10,25 z
`);
}
makeCopyIcon() {
return this.makeIconFromPath(`
M 45,10 45,55 90,55 90,10 45,10 z
M 10,25 10,90 70,90 70,60 40,60 40,25 10,25 z
`);
}
makePasteIcon() {
const icon = this.makeIconFromPath(`
M 50 0 L 50 5 L 35 5 L 40 24.75 L 20 25 L 20 100 L 85 100 L 100 90 L 100 24 L 75.1 24.3 L 80 5 L 65 5 L 65 0 L 50 0 z
M 10 15 L 10 115 L 110 115 L 110 15 L 85 15 L 83 20 L 105 20 L 105 110 L 15 110 L 15 20 L 32 20 L 30 15 L 10 15 z
M 25 35 L 90 35 L 90 40 L 25 40 L 25 35 z
M 25 45 L 90 45 L 90 50 L 25 50 L 25 45 z
M 25 55 L 85 55 L 85 60 L 25 60 L 25 55 z
M 25 65 L 90 65 L 90 70 L 25 70 L 25 65 z
`);
icon.setAttribute('viewBox', '0 0 120 120');
return icon;
}
makeDeleteSelectionIcon() {
return __classPrivateFieldGet(this, _IconProvider_instances, "m", _IconProvider_makeXIcon).call(this);
}
makeCloseIcon() {
return __classPrivateFieldGet(this, _IconProvider_instances, "m", _IconProvider_makeXIcon).call(this);
}
makeSaveIcon() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `
<style>
.toolbar-save-icon {
stroke: var(--icon-color);
stroke-width: 6;
stroke-linejoin: round;
stroke-linecap: round;
fill: none;
}
</style>
<path
d='
M 15,55 30,70 85,20
'
class='toolbar-save-icon'
/>
`;
svg.setAttribute('viewBox', '0 0 100 100');
return svg;
}
makeConfigureDocumentIcon() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `
<path
d='
M 5,5 V 95 H 95 V 5 Z m 5,5 H 90 V 90 H 10 Z
m 5,10 V 30 H 50 V 25 H 20 v -5 z
m 40,0 V 50 H 85 V 20 Z
m 2,2 H 83 V 39 L 77,28 70,42 64,35 57,45 Z
m 8.5,5 C 64.67,27 64,27.67 64,28.5 64,29.33 64.67,30 65.5,30 66.33,30 67,29.33 67,28.5 67,27.67 66.33,27 65.5,27 Z
M 15,40 v 5 h 35 v -5 z
m 0,15 v 5 h 70 v -5 z
m 0,15 v 5 h 70 v -5 z
'
style='fill: var(--icon-color);'
/>
`;
svg.setAttribute('viewBox', '0 0 100 100');
return svg;
}
makeOverflowIcon() {
return this.makeIconFromPath(`
M 15 40
A 12.5 12.5 0 0 0 2.5 52.5
A 12.5 12.5 0 0 0 15 65
A 12.5 12.5 0 0 0 27.5 52.5
A 12.5 12.5 0 0 0 15 40
z
M 50 40
A 12.5 12.5 0 0 0 37.5 52.5
A 12.5 12.5 0 0 0 50 65
A 12.5 12.5 0 0 0 62.5 52.5
A 12.5 12.5 0 0 0 50 40
z
M 85 40
A 12.5 12.5 0 0 0 72.5 52.5
A 12.5 12.5 0 0 0 85 65
A 12.5 12.5 0 0 0 97.5 52.5
A 12.5 12.5 0 0 0 85 40
z
`);
}
makeHelpIcon() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `
<circle
style="stroke-width:1.587; stroke: var(--icon-color);"
fill="none"
cx="13.23"
cy="13.23"
r="11.9"
/>
<path
style="stroke-width: 3; stroke-linecap: butt; stroke: var(--icon-color);"
fill="none"
d="M 9.26,6.61 C 18.7,3.25 19.95,10.4 14.3,13.4 c -1.15,0.61 -1.32,1.32 -1.32,2.65 v 2.12"
/>
<circle
style="fill: var(--icon-color);"
cx="13"
cy="21.32"
r="1.9"
/>
`;
svg.setAttribute('viewBox', '0 0 26.46 26.46');
svg.setAttribute('width', '100');
svg.setAttribute('height', '100');
return svg;
}
/**
* @param pathData - SVG path data (e.g. `m10,10l30,30z`)
* @param fill - A valid CSS color (e.g. `var(--icon-color)` or `#f0f`). This can be `none`.
*/
makeIconFromPath(pathData, fill = 'var(--icon-color)', strokeColor = 'none', strokeWidth = '0px') {
const icon = document.createElementNS(svgNamespace, 'svg');
const path = document.createElementNS(svgNamespace, 'path');
path.setAttribute('d', pathData);
path.style.fill = fill;
path.style.stroke = strokeColor;
path.style.strokeWidth = strokeWidth;
icon.appendChild(path);
icon.setAttribute('viewBox', '0 0 100 100');
return icon;
}
/**
* @returns An object with both the definition of a checkerboard pattern and the syntax to
* reference that pattern. The defs provided by this function should be wrapped within a
* `<defs></defs>` element.
*
* **Note**: This function's return value includes both `patternDefElement` (which returns
* an Element) and a (deprecated) `patternDef` string. Avoid using the `patternDef` result.
*/
makeCheckerboardPattern() {
return makeCheckerboardPattern();
}
/**
* @returns true if the given `penStyle` is known to match a rounded tip type of pen.
*/
isRoundedTipPen(penStyle) {
return penStyle.factory === FreehandLineBuilder_1.makeFreehandLineBuilder || penStyle.factory === PolylineBuilder_1.makePolylineBuilder;
}
isPolylinePen(penStyle) {
return penStyle.factory === PolylineBuilder_1.makePolylineBuilder;
}
/** Must be overridden by icon packs that need attribution. */
licenseInfo() {
return null;
}
}
_IconProvider_instances = new WeakSet(), _IconProvider_makeXIcon = function _IconProvider_makeXIcon() {
const strokeWidth = '6px';
const strokeColor = 'var(--icon-color)';
const fillColor = 'none';
return this.makeIconFromPath(`
M 15,15 85,85
M 15,85 85,15
`, fillColor, strokeColor, strokeWidth);
};
exports.default = IconProvider;
;