Published
Edited
Jan 28, 2020
1 fork
5 stars
Insert cell
Insert cell
/*
* Actually, this set of fallbacks is probably overkill
* (does Observable even work on IE8?) but it won't
* harm anyone so I didn't bother to simplify it
*/
pixelatedCSS = html`<style>
.pixelated {
image-rendering:optimizeSpeed; /* Legal fallback */
image-rendering:-moz-crisp-edges; /* Firefox */
image-rendering:-o-crisp-edges; /* Opera */
image-rendering:-webkit-optimize-contrast; /* Safari */
image-rendering:optimize-contrast; /* CSS3 Proposed */
image-rendering:crisp-edges; /* CSS4 Proposed */
image-rendering:pixelated; /* CSS4 Proposed */
-ms-interpolation-mode:nearest-neighbor; /* IE8+ */
}
</style>`
Insert cell
Insert cell
canvas = {
const ctx = DOM.canvas(40, 40).getContext('2d');
const canvas = ctx.canvas;
// Note that images drawn on the canvas are still smoothed when upscaled or downscaled!
// See below for how to fix that if necessary
canvas.className = "pixelated";
canvas.style.width = `${Math.min(width, 400)}px`;
canvas.style.height = `${Math.min(width, 400)}px`;

let angle = 0;
let steps = 128;
while(true){
ctx.fillStyle = '#FFFFFF10';
ctx.fillRect(0, 0, 100, 100);
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.ellipse(20, 20, 25, 20, angle*Math.PI/steps, 0, 2*Math.PI, false);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(20, 20, 20, 15, (steps-1-angle)*Math.PI/steps, 0, 2*Math.PI, false);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(20, 20, 15, 10, angle*Math.PI/steps, 0, 2*Math.PI, false);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(20, 20, 5, 10, (steps-1-angle)*Math.PI/steps, 0, 2*Math.PI, false);
ctx.stroke();
angle = (angle + 1) % steps
yield canvas;
}
}
Insert cell
Insert cell
imgDavidSmoothed = html`
<img
src='https://file-hamhdaleym.now.sh/' style="width:${Math.min(davidWidth, width)}px"
>`
Insert cell
imgDavidPixelated = html`
<img
src='https://file-hamhdaleym.now.sh/'
class='pixelated' style="width:${Math.min(davidWidth, width)}px"
>`
Insert cell
imgDavidDynamic = {
let img = new Image();
img.crossOrigin = '*';
img.src = 'https://file-hamhdaleym.now.sh/';
img.style.width = `${Math.min(davidWidth, width)}px`;
img.className = 'pixelated';
await new Promise(resolve => img.addEventListener('load', resolve));
// We don't actually care about extracting image data here,
// but just for the sake of giving an example:
/*
let ctx = DOM.canvas(img.width, img.height).getContext('2d');
ctx.drawImage(img, 0, 0);
return {
data: ctx.getImageData(0, 0, img.width, img.height).data,
width: img.width,
height: img.height,
};
*/
return img;
}
Insert cell
Insert cell
canvas2 = {
const davidHeight = davidWidth*imgDavidDynamic.height/imgDavidDynamic.width | 0;
const ctx = DOM.canvas(davidWidth, davidHeight * 2).getContext('2d');

ctx.imageSmoothingEnabled = true;
ctx.drawImage(imgDavidDynamic, 0, 0, davidWidth, davidHeight);
ctx.imageSmoothingEnabled = false;
ctx.drawImage(imgDavidDynamic, 0, davidHeight, davidWidth, davidHeight);

const canvas = ctx.canvas;
canvas.className = "pixelated";
canvas.style.width = `${Math.min(width, davidWidth)}px`;
return canvas;
}
Insert cell
// taken from the original pixel dimensions of the image
davidWidth = 180*4;
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more