I'm using Canvas animation for image sequences on the scroll.
And this animation is working fine but I need to reduce the loading time because I'm using almost 884 images for this animation.
So, how can I add section-wise division in this loop? For example, the first 100 images will upload on start and after 5 seconds next 100 images will upload. So every after 5 seconds next 100 images will upload til 884 images.
const html = document.documentElement;
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");
const frameCount = 884;
const currentFrame = index => (
`compressed/${index.toString().padStart(9, 'web_0000')}.webp`
)
const preloadImages = () => {
for (let i = 1; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(i);
}
};
const img = new Image()
img.src = currentFrame(1);
canvas.width= window.innerWidth;
canvas.height=window.innerHeight;
img.onload=function(){
scaleToFill(this);
}
function scaleToFill(img){
var scale = Math.max(canvas.width / img.width, canvas.height / img.height);
var x = (canvas.width / 2) - (img.width / 2) * scale;
var y = (canvas.height / 2) - (img.height / 2) * scale;
context.drawImage(img, x, y, img.width * scale, img.height * scale);
}
const updateImage = index => {
img.src = currentFrame(index);
}
window.addEventListener('scroll', () => {
const scrollTop = html.scrollTop;
const maxScrollTop = html.scrollHeight - window.innerHeight;
const scrollFraction = scrollTop / maxScrollTop;
const frameIndex = Math.min(
frameCount - 1,
Math.ceil(scrollFraction * frameCount)
);
requestAnimationFrame(() => updateImage(frameIndex + 1))
});
preloadImages()
HTML
<canvas id="hero-lightpass"></canvas>
You can do that with an interval ...
We add a new variable loadedImages and change the preloadImages
let loadedImages = 0
let loadedImages = 0
const frameCount = 884;
const currentFrame = index => (
`compressed/${index.toString().padStart(9, 'web_0000')}.webp`
)
const preloadImages = () => {
for (let i = loadedImages + 1; i < Math.min(loadedImages + 100, frameCount); i++) {
const img = new Image();
img.src = currentFrame(i);
loadedImages++
}
};
setInterval(preloadImages, 5000)
...
preloadImages()
Related
I'm using Canvas animation for image sequences on the scroll.
And this animation is working fine but I need to reduce the loading time because I'm using almost 884 images for this animation.
so I need to add section-wise division in this loop. for example, the first 100 images will upload on start and after 5 seconds next 100 images will upload. so every after 5 seconds next 100 images will upload til 884 images.
please check my code and give me suggestions or help me please. thank you in advance.
const html = document.documentElement;
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");
const frameCount = 884;
const currentFrame = index => (
`compressed/${index.toString().padStart(9, 'web_0000')}.webp`
)
const preloadImages = () => {
for (let i = 1; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(i);
}
};
const img = new Image()
img.src = currentFrame(1);
canvas.width= window.innerWidth;
canvas.height=window.innerHeight;
img.onload=function(){
scaleToFill(this);
}
function scaleToFill(img){
var scale = Math.max(canvas.width / img.width, canvas.height / img.height);
var x = (canvas.width / 2) - (img.width / 2) * scale;
var y = (canvas.height / 2) - (img.height / 2) * scale;
context.drawImage(img, x, y, img.width * scale, img.height * scale);
}
const updateImage = index => {
img.src = currentFrame(index);
}
window.addEventListener('scroll', () => {
const scrollTop = html.scrollTop;
const maxScrollTop = html.scrollHeight - window.innerHeight;
const scrollFraction = scrollTop / maxScrollTop;
const frameIndex = Math.min(
frameCount - 1,
Math.ceil(scrollFraction * frameCount)
);
requestAnimationFrame(() => updateImage(frameIndex + 1))
});
preloadImages()
HTML
<canvas id="hero-lightpass"></canvas>
I have two images locally. First image is a cup and another is a banner.
How do I warp and banner with the cup and then output a new file?
I've found the below function but how do I convert it to use in nodejs.
Wrap an image around a cylindrical object in HTML5 / JavaScript
function canvas3() {
var canvas = document.getElementById("canvas3");
var ctx = canvas.getContext("2d");
var productImg = new Image();
productImg.onload = function() {
var iw = productImg.width;
var ih = productImg.height;
canvas.width = iw;
canvas.height = ih;
ctx.drawImage(productImg, 0, 0, productImg.width, productImg.height,
0, 0, iw, ih);
loadUpperIMage()
};
productImg.src = "http://res.cloudinary.com/pussyhunter/image/upload/h_350/right_handle_cup_dsdhr7.jpg"
function loadUpperIMage() {
var img = new Image();
img.src = "http://res.cloudinary.com/pussyhunter/image/upload/v1488184107/500_F_97150423_M13q2FeAUZxxIx6CaPixHupprmyiVVli_skh6fe.jpg"
img.onload = function() {
var iw = img.width;
var ih = img.height;
//alert(iw)
var xOffset = 102, //left padding
yOffset = 110; //top padding
var a = 75.0; //image width
var b = 10; //round ness
var scaleFactor = iw / (3 * a);
// draw vertical slices
for (var X = 0; X < iw; X += 1) {
var y = b / a * Math.sqrt(a * a - (X - a) * (X - a)); // ellipsis equation
ctx.drawImage(img, X * scaleFactor, 0, iw / 1.5, ih, X + xOffset, y + yOffset, 1, 174);
}
};
}
};
You can use canvas package in node.js too.
https://www.npmjs.com/package/canvas
import {loadImage, createCanvas } from "canvas";
...
router.get("/test", async (req: Request, res: Response) => {
const myImg = await loadImage('https://res.cloudinary.com/pussyhunter/image/upload/h_350/right_handle_cup_dsdhr7.jpg');
const canvas = createCanvas(400, 400);
const ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, 500, 500)
const myImg2 = await loadImage('https://i.stack.imgur.com/NkKnV.png');
canvas.getContext("2d").drawImage(myImg,0,0,myImg.width, myImg.height);
// flat
// canvas.getContext("2d").drawImage(myImg2,myImg.width/2-30,myImg.height/2-30,60,60);
//rounded
draw(ctx, myImg2)
const buffer = canvas.toBuffer('image/jpeg');
// write a copy to the disk
//fs.writeFileSync("c:\\dev\\image.png", buffer);
res.write(buffer);
res.status(200);
res.end();
});
function draw(ctx, image) {
const iw = image.width;
const ih = image.height;
const xOffset = 102; //left padding
const yOffset = 110; //top padding
const a = 75.0; //image width
const b = 10; //round ness
const scaleFactor = iw / (4 * a);
// draw vertical slices
for (let X = 0; X < iw; X += 1) {
const y = b / a * Math.sqrt(a * a - (X - a) * (X - a)); // ellipsis equation
ctx.drawImage(image, X * scaleFactor, 0, iw / 9, ih, X + xOffset, y + yOffset, 1, 174);
}
}
And the result;
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I have base64SquareCrop function which resize images, the problem here that I can not return value from onload function and it was returned with undefined:
async function base64SquareCrop(imgbase64, size = 224) {
const img = document.createElement("img");
await img.setAttribute("src", imgbase64);
let width = 1240;
let height = 698;
const min = Math.min(width, height);
const scale = size / min;
const scaledW = Math.ceil(width * scale);
const scaledH = Math.ceil(height * scale);
const dx = scaledW - size;
const dy = scaledH - size;
canvasImage.width = canvasImage.height = size;
const ctx_img = canvasImage.getContext("2d");
img.onload = function() { ctx_img.drawImage(
img,
~~(dx / 2) * -1,
~~(dy / 2) * -1,
scaledW,
scaledH
);
return canvasImage.toDataURL("image/png");
}
}
You have to use promises to wait for the onload event.
function base64SquareCrop(imgbase64, size = 224) {
const img = document.createElement("img");
await img.setAttribute("src", imgbase64);
let width = 1240;
let height = 698;
const min = Math.min(width, height);
const scale = size / min;
const scaledW = Math.ceil(width * scale);
const scaledH = Math.ceil(height * scale);
const dx = scaledW - size;
const dy = scaledH - size;
canvasImage.width = canvasImage.height = size;
const ctx_img = canvasImage.getContext("2d");
var loadPromise = new Promise(function (resolve) {
img.onload = function() {
ctx_img.drawImage(
img,
~~(dx / 2) * -1,
~~(dy / 2) * -1,
scaledW,
scaledH
);
resolve(canvasImage.toDataURL("image/png"));
}
}, function (reject) {reject("ERROR!")});
return loadPromise;
}
From there, you'll have to await base64SquareCrop(...) inside of an asynchronous function. I don't know any better way to do it.
I have this portion of JavaScript code which draws a bar (for let's say a bar diagram):
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerHeight / 3 * 4;
canvas.height = window.innerHeight;
const xCharCnt = window.innerHeight / 3 * 4 / 48;
const yCharCnt = window.innerHeight / 34;
const foreground1 = "#AF5BEC";
let offset = 0;
const barHeight = 20;
const speed = 4;
const limit = yCharCnt * barHeight;
let requestId = window.requestAnimationFrame(render);
function render() {
requestId = window.requestAnimationFrame(render);
// Clear screen
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw bar
ctx.fillStyle = foreground1;
ctx.fillRect(xCharCnt * 7, yCharCnt * 28, xCharCnt, -offset);
offset = offset + speed;
// Cancel animation
if (offset >= limit) window.cancelAnimationFrame(requestId);
}
Questions:
a) Is it the right way to do an animation?
b) Does the animation run always with the same speed, regardless the resolution of the device it's running on?
It will be framerate dependent, so it will differ between devices.
The number of callbacks is usually 60 times per second, but will generally match the display refresh rate in most web browsers as per W3C recommendation. requestAnimationFrame() calls are paused in most browsers when running in background tabs or hidden s in order to improve performance and battery life.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
The above link also gives a suggestion on how you should code your animations so they do always run at the same speed. Translated to your code that would look like:
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerHeight / 3 * 4;
canvas.height = window.innerHeight;
const xCharCnt = window.innerHeight / 3 * 4 / 48;
const yCharCnt = window.innerHeight / 34;
const foreground1 = "#AF5BEC";
let offset = 0;
const barHeight = 20;
const speed = 4;
const limit = yCharCnt * barHeight;
let requestId = window.requestAnimationFrame(render);
let previousTimestamp;
function render(timestamp) {
if(previousTimestamp === undefined) {
previousTimestmap = timestamp;
}
const delta = timestamp - previousTimestamp;
offset = Math.min(offset + (speed * delta), limit);
// Clear screen
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw bar
ctx.fillStyle = foreground1;
ctx.fillRect(xCharCnt * 7, yCharCnt * 28, xCharCnt, -offset);
// Cancel animation
requestId = window.requestAnimationFrame(render);
if (offset >= limit) window.cancelAnimationFrame(requestId);
previousTimestmap = timestamp;
}
I am using Three js to generate point cloud from depth image, but I'm not able to export this point cloud in ply format. Can someone help me, this is the code.
I tried to add it with the html of this from the library of three js to export in ply but I didn't have a good result.
Please Someone can help me.
<canvas></canvas>
<style>
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
</style>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r94/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r94/js/controls/OrbitControls.js"></script>
<script>
'use strict';
/* global THREE */
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = (e) => { resolve(img); };
img.onerror = reject;
img.src = url;
});
}
function getImageData(img) {
const ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
ctx.drawImage(img, 0, 0);
return ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
}
// return the pixel at UV coordinates (0 to 1) in 0 to 1 values
function getPixel(imageData, u, v) {
const x = u * (imageData.width - 1) | 0;
const y = v * (imageData.height - 1) | 0;
if (x < 0 || x >= imageData.width || y < 0 || y >= imageData.height) {
return [0, 0, 0, 0];
} else {
const offset = (y * imageData.width + x) * 4;
return Array.from(imageData.data.slice(offset, offset + 4)).map(v => v / 255);
}
}
async function main() {
const images = await Promise.all([
loadImage("https://i.imgur.com/UKBsvV0.jpg"), // RGB
loadImage("https://i.imgur.com/arPMCZl.jpg"), // Depth
]);
const data = images.map(getImageData);
const canvas = document.querySelector('canvas');
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
const fov = 75;
const aspect = 2; // the canvas default
const near = 1;
const far = 4000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2000;
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 0, 0);
controls.update();
const scene = new THREE.Scene();
const rgbData = data[0];
const depthData = data[1];
const skip = 20;
const across = Math.ceil(rgbData.width / skip);
const down = Math.ceil(rgbData.height / skip);
const positions = [];
const colors = [];
const color = new THREE.Color();
const spread = 1000;
const depthSpread = 1000;
const imageAspect = rgbData.width / rgbData.height;
for (let y = 0; y < down; ++y) {
const v = y / (down - 1); for (let x = 0; x < across; ++x) {
const u = x /
(across - 1); const rgb = getPixel(rgbData, u, v); const depth = 1 - getPixel(depthData, u, v)[0];
positions.push((u * 2 - 1) * spread * imageAspect, (v * -2 + 1) * spread, depth * depthSpread,);
colors.push(...rgb.slice(0, 3));
}
} const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.addAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.computeBoundingSphere(); const material = new THREE.PointsMaterial({
size: 15, vertexColors:
THREE.VertexColors
}); const points = new THREE.Points(geometry, material); scene.add(points); function
resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement; const
width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width ||
canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize;
} function render(time) {
time *= 0.001; if (resizeRendererToDisplaySize(renderer)) {
const
canvas = renderer.domElement; camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
} renderer.render(scene, camera); requestAnimationFrame(render);
}
requestAnimationFrame(render);
} main(); </script>