Here's my code. Need help with drawing an image of a cloud in between the mountain landscape using html 5 canvas element and javascript code.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<canvas id="myCanvas" style="border:2px solid black;"></canvas>
</head>
<body>
<script>
var c= document.getElementById("myCanvas");
var d=c.getContext("2d");
d.beginPath();
d.strokeStyle="red";
d.moveTo(0,50);<!-- width is 0 and height is 50-->
d.lineTo(100,0);
d.moveTo(100,0);<!-- width is 0 and height is 50-->
d.lineTo(150,50);
d.moveTo(150,50);
d.lineTo(200,0);
d.moveTo(200,0);
d.lineTo(300,50);
d.lineTo(0,50);
d.stroke();
d.beginPath();
d.arc(150,15,10,0,2*Math.PI);
d.stroke();
d.beginPath();
d.strokeStyle="black";
d.moveTo(100,100);
d.lineTo(200,100);
d.lineTo(150,60);
d.lineTo(100,100);
d.lineTo(100,150);
d.lineTo(200,150);
d.lineTo(200,100);
d.stroke();
d.moveTo(135,150);
d.lineTo(135,120);
d.lineTo(135,120);
d.lineTo(160,120);
d.lineTo(160,150);
d.stroke();
d.beginPath();
d.arc(20,20,10,.25*Math.PI,.75*Math.PI);
d.stroke();
</script>
</body>
</html>
Please add any suitable code below mine to include the image of a cloud
You can draw clouds using cubic Bezier curves.
You can also move and resize the clouds as needed using transforms. The translate command will move the starting [x,y] point of your drawing. The scale command will scale the drawing larger and smaller.
Another set of useful commands is save() and restore(). context.save()will save the context state before you change drawing colors or do transformes. context.restore() will restore the original context as it existed before the last context.save. Otherwise, you would need to manually undo all the transforms and reset the colors.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var d=canvas.getContext("2d");
d.fillStyle='skyblue';
d.fillRect(0,0,canvas.width,canvas.height);
cloud(50,100,0.50);
function cloud(x,y,scale){
d.save();
d.translate(x,y);
d.scale(scale,scale);
d.beginPath();
d.moveTo(0, 0);
d.bezierCurveTo(-40, 20, -40, 70, 60, 70);
d.bezierCurveTo(80, 100, 150, 100, 170, 70);
d.bezierCurveTo(250, 70, 250, 40, 220, 20);
d.bezierCurveTo(260, -40, 200, -50, 170, -30);
d.bezierCurveTo(150, -75, 80, -60, 80, -30);
d.bezierCurveTo(30, -75, -20, -60, 0, 0);
d.strokeStyle='lightgray';
d.fillStyle='white';
d.fill();
d.stroke();
d.restore();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
#markE Apologies, my message was unclear.
I 100% agree with you. I upvoted your answer because it is absolutely the correct and most flexible way to do this! I assumed OP would have loved your answer.
I was surprised to read, after your thorough explanation, that #newbie said "..it did not answer my original question which required creating clouds with arc...".
I was just trying to answer him, but was trying to point out that using arc() would be inflexible and not recommended.
Sorry for the misinterpretation.
I should just rewrite my response to say: "Ditto what #markE said" :)
Related
This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 1 year ago.
If run below code and DOM, my browser is renderred double all height value.
First, I tested below code in about:blank.
In html:
...
<canvas id="canvasArea" style="
width: 500px;
height: 500px;
background-color: E0E0E0;
"></canvas>
...
and In js:
let cv = document.getElementById("canvasArea");
let cvArea = cv.getContent('2d');
cvArea.fillRect(10, 10, 50, 50); // I was thinking this Rect is square
cvArea.fillRect(60, 10, 50, 25); // and this Rect is long rectangle
I was thinking first rect will be draw square.
But first is long rectangle.
Why does this happen?
JS Canvases are not aware of dimensions set by CSS.
Use HTML attributes or set using JS.
let cv = document.getElementById("canvasArea");
let cvArea = cv.getContext('2d');
cvArea.fillRect(10, 10, 50, 50); // I was thinking this Rect is square
//cvArea.fillRect(60, 10, 50, 25); // and this Rect is long rectangle
<canvas id="canvasArea" width="500" height="500" style="
background-color: #E0E0E0;
"></canvas>
I have a WWWeb page with stacked <canvas> elements. The goal is to draw something persistent in the lower canvas and draw, clear, and redraw, repeatedly, in the upper canvas. According to w3.org and this StackOverflow article (How do I make a transparent canvas in html5?), canvas elements are, by default, transparent. What I am seeing is that not only are they not transparent, but that overlaying via z-index is not working. Here's a "vanilla" version of the page's code (complete and used to generate the images):
<html>
<head>
<title>Canvas Stack</title>
<script>
function doStuff() {
drawStuff(document.getElementById("lowerCanvas"), 0, 1);
drawStuff(document.getElementById("upperCanvas"), 1, 0);
}
function drawStuff(cvs, p0X, p1X) {
var ctx = cvs.getContext("2d");
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.strokeStyle = cvs.style.color;
ctx.beginPath();
ctx.moveTo(p0X * cvs.width, 0);
ctx.lineTo(p1X * cvs.width, cvs.height);
ctx.stroke();
}
</script>
</head>
<body onload="doStuff();" style="border:solid;">
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
</body>
</html>
and here's the result:
If I swap the order of the canvas elements
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />
the result is
It seems as if the z-index has been ignored and that the order of declaration has primacy.
What I want is
(synthetic image)
The behavior is identical in Chrome, Edge, Firefox, and Internet Explorer under Windows 10. That makes me confident that I'm just missing some detail rather than experiencing an anomaly. However, I'm getting a flattened forehead from whacking my head against a wall and would really appreciate some guidance, here.
Thank you, all!
Some notes (maybe irrelevant; maybe not):
style="position:absolute;... (without the left and top entries) seems to do the same thing as style="left:0;position:absolute;top:0;...
In similar fashion, style="position:inherit;... is probably necessary if the canvas is to reside within a table's <td> and that <td> is other than the first one in a <tr>.
<html>
<head>
<title>Canvas Stack</title>
<script>
function doStuff() {
drawStuff(document.getElementById("lowerCanvas"), 0, 1);
drawStuff(document.getElementById("upperCanvas"), 1, 0);
}
function drawStuff(cvs, p0X, p1X) {
var ctx = cvs.getContext("2d");
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.strokeStyle = cvs.style.color;
ctx.beginPath();
ctx.moveTo(p0X * cvs.width, 0);
ctx.lineTo(p1X * cvs.width, cvs.height);
ctx.stroke();
}
</script>
</head>
<body onload="doStuff();" style="border:solid;">
<div style="position:relative;min-height:200px">
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:absolute;top:0;width:300px;z-index:0;"></canvas>
<canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:absolute;top:0;width:300px;z-index:1;"></canvas>
</body>
</html>
You need to close your canvas elements explicitly. Simply close it with:
<canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;"></canvas>
instead of the embedded close "/>"
I also enclosed them in a div and used position:absolute so that they actually overlap...
This question already has answers here:
html5: copy a canvas to image and back
(3 answers)
Closed 9 years ago.
how to take screenshot of canvas?
or How create image, which will consist of image + free zone , located on canvas?
It depends on your framework but basically you can use canvas.toDataURL()
Here is a complete example
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();
</script>
</body>
</html>
dataUrl will contains the image and you can save it wherever you want.
It depends what you want to do, the easiest way is to use toDataUrl on your canvas.
canvas.toDataURL('png')
This will encode your canvas to base64, then you could use it in a download link like this
<a href="%dataURI%" download>download</a>
Or just stick it back into the dom in an image tag.
You can then write a controller which is more backend using what ever language to convert that base64 to an image file if you wanted to store an actual copy off the image.
See this post for more info
How to save a PNG image server-side, from a base64 data string
I believe I have a syntax error, but I have tried everything and can't figure this out. I am using the Raphael Javascript vector graphics library, and trying to draw a black line from 170, 170 to 150, 150, but nothing is being displayed. Can anyone tell why?
<html>
<head>
<script src="raphael.js"></script>
<script src="jquery-1.7.2.js"></script>
</head>
<body>
<div id="sample-2" style=" background-color:blue; width:500px;"></div>
<script type="text/javascript">
var paper = Raphael("sample-2", 900, 500);
//var curvePath = paper.path("M100,100 L400,400 C500,400 500,100 400,100");
//curvePath.attr({fill:"blue", stroke:"black"});
//var circle = paper.circle(175, 175, 50);
var newpath = paper.path({type:"path", path:"M170, 170 L150, 150", stroke:"black"});
//circle.attr({"fill": "orange"});
//circle.attr({"stroke": "black"});
</script>
</body>
</html>
You're misusing the Paper.path() constructor. Call it with a single string argument, representing the path string:
var newpath = paper.path("M170, 170 L150, 150");
If you wish to change the path's attributes, e.g. stroke color, fill, fonts use the attr() method, like so:
newpath.attr({
'stroke' : 'black',
'stroke-width' : 3
});
Raphaël Reference:
Paper.path()
Element.attr()
I am making a loading spinner with html5 canvas. I have my graphic on the canvas but when i rotate it the image rotates off the canvas. How do I tell it to spin the graphic on its center point?
<!DOCTYPE html>
<html>
<head>
<title>Canvas test</title>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas && drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
//Load the image object in JS, then apply to canvas onload
var myImage = new Image();
myImage.onload = function() {
context.drawImage(myImage, 0, 0, 27, 27);
}
myImage.src = "img/loading.png";
context.rotate(45);
}
}
</script>
</head>
<body>
<canvas id="myDrawing" width="27" height="27">
</canvas>
</body>
</html>
Here is the complete working example:)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Cog</title>
<script type="text/javascript">
var cog = new Image();
function init() {
cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path
setInterval(draw,10);
}
var rotation = 0;
function draw(){
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.clearRect(0,0,27,27);
ctx.translate(13.5,13.5); // to get it in the origin
rotation +=1;
ctx.rotate(rotation*Math.PI/64); //rotate in origin
ctx.translate(-13.5,-13.5); //put it back
ctx.drawImage(cog,0,0);
ctx.restore();
}
init();
</script>
</head>
<body>
<canvas width="27" height="27" id="myCanvas"></canvas>
</body>
</html>
rotate turns the canvas(?) around your current position, which is 0, 0 to start. you need to "move" to your desired center point, which you can accomplish with
context.translate(x,y);
after you move your reference point, you want to center your image over that point. you can do this by calling
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
this tells the browser to start drawing the image from above and to the left of your current reference point, by have the size of the image, whereas before you were starting at your reference point and drawing entirely below and to the right (all directions relative to the rotation of the canvas).
since your canvas is the size of your image, your call to translate will use the same measurement, (27/2), for x and y coordinates.
so, to put it all together
// initialization:
context.translate(27/2, 27/2);
// onload:
context.rotate(Math.PI * 45 / 180);
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
edit: also, rotation units are radians, so you'll need to translate degrees to radians in your code.
edits for rearranging stuff.
For anyone else looking into something like this, you might want to look at this script which does exactly what was originally being requested:
http://projects.nickstakenburg.com/spinners/
You can find the github source here:
https://github.com/staaky/spinners
He uses rotate, while keeping a cache of rectangles which slowly fade out, the older they are.
I find another way to do html loading spinner. You can use sprite sheet animation. This approach can work both by html5 canvas or normal html/javascript/css. Here is a simple way implemented by html/javascript/css.
It uses sprite sheet image as background. It create a Javascript timer to change the background image position to control the sprite sheet animation. The example code is below. You can also check the result here: http://jmsliu.com/1769/html-ajax-loading-spinner.html
<html>
<head><title></title></head>
<body>
<div class="spinner-bg">
<div id="spinner"></div>
</div>
<style>
.spinner-bg
{
width:44px;
height:41px;
background: #000000;
}
#spinner
{
width: 44px;
height: 41px;
background:url(./preloadericon.png) no-repeat;
}
</style>
<script>
var currentbgx = 0;
var circle = document.getElementById("spinner");
var circleTimer = setInterval(playAnimation, 100);
function playAnimation() {
if (circle != null) {
circle.style.backgroundPosition = currentbgx + "px 0";
}
currentbgx -= 44; //one frame width, there are 5 frame
//start from 0, end at 176, it depends on the png frame length
if (currentbgx < -176) {
currentbgx = 0;
}
}
</script>
</body>