Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor] Move the code to generate the SVG path from draw_layer.js to outliner.js #17499

Merged
merged 1 commit into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 21 additions & 42 deletions src/display/draw_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,34 @@ class DrawLayer {
return svg;
}

highlight({ outlines, box }, color, opacity) {
#createClipPath(defs, pathId) {
const clipPath = DrawLayer._svgFactory.createElement("clipPath");
defs.append(clipPath);
const clipPathId = `clip_${pathId}`;
clipPath.setAttribute("id", clipPathId);
clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
const clipPathUse = DrawLayer._svgFactory.createElement("use");
clipPath.append(clipPathUse);
clipPathUse.setAttribute("href", `#${pathId}`);
clipPathUse.classList.add("clip");

return clipPathId;
}

highlight(outlines, color, opacity) {
const id = this.#id++;
const root = this.#createSVG(box);
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",
DrawLayer.#extractPathFromHighlightOutlines(outlines)
);
path.setAttribute("d", outlines.toSVGPath());

// Create the clipping path for the editor div.
const clipPath = DrawLayer._svgFactory.createElement("clipPath");
defs.append(clipPath);
const clipPathId = `clip_${pathId}`;
clipPath.setAttribute("id", clipPathId);
clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
const clipPathUse = DrawLayer._svgFactory.createElement("use");
clipPath.append(clipPathUse);
clipPathUse.setAttribute("href", `#${pathId}`);
clipPathUse.classList.add("clip");
const clipPathId = this.#createClipPath(defs, pathId);

const use = DrawLayer._svgFactory.createElement("use");
root.append(use);
Expand All @@ -106,24 +109,21 @@ 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);
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)
);
path.setAttribute("d", outlines.toSVGPath());
path.setAttribute("vector-effect", "non-scaling-stroke");

const use1 = DrawLayer._svgFactory.createElement("use");
Expand All @@ -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);
}
Expand Down
49 changes: 48 additions & 1 deletion src/display/editor/outliner.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class Outliner {
}
outline.push(lastPointX, lastPointY);
}
return { outlines, box: this.#box };
return new HighlightOutline(outlines, this.#box);
}

#binarySearch(y) {
Expand Down Expand Up @@ -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 };