#Hey-PeePs. The issue is happening in p5js:
I have: 1 function(), 1 draw(), 2 sketches(canvas)
Using: Instance Mode
All I want is a gallery! there is an image in thumbnail size, when click goes full-size, which is the reason I have 2 canvases. The following code is working. It will create a canvas with the thumbnail size of the image and then when I click on it, it will create a DIV which contains the full-screen image.
The issue is, every time I click on the thumbnail, it will create another DIV and it just goes on. How can I set a condition for this? So it will only draw once!
var PictureThumbnail = function(p) {
let ThumbImage;
let fullSize;
p.preload = function() {
ThumbImage = p.loadImage('https://www.paulwheeler.us/files/Coin120.png');
};
p.setup = function() {
var canvas = p.createCanvas(100, 100);
canvas.parent('#Thumbnail');
fullSize = createDiv('Full Size Image');
fullSize.addClass('fullSize');
fullSize.hide();
};
p.draw = function() {
p.image(ThumbImage, 0, 0, 700, 70);
if (mouseIsPressed) {
if ((p.mouseX > 0) && (p.mouseX < 100) && (p.mouseY > 0) && (p.mouseY < 100)) {
fullSize.show();
let sketch2 = function(p) {
p.setup = function() {
p.createCanvas(500, 500);
p.background(255);
}
};
new p5(sketch2, window.document.getElementById('fullSize'));
}
}
};
};
let sketch = new p5(PictureThumbnail);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
<div id="Thumbnail"></div>
</body>
</html>
The last line of code is the issue.
new p5(sketch2, window.document.getElementById('fullSize'));
There are a number of issues:
1. Invalid references:
You have several references to global p5.js methods and properties where you should be referencing the instance methods (createDiv and mouseIsPressed).
2. Action in draw() that should be in mousePressed()
The way you're using mouseIsPressed is flawed. Draw is going to be running repeatedly and mouseIsPressed will be true over several calls so you're going to be repeatedly creating sketch2.
3. Attempt to get an element by id that does not exist
You create a div with the class 'fullSize' and no id and then you attempt to get an element with the id 'fullSize' but no such element exist.
Here's a working example:
var PictureThumbnail = function(p) {
let ThumbImage;
let fullSize;
let fullSizeOpen = false;
p.preload = function() {
ThumbImage = p.loadImage('https://www.paulwheeler.us/files/Coin120.png');
};
p.setup = function() {
var canvas = p.createCanvas(100, 100);
canvas.parent('#Thumbnail');
fullSize = p.createDiv('Full Size Image');
fullSize.addClass('fullSize');
fullSize.id('fullSize');
fullSize.hide();
};
p.mousePressed = function() {
if ((p.mouseX > 0) && (p.mouseX < 100) && (p.mouseY > 0) && (p.mouseY < 100)) {
if (!fullSizeOpen) {
fullSizeOpen = true;
fullSize.show();
let sketch2 = function(p) {
p.setup = function() {
p.createCanvas(500, 500);
p.background('red');
}
};
new p5(sketch2, window.document.getElementById('fullSize'));
}
}
}
p.draw = function() {
p.image(ThumbImage, 0, 0, 700, 70);
};
};
let sketch = new p5(PictureThumbnail);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
<div id="Thumbnail"></div>
</body>
</html>
Related
this is my first question here!
im trying to make a website that show videos that i make and i want my viewers can see a preview of video when they hover mouse on the a element or element .
i just do it but i have some problems and questions. lemme show you code example first and then i ask my questions.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="thumbs" style="width:216px;height:468px;border: 5px solid blue;background-color:red;"><canvas onmouseover="getid1(this);" onmouseout="getid2(this);" id="canvas1"></canvas></div>
<script>
var thumbsList = [];
var delay = 100;
var i = 0;
var video = document.createElement("video");
var a = 0;
var m = document.getElementById("canvas1");
var mtx = m.getContext("2d");
var generate = true;
var animstop = false;
var vidFrames = 64;
m.width = 216;
m.height = 468;
video.preload = "auto";
video.src = "aaaa.mp4";
function stranim(bb){
if(generate){
animstop = false;
video.currentTime = i;
generateVid();
generate = false;
}else{
animstop = false;
startAnim();
}
}
function stpanim(bb) {
clearTimeout();
animstop = true;
mtx.drawImage(thumbsList[0], 0, 0);
}
// if i replace this section with generateVid() the code is working
/*video.addEventListener('seeked', function() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid()
if(d == i){
startAnim();
}
}
});*/
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid();
if(d == i){
startAnim();
}
}
}
function generateFirstThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
thumbs.appendChild(m);
mtx.drawImage(thumbsList[0], 0, 0);
i += video.duration / vidFrames;
}
function generateThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
}
function startAnim() {
var currentFrame = 0;
function anim() {
if(currentFrame != (vidFrames - 1) && animstop == false){
currentFrame = (currentFrame + 1) % thumbsList.length;
mtx.drawImage(thumbsList[currentFrame], 0, 0);
setTimeout(anim, delay);
}
}
anim();
}
function getid1(obj) {
stranim(obj.id)
}
function getid2(obj) {
stpanim(obj.id)
}
window.onload = function(){
generateFirstThumbnail();
};
</script>
</body>
</html>
the questions are :
1- why my generatevid() function is not working? this function is just like that eventlistener.
2- i want to add this code on a class to use it on multiple videos but idk how and i think this cant be done with js classes.( i search so many sites for it)
3-i can use 2d arrays for saving my video previews but is it dont make my site lower on load speed or it dont fill the ram of user?
4-there is any way that i make this code better and easyer?(i dont want to use jquery for no reason).
For a pure js approach you can check this not mine btw: https://codepen.io/tepexic/pen/BazYgJe
html:
<input type="file" accept="video/*" id="input-tag"/>
<hr>
<video controls id="video-tag">
<source id="video-source" src="splashVideo">
Your browser does not support the video tag.
</video>
JS
const videoSrc = document.querySelector("#video-source");
const videoTag = document.querySelector("#video-tag");
const inputTag = document.querySelector("#input-tag");
inputTag.addEventListener('change', readVideo)
function readVideo(event) {
console.log(event.target.files)
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
console.log('loaded')
videoSrc.src = e.target.result
videoTag.load()
}.bind(this)
reader.readAsDataURL(event.target.files[0]);
}
}
But for other approach i would probably use http://ffmpeg.org/ library to generate a preview video (e.g 10 seconds video) and https://videojs.com library for video player so you have a control when user hover the player.
I just did some test on your code, your video is getting seeked only once. No event is raised after that, which means your thumbnail will remain same.
Here is how I was able to fix it
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
console.log("starting seeking");
if(d == i){
startAnim();
}
}
}
video.onseeked = (event) => {
if (animstop == false)
{
setTimeout(generateVid, delay);
}
console.log("seeked");
};
I am trying to implement the handleOnPress function, the code is provided by the textbook which is confusing because it doesn't seem to be working as expected, in fact it does nothing.
The function is supposed to allow me to click the squares in the memory game, if the squares are the same color both of the chosen squares disappear, if you click on the same square twice the function resets and if you match two that aren't the same the function resets.
It would be really appreciated if anyone can take a look and point out any errors they see, thank you!
<!DOCTYPE html>
<html>
<head>
<title>Recipe: Drawing a square</title>
<script src="easel.js"></script>
<script type="text/javascript">
var canvas;
var stage;
var squareSide = 70;
var squareOutline = 5;
var max_rgb_color_number = 255;
var gray = createjs.Graphics.getRGB(20, 20, 20);
var placementArray = [];
var highlight = createjs.Graphics.getRGB(255, 255, 0);
var tileClicked;
function init() {
var rows = 6;
var columns = 6;
var squarePadding = 10;
canvas = document.getElementById('myCanvas');
stage = new createjs.Stage(canvas);
var numberOfTiles = rows*columns;
setPlacementArray(numberOfTiles);
for(var i=0;i<numberOfTiles;i++){
var placement = getRandomPlacement(placementArray);
if(i % 2 === 0){
var color = randomColor();
}
square = drawSquare(color);
square.color = color;
square.x = (squareSide+squarePadding) * (placement%columns);
square.y = (squareSide+squarePadding) * Math.floor(placement/columns);
stage.addChild(square);
square.onPress = handleOnPress;
stage.update();
}
}
function drawSquare(color) {
var shape = new createjs.Shape();
var graphics = shape.graphics;
graphics.setStrokeStyle(squareOutline);
graphics.beginStroke(gray);
graphics.beginFill(color);
graphics.rect(squareOutline, squareOutline, squareSide, squareSide);
return shape;
}
function randomColor(){
var color = Math.floor(Math.random()*max_rgb_color_number);
var color2 = Math.floor(Math.random()*max_rgb_color_number);
var color3 = Math.floor(Math.random()*max_rgb_color_number);
return createjs.Graphics.getRGB(color, color2, color3);
}
function setPlacementArray(numberOfTiles){
for(var i=0;i<numberOfTiles;i++){
placementArray.push(i);
}
}
function getRandomPlacement(placementArray){
randomNumber = Math.floor(Math.random()*placementArray.length);
return placementArray.splice(randomNumber, 1)[0];
}
function handleOnPress(event){
var tile = event.target;
if(!!tileClicked === false){
tile.graphics.setStrokeStyle(squareOutline).beginStroke(highlight)
.rect(squareOutline, squareOutline, squareSide, squareSide);
tileClicked = tile;
}
else{
if(tileClicked.color === tile.color && tileClicked !== tile){
tileClicked.visible = false;
tile.visible = false;
}
else{
tileClicked.graphics.setStrokeStyle(squareOutline).beginStroke(gray)
.rect(squareOutline, squareOutline, squareSide, squareSide);
}
tileClicked = null;
}
stage.update();
}
</script>
</head>
<body onload="init()">
<canvas id="myCanvas" width="960" height="600"></canvas>
</body>
</html>
The onEvent-style handlers (onClick, onMouseDown, etc) were deprecated and removed a long time ago (Version 0.7.0, September 25, 2013).
Instead, use events, such as
square.addEventListener("mousedown", handleOnPress);
or the shortcut on() method:
square.on("mousedown", handleOnPress);
Note also there is no "press" event. There is a "mousedown" event, as well as "pressmove"/"pressup" events for drag and drop-style events.
Here is a listing of events on all display objects: https://createjs.com/docs/easeljs/classes/DisplayObject.html#event_mousedown
I don't know if this will solve everything, but it should get your click handlers firing.
I have it so that when you (the PaintBrush) hit the finish everything clears and a button appears. When the button is clicked it starts level two, here it creates a new canvas. I've added some code so that when the button is clicked the old canvas is deleted, then the new one is made. However, this requires the canvas to have an id. how do i get this code:
canvas: document.createElement("canvas"),
To also include an id for it? I cannot have it say var canvas = blah blah and then have
canvas.id = "canvas";
because of the way i have it set up.
P.S the remove code is this if you need to know:
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = this.length - 1; i >= 0; i--) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
and in the button "click" function area i put this for the remove:
document.getElementById("canvas").remove();
Please help! Thanks in Advance!
EDIT: Here is some extra code to help, it is what occurs when the PaintBrush hits the finish:
else if (PaintBrush.crashWith(Finish)) {
PaintBrush.y = 50;
var button = document.createElement("button");
button.innerHTML = "Level 3";
button.id = "button-2"; // add the id to the button
document.body.appendChild(button); // append to body
GameArena2.clear();
GameArena2.stop();
button.addEventListener ("click", function() {
startGame2();
document.getElement("canvas").remove();
document.getElementById("button-2").remove();
});
EDIT 2: Game canvas code:
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 1280;
this.canvas.height = 480;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea2, 20);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
},
drawGameOver: function() {
ctx2 = GameArena2.context;
ctx2.fillStyle = "rgba(0,0,0,"+fader +")";
ctx2.fillRect(0,0,GameArena2.width,GameArena2.height);
drawStatic(fader/2);
fader += .1 * 1/fps
ctx2.fillStyle = "rgba(255,255,255," + fader + ")";
ctx2.font = "72px sans-serif";
ctx2.fillText("GAME OVER",GameArena2.width/2 - 220,GameArena2.height/2);
}
}
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
else if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
return false;
}
I think the best way is to create a static function like this:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
console.log(createElementOnDom('CANVAS','myId'));
So you can simply create the canvas adding it his specific id using a simple single row function call like you need.
I only know a way to do direcly this on jQuery, that you wouldn't like to use.
simply you need to do that:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
var GameArena2 = {
canvas: createElementOnDom('CANVAS','myId'),
Simple! Just assign it immediately after the GameArena2 object is created.
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
...
...
}
// give id to a canvas
GameArena2.canvas.id = "GameArena2";
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
...
...
}
I'm trying to create a Tri Peaks Solitaire game in Javascript, using CreateJS to help interact with the HTML canvas. I'm not entirely new to programming, as I've taken college courses on Java and C, but I am new to both Javascript and HTML.
I created a large amount of the card game using a Card class and Deck class, with the image adding, event listening, and game logic done in one Javascript file, but this resulted in a lot of messy, somewhat buggy code that I felt needed cleaning up.
I'm trying to implement a separate class for the card table, which will be the canvas, or stage, and it will draw the 4 rows of playable cards, the stock pile, and the waste pile. I'm currently just trying to get the stock pile to show up on the canvas, but it's not happening.
My question is, why is my stock pile not showing up? Also, as you can see, the card images are being loaded when the cards are created. Should I be doing that differently?
Card class:
var Card = function(number) {
this.isFaceUp = false;
//number for image file path
this.number = number;
this.value = Math.ceil( (this.number)/4 );
//back of the card is default image
this.initialize("images/" + 0 + ".png");
console.log("card created")
this.height = this.getBounds().height;
this.width = this.getBounds().width;
//load the card's front image
this.frontImage = new Image();
this.frontImage.src = ( this.getImagePath() );
};
Card.prototype = new createjs.Bitmap("images/" + this.number + ".png");
Card.prototype.getImagePath = function() {
return "images/" + this.number + ".png";
};
Card.prototype.getValue = function () {
return this.value;
}
Card.prototype.flip = function() {
// this.image = new Image();
// this.image.src = ( this.getImagePath() );
this.image = this.frontImage;
this.isFaceUp = true;
};
Card.prototype.getHeight = function() {
return this.height;
};
Card.prototype.getWidth = function() {
return this.width;
};
CardDeck class:
function CardDeck() {
//create empty array
this.deck = [];
//fill empty array
for(i=1; i<=52; i++) {
//fill deck with cards, with i being the number of the card
this.deck[i-1] = new Card(i);
}
//shuffle deck
this.shuffle();
}
CardDeck.prototype.getCard = function() {
if(this.deck.length < 1) alert("No cards in the deck");
return this.deck.pop();
};
CardDeck.prototype.getSize = function() {
return this.deck.length;
};
CardDeck.prototype.shuffle = function() {
for (i=0; i<this.deck.length; i++) {
var randomIndex = Math.floor( Math.random()*this.deck.length );
var temp = this.deck[i];
this.deck[i] = this.deck[randomIndex];
this.deck[randomIndex] = temp;
}
};
CardDeck.prototype.getRemainingCards = function() {
return this.deck.splice(0);
}
CardDeck.prototype.listCards = function() {
for(i=0; i<this.deck.length; i++) {
console.log(this.deck[i].number);
}
};
CardTable class:
var CardTable = function(canvas) {
this.initialize(canvas);
this.firstRow = [];
this.secondRow = [];
this.thirdRow = [];
this.fourthRow = [];
this.stockPile = [];
this.wastePile = [];
//startX is card width
this.startX = ( new Card(0) ).width*3;
//startY is half the card height
this.startY = ( new Card(0) ).height/2;
};
CardTable.prototype = new createjs.Stage();
CardTable.prototype.createStockPile = function(cards) {
for(i=0; i<23; i++) {
cards[i].x = 10;
cards[i].y = 50;
this.stockPile[i] = cards[i];
}
};
CardTable.prototype.addToWastePile = function(card) {
card.x = startX + card.width;
card.y = startY;
this.wastePile.push(card);
this.addChild(card);
this.update();
};
CardTable.prototype.drawStockPile = function() {
for(i=0; i<this.stockPile.length; i++) {
console.log("this.stockPile[i]");
this.addChild(this.stockPile[i]);
}
this.update();
};
HTML file:
<html>
<head>
<title>Tri-Peaks Solitaire</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.createjs.com/easeljs-0.8.1.min.js"></script>
<script src="card.js"></script>
<script src="carddeck.js"></script>
<script src="cardtable.js"></script>
<script>
function init(){
var canvas = document.getElementById("canvas");
var table = new CardTable("canvas");
deck = new CardDeck();
table.createStockPile(deck.getRemainingCards());
table.drawStockPile();
table.update();
}
</script>
</head>
<body onload="init()">
<h1>Tri-Peaks Solitaire</h1>
<canvas style='border: 5px solid green; background: url("images/background.jpg");'
id="canvas" width="1000" height="450">
</canvas>
</body>
</html>
PRELOADJS UPDATE:
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
var gameDeck = new CardDeck();
var numbers = [];
var preloader;
var progressText = new createjs.Text("", "20px Arial","#FF0000");
progressText.x = 50;
progressText.y = 20;
stage.addChild(progressText);
stage.update();
setupManifest();
startPreload();
function setupManifest() {
for(i=0; i<=52; i++) {
console.log("manifest");
manifest.push( {src:"images/" + i + ".png",
id: i} );
numbers.push(i);
}
}
function startPreload() {
preload = new createjs.LoadQueue(true);
preload.on("fileload", handleFileLoad);
preload.on("progress", handleFileProgress);
preload.on("complete", loadComplete);
preload.on("error", loadError);
preload.loadManifest(manifest);
}
function handleFileLoad(event) {
console.log("A file has loaded of type: " + event.item.type);
//console.log(numbers.pop());
var cardNumber = numbers.pop();
var newCard = new Card(cardNumber);
//faces.push( new Image() );
//faces[ faces.length - 1 ].src = "images/" + cardNumber + ".png";
gameDeck.insertCard(newCard);
}
function loadError(evt) {
console.log("error",evt.text);
}
function handleFileProgress(event) {
progressText.text = (preload.progress*100|0) + " % Loaded";
stage.update();
}
function loadComplete(event) {
console.log("Finished Loading Assets");
}
You are only updating the stage immediately after creating the cards. The cards are loading bitmap images, which is a concurrent operation that takes time. As such, the only time you render the stage is before the images load.
I would suggest using PreloadJS to preload your card images. This will also give you a lot more control over when / how they load, and let you show a progress bar or distractor to the user as they load.
I would suggest waiting for all the images to load and then calling stage.update(). Alternatively use the createjs.Ticker.addEventListener("tick", handleTick); event handler to update the stage for you.
Reference: http://www.createjs.com/docs/easeljs/classes/Ticker.html
I am in desperate need to fix a problem I have in html5 canvas. I am making an educational game, but after adding another photo and making the necessary code changes, but the canvas blanked out. I reverted the changes, but the problem persisted. I spent the past week or so trying to fix it, but I've run out of ideas :( Here is the relevent code (if anyone needs another part, just say so):
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1041;
canvas.height = 550;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/introbackground.png";
//.... rest of the photos load like this so I won't put it...
// Level 1 background 1 image
var bbg1Ready = false;
var bbg1Image = new Image();
bbg1Image.onload = function () {
bbg1Ready = false; //Exception since it shouldn't load at the beginning
};
bbg1Image.src = "images/pollutedbeach1.png";
// Game objects
var hero = {
speed: 200 // movement in pixels per second
};
var level1;
var level2;
var biolevel = false;
//...Code to make the hero picture move with arrow keys and to reset the game are skipped...
if (hero.x <= (level1.x + 345)
&& level1.x <= (hero.x + 32)
&& hero.y <= (level1.y +50)
&& level1.y <= (hero.y + 32)){
biolevel = true;
return biolevel;
}
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
//...The same for all photos previously loaded...
if (biolevel == true){
level1Ready = false;
level2Ready = false;
bbg1Ready = true;
hero.speed = 125;
}
};
//...Then the main game loop to animate it...
Sorry It's kind of long, but I really need a solution. Thanks!