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:
calixteman 2024-01-12 13:59:26 +01:00 committed by GitHub
commit 61e5dae7fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 44 deletions

View File

@ -69,22 +69,7 @@ class DrawLayer {
return svg;
}
highlight({ outlines, box }, color, opacity) {
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.
#createClipPath(defs, pathId) {
const clipPath = DrawLayer._svgFactory.createElement("clipPath");
defs.append(clipPath);
const clipPathId = `clip_${pathId}`;
@ -95,6 +80,24 @@ class DrawLayer {
clipPathUse.setAttribute("href", `#${pathId}`);
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");
root.append(use);
root.setAttribute("fill", color);
@ -106,13 +109,13 @@ class DrawLayer {
return { id, clipPathId: `url(#${clipPathId})` };
}
highlightOutline({ outlines, box }) {
highlightOutline(outlines) {
// We cannot draw the outline directly in the SVG for highlights because
// 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
// its own SVG.
const id = this.#id++;
const root = this.#createSVG(box);
const root = this.#createSVG(outlines.box);
root.classList.add("highlightOutline");
const defs = DrawLayer._svgFactory.createElement("defs");
root.append(defs);
@ -120,10 +123,7 @@ class DrawLayer {
defs.append(path);
const pathId = `path_p${this.pageIndex}_${id}`;
path.setAttribute("id", pathId);
path.setAttribute(
"d",
DrawLayer.#extractPathFromHighlightOutlines(outlines)
);
path.setAttribute("d", outlines.toSVGPath());
path.setAttribute("vector-effect", "non-scaling-stroke");
const use1 = DrawLayer._svgFactory.createElement("use");
@ -139,27 +139,6 @@ class DrawLayer {
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) {
DrawLayer.#setBox(this.#mapping.get(id), box);
}

View File

@ -170,7 +170,7 @@ class Outliner {
}
outline.push(lastPointX, lastPointY);
}
return { outlines, box: this.#box };
return new HighlightOutline(outlines, this.#box);
}
#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 };