mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 08:58:58 +01:00
chore(react/type_widget): restore pan/zoom
This commit is contained in:
parent
8e9f5fb486
commit
145ff1a2a5
@ -84,5 +84,10 @@
|
||||
}
|
||||
|
||||
/* #region SVG */
|
||||
|
||||
.note-detail-split.svg-editor .render-container,
|
||||
.note-detail-split.svg-editor .render-container svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
/* #endregion */
|
||||
@ -10,6 +10,7 @@ import { ComponentChildren } from "preact";
|
||||
import ActionButton, { ActionButtonProps } from "../../react/ActionButton";
|
||||
|
||||
export interface SplitEditorProps extends EditableCodeProps {
|
||||
className?: string;
|
||||
error?: string | null;
|
||||
splitOptions?: Split.Options;
|
||||
previewContent: ComponentChildren;
|
||||
@ -25,7 +26,7 @@ export interface SplitEditorProps extends EditableCodeProps {
|
||||
* - Can display errors to the user via {@link setError}.
|
||||
* - Horizontal or vertical orientation for the editor/preview split, adjustable via the switch split orientation button floating button.
|
||||
*/
|
||||
export default function SplitEditor({ note, error, splitOptions, previewContent, previewButtons, ...editorProps }: SplitEditorProps) {
|
||||
export default function SplitEditor({ note, error, splitOptions, previewContent, previewButtons, className, ...editorProps }: SplitEditorProps) {
|
||||
const splitEditorOrientation = useSplitOrientation();
|
||||
const [ readOnly ] = useNoteLabelBoolean(note, "readOnly");
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@ -72,7 +73,7 @@ export default function SplitEditor({ note, error, splitOptions, previewContent,
|
||||
}, [ readOnly, splitEditorOrientation ]);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className={`note-detail-split note-detail-printable ${"split-" + splitEditorOrientation} ${readOnly ? "split-read-only" : ""}`}>
|
||||
<div ref={containerRef} className={`note-detail-split note-detail-printable ${"split-" + splitEditorOrientation} ${readOnly ? "split-read-only" : ""} ${className ?? ""}`}>
|
||||
{splitEditorOrientation === "horizontal"
|
||||
? <>{editor}{preview}</>
|
||||
: <>{preview}{editor}</>}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import { t } from "../../../services/i18n";
|
||||
import SplitEditor, { PreviewButton, SplitEditorProps } from "./SplitEditor";
|
||||
import { RawHtmlBlock } from "../../react/RawHtml";
|
||||
import server from "../../../services/server";
|
||||
import svgPanZoom from "svg-pan-zoom";
|
||||
|
||||
interface SvgSplitEditorProps extends Omit<SplitEditorProps, "previewContent"> {
|
||||
/**
|
||||
@ -22,6 +23,7 @@ interface SvgSplitEditorProps extends Omit<SplitEditorProps, "previewContent"> {
|
||||
export default function SvgSplitEditor({ note, attachmentName, renderSvg, ...props }: SvgSplitEditorProps) {
|
||||
const [ svg, setSvg ] = useState<string>();
|
||||
const [ error, setError ] = useState<string | null | undefined>();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Render the SVG.
|
||||
async function onContentChanged(content: string) {
|
||||
@ -50,14 +52,49 @@ export default function SvgSplitEditor({ note, attachmentName, renderSvg, ...pro
|
||||
server.post(`notes/${note.noteId}/attachments?matchBy=title`, payload);
|
||||
}
|
||||
|
||||
// Pan & zoom.
|
||||
const lastPanZoom = useRef<{ pan: SvgPanZoom.Point, zoom: number }>();
|
||||
const lastNoteId = useRef<string>();
|
||||
useEffect(() => {
|
||||
const shouldPreservePanZoom = (lastNoteId.current === note.noteId);
|
||||
const svgEl = containerRef.current?.querySelector("svg");
|
||||
if (!svgEl) return;
|
||||
const zoomInstance = svgPanZoom(svgEl, {
|
||||
zoomEnabled: true,
|
||||
controlIconsEnabled: false
|
||||
});
|
||||
|
||||
// Restore the previous pan/zoom if the user updates same note.
|
||||
if (shouldPreservePanZoom && lastPanZoom.current) {
|
||||
zoomInstance.zoom(lastPanZoom.current.zoom);
|
||||
zoomInstance.pan(lastPanZoom.current.pan);
|
||||
} else {
|
||||
zoomInstance.resize().center().fit();
|
||||
}
|
||||
|
||||
lastNoteId.current = note.noteId;
|
||||
return () => {
|
||||
lastPanZoom.current = {
|
||||
pan: zoomInstance.getPan(),
|
||||
zoom: zoomInstance.getZoom()
|
||||
}
|
||||
zoomInstance.destroy();
|
||||
};
|
||||
}, [ svg ]);
|
||||
|
||||
return (
|
||||
<SplitEditor
|
||||
className="svg-editor"
|
||||
note={note}
|
||||
error={error}
|
||||
onContentChanged={onContentChanged}
|
||||
dataSaved={onSave}
|
||||
previewContent={(
|
||||
<RawHtmlBlock className="render-container" html={svg} />
|
||||
<RawHtmlBlock
|
||||
className="render-container"
|
||||
containerRef={containerRef}
|
||||
html={svg}
|
||||
/>
|
||||
)}
|
||||
previewButtons={
|
||||
<>
|
||||
|
||||
@ -65,11 +65,6 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget {
|
||||
super.doRender();
|
||||
}
|
||||
|
||||
cleanup(): void {
|
||||
this.#destroyResizer();
|
||||
this.editorTypeWidget.cleanup();
|
||||
}
|
||||
|
||||
async doRefresh(note: FNote) {
|
||||
this.#adjustLayoutOrientation();
|
||||
|
||||
|
||||
@ -106,51 +106,6 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy
|
||||
|
||||
abstract get attachmentName(): string;
|
||||
|
||||
/**
|
||||
* @param preservePanZoom `true` to keep the pan/zoom settings of the previous image, or `false` to re-center it.
|
||||
*/
|
||||
async #setupPanZoom(preservePanZoom: boolean) {
|
||||
// Clean up
|
||||
let pan: SvgPanZoom.Point | null = null;
|
||||
let zoom: number | null = null;
|
||||
if (preservePanZoom && this.zoomInstance) {
|
||||
// Store pan and zoom for same note, when the user is editing the note.
|
||||
pan = this.zoomInstance.getPan();
|
||||
zoom = this.zoomInstance.getZoom();
|
||||
this.#cleanUpZoom();
|
||||
}
|
||||
|
||||
const $svgEl = this.$renderContainer.find("svg");
|
||||
|
||||
// Fit the image to bounds
|
||||
$svgEl.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.css("max-width", "100%");
|
||||
|
||||
if (!$svgEl.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const svgPanZoom = (await import("svg-pan-zoom")).default;
|
||||
const zoomInstance = svgPanZoom($svgEl[0], {
|
||||
zoomEnabled: true,
|
||||
controlIconsEnabled: false
|
||||
});
|
||||
|
||||
if (preservePanZoom && pan && zoom) {
|
||||
// Restore the pan and zoom.
|
||||
zoomInstance.zoom(zoom);
|
||||
zoomInstance.pan(pan);
|
||||
} else {
|
||||
// New instance, reposition properly.
|
||||
zoomInstance.resize();
|
||||
zoomInstance.center();
|
||||
zoomInstance.fit();
|
||||
}
|
||||
|
||||
this.zoomInstance = zoomInstance;
|
||||
}
|
||||
|
||||
buildSplitExtraOptions(): Split.Options {
|
||||
return {
|
||||
onDrag: () => this.zoomHandler?.()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user