Add downscale option

main
Shad Amethyst 2 years ago
parent d6fa38f9af
commit 096a0ebe64

@ -14,29 +14,32 @@ export const MAX_CANVAS_SIZE = 10000;
* the dimensions of the canvas.
* @prop {AttachCanvasUpdate=} onResize - A callback function which will be called whenever the
* dimensions of the canvas change.
* @prop {number=} downscale - An integer to downscale the canvas by,
* can be used to render the canvas at a lower resolution.
**/
/**
* A function to call to unbind the event listeners attached to a canvas through `attachCanvas`.
* @callback AttachCanvasUnbind
* @returns {void}
**/
/**
* @typedef {object} AttachCanvas
* @prop {AttachCanvasUnbind} unbind - Call this function to remove the event listeners attached
* to the canvas
**/
/**
* Makes the given canvas pixel-perfect, by dynamically resizing it
* in order to have the canvas pixel resolution be always equal to the device resolution.
*
* Returns a function to "unbind" the bound listeners.
*
* @param {HTMLCanvasElement} canvas
* @param {AttachCanvasOptions} options
* @returns {HTMLCanvasElement & AttachCanvas}
* @returns {AttachCanvasUnbind}
**/
export function attachCanvas(canvas, options = {}) {
const EPSILON = 0.001;
canvas.style.imageRendering = "pixelated";
const container = options.container ?? canvas.parentNode;
const onResize = options.onResize ?? (() => {});
const downscale = options.downscale ?? 1;
let old_width = null;
let old_height = null;
@ -50,8 +53,8 @@ export function attachCanvas(canvas, options = {}) {
};
// Compute native dimensions of canvas
width = width * dpr;
height = height * dpr;
width = width * dpr / downscale;
height = height * dpr / downscale;
if (isInteger(width, EPSILON) && isInteger(height, EPSILON)) {
width = Math.round(width);
height = Math.round(height);
@ -82,8 +85,8 @@ export function attachCanvas(canvas, options = {}) {
canvas.height = height;
// Set style width to guarantee perfect scaling
canvas.style.width = `${width / dpr}px`;
canvas.style.height = `${height / dpr}px`;
canvas.style.width = `${width / dpr * downscale}px`;
canvas.style.height = `${height / dpr * downscale}px`;
onResize(canvas, width, height);
}
@ -106,7 +109,7 @@ export function attachCanvas(canvas, options = {}) {
resize(window.devicePixelRatio ?? 1);
}, 0);
canvas.unbind = function unbind() {
return function unbind() {
if (resize_observer) {
resize_observer.disconnect();
// Drop resize_observer
@ -119,8 +122,6 @@ export function attachCanvas(canvas, options = {}) {
unbind_dpr = null;
}
};
return canvas;
}
export function listenPixelRatio(element, callback, fire_first = false) {

@ -1,5 +1,5 @@
import { JSX, Component, createEffect, onCleanup } from "solid-js";
import { attachCanvas } from '../index';
import { attachCanvas, AttachCanvasOptions } from '../index';
import styles from './PixelPerfectCanvas.module.css';
export type PixelPerfectCanvasProps = {
@ -28,7 +28,7 @@ export type PixelPerfectCanvasProps = {
* Callback called after the event listeners for dimension and DPR changes are detached.
**/
onDetach?: (canvas: HTMLCanvasElement) => void,
}
} & Omit<AttachCanvasOptions, 'onResize' | 'container'>
/**
* A canvas that is wrapped in a container (which will be styled with `style` or `class`),
@ -43,20 +43,19 @@ export const PixelPerfectCanvas: Component<PixelPerfectCanvasProps> = (props) =>
let canvasRef: HTMLCanvasElement;
let containerRef: HTMLDivElement;
createEffect<ReturnType<typeof attachCanvas>>((old) => {
const result = attachCanvas(canvasRef, {
createEffect(() => {
const unbind = attachCanvas(canvasRef, {
container: containerRef,
onResize: props.onResize,
downscale: props.downscale
});
props.onAttach?.(result);
props.onAttach?.(canvasRef);
onCleanup(() => {
result.unbind();
props.onDetach?.(result);
unbind();
props.onDetach?.(canvasRef);
});
return result;
});
return (<div

@ -38,6 +38,7 @@ const App: Component = () => {
}}
onResize={update}
onAttach={setCanvasRef}
downscale={8}
/>
<input
type="checkbox"

@ -21,6 +21,10 @@ export default defineConfig({
}
},
rollupOptions: {
output: {
sourcemap: true,
format: 'iife',
},
external: ["solid-js"],
plugins: []
}

Loading…
Cancel
Save