I got this small example where I am adding images to the DOM. I tried to create a function for clearing the element to where I am adding the images by:
document.querySelector("#photo2").innerHTML = ""; but it didnt work as I expected.
How can I clear the element without reloading the page?
Here is my codepen: '
https://codepen.io/haangglide/pen/VwjqmZp
Updated code with more comments in the code, i tried to make it more compact as well
I think basically my problem is that Im creating new Image elements for each snapshot where i place the generated imageuri. I started creating multiple canvases but pretty soon it got very heavy.
HTML
<button id="btn" disabled>take a snapshot</button>
<button id="btn-remove">remove all the images</button>
<video></video>
<canvas id="photo2"></canvas>
And my javascript
const vid = document.querySelector('video');
let images = [];
navigator.mediaDevices.getUserMedia({video: true }) // request cam
.then(stream => {
vid.srcObject = stream;
return vid.play(); // returns a Promise
})
.then(()=>{ // enable the button
const btn = document.querySelector('#btn');
btn.disabled = false;
btn.onclick = e => {
train0Snap()
};
const btnremove = document.querySelector('#btn-remove');
btnremove.disabled = false;
btnremove.onclick = e => {
clearAllImages();
};
});
function clearAllImages() {
document.querySelector("#photo2").innerHTML = "";
}
function train0Snap(){
// set random position
let x = Math.floor(Math.random() * 20);
let y = Math.floor(Math.random() * 20);
let angleInRadians = (Math.random() * 0.2) - 0.1;
// 1) CREATING A CANVAS FOR DOING THE TRANSFORMATIONS IN
const newCanvas = document.createElement('canvas');
// Set width and height of thumb based on the video
newCanvas.width = vid.videoWidth * 0.3;
newCanvas.height = vid.videoHeight * 0.3;
// getting canvas 2D rendering context pf the created canvas
const ctx = newCanvas.getContext('2d');
// centrate thumbsize
var xx = newCanvas.width / 2;
var yy = newCanvas.height / 2;
// create rotationmatrix
ctx.translate(xx, yy);
ctx.rotate(angleInRadians);
// 2) DRAW THE VIDEO IN THE CONTEXT BASED ON THE NEW SIZE
ctx.drawImage(vid, -newCanvas.width /2 , -newCanvas.height /2, newCanvas.width/2, newCanvas.height/2);
// 3) GET THE CANVAS ELEMENT FROM THE DOM FOR DRAWING EVERYTHING
var canvas2 = document.getElementById('photo2');
// creating a rendering context for the output
var ctxoutput = canvas2.getContext('2d');
// creating a new Image element for each image and put it in the context
var image2 = new Image();
image2.onload = function() {
ctxoutput.drawImage(image2, 20, 0);
};
// returns a data URI containing a representation of the image
var canvasToUrl = newCanvas.toDataURL();
// 4) SET THE IMAGESOURCE OF THE NEW IMAGE ELEMENT
image2.src = canvasToUrl;
}
SOLUTION
function clearAllImages() {
var canvas2 = document.getElementById('photo2');
const context = canvas2.getContext('2d');
context.clearRect(0, 0, canvas2.width, canvas2.height);
}
Related
sorry for the amatuer question, I'm really new to Pixi.js
Well, I'm trying to make a scratch card.
There will be two image, one for background("A"), and one for hidden background( "B" , I think this is mask, but I'm not sure about this terminology , so to avoid confusion I'll describe as hidden background)
So, image 'A' will cover up image 'B'.
Then, I'will use bristle image for the brush.
When I execute dragging event on Image "A" , I want to show up image 'B" along path mouse moved.
Sorry , for my terrible description. Think I'm cloning this website ( https://art4globalgoals.com/en )
I followed this example( https://pixijs.io/examples/#/demos-advanced/scratchcard.js ), and succeed to make a brush effect, with only 1 image. But couldn't implement it with two image.
Precisely speaking , when I run my app, there is black screen rendered , and if I scratch screen, the hidden Image appears.
but the problem is that, I want to set other Image instead of black screen.
below image is my current status , which will happen when running below code
import * as PIXI from 'pixi.js';
// const canvas = document.getElementById('webgl');
const screenSize = {
width: window.innerWidth,
height: window.innerHeight
};
let brushWidth = (window.innerHeight / window.innerWidth) * 200;
let brushHeight = (window.innerHeight / window.innerWidth) * 200;
// canvas.width = screenSize.width;
// canvas.height = screenSize.height;
const app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
resolution: window.devicePixelRatio,
autoDensity: true
});
document.body.appendChild(app.view);
app.loader
.add('background', '/png/effel.png')
.add('mask', '/png/effel-gray.png')
.add('bristle1', '/png/brush6.png')
.add('bristle2', '/png/bristle2.png')
.load(() => {
setup();
});
const setup = () => {
const brushTexture = app.loader.resources.bristle1.texture;
const brushTexture2 = app.loader.resources.bristle2.texture;
const brush = new PIXI.Sprite(brushTexture);
const brush2 = new PIXI.Sprite(brushTexture2);
brush.width = brushWidth;
brush.height = brushHeight;
brush2.width = brushWidth;
brush2.height = brushHeight;
const backgroundTexture = app.loader.resources.background.texture;
const maskTexture = app.loader.resources.mask.texture;
const background = new PIXI.Sprite(backgroundTexture);
background.x = app.renderer.screen.width / 2;
background.y = app.renderer.screen.height / 2;
background.anchor.x = 0.5;
background.anchor.y = 0.5;
background.width = window.innerWidth;
background.height = window.innerHeight;
const Mask = new PIXI.Sprite(maskTexture);
Mask.width = app.renderer.screen.width;
Mask.height = app.renderer.screen.height;
Mask.x = app.renderer.screen.width / 2;
Mask.y = app.renderer.screen.height / 2;
Mask.anchor.x = 0.5;
Mask.anchor.y = 0.5;
Mask.width = window.innerWidth;
Mask.height = window.innerHeight;
// app.stage.addChild(background);
app.stage.addChild(Mask);
const renderTexture = PIXI.RenderTexture.create(app.screen.width, app.screen.height);
const renderTextureSprite = new PIXI.Sprite(renderTexture);
app.stage.addChild(renderTextureSprite);
Mask.mask = renderTextureSprite;
app.stage.interactive = true;
app.stage.on('pointerdown', pointerDown);
app.stage.on('pointerup', pointerUp);
app.stage.on('pointermove', pointerMove);
let dragging = false;
let bristle2Render = false;
function pointerMove(event) {
if (dragging) {
brush.position.copyFrom(event.data.global);
// brushWidth += 0.5;
// brush.width = brushWidth;
if (!bristle2Render) {
setTimeout(() => (bristle2Render = true), 500);
}
app.renderer.render(brush, renderTexture, false, null, false);
if (bristle2Render) {
brush2.position.copyFrom(event.data.global);
app.renderer.render(brush2, renderTexture, false, null, false);
}
// if (brush.width === 100) {
// dragging = false;
// brushWidth = 0;
// }
}
}
function pointerDown(event) {
dragging = true;
console.log(11);
pointerMove(event);
}
function pointerUp(event) {
dragging = false;
bristle2Render = false;
}
window.addEventListener('resize', () => {
screenSize.width = window.innerWidth;
screenSize.height = window.innerHeight;
app.renderer.resize(window.innerWidth, window.innerHeight);
app.renderer.stage.width = window.innerWidth;
app.renderer.stage.height = window.innerHeight;
});
};
// const backgroundTexture = PIXI.Texture.from('/png/effel.png');
// const maskTexture = PIXI.Texture.from('/png/effel-gray.png');
I guess the problem is that you haven't added background to the stage, because you commented it.
// app.stage.addChild(background);
app.stage.addChild(Mask);
So, there is nothing to be shown at the beginning, so it is a black screen.
Here is a CodePen that I created. I removed some comments and replaced the resources with some other images. It should be somehow working after you uncommented the line.
By the way, you may want to ensure that:
your variables have a capital name only for some special reasons (e.g. Mask)
you don't overwrite values that you have set before (e.g. Mask.width = ...).
Although the code still works without fixing the above, this may make the code harder to work with for others, including a future "you". ;)
When your code works, you may want to post it on Code Review to see how to improve the code.
In javascript, I have a reference to a DOM <img> element. I need to change the image displayed by the <img> from within the javascript.
So far, I have tried this by changing the image.src attribute to the URL of the new image. This worked, but there is still a problem: I need the image to be changed many times per second, and changing the src attribute causes the browser to do a new GET request for the image (which is already cached), which puts strain on the web server since there will be hundreds of simultanious clients.
My current (inefficient) solution is done like this:
let image = document.querySelector("img");
setInterval(function(){
image.src = getNextImageURL();//this causes a GET request
}, 10);
function getNextImageURL() {
/*...implementation...*/
}
<img>
I am looking for a more efficient way of changing the image, that does not cause any unnecessary HTTP requests.
I think you need to code in a different way...
if you want to reduce requests you should combine all image in one sprite Sheet.
this trick is used so many in-game animations.
But you will need to change <img/> tag to another tag like <div></div>
the idea here is that we have one image and we just change the viewport for what we want
sample For sprite sheet
let element = document.querySelector("div");
let i = 1
setInterval(function(){
element.style.backgroundPosition= getNextImagePostion(i++);//this will change the posion
}, 100);
function getNextImagePostion(nextPos) {
/*...implementation...*/
// this just for try
// 6 is the number of images in sheet
// 20 is the height for one segment in sheet
var posX = 100*(nextPos%6);
// first is position on x and latter is position on y
return "-"+posX+"px 0px ";
}
.image {
width: 100px; /* width of single image*/
height: 100px; /*height of single image*/
background-image: url(https://picsum.photos/500/100?image=8) /*path to your sprite sheet*/
}
<div class="image">
</div>
If the sprite-sheet idea doesn't work (e.g because you have big images), then use a canvas.
You just need to preload all your images, store them in an Array and then draw them one after the other on your canvas:
const urls = new Array(35).fill(0).map((v, i) =>
'https://picsum.photos/500/500?image=' + i
);
// load all the images
const loadImg = Promise.all(
urls.map(url =>
new Promise((res, rej) => {
// each url will have its own <img>
const img = new Image();
img.onload = e => res(img);
img.onerror = rej;
img.src = url;
})
)
);
// when they're all loaded
loadImg.then(imgs => {
// prepare the canvas
const canvas = document.getElementById('canvas');
// set its size
canvas.width = canvas.height = 500;
// get the drawing context
const ctx = canvas.getContext('2d');
let i = 0;
// start the animation
anim();
function anim() {
// do it again at next screen refresh (~16ms on a 60Hz monitor)
requestAnimationFrame(anim);
// increment our index
i = (i + 1) % imgs.length;
// draw the required image
ctx.drawImage(imgs[i], 0, 0);
}
})
.catch(console.error);
<canvas id="canvas"></canvas>
And if you wish time control:
const urls = new Array(35).fill(0).map((v, i) =>
'https://picsum.photos/500/500?image=' + i
);
// load all the images
const loadImg = Promise.all(
urls.map(url =>
new Promise((res, rej) => {
// each url will have its own <img>
const img = new Image();
img.onload = e => res(img);
img.onerror = rej;
img.src = url;
})
)
);
// when they're all loaded
loadImg.then(imgs => {
// prepare the canvas
const canvas = document.getElementById('canvas');
// set its size
canvas.width = canvas.height = 500;
// get the drawing context
const ctx = canvas.getContext('2d');
const duration = 100; // the number of ms each image should last
let i = 0;
let lastTime = performance.now();
// start the animation
requestAnimationFrame(anim);
// rAF passes a timestamp
function anim(time) {
// do it again at next screen refresh (~16ms on a 60Hz monitor)
requestAnimationFrame(anim);
const timeDiff = time - lastTime;
if(timeDiff < duration) { // duration has not yet elapsed
return;
}
// update lastTime
lastTime = time - (timeDiff - duration);
// increment our index
i = (i + 1) % (imgs.length);
// draw the required image
ctx.drawImage(imgs[i], 0, 0);
}
})
.catch(console.error);
<canvas id="canvas"></canvas>
So, I'm relatively new to Javascrip. Though what I want to do is give a moving image on my canvas an id, so that I can ultimately use onclick to use the image as a clickable image, so I can redirect the user to another page, which is what would happen when the image is clicked. Here is my code so far. I need help. If you need any more clarification I will try to explain further.
var ctx;
var imgBg;
var imgDrops;
var x = 0;
var y = 0;
var noOfDrops = 50;
var fallingDrops = [];
function drawBackground(){
ctx.drawImage(imgBg, 0, 0); //Background
}
function draw() {
drawBackground();
for (var i=0; i< noOfDrops; i++)
{
ctx.drawImage (fallingDrops[i].image, fallingDrops[i].x, fallingDrops[i].y); //The rain drop
fallingDrops[i].y += fallingDrops[i].speed; //Set the falling speed
if (fallingDrops[i].y > 1000) { //Repeat the raindrop when it falls out of view
fallingDrops[i].y = -25 //Account for the image size
fallingDrops[i].x = Math.random() * 10000; //Make it appear randomly along the width
}
}
}
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
imgBg = new Image();
imgBg.src = "http://images.susu.org/unionfilms/films/backgrounds/hd/space-jam.jpg";
setInterval(draw, 36);
for (var i = 0; i < noOfDrops; i++) {
// Charles Barkley
var fallingDr = new Object();
fallingDr["image"] = new Image();
fallingDr.image.src = 'http://xenboards.ignimgs.com/external_data/attachments/8/8795-f09b907a01726a25ca2fbd2f588e3f0e.jpg';
fallingDr["x"] = Math.random() * 10000;
fallingDr["y"] = Math.random() * 5;
fallingDr["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr);
// Bugs bunny
var fallingDr2 = new Object();
fallingDr2["image"] = new Image();
fallingDr2.image.src = 'http://i.imgur.com/zN2CSAf.png'
fallingDr2["x"] = Math.random() * 10000;
fallingDr2["y"] = Math.random() * 5;
fallingDr2["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr2);
// Michael Jordan
var fallingDr3 = new Object();
fallingDr3["image"] = new Image();
fallingDr3.image.src = 'http://i.imgur.com/XxvJiGg.png'
fallingDr3["x"] = Math.random() * 10000;
fallingDr3["y"] = Math.random() * 5;
fallingDr3["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr3);
// Daffy duck
var fallingDr4 = new Object();
fallingDr4["image"] = new Image();
fallingDr4.image.src = 'http://i.imgur.com/QZogw2L.png'
fallingDr4["x"] = Math.random() * 10000;
fallingDr4["y"] = Math.random() * 5;
fallingDr4["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr4);
fallingDr4.image.id = "Daffy";
}
}
}
setup();
window.onload = function(){
document.getElementById("Daffy").onclick=function(){
alert("Hello World");
}
}
Try:
fallingDr4.image.onclick=function(){
alert(this.id);
}
should alert "Duffy".
Your problem is that you're trying to catch the click event on an element that is not in the document and hence, not clickable by the user.
When you call var img = new Image() a new <img> element is created, with all its properties that you can already modify in your javascript. But this element is only available to your scripts, and is not displayed into the page until you call document.anyElement.appendChild(img). So it's better to consider this as an imageObject more than to an element (even if it actually also is).
What is in your document, and accessible to your user, is the <canvas> element. So if you want to know if the user has clicked, you will have to attach the eventListener to this canvasElement.
But the canvasElement doesn't know what it does represent. When you call context.drawImage(), you're just applying the pixels from the imageSource to the ones of the canvas, and all reference to the original imageObject are lost.
To workaround this, you'll then have to store the position of your drawn image into the canvas, and then check if the click event you caught was inside these positions.
Click events' clientX and clientY properties of the Event passed as arguments of you handler will give you the position of the cursor when the event occurred. But the positions are relative to the top-left corner of the window. So you'll also need to make these relative to the top-left corner of your canvas, which can be done by calling the getBoundingClientRect() method of the canvasElement.
Here is a simplified example :
// this function will be called at image's load
var init = function() {
// a reference to our "in-screen" canvasElement
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// "kitty" will be the js object that will help us know if we clicked on our image
// "this" refers to the imageObject
var kitty = {
width: this.width,
height: this.height,
// random positions
left: Math.random() * (canvas.width - this.width),
top: Math.random() * (canvas.height - this.height),
};
// draw our image at the random positions we created
ctx.drawImage(this, kitty.left, kitty.top, kitty.width, kitty.height);
// here we're listening to mousemove event,
// but click event shares the same clientX & clientY properties
var moveHandler = function(evt) {
// in the "evt" object passed, we can get the x and y positions relative to the window
// so we make these relatives to the canvas ones
var canvasRect = canvas.getBoundingClientRect();
var x = evt.clientX - canvasRect.left;
var y = evt.clientY - canvasRect.top;
// now we've got our relative positions, we can check if we were inside the image
if (x >= kitty.left && x <= (kitty.left + kitty.width) && y >= kitty.top && y <= (kitty.top + kitty.height) ) {
// we are over the image, do something
canvas.style.cursor = 'pointer';
document.body.style.backgroundColor = 'lightblue';
} else {
canvas.style.cursor = 'default';
document.body.style.backgroundColor = 'transparent';
}
};
// attach this event handler to the canvasElement
canvas.addEventListener('mousemove', moveHandler);
};
// this will create an imageObject, which will stay "off-screen" (never appendded to the document)
var img = new Image();
// wait that the image has loaded before trying to make any magic
img.onload = init;
img.src = "http://lorempixel.com/200/70/cats";
body {
width: 100vw;
text-align: center;
}
canvas {
margin: 0 auto;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
(you may need to scroll to actually see the image, or go fullscreen)
The Problem
I am finding it rather difficult to get my head around this, I am attempting to move an image using the mouse along the X axis only. I am finding it hard to even move the image at all and the many tutorials I have looked at arnt really helping me. Here is what I am trying to say:
As you can see by my beautiful image above I only want to image to move left and right at the bottom of the page.
The Code and the Question
Here is my first attempt, when I try this all the images loaded on the canvas no longer appear making it very hard for me to understand why it isnt working.
<script type="text/javascript">
//Referencing the canvas
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var width = canvas.getAttribute('width');
var height = canvas.getAttribute('height');
//Images
var bggameImage = new Image();
var playerImage = new Image();
var enemyImage = new Image();
var projectileImage = new Image();
var livesImage = new Image();
//Canvas dimensions
var width = 480;
var height = 320;
//Loading in the backgroundImage
bggameImage.src = "Images/bggameImage.png";
bggameImage.onload = function(){
context.drawImage(bggameImage, 0, 0);
}
//Loading in the playerImage
playerImage.src = "Images/playerImage.png";
playerImage.onload = function(){
context.drawImage(playerImage, 165, 240);
}
//Loading in the projectileImage
projectileImage.src = "Images/projectileImage.png";
projectileImage.onload = function(){
context.drawImage(projectileImage, 65, 240);
}
var playerImage = {
x:176,
y:74,
}
function init() {
playerImage.src = "Images/playerImage.png";
//Moving player
myCanvas.addEventListener("mousemove", function (e) {
var bounding_box = myCanvas.getBoundingClientRect();
playerImage = (e.clientX - bounding_box.left) * (myCanvas.width / bounding_box.width) - playerImage.width / 2;
playerImage = (e.clientY - bounding_box.top) * (myCanvas.height / bounding_box.height) - playerImage.height / 2;
}
)
</script>
The whole "function init()" part is what I have just tried but I thought I would include this anyway, I understand that I am loading in the playerImage twice.
You're using the same variable name twice (playerImage), so your image is being overwritten. You're using it for the image and also to store the position. Change the playerImage that's storing x and y to be playerPosition or something like that. Update that variable on your mouse event and then render the image according to that variable's values.
Ultimately, you're going to have to look at a game loop using setTimeout or requestAnimationFrame. So, this will become crucial at that stage. And yes, you shouldn't be loading the player image twice either. Do all of that at the start and only start your game when all your assets have successfully loaded.
For instance...
var playerImage;
var alienImage;
var bulletImage;
var assetCount = 0;
function loadAssets() {
playerImage = new Image();
playerImage.onload = checkAssetsLoaded;
playerImage.src = "assets/images/Brush01.png";
alienImage = new Image();
alienImage.onload = checkAssetsLoaded;
alienImage.src = "assets/images/Brush02.png";
bulletImage = new Image();
bulletImage.onload = checkAssetsLoaded;
bulletImage.src = "assets/images/Brush03.png";
}
function checkAssetsLoaded(event) {
assetCount++;
console.log("An asset has loaded!: " + assetCount);
if (assetCount == 3) {
startGame();
}
}
function startGame() {
// Start your game initialization logic here.
console.log("Game starting!");
}
I'm trying to add images to canvas strictly, but images are added randomly.
What's the problem?
Here is my simple code.
var canvas = new fabric.Canvas("preview");
var imgs = ['bgBottom','bgTop', 'bgLevel', 'bgCircle'];
for (var i=0; i<imgs.length;i++){
var url = imgs[i]+'.png';
fabric.Image.fromURL(url, function (oImg) {
canvas.add(oImg)
})
}
fabric.Image.fromURL loads the image in the background and runs the anonymous function you pass to it once image load is complete which adds it to the canvas. The order that the browser loads the images will vary and you can't rely on it being in a specific order.
Check out this jsfiddle that shows loading an array of images and making sure they're displayed in a set order. This works by adding the image to the canvas before it's loaded; it just doesn't render until the image is available to be displayed.
The code from the jsfiddle:
var SelfLoadingImage = fabric.util.createClass(fabric.Object, {
initialize: function(src) {
this.image = new Image();
this.image.src = src;
this.image.onload = (function() {
this.width = this.image.width;
this.height = this.image.height;
this.loaded = true;
this.setCoords();
this.fire('image:loaded');
canvas.renderAll();
}).bind(this);
},
_render: function(ctx)
{
if (this.loaded) {
ctx.drawImage(this.image, -this.width / 2, -this.height / 2);
}
}
});
var canvas = new fabric.Canvas("preview");
var imgs = [
'http://icons.iconarchive.com/icons/fasticon/ifunny/128/dog-icon.png', // dog
'http://33.media.tumblr.com/avatar_14ee6ada72a4_128.png', // cat
'http://upload.wikimedia.org/wikipedia/commons/b/bc/Nuvola_devices_mouse.png' // mouse
];
for (var i=0; i<imgs.length;i++){
var url = imgs[i];
var img = new SelfLoadingImage(url);
canvas.add(img);
}