Zoom buttons

This commit is contained in:
1ilit 2023-09-19 15:49:36 +03:00
parent 5661984992
commit 94df100726
3 changed files with 70 additions and 49 deletions

View File

@ -3,7 +3,12 @@ import Table from "./table";
import { Cardinality, Constraint, ObjectType } from "../data/data"; import { Cardinality, Constraint, ObjectType } from "../data/data";
import Area from "./area"; import Area from "./area";
import Relationship from "./relationship"; import Relationship from "./relationship";
import { AreaContext, NoteContext, TableContext } from "../pages/editor"; import {
AreaContext,
NoteContext,
SettingsContext,
TableContext,
} from "../pages/editor";
import Note from "./note"; import Note from "./note";
export default function Canvas(props) { export default function Canvas(props) {
@ -11,6 +16,7 @@ export default function Canvas(props) {
useContext(TableContext); useContext(TableContext);
const { areas, setAreas } = useContext(AreaContext); const { areas, setAreas } = useContext(AreaContext);
const { notes, setNotes } = useContext(NoteContext); const { notes, setNotes } = useContext(NoteContext);
const { settings, setSettings } = useContext(SettingsContext);
const [dragging, setDragging] = useState([ObjectType.NONE, -1]); const [dragging, setDragging] = useState([ObjectType.NONE, -1]);
const [linking, setLinking] = useState(false); const [linking, setLinking] = useState(false);
const [line, setLine] = useState({ const [line, setLine] = useState({
@ -45,7 +51,6 @@ export default function Canvas(props) {
mouseY: 0, mouseY: 0,
}); });
const [cursor, setCursor] = useState("default"); const [cursor, setCursor] = useState("default");
const [zoom, setZoom] = useState(1);
const canvas = useRef(null); const canvas = useRef(null);
@ -54,22 +59,22 @@ export default function Canvas(props) {
if (type === ObjectType.TABLE) { if (type === ObjectType.TABLE) {
const table = tables.find((t) => t.id === id); const table = tables.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / zoom - table.x, x: clientX / settings.zoom - table.x,
y: clientY / zoom - table.y, y: clientY / settings.zoom - table.y,
}); });
setDragging([ObjectType.TABLE, id]); setDragging([ObjectType.TABLE, id]);
} else if (type === ObjectType.AREA) { } else if (type === ObjectType.AREA) {
const area = areas.find((t) => t.id === id); const area = areas.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / zoom - area.x, x: clientX / settings.zoom - area.x,
y: clientY / zoom - area.y, y: clientY / settings.zoom - area.y,
}); });
setDragging([ObjectType.AREA, id]); setDragging([ObjectType.AREA, id]);
} else if (type === ObjectType.NOTE) { } else if (type === ObjectType.NOTE) {
const note = notes.find((t) => t.id === id); const note = notes.find((t) => t.id === id);
setOffset({ setOffset({
x: clientX / zoom - note.x, x: clientX / settings.zoom - note.x,
y: clientY / zoom - note.y, y: clientY / settings.zoom - note.y,
}); });
setDragging([ObjectType.NOTE, id]); setDragging([ObjectType.NOTE, id]);
} }
@ -83,16 +88,16 @@ export default function Canvas(props) {
setLine({ setLine({
...line, ...line,
endX: (e.clientX - offsetX) / zoom, endX: (e.clientX - offsetX) / settings.zoom,
endY: (e.clientY - offsetY) / zoom, endY: (e.clientY - offsetY) / settings.zoom,
}); });
} else if ( } else if (
panning && panning &&
dragging[0] === ObjectType.NONE && dragging[0] === ObjectType.NONE &&
areaResize.id === -1 areaResize.id === -1
) { ) {
const dx = (e.clientX - panOffset.x) / zoom; const dx = (e.clientX - panOffset.x) / settings.zoom;
const dy = (e.clientY - panOffset.y) / zoom; const dy = (e.clientY - panOffset.y) / settings.zoom;
setPanOffset({ x: e.clientX, y: e.clientY }); setPanOffset({ x: e.clientX, y: e.clientY });
setTables((prev) => setTables((prev) =>
@ -121,8 +126,8 @@ export default function Canvas(props) {
if (t.id === dragging[1]) { if (t.id === dragging[1]) {
return { return {
...t, ...t,
x: e.clientX / zoom - offset.x, x: e.clientX / settings.zoom - offset.x,
y: e.clientY / zoom - offset.y, y: e.clientY / settings.zoom - offset.y,
}; };
} }
return t; return t;
@ -156,8 +161,8 @@ export default function Canvas(props) {
if (t.id === dragging[1]) { if (t.id === dragging[1]) {
const updatedArea = { const updatedArea = {
...t, ...t,
x: e.clientX / zoom - offset.x, x: e.clientX / settings.zoom - offset.x,
y: e.clientY / zoom - offset.y, y: e.clientY / settings.zoom - offset.y,
}; };
return updatedArea; return updatedArea;
} }
@ -170,8 +175,8 @@ export default function Canvas(props) {
if (t.id === dragging[1]) { if (t.id === dragging[1]) {
return { return {
...t, ...t,
x: e.clientX / zoom - offset.x, x: e.clientX / settings.zoom - offset.x,
y: e.clientY / zoom - offset.y, y: e.clientY / settings.zoom - offset.y,
}; };
} }
return t; return t;
@ -184,8 +189,8 @@ export default function Canvas(props) {
let newY = initCoords.y; let newY = initCoords.y;
let newWidth = initCoords.width; let newWidth = initCoords.width;
let newHeight = initCoords.height; let newHeight = initCoords.height;
const mouseX = e.clientX / zoom; const mouseX = e.clientX / settings.zoom;
const mouseY = e.clientY / zoom; const mouseY = e.clientY / settings.zoom;
setPanning(false); setPanning(false);
if (areaResize.dir === "br") { if (areaResize.dir === "br") {
newWidth = initCoords.width + (mouseX - initCoords.mouseX); newWidth = initCoords.width + (mouseX - initCoords.mouseX);
@ -278,9 +283,9 @@ export default function Canvas(props) {
const handleMouseWheel = (e) => { const handleMouseWheel = (e) => {
e.preventDefault(); e.preventDefault();
if (e.deltaY <= 0) { if (e.deltaY <= 0) {
setZoom((prev) => prev * 1.05); setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.05 }));
} else { } else {
setZoom((prev) => prev / 1.05); setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.05 }));
} }
}; };
@ -292,7 +297,7 @@ export default function Canvas(props) {
return () => { return () => {
canvasElement.removeEventListener("wheel", handleMouseWheel); canvasElement.removeEventListener("wheel", handleMouseWheel);
}; };
}, []); });
return ( return (
<div className="flex-grow h-full" id="canvas"> <div className="flex-grow h-full" id="canvas">
@ -332,7 +337,12 @@ export default function Canvas(props) {
height="100%" height="100%"
fill="url(#pattern-circles)" fill="url(#pattern-circles)"
></rect> ></rect>
<g style={{ transform: `scale(${zoom})`, transformOrigin: "0 0" }}> <g
style={{
transform: `scale(${settings.zoom})`,
transformOrigin: "0 0",
}}
>
{areas.map((a) => ( {areas.map((a) => (
<Area <Area
key={a.id} key={a.id}
@ -343,7 +353,7 @@ export default function Canvas(props) {
setResize={setAreaResize} setResize={setAreaResize}
initCoords={initCoords} initCoords={initCoords}
setInitCoords={setInitCoords} setInitCoords={setInitCoords}
zoom={zoom} zoom={settings.zoom}
></Area> ></Area>
))} ))}
{tables.map((table) => ( {tables.map((table) => (

View File

@ -18,7 +18,7 @@ import {
Button, Button,
Divider, Divider,
Dropdown, Dropdown,
Form, InputNumber,
Image, Image,
Modal, Modal,
Spin, Spin,
@ -72,7 +72,7 @@ export default function ControlPanel(props) {
}); });
const [data, setData] = useState(null); const [data, setData] = useState(null);
const { layout, setLayout } = useContext(LayoutContext); const { layout, setLayout } = useContext(LayoutContext);
const { setSettings } = useContext(SettingsContext); const { settings, setSettings } = useContext(SettingsContext);
const { relationships, tables, setTables, setRelationships } = const { relationships, tables, setTables, setRelationships } =
useContext(TableContext); useContext(TableContext);
const { notes, setNotes } = useContext(NoteContext); const { notes, setNotes } = useContext(NoteContext);
@ -316,11 +316,13 @@ export default function ControlPanel(props) {
}, },
"Zoom in": { "Zoom in": {
children: [], children: [],
function: () => {}, function: () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 })),
}, },
"Zoom out": { "Zoom out": {
children: [], children: [],
function: () => {}, function: () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 })),
}, },
Fullscreen: { Fullscreen: {
children: [], children: [],
@ -395,35 +397,37 @@ export default function ControlPanel(props) {
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item>Fit window</Dropdown.Item> <Dropdown.Item>Fit window</Dropdown.Item>
<Dropdown.Divider /> <Dropdown.Divider />
{[ {[0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0, 3.0].map((e, i) => (
"25%", <Dropdown.Item
"50%", key={i}
"75%", onClick={() => {
"100%", setSettings((prev) => ({ ...prev, zoom: e }));
"125%", }}
"150%", >
"200%", {Math.floor(e * 100)}%
"300%", </Dropdown.Item>
].map((e, i) => (
<Dropdown.Item key={i}>{e}</Dropdown.Item>
))} ))}
<Dropdown.Divider /> <Dropdown.Divider />
<Dropdown.Item> <Dropdown.Item>
<Form> <InputNumber
<Form.InputNumber field="zoom"
field="zoom" label="Custom zoom"
label="Custom zoom" placeholder="Zoom"
placeholder="Zoom" suffix={<div className="p-1">%</div>}
suffix={<div className="p-1">%</div>} onChange={(v) =>
/> setSettings((prev) => ({
</Form> ...prev,
zoom: parseFloat(v) * 0.01,
}))
}
/>
</Dropdown.Item> </Dropdown.Item>
</Dropdown.Menu> </Dropdown.Menu>
} }
trigger="click" trigger="click"
> >
<div className="py-1 px-2 hover:bg-slate-200 rounded flex items-center justify-center"> <div className="py-1 px-2 hover:bg-slate-200 rounded flex items-center justify-center">
<div>zoom</div> <div className="w-[40px]">{Math.floor(settings.zoom * 100)}%</div>
<div> <div>
<IconCaretdown /> <IconCaretdown />
</div> </div>
@ -432,12 +436,18 @@ export default function ControlPanel(props) {
<button <button
className="py-1 px-2 hover:bg-slate-200 rounded text-lg" className="py-1 px-2 hover:bg-slate-200 rounded text-lg"
title="Zoom in" title="Zoom in"
onClick={() =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 }))
}
> >
<i className="fa-solid fa-magnifying-glass-plus"></i> <i className="fa-solid fa-magnifying-glass-plus"></i>
</button> </button>
<button <button
className="py-1 px-2 hover:bg-slate-200 rounded text-lg" className="py-1 px-2 hover:bg-slate-200 rounded text-lg"
title="Zoom out" title="Zoom out"
onClick={() =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 }))
}
> >
<i className="fa-solid fa-magnifying-glass-minus"></i> <i className="fa-solid fa-magnifying-glass-minus"></i>
</button> </button>

View File

@ -39,6 +39,7 @@ export default function Editor(props) {
const [settings, setSettings] = useState({ const [settings, setSettings] = useState({
strictMode: false, strictMode: false,
showFieldSummary: true, showFieldSummary: true,
zoom: 1,
}); });
const dragHandler = (e) => { const dragHandler = (e) => {