Is there any way to force a canvas to update? I'd like to display a loading message but the game locks up loading before it displays. I feel like I need to tell the canvas to "draw now" before load function is called, but maybe there is a another way...
EDIT:
ok, just to be clear i've written a very small dirty script (best i can do in my tea break :P) to demonstrate what i'm trying to over come. Here:
<html>
<head>
<title>test page</title>
</head>
<body onload="init();">
<canvas id="cnv" width="300" height="300">
canvas not supported.<br/>
</canvas>
</body>
</html>
<script type="text/javascript">
var ctx;
function init()
{
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
FakeLoad();
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}
function FakeLoad()
{
var d = new Date();
var start = d.getTime();
while (new Date().getTime() - start < 5000)
{
//emulate 5 secs of loading time
}
}
</script>
now the idea is the script should draw a red square to show its "loading" and a green square when finished. but all you will see if you copy that into a html file is a pause of 5 seconds then the green appears, never red. In my head I wanted to have some command like ctx.Refresh(); after i draw the green square to tell it "update now! don't wait!" but judging from replies this is not the way to handle the problem.
what should I do? :)
Another thing you could do to allow the canvas to display before you do the longer task is begin FakeLoad after a short timeout:
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
setTimeout(function() {
FakeLoad();
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}, 20); // 20 ms - should be enough to draw something simple
If I understand you correctly, there's no way to update a canvas in the same way that you may be able to re-render/paint in WPF or re-flow the HTML DOM.
This is because a canvas uses intermediate mode graphics. Essentially, the only thing that the canvas retains knowledge of is the pixels which make up the canvas. When you call draw rect or draw line, the pixels that make up the rectangle or line are added to the canvas and as far as the canvas is concerned, it forgets all about the draw rect or draw circle call and therefore we cannot refresh the canvas and get the same result.
If your looking for something that 'retains' knowledge of the graphics rendered into it, you could try SVG, this uses retained mode graphics. Essentially it has it's own DOM (heirachy of objects (circle, rect etc)), which are re-rendered each time a region is made dirty.
In short, this page is very good at helping you understand the difference between immediate mode graphics and retained mode graphics: http://msdn.microsoft.com/en-us/library/ie/gg193983(v=vs.85).aspx
All that said, if I'm misunderstanding your question, please accept my apologies!
Update
From the extra info in the question,
The reason why you never see the green square is because the main javascript thread is always busy with your five second loop. It never has any time to update the UI. To allow time for the canvas to update with your loading screen, you'll need to do all your loading asynchronously.
What sort of loading will you be doing? If it's images etc, you can grab them using $.ajax and jQuery. This will asynchronously get the images from their location and once the last image has been retrieved, you can then clear and repaint the canvas with your content.
I guess something like this:
<script type="text/javascript">
var ctx;
function init()
{
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
FakeLoad();
}
function FakeLoad()
{
$.ajax({
url: "www.foo.com/bar.jpg",
success: function(data)
{
// Do something with the data (persist it)
RenderApp();
}
});
}
function RenderApp()
{
// Rendering the rest of the application / game
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}
</script>
Obviously this is kinda psudo-code, but hopefully it'll give you some idea!
let me know if you need any clarification!
Related
I'm looking at sample code on how to draw shapes using only JavaScript.
I'm trying to test this sample code in JSFiddle.net, and while hitting 'Run' doesn't produce any errors, the result is completely blank.
Does anyone know how to make something actually appear on the screen in JsFiddle.net?
draw = function() {
//sky
background(172, 238, 247);
//ground
fill(95, 156, 83);
rect(0, 350, 400, 50);
};
draw();
Link to non-working Fiddle:
https://jsfiddle.net/skdopL1b/
So the way javascript works with HTML to draw things is through the Canvas API. First you have to contextualization and establish interactions between JS code and <canvas> element. This is done with built in function and then a little bit of code to make it short-hand.
<html>
<canvas id="canvas" width="500" height="400"></canvas>
<script>
const c = document.getElementById("canvas"); //Grab canvas element to use as object
const ctx = c.getContext('2d'); //Function that enable the 2d functions of Canvas API
ctx.fillRect(0,0,10,10) //Example of ctx function
<script>
</html>
From the JS Fiddle you gave us, It looks like you probably copied functions from a video that pre-established these function as they are not normal canvas function but custom functions. I can show you example of how to write one of these custom functions
function background(red,green,blue) {
ctx.fillStyle = 'rgb('+red+','+green+','+blue+')';;
ctx.fillRect(0,0,c.width,c.height); //Makes a rectangle the size of the canvas
}
background(172,238,247); //Creates a canvas sized rectangle with rgb(172,238,247)
You will have to either find his function declarations or write your own (or just use the raw canvas functions) to work with the javascript this way. You also need to define a canvas element with an ID. Lucky for you Im working on making a JSFiddle that works for you since you seem fairly new to this whole HTML5/JS thing.
-------EDIT-------
Heres your fiddle link friend, I included comments to help you understand everything https://jsfiddle.net/xwqg1cez/2/
Cannot get rectangle drawn on canvas with javascript in Adobe Animate with code below.
Successful only when using Createjs Ticker function with eventListener. Please note I'm NOT asking about animation -- but just about drawing something on the Canvas.
Am I incurring in a coding or in a conceptual error?
Thanks in advance for kind help to beginner.
this.stop();
//Line below not needed as far as I checked (when in in Adobe Animate)
//var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// I get the rectangle and text on Canvas ONLY when I uncomment the three commented lines below
//createjs.Ticker.addEventListener("tick", handleTick);
//function handleTick() {
alert("ctx 25")
ctx.lineWidth = 5;
ctx.strokeRect(20, 20, 100, 100);
ctx.font = "bold 25px Verdana";
ctx.fillText("Index", 200, 70);
//}
You are accessing the context directly. EaselJS will clear the canvas each time it redraws.
There are a number of ways to add your own content:
1. Ensure it happens after the stage.update() or after a child's draw method
2. Draw to an external canvas, and use that as a source of a Bitmap
3. Draw to EaselJS's display list instead.
Here is how to draw to the stage using EaselJS
// You just need to do this once, not on every tick
var shape = new createjs.Shape();
shape.graphics.setLineStyle(5).drawRect(0,0,100,100);
shape.set({x: 20, y: 20}); // You can also set the x/y directly, or offset the shape in the drawRect call
stage.addChild(shape); // Wherever the stage is constructed.
var text = new createjs.Text("Index", "bold 25px Verdana", "#000");
text.set({x: 200, y:70});
stage.addChild(text);
Hope that helps!
I am trying to create my first website using the p5.js library, with the end goal being an online digital portfolio. I am currently working on a splash screen, in which I have some large title text filling the center of the screen on a simple black background, which actively resizes to fill the window.
I would like to place a simple doodle in the background to add some interest. My challenge is that I would not like this doodle to draw on top of my text, but instead place it underneath my text. Initially I was thinking of infinitely redrawing the text so it stays at the top, however I have deduced there is no way to do this while still animating something beneath it.
My knowledge of HTML / CSS is minimal, however I was thinking of making the background of the title sketch transparent, a separate sketch with the doodle, and use the z index property in CSS to place the doodle beneath the title, is this even possible?
Thanks!
Further edits based on recommendations:
function preload() {
myFont = loadFont('assets/HighTide.otf');
}
function setup() {
canvas = createCanvas(window.innerWidth, window.innerHeight);
title = text("Welcome", width/2, height/2);
background(30);
fsize = window.innerHeight/4;
pg = createGraphics(window.innerWidth, window.innerHeight);
}
function draw() {
background(30);
pg.fill(random(0,255), random(0,255), random(0,255));
//pg.translate(width/2, height/2);
pg.ellipse(random(window.innerWidth), random(window.innerHeight), 60, 60)
image(pg, 0, 0);
textFont(myFont);
textSize(fsize);
textAlign(CENTER);
fill(255);
text("Welcome", width/2, height/2);
}
window.onresize = function() {
var w = window.innerWidth;
var h = window.innerHeight;
canvas.size(w,h);
fsize = window.innerHeight/4;
title.textSize(fsize);
width = w;
height = h;
}
It depends on exactly how you're drawing everything, but if you're doing this all in P5.js then you've already described exactly what you need to do.
Step 1: Each frame, clear out old frames by calling the background() function.
Step 2: Then draw your doodle.
Step 3: Finally, draw your text. Since you're drawing the text after the doodle, it shows up "on top" of the doodle.
This is how most P5.js sketches work: every frame, you clear out the old frames and then draw the next frame.
Edit: If you need a sketch that doesn't clear out old frames but still shows two different layers (your doodle and your text), then what you could do is draw your doodle to a buffer, then draw that buffer each frame, then draw the text on top of the buffer. Check out the createGraphics() function in the reference.
I have been trying to print arc in the html page. How can i remove the already drawn arch from the page?. i have written the below code.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="1200" height="1000"
style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
/*ctx.beginPath();
ctx.arc(600,500,20, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(600,500,40, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
*/
var radius=20;
for (i=0; i<10; i++)
{
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(600,500,radius, 0.5*Math.PI, 2*Math.PI);
ctx.stroke();
radius= radius+30;
}
</script>
</body>
</html>
How can i achieve this?.
Call clearRect method:
ctx.clearRect(0, 0, 1200, 1000)
The four arguments are:
axis-X of left top corner of the area to wipe
axis-Y of left top corner of the area to wipe
width of the area to wipe
height of the area to wipe
So with this method, you could wipe either the whole canvas or just a certain part of it.
If you want to remove the whole previously drawn image please take a look at the other anwers. In the comments OP made it clear that this is not what he was trying to achieve. So instead I will answer the intended question:
How do I un-stroke a path?
A bitmap is not a vector graphic. You cannot simply remove or modify things you've drawn previously. By drawing on a canvas you modify the pixel color values of its image data. If you need to undo things you have to maintain a separate data structure with the relevant data yourself.
For example you could create a copy of the image data before drawing something. Then you could return to this snapshot afterwards. HTMLCanvasElement#toDataURL returns the complete image as an url which you can use as the src of an image. Later you can draw this image on the canvas to revert all subsequent changes. HTMLCanvasElement#toBlob does about the same but it returns a blob. This might consume less memory but it's a little more inconvenient to use. The most convenient method is CanvasRenderingContext2D#getImageData. You can even use it to copy only a small part of the image. This is useful if you have a big canvas but only modify pixels in a small region.
Another way to make modifications undoable is by maintaining a detailed list of your steps. For example whenever you draw an arc you store the exact parameters as one entry in the list. steps.push({type: 'stroke', style: 'rgb(0,0,0)', shapes: [{type: 'arc', x: 600, y: 500, radius: radius, from: 0.5 * Math.PI, to: 2 * Math.PI}]}) You can remove, rearrange or modify the elements in this list any way you like and have all necessary information to draw the resulting image from scratch. Basically you've implemented just another vector graphic library.
I have drawn 2 images in canvas using javascript (lineTo, moveTo, rect etc.), and I want to manipulate these images in a rollover kinda way. I know I'm supposed to write functions like "onmouseover" and "onmouseaway", thing is I don't know how I can manipulate the two shapes I already have in the canvas given that I don't have their sources... I tried googling but it got a bit confusing.
alert: i'm beginner in JS
http://jsfiddle.net/aertop9416/J7Brj/embedded/result/
.js file
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
function drawTriangle(){
context.beginPath();
context.moveTo(225,275);
context.lineTo(25,25);
context.lineTo(0,275);
context.fill();
// context.fillStyle = 'rgb(200, 95, 124)';
};
function drawRect(){
context.fillRect(300,25,100,100);
// context.clearRect(245,245,60,60);
// context.strokeRect(250,250,50,50);
context.fillStyle = 'rgb(120, 195, 124)';
};
If you're not using a library such as EasleJS for interactivity (http://www.ajohnstone.com/test/hackday/CreateJS-EaselJS-b262a85/tutorials/Mouse%20Interaction/), It's going to be a bit tricky, since canvas uses immediate render mode you need to retain the state of your objects. Use the mouse interaction event listeners to trigger an animation loop (hopefully using requestAnimationFrame for performance see: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/). I hope this gets you going in the right direction.