@rbuljan/zoompan
Version:
Zoomable and pannable area with scrollbars. Inspired by graphical editors like Photoshop.
235 lines (203 loc) • 6.99 kB
HTML
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="shortcut icon" href="#!" type="image/x-icon">
<title>ZoomPan - @rokobuljan</title>
<link rel="stylesheet" href="./../zoompan.css">
<style>
* {
margin: 0;
box-sizing: border-box;
}
body {
background: hsl(200, 4%, 16%);
font: 1rem/1.4 sans-serif;
color: rgba(255, 255, 255, 0.8);
display: flex;
}
a,
h1,
h2 {
color: #0bf;
font-weight: 100;
}
h1 {
font-size: 2rem;
}
aside {
flex: none;
padding: 2rem;
font-size: 0.8rem;
max-width: 240px;
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
main {
position: relative;
flex: 1;
height: 100vh;
}
#myEditor {
position: absolute;
width: 100%;
height: 100%;
}
#controls {
display: flex;
gap: 2px;
}
#controls button,
#controls select {
flex: none;
outline: none;
border: 0;
background: rgba(0, 0, 0, 0.3);
color: rgba(255, 255, 255, 0.6);
font-size: 11px;
padding: 0 0.5rem;
}
#controls option {
color: #000;
}
#zoomPct {
width: 4.5rem;
}
#zoomPct option[disabled] {
display: none;
}
/* ZoomPan: Custom overrides: */
.zoompan {
background: rgba(0, 0, 0, 0.2);
}
.zoompan .zoompan-canvas {
display: flex;
align-items: center;
justify-content: center;
color: #000;
font-size: 3rem;
background-size: 50px 50px, 50px 50px, cover;
background-image:
linear-gradient(to right, black 1px, transparent 1px),
linear-gradient(to bottom, black 1px, transparent 1px),
linear-gradient(45deg,
hsl(0, 100%, 50%),
hsl(30, 100%, 50%),
hsl(60, 100%, 50%),
hsl(90, 100%, 50%),
hsl(120, 100%, 50%),
hsl(150, 100%, 50%),
hsl(180, 100%, 50%),
hsl(210, 100%, 50%),
hsl(240, 100%, 50%),
hsl(270, 100%, 50%),
hsl(300, 100%, 50%),
hsl(330, 100%, 50%),
hsl(360, 100%, 50%));
}
.zoompan .zoompan-track-x {
/* Smaller track, to make space for #controls */
left: 150px;
}
</style>
</head>
<body>
<aside>
<h1>ZoomPan</h1>
<br>
In this example we respect the user experience by the way browsers wheel and keyboard shortcuts already handle scaling and scrolling.
You can always change and customize this hotkeys as desired.
<br>
<br>
<h3>Controls</h3>
<br>
<h2>Scale</h2>
Ctrl WheelUp/Down<br>
Ctrl +<br>
Ctrl -<br>
Pinch<br>
<br>
<h2>Pan</h2>
Ctrl Drag<br>
Ctrl Arrows<br>
WheelUp/Down<br>
Shift WheelUp/Down<br>
<footer>
Git: <a href="https://github.com/rokobuljan/zoompan">ZoomPan</a><br>
Author: <a href="https://github.com/rokobuljan">rokobuljan</a><br>
Licence: MIT
</footer>
</aside>
<main>
<div id="myEditor">
<div id="controls">
<button id="zoomOut">-</button>
<button id="zoomIn">+</button>
<select id="zoomPct">
<option disabled></option>
<option value="0.25">25%</option>
<option value="0.50">50%</option>
<option value="0.75">75%</option>
<option value="1.00">100%</option>
<option value="1.25">125%</option>
<option value="1.50">150%</option>
<option value="2.00">200%</option>
</select>
<button id="fit">Fit</button>
</div>
</div>
</main>
<script type="module">
import ZoomPan from "./../zoompan.js";
import { hotkeys } from "./lib/hotkeys.js";
// DOM helper functions:
const el = (sel, par) => (par || document).querySelector(sel);
// Scale select box:
const elZoomPct = el("#zoomPct");
const setSelectOptionText = (scale) => {
const elOpt0 = el("option", elZoomPct);
elOpt0.textContent = Math.round(scale * 100) + "%";
elZoomPct.selectedIndex = 0;
};
// Initialize ZoomPan with options
const ZP = new ZoomPan("#myEditor", {
width: 800,
height: 500,
canDrag: false, // We want to use "Ctrl" key to drag-pan (See below)
onInit() {
this.elCanvas.textContent = "Welcome to ZoomPan";
},
onChange() {
setSelectOptionText(this.scale);
}
});
// Allow dragging only while Ctrl key is pressed
ZP.elViewport.addEventListener("pointermove", (ev) => ZP.canDrag = ev.ctrlKey );
// Example calling ZP methods on specific hotkeys
// This example uses an external library for hotkeys
hotkeys({
"ctrl wheelup": (ev) => ZP.scaleWheel(ev),
"ctrl wheeldown": (ev) => ZP.scaleWheel(ev),
"ctrl +": () => ZP.scaleUp(),
"ctrl -": () => ZP.scaleDown(),
"ctrl arrowup": () => ZP.panDown(),
"ctrl arrowdown": () => ZP.panUp(),
"ctrl arrowleft": () => ZP.panRight(),
"ctrl arrowright": () => ZP.panLeft(),
"wheelup": () => ZP.panDown(),
"wheeldown": () => ZP.panUp(),
"shift wheelup": () => ZP.panRight(),
"shift wheeldown": () => ZP.panLeft(),
}, ZP.elViewport);
// UI inputs events:
elZoomPct.addEventListener("input", () => ZP.scaleTo(+elZoomPct.value));
el("#zoomIn").addEventListener("click", () => ZP.scaleUp());
el("#zoomOut").addEventListener("click", () => ZP.scaleDown());
el("#fit").addEventListener("click", () => ZP.fit());
</script>
</body>
</html>