My code is like this:
(function() {
var c = $('#board')[0].getContext('2d');
$('#board').click(_tst);
var _tst_idx = 0;
function _tst(e) {
c.fillRect(40 + (_tst_idx++) * 50, 40, 40, 40);
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="board" width="500" height="500"></canvas>
http://jsfiddle.net/u063s0s4/
Just click the canvas and draw a box on it.
But, when I focus another window, the 2nd box disappear unexpected.
Like this: http://i2.tietuku.com/8398bd6aacc39e5d.png
I used Chrome 39.0.2171.95/Win 7, I don't know what's wrong with this code.
Thanks.
============ more ==================
I have tried to use the stealth mode of chrome or disable all extensions, the 2nd box was still disappeared.
But the code works all right on the other computer of mine.
That's so strange!
Only the 2nd rendering to canvas will disappear.
So I used this code on init to avoid it:
(function(a,b){
a(function(){
b(0, 0, 1, 1);
a(function(){
b(0, 0, 1, 1);
});
});
})(requestAnimationFrame, c.clearRect.bind(c));
=============== more =============
When I disabled "Use hardware acceleration when available" in the chrome setting, it became fine.
My GPU: NVIDIA 560TI
Related
How can I use css variables to set canvas colours?
Example:
<html>
<head>
<style>
:root {
--color-bright:#ffca00;
--color-bg:#40332e;
}
body {
background-color: var(--color-bg);
color: var(--color-bright);
}
</style>
</head>
<body>
<center>
<div>
<canvas id="loadingCanvas" oncontextmenu="event.preventDefault()" width="800" height="600"></canvas>
</div>
</center>
This text is actually yellowish.
<script type='text/javascript'>
var loadingContext = document.getElementById('loadingCanvas').getContext('2d');
var canvas = loadingContext.canvas;
loadingContext.fillStyle = "rgb( 0, 0, 0 )";
// Doesn't work (should be brown instead of black):
loadingContext.fillStyle = "var(--color-bg)";
loadingContext.fillRect(0, 0, canvas.scrollWidth, canvas.scrollHeight);
loadingContext.font = '30px sans-serif';
loadingContext.textAlign = 'center'
loadingContext.fillStyle = "rgb( 200, 200, 200 )";
// Doesn't work (should be yellow instead of white):
loadingContext.fillStyle = "var(--color-bright)";
loadingContext.fillText("This text should be yellowish.", canvas.scrollWidth / 2, canvas.scrollHeight / 2);
</script>
</body>
</html>
No you can't, at least not currently. I must admit that I'm not 100% certain if it should work or not, navigating the CSS parse a grammar is quite complex for me right now, but anyway, no browser supports it, so even if the specs actually were telling that it should work, the specs would be wrong (I'll investigate this further and maybe open an issue there).
Note that it is clear though that currentColor should work, and indeed it does in Firefox, but neither in Blink nor in WebKit, so better consider it unsupported.
What you can do however is to get the parsed value yourself, by calling getComputedStyle(context.canvas).getPropertyValue("--the-property"):
const loadingContext = document.getElementById('loadingCanvas').getContext('2d');
const canvas = loadingContext.canvas;
loadingContext.fillStyle = "rgb( 0, 0, 0 )";
loadingContext.fillStyle = getComputedStyle(canvas).getPropertyValue("--color-bg");
loadingContext.fillRect(0, 0, canvas.scrollWidth, canvas.scrollHeight);
loadingContext.font = '30px sans-serif';
loadingContext.textAlign = 'center'
loadingContext.fillStyle = "rgb( 200, 200, 200 )";
loadingContext.fillStyle = getComputedStyle(canvas).getPropertyValue("--color-bright");
loadingContext.fillText("This text should be yellowish.", canvas.scrollWidth / 2, canvas.scrollHeight / 2);
:root {
--color-bright:#ffca00;
--color-bg:#40332e;
}
body {
background-color: var(--color-bg);
color: var(--color-bright);
}
<canvas id="loadingCanvas" width="800" height="600"></canvas>
This text is actually yellowish.
Note that even if it did work the way you wanted, the value would be parsed only at setting of the property, so doing it this way works exactly the same, also, this obviously doesn't work for canvases that are not connected in the DOM.
Ps: Chrome and Safari actually do support setting the fillStyle to "currentColor", but only when the color is set as a direct color (no currentColor, nor var(--prop)), and when set as the canvas element's style attribute (not through a stylesheet nor inheritance). That's quite bad IMO, and I'll open a few issues to at least get this working.
I am making a button with javascript. When I click on the box that says "click me", it should print the line "now you clicked me". However, when I embedded it in an HTML file and open it with chrome, something went wrong. Initially, the button appears, but when the mouse hovers over it, the entire button disappears. When I click on where the button was, it still prints the line. Here is my code, adapted from khan academy computer science courses on drawing buttons. Also, the code works in khan academy but not when I open it with chrome. Is there any way I can make the button stay on the screen even I hover above it?
<!DOCTYPE html>
<!-- This is based on DillingerLee's great template here:
https://github.com/Team-Code/KA_Offline -->
<html>
<head>
<title>Processing.JS inside Webpages: Template</title>
</head>
<body>
<p align="center">
<!--This draws the Canvas on the webpage -->
<canvas id="mycanvas"></canvas>
</p>
</body>
<!-- Run all the JavaScript stuff -->
<!-- Include the processing.js library -->
<!-- See https://khanacademy.zendesk.com/hc/en-us/articles/202260404-What-parts-of-ProcessingJS-does-Khan-Academy-support- for differences -->
<script src="https://cdn.jsdelivr.net/processing.js/1.4.8/processing.min.js"></script>
<script>
var sketchProc = function(processingInstance) {
with (processingInstance) {
size(600, 400);
frameRate(30);
/******************
*Button Object Type
*******************/
var Button = function(config) {
this.x = config.x || 0;
this.y = config.y || 0;
this.width = config.width || 80;
this.height = config.height || 50;
this.label = config.label || "Click";
this.color = config.color || color(207, 85, 85);
this.onClick = config.onClick || function() {};
};
//draw the button
Button.prototype.draw = function() {
if (this.isMouseInside() && mouseIsPressed()) {
fill(255, 255, 255);
}
else {
fill(this.color);
}
rectMode(CENTER);
rect(this.x, this.y, this.width, this.height, 5);
fill(0, 0, 0);
textSize(19);
textAlign(CENTER, CENTER);
text(this.label, this.x, this.y);
};
//check if mouse cursor is inside the button
Button.prototype.isMouseInside = function() {
return mouseX > this.x-this.width/2 &&
mouseX < (this.x + this.width/2) &&
mouseY > this.y - this.height/2 &&
mouseY < (this.y + this.height/2);
};
//handle mouse clicks for the button
Button.prototype.handleMouseClick = function() {
if (this.isMouseInside()) {
this.onClick();
}
};
/** create object instances **/
//create button
var btn1 = new Button(
{
x:width/2,
y:height/2,
width : 72,
height : 36,
label : "Click me",
color: color(35, 176, 110),
onClick : function(){
println("Now you clicked me");
}
}
);
draw = function() {
background(98, 122, 54);
//Draw the button
btn1.draw();
};
mouseClicked = function() {
btn1.handleMouseClick();
};
}};
// Get the canvas that Processing-js will use
var canvas = document.getElementById("mycanvas");
// Pass the function sketchProc (defined in myCode.js) to Processing's constructor.
var processingInstance = new Processing(canvas, sketchProc);
</script>
</html>
When running your code, as you hover over the button, the following error is printed in the browser's console (press F12 and click console to see this):
Meaning that something on line 42 of the HTML file throws an error. Let's investigate!
On this line, the following code can be found:
if (this.isMouseInside() && mouseIsPressed())
Apparently, the second part of this if statement is not defined.
Looking into the documentation on the p5.js website (link), it looks like mouseIsPressed is a boolean value (true or false) and not a function, and should thus not be invoked using brackets. The following should then work:
if (this.isMouseInside() && mouseIsPressed)
However, at least for me, this still does not work as intended. A similar error is thrown. Looking in the processing.org online documentation, I came across a reference to the mousePressed boolean instead (link).
Finally, using this, the code works as intended:
if (this.isMouseInside() && mousePressed)
If I understand it correctly, you can make your own custom functions called mouseIsPressed and mousePressed, which are then called automatically by processing when such an event occurs, but in this case using the boolean is simpler and should suffice.
The code is using a library called Processing. It is a problem in line 42. Instead of mouseIsPressed(), you should use this.mouseIsPressed
if (this.isMouseInside() && this.mouseIsPressed) {
fill(255, 255, 255);
}
With the wrong code, if you open Chrome dev tools (F12), and try to hover above it, you see an error message on the console, says "mouseIsPressed() is not a function", because you did not define this function. You should refer to the Button object with the this keyword, then access mouseIsPressed, which looks like to me a build-in Processing variable.
This is my 1st question on stackoverflow. I'm still a bit new to javascript and I'm trying to make a simple interactive story.
There is a list of sentences that I want to go through. Each sentence is to be displayed on the canvas and a button would move to the next sentence. I've tried using a few different solutions but the canvas isn't changing when I press the Next button.
I have called the increment function (plusOne) during the code to test if the function actually works and it does. It seems the problem is in relation to the button.
Here's the canvas and button:
<canvas id="myCanvas" width="480" height = "320"></canvas>
<button onclick = "plusOne()">Next</button>
Here's the function and the variables
const plusOne = () =>{
lineMarker++;
}
//making a list of words and getting font
var myLines = ["Hello and welcome",
"How are you doing?",
"I'm doing quite well thank you"]
var lineMarker = 0;
I called the plusOne() function 4 times just to check that the canvas displayed the value of lineMarker as 4, which it did!
And here are the lines of code that draw to the canvas:
ctx.fillText(myLines[lineMarker%3], 8, 250);
ctx.fillText(("Line number is: "+lineMarker.toString()), 10,80);
The canvas displays the value of lineMarker and the sentence that's in the list.
However, the button is not incrementing the value and I have tried making a separate button in javascript but that also failed to work.
I've held off on asking questions for a long time, for fear that I might be missing something completely obvious which I'll figure out sooner or later, but forums and tutorials have convinced me to ask around, so here I am!
Anyone know how to sort this out?
You are close just a few small changes.
Firstly, you needed to update the canvas within the plusOne function.
You also needed to clear the canvas from the previous fillText
var lineMarker = 0;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
const plusOne = () => {
lineMarker++;
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillText(myLines[lineMarker % 3], 8, 250);
ctx.fillText(("Line number is: " + lineMarker.toString()), 10, 80);
}
//making a list of words and getting font
var myLines = ["Hello and welcome",
"How are you doing?",
"I'm doing quite well thank you"
];
ctx.fillText(myLines[lineMarker % 3], 8, 250);
ctx.fillText(("Line number is: " + lineMarker.toString()), 10, 80);
<canvas id="myCanvas" width="480" height = "320"></canvas>
<button onclick = "plusOne()">Next</button>
I have been practicing using sprites for a game I am going to make and have watched and read a few tutorials, I thought I was close to getting my sprite to appear so I could finally start my game but while practicing I cant get it to work, I have dont 2 seperate tutorials where I can get the sprite and the background to appear by themselfs but cannot get them to work together, I have been using EaselJS too. some of the sprite animation code has been copied from tutorials too.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>sprite prac<title>
<!-- EaselJS library -->
<script src="lib/easel.js"></script>
<script>
// Initialize on start up so game runs smoothly
function init() {
canvas = document.getElementById("canvas");
stage = new Stage(canvas);
bg = new Image();
bg.src = "img/grassbg.jpg";
bg.onload = setBG;
stage.addChild(background);
imgMonsterARun = new Image();
imgMonsterARun.onload = handleImageLoad;
imgMonsterARun.onerror = handleImageError;
imgMonsterARun.src = "img/MonsterARun.png";
stage.update();
}
function handleImageLoad(e) {
startGame();
}
// Simple function for setting up the background
function setBG(event){
var bgrnd = new Bitmap(bg);
stage.addChild(bgrnd);
stage.update();
}
function startGame() {
// create a new stage and point it at our canvas:
stage = new createjs.Stage(canvas);
// grab canvas width and height for later calculations:
screen_width = canvas.width;
screen_height = canvas.height;
// create spritesheet and assign the associated data.
var spriteSheet = new createjs.SpriteSheet({
// image to use
images: [imgMonsterARun],
// width, height & registration point of each sprite
frames: {width: 64, height: 64, regX: 32, regY: 32},
animations: {
walk: [0, 9, "walk"]
}
});
// create a BitmapAnimation instance to display and play back the sprite sheet:
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
// start playing the first sequence:
bmpAnimation.gotoAndPlay("walk"); //animate
// set up a shadow. Note that shadows are ridiculously expensive. You could display hundreds
// of animated rats if you disabled the shadow.
bmpAnimation.shadow = new createjs.Shadow("#454", 0, 5, 4);
bmpAnimation.name = "monster1";
bmpAnimation.direction = 90;
bmpAnimation.vX = 4;
bmpAnimation.x = 16;
bmpAnimation.y = 32;
// have each monster start at a specific frame
bmpAnimation.currentFrame = 0;
stage.addChild(bmpAnimation);
// we want to do some work before we update the canvas,
// otherwise we could use Ticker.addListener(stage);
createjs.Ticker.addListener(window);
createjs.Ticker.useRAF = true;
createjs.Ticker.setFPS(60);
}
//called if there is an error loading the image (usually due to a 404)
function handleImageError(e) {
console.log("Error Loading Image : " + e.target.src);
}
function tick() {
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpAnimation.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpAnimation.direction = -90;
}
if (bmpAnimation.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpAnimation.direction = 90;
}
// Moving the sprite based on the direction & the speed
if (bmpAnimation.direction == 90) {
bmpAnimation.x += bmpAnimation.vX;
}
else {
bmpAnimation.x -= bmpAnimation.vX;
}
// update the stage:
stage.update();
}
</script>
</head>
<body onload="init();">
<canvas id="canvas" width="500" height="500" style="border: thin black solid;" ></canvas>
</body>
</html>
There are a few places where you are using some really old APIs, which may or may not be supported depending on your version of EaselJS. Where did you get the easel.js script you reference?
Assuming you have a version of EaselJS that matches the APIs you are using, there are a few issues:
You add background to the stage. There is no background, so you are probably getting an error when you add it. You already add bgrnd in the setBackground method, which should be fine. If you get an error here, then this could be your main issue.
You don't need to update the stage any time you add something, just when you want the stage to "refresh". In your code, you update after setting the background, and again immediately at the end of your init(). These will fire one after the other.
Are you getting errors in your console? That would be a good place to start debugging. I would also recommend posting code if you can to show an actual demo if you continue to have issues, which will help identify what is happening.
If you have a newer version of EaselJS:
BitmapAnimation is now Sprite, and doesn't support direction. To flip Sprites, use scaleX=-1
Ticker no longer uses addListener. Instead it uses the EventDispatcher. createjs.Ticker.addEventListener("tick", tickFunction);
You can get new versions of the CreateJS libraries at http://code.createjs.com, and you can get updated examples and code on the website and GitHub.
I'm creating a HTML5 game which can be made to run on Android also. I went through few articles and didn't get the solution yet. I have a image which i'm generating through javascript and I want to move this image using touchmove so that I can run it in my Android device. This is the code:
gameCanvas.addEventListener("touchmove", touchXY, true);
function touchXY(e) {
if (!e)
var e = event;
e.preventDefault();
avatarX = e.targetTouches[0].pageX - gameCanvas.offsetLeft;
avatarY = e.targetTouches[0].pageY - gameCanvas.offsetTop;
}
This is not working. I got this code from https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/HTML-canvas-guide/AddingMouseandTouchControlstoCanvas/AddingMouseandTouchControlstoCanvas.html
And this is my canvas:
<canvas id="gameCanvas" onclick="setUpGame();" width="400" height="300"></canvas>
This is my image:
avatarImage.src = "img/avatar.png";
gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
I just want to move the image inside the canvas.
I wrote a full example, hopefully it's not too verbose.
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
</head>
<body>
<canvas id='canvas' width='512' height='512'></canvas>
<script>
var c=document.getElementById('canvas'),
ctx=c.getContext('2d'),
activeBox='none',
//populate the map with objects
box=[
{
x:256,
y:128,
width:32,
height:64
},
{
x:128,
y:64,
width:64,
height:64
},
{
x:32,
y:32,
width:32,
height:32
},
];
function draw(){
//clear the screen, draw population
ctx.clearRect(0,0,c.width,c.height);
for(var i=0;i<box.length;i++){
ctx.fillRect(box[i].x,box[i].y,box[i].width,box[i].height);
}
//repeat at 60fps if possible, pause if window looses focus
requestAnimationFrame(draw);
}
function startTouch(e){
//this makes it easier to write control flow later and keeps XY relative to canvas
var xTouch=e.touches[0].pageX-c.offsetLeft,
yTouch=e.touches[0].pageY-c.offsetTop;
//its best to go through this loop in touchstart, because it only happens once per touch
for(var i=0;i<box.length;i++){
if(xTouch>box[i].x&&xTouch<box[i].x+box[i].width){
if(yTouch>box[i].y&&yTouch<box[i].y+box[i].height){
activeBox=i;
}
}
}
}
function moveTouch(e){
//grab a box by the center
if(activeBox!='none'){
box[activeBox].x=e.changedTouches[0].pageX-box[activeBox].width/2;
box[activeBox].y=e.changedTouches[0].pageY-box[activeBox].height/2;
}
}
function endTouch(){
//clear active so that dragging empty space wont move the last active box
activeBox='none';
}
canvas.addEventListener('touchstart',startTouch);
canvas.addEventListener('touchmove',moveTouch);
canvas.addEventListener('touchend',endTouch);
window.addEventListener('load',draw);
</script>
</body>
</html>
I used fillRect for simplicity, but if you want to replace it with drawImage you'll need to create a new element for each and add a source property to the box object array. Here's a partial example.
//you need a new one of these for every image
var img=new Image();
img.src='http://www.w3schools.com/images/w3logotest2.png';
var box={
source:img,
x:Math.floor((Math.random()*256)+1),
y:Math.floor((Math.random()*256)+1)
};
//make sure the image doesnt load before the script
window.onload=function(){
ctx.drawImage(img,box.x,box.y);
}