Merge pull request #17499 from calixteman/editor_outliner
[Editor] Move the code to generate the SVG path from draw_layer.js to outliner.js
This commit is contained in:
commit
61e5dae7fd
@ -69,22 +69,7 @@ class DrawLayer {
|
|||||||
return svg;
|
return svg;
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight({ outlines, box }, color, opacity) {
|
#createClipPath(defs, pathId) {
|
||||||
const id = this.#id++;
|
|
||||||
const root = this.#createSVG(box);
|
|
||||||
root.classList.add("highlight");
|
|
||||||
const defs = DrawLayer._svgFactory.createElement("defs");
|
|
||||||
root.append(defs);
|
|
||||||
const path = DrawLayer._svgFactory.createElement("path");
|
|
||||||
defs.append(path);
|
|
||||||
const pathId = `path_p${this.pageIndex}_${id}`;
|
|
||||||
path.setAttribute("id", pathId);
|
|
||||||
path.setAttribute(
|
|
||||||
"d",
|
|
||||||
DrawLayer.#extractPathFromHighlightOutlines(outlines)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create the clipping path for the editor div.
|
|
||||||
const clipPath = DrawLayer._svgFactory.createElement("clipPath");
|
const clipPath = DrawLayer._svgFactory.createElement("clipPath");
|
||||||
defs.append(clipPath);
|
defs.append(clipPath);
|
||||||
const clipPathId = `clip_${pathId}`;
|
const clipPathId = `clip_${pathId}`;
|
||||||
@ -95,6 +80,24 @@ class DrawLayer {
|
|||||||
clipPathUse.setAttribute("href", `#${pathId}`);
|
clipPathUse.setAttribute("href", `#${pathId}`);
|
||||||
clipPathUse.classList.add("clip");
|
clipPathUse.classList.add("clip");
|
||||||
|
|
||||||
|
return clipPathId;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight(outlines, color, opacity) {
|
||||||
|
const id = this.#id++;
|
||||||
|
const root = this.#createSVG(outlines.box);
|
||||||
|
root.classList.add("highlight");
|
||||||
|
const defs = DrawLayer._svgFactory.createElement("defs");
|
||||||
|
root.append(defs);
|
||||||
|
const path = DrawLayer._svgFactory.createElement("path");
|
||||||
|
defs.append(path);
|
||||||
|
const pathId = `path_p${this.pageIndex}_${id}`;
|
||||||
|
path.setAttribute("id", pathId);
|
||||||
|
path.setAttribute("d", outlines.toSVGPath());
|
||||||
|
|
||||||
|
// Create the clipping path for the editor div.
|
||||||
|
const clipPathId = this.#createClipPath(defs, pathId);
|
||||||
|
|
||||||
const use = DrawLayer._svgFactory.createElement("use");
|
const use = DrawLayer._svgFactory.createElement("use");
|
||||||
root.append(use);
|
root.append(use);
|
||||||
root.setAttribute("fill", color);
|
root.setAttribute("fill", color);
|
||||||
@ -106,13 +109,13 @@ class DrawLayer {
|
|||||||
return { id, clipPathId: `url(#${clipPathId})` };
|
return { id, clipPathId: `url(#${clipPathId})` };
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightOutline({ outlines, box }) {
|
highlightOutline(outlines) {
|
||||||
// We cannot draw the outline directly in the SVG for highlights because
|
// We cannot draw the outline directly in the SVG for highlights because
|
||||||
// it composes with its parent with mix-blend-mode: multiply.
|
// it composes with its parent with mix-blend-mode: multiply.
|
||||||
// But the outline has a different mix-blend-mode, so we need to draw it in
|
// But the outline has a different mix-blend-mode, so we need to draw it in
|
||||||
// its own SVG.
|
// its own SVG.
|
||||||
const id = this.#id++;
|
const id = this.#id++;
|
||||||
const root = this.#createSVG(box);
|
const root = this.#createSVG(outlines.box);
|
||||||
root.classList.add("highlightOutline");
|
root.classList.add("highlightOutline");
|
||||||
const defs = DrawLayer._svgFactory.createElement("defs");
|
const defs = DrawLayer._svgFactory.createElement("defs");
|
||||||
root.append(defs);
|
root.append(defs);
|
||||||
@ -120,10 +123,7 @@ class DrawLayer {
|
|||||||
defs.append(path);
|
defs.append(path);
|
||||||
const pathId = `path_p${this.pageIndex}_${id}`;
|
const pathId = `path_p${this.pageIndex}_${id}`;
|
||||||
path.setAttribute("id", pathId);
|
path.setAttribute("id", pathId);
|
||||||
path.setAttribute(
|
path.setAttribute("d", outlines.toSVGPath());
|
||||||
"d",
|
|
||||||
DrawLayer.#extractPathFromHighlightOutlines(outlines)
|
|
||||||
);
|
|
||||||
path.setAttribute("vector-effect", "non-scaling-stroke");
|
path.setAttribute("vector-effect", "non-scaling-stroke");
|
||||||
|
|
||||||
const use1 = DrawLayer._svgFactory.createElement("use");
|
const use1 = DrawLayer._svgFactory.createElement("use");
|
||||||
@ -139,27 +139,6 @@ class DrawLayer {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static #extractPathFromHighlightOutlines(polygons) {
|
|
||||||
const buffer = [];
|
|
||||||
for (const polygon of polygons) {
|
|
||||||
let [prevX, prevY] = polygon;
|
|
||||||
buffer.push(`M${prevX} ${prevY}`);
|
|
||||||
for (let i = 2; i < polygon.length; i += 2) {
|
|
||||||
const x = polygon[i];
|
|
||||||
const y = polygon[i + 1];
|
|
||||||
if (x === prevX) {
|
|
||||||
buffer.push(`V${y}`);
|
|
||||||
prevY = y;
|
|
||||||
} else if (y === prevY) {
|
|
||||||
buffer.push(`H${x}`);
|
|
||||||
prevX = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.push("Z");
|
|
||||||
}
|
|
||||||
return buffer.join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
updateBox(id, box) {
|
updateBox(id, box) {
|
||||||
DrawLayer.#setBox(this.#mapping.get(id), box);
|
DrawLayer.#setBox(this.#mapping.get(id), box);
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ class Outliner {
|
|||||||
}
|
}
|
||||||
outline.push(lastPointX, lastPointY);
|
outline.push(lastPointX, lastPointY);
|
||||||
}
|
}
|
||||||
return { outlines, box: this.#box };
|
return new HighlightOutline(outlines, this.#box);
|
||||||
}
|
}
|
||||||
|
|
||||||
#binarySearch(y) {
|
#binarySearch(y) {
|
||||||
@ -259,4 +259,51 @@ class Outliner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Outline {
|
||||||
|
toSVGPath() {
|
||||||
|
throw new Error("Abstract method `toSVGPath` must be implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
get box() {
|
||||||
|
throw new Error("Abstract getter `box` must be implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HighlightOutline extends Outline {
|
||||||
|
#box;
|
||||||
|
|
||||||
|
#outlines;
|
||||||
|
|
||||||
|
constructor(outlines, box) {
|
||||||
|
super();
|
||||||
|
this.#outlines = outlines;
|
||||||
|
this.#box = box;
|
||||||
|
}
|
||||||
|
|
||||||
|
toSVGPath() {
|
||||||
|
const buffer = [];
|
||||||
|
for (const polygon of this.#outlines) {
|
||||||
|
let [prevX, prevY] = polygon;
|
||||||
|
buffer.push(`M${prevX} ${prevY}`);
|
||||||
|
for (let i = 2; i < polygon.length; i += 2) {
|
||||||
|
const x = polygon[i];
|
||||||
|
const y = polygon[i + 1];
|
||||||
|
if (x === prevX) {
|
||||||
|
buffer.push(`V${y}`);
|
||||||
|
prevY = y;
|
||||||
|
} else if (y === prevY) {
|
||||||
|
buffer.push(`H${x}`);
|
||||||
|
prevX = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.push("Z");
|
||||||
|
}
|
||||||
|
return buffer.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
get box() {
|
||||||
|
return this.#box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export { Outliner };
|
export { Outliner };
|
||||||
|
Loading…
Reference in New Issue
Block a user