对于一个程序,我需要在容器中显示一个文档(而不是HTML文档元素),并且该文档将其作为固定宽度和高度,并且应允许用户缩放。对我来说,这很难,我需要帮助来创建它。 我想制作的功能与MS Word和Libreoffice Writer缩放文档的方式相同。 在这里,我已经逆转了它的工作方式:
文档rect从水平开始中心。
import { createRef } from "preact";
import { useLayoutEffect, useState } from "preact/hooks";
import type { JSX } from "preact/jsx-runtime";
export interface ContainerScrollScalableProps
{
width: number,
height: number,
scale: number,
children?: any,
}
export const ContainerScrollScalable = (props: ContainerScrollScalableProps): JSX.Element =>
{
const container = createRef<HTMLDivElement>();
const [containerW, setW] = useState<number>(0);
const [containerH, setH] = useState<number>(0);
useLayoutEffect(() =>
{
if (container.current)
{
setW(container.current.clientWidth);
setH(container.current.clientHeight);
console.log(container.current.scrollTop);
}
}, [container.current]);
const padTop = containerH * 0.2;
const padBottom = containerH * 0.4;
const padXs = 16 * props.scale;
const scaledW = (props.width * props.scale) + (padXs * 2);
const sizeW = containerW > scaledW ? containerW : scaledW;
return (
<div class="w-100 h-100 overflow-y-scroll overflow-x-auto d-flex" ref={container} >
<div class="border" style={"transform-origin: top center;"
+ `min-width: ${sizeW.toFixed(0)}px; min-height: ${props.height}px;`} >
<div style={`width: ${props.width}px; height: ${props.width}px;`
+ "transform-origin: top center;"
+ `transform: translate(${((sizeW / 2) - (props.width / 2) + padXs).toFixed(0)}px, ${(padTop).toFixed(0)}px) scale(${props.scale});`}
children={props.children} />
</div>
</div>
);
}
const zoom = getUserZoom(); // range 0.1 --> 3.0
// ...
<ContainerScrollScalable width={1080} height={1920} scale={zoom} />
该组件有一些问题:
它需要知道儿童的大小作为道具。
规模并不完美,因为它不考虑孩子的整个矩形。我想添加一些填充以防止缩放的文档触摸屏幕的边界,而且数学仍然不够完美。
滚动栏位置不遵循变焦,这非常重要。
如何让此组件正确扩展其内容并允许滚动栏的位置遵循规模?
import { createRef } from "preact";
import { useLayoutEffect, useState } from "preact/hooks";
import type { JSX } from "preact/jsx-runtime";
export interface ScalableProps {
initialWidth: number;
initialHeight: number;
scale: number;
children?: any;
}
export const ScalableContainer = (props: ScalableProps): JSX.Element => {
const containerRef = createRef<HTMLDivElement>();
const [containerDims, setDims] = useState({ width: 0, height: 0 });
useLayoutEffect(() => {
const update = () => {
if (containerRef.current)
setDims({
width: containerRef.current.clientWidth,
height: containerRef.current.clientHeight,
});
};
update();
window.addEventListener("resize", update);
return () => window.removeEventListener("resize", update);
}, []);
const scaledW = props.initialWidth * props.scale;
const scaledH = props.initialHeight * props.scale;
const padding = 16;
return (
<div
ref={containerRef}
class="w-100 h-100 overflow-scroll"
style={{ position: "relative" }}
>
<div
style={{
width: `${scaledW + padding * 2}px`,
height: `${scaledH + padding * 2}px`,
transform: `scale(${props.scale})`,
transformOrigin: "top center",
padding,
}}
>
<div
style={{
width: `${props.initialWidth}px`,
height: `${props.initialHeight}px`,
border: "1px solid #ccc",
background: "#f0f0f0",
}}
>
{props.children}
</div>
</div>
</div>
);
};
<ScalableContainer initialWidth={1080} initialHeight={1920} scale={1.5} />