I'm just started working with Leap Motion (it is so much fun). The Leap works mainly with vectors. And now I want to create a program where I can visualise where is a vector pointing. The only way I can imagine doing this is by using a small image which appears when this fuction is on and positioning by using the img.style.left , img.style.top instructions. Any other ideas?
If your goal is to represent 2D Vectors,
You can use canvas to draw lines.
A canvas is like a div but you can draw whatever you want in it, I don't know anything about Leap Motion but if you want to draw lines and circles at precise coordinates, it may be a good solution instead of working with the DOM itself.
The JS part looks like this :
var canvas = document.getElementById('my-canvas');
var ctx = canvas.getContext('2d');
//For exemple here is how to draw a rectangle
//fillStyle support all valid css color
ctx.fillStyle = "rgba(50, 255, 24, 0.7)";
//Create the rectangle, with (startX, startY, height, width)
ctx.fillRect(20, 15, 50, 50);
ctx.beginPath(); //Tells canvas we want to draw
ctx.moveTo(250,250); //Moves the cursor to the coordinates (250, 250);
ctx.lineTo(75, 84); //Draws a line from the cursor (250, 250) to (75, 84);
ctx.closePath(); //Tells canvas to 'close' the drawing
ctx.strokeStyle = "red";
ctx.stroke(); //Draws the line stroke
And the HTML is simply :
<canvas id="my-canvas" height="500px" width="500px">
Here is the text displayed when the browser doesnt support canvas.
</canvas>
I made a jsfiddle to show you what simple things we can do with canvas.
http://jsfiddle.net/pq8g0bf0/1/
A nice website to learn canvas : http://www.html5canvastutorials.com/tutorials/html5-canvas-element/
Since it's javascript, you are free to do calculations for your vectors coordinates, addding eventListeners etc ...
Related
Say I have drawn a circle on a canvas that has something else drawn on it that stops me from clearing the canvas - due to the other element being randomly generated
var circleX = 50;
var circleY = 10;
var moveCircX = 2;
var moveCircY = 3;
function createCirc(){
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(circleX, circleY, 10, 0, Math.PI*2, true);
ctx.fill();
}
function circMove(){
circleY = (circleY + circMoveY)
//then validation to stop it from being drawn of the canvas
So what I'm trying to do is move the circle but clear the previous drawn circle from the canvas. So is there a solution to clearing the circle or would it be easier to create a sprite that replicates the circle?
Since your background isn't changing, the simplest strategy is to copy the background before you first draw your circle, then draw your circle. When you're moving, redraw that part of the background from the copy you kept, then draw your circle in the new place.
An efficient way to do that is to use getImageData and putImageData.
So, (my javascript is rusty, so this may not be perfect. Feel free to correct any mistakes), before the first time you createCirc, simply do:
imageData = ctx.getImageData(0,0, ctx.canvas.width, ctx.canvas.height)
And, in your circMove function, before you move and redraw the circle, you want:
ctx.putImageData(imageData, circleX, circleY, circleX, circleY, 2*circle_radius, 2*circle_radius)
(You don't define circle_radius, but I'm sure you must have a similar value. I'm using 2x the radius to presumably be the size of the image that is drawn.)
I want to use an image like this on canvas:
The user will "paint and fill" the image, but not on top of the outline.
The problem is:
If I put behind the canvas, the paint will cover the outline.
If I put over the canvas the image block canvas interaction.
Can you help me guys?
Use compositing mode "destination-over" to draw behind existing content (from image, vectors etc.). It's necessary that the existing content provide an alpha channel or composition won't work. If there is no alpha-channel you can convert inverse luma / matte (the white) to alpha channel.
// a quick-n-dirty demo
var ctx = c.getContext("2d");
ctx.lineWidth = 10;
ctx.moveTo(100, 0); ctx.lineTo(150, 150); ctx.stroke();
ctx.fillStyle = "#09f";
// KEY: composite mode -
ctx.globalCompositeOperation = "destination-over";
// draw behind the line
c.onmousemove = function(e) {
ctx.fillRect(e.clientX - 10, e.clientY - 10, 20, 20);
};
body {margin:0}
canvas {border:#777 solid 1px}
<canvas id="c"></canvas>
Here is the example of drawImage function. You can draw any preloaded image onto canvas. You can also try to place the <img> overlay in front of the canvas and disable mouse events for it using pointer-events: none CSS property.
I have a simple task - I need to draw one rectangle, rotate and copy it and clone its rotated version. I try to do it like so:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
//1. rotate canvas
ctx.rotate(-30 * Math.PI / 180);
ctx.rect(10, 60, 80, 40);
ctx.stroke();
//2. copy rotated rectangle
var img = ctx.getImageData(0, 0, 140, 140);
//3. rotate back
ctx.rotate(30 * Math.PI / 180);
//4. draw rotated version of the rectangle
ctx.putImageData(img, 80, 100);
The idea is very simple. At first step I draw a rectangle, at the second step I rotate my canvas and do what I think is a snapshot (or create a copy of my rotated rectangle), at the third step I rotate my canvas back (so my rotated rectangle must not be rotated any longer) and at the final step I add a new object to the canvas - the copy of the rotated rectangle. But this is what I get:
Whereas I expected to get this picture:
What am I doing wrong and how can I get the desired result?
"putImageData is not affected by the transformation matrix"
See here: putImageData() on rotated canvas work incorrect
Instead, if you want a complex image to be copied into memory, and then repeatedly drawn on the screen at different angles, you might consider using a temporary canvas. This post gives a good example:
How to rotate the existing content of HTML5 canvas?
If you need to create multiple image sprites, and creating multiple canvases won't do, consider drawing your sprite to an appropriately sized temporary canvas, and then convert the contents of the temporary canvas to an image using canvas.toDataUrl
The post gives a nice example:
https://davidwalsh.name/convert-canvas-image
I am trying to make a 2d top-down game in Javascript at the moment. I've currently got a day/night system working where a black rectangle gradually becomes more opaque (as the day goes on) before it finally is fully opaque, simulating the peak of the night where the player can not see.
I want to implement an artificial light system, where the player could use a torch that will illuminate a small area in-front of them. However, my problem is that I don't seem to be able to find a way to 'cut out' a shape from my opaque rectangle. By cutting out a shape, it would look like the player has a torch.
Please find an example mock-up image I made below to show what I mean.
http://i.imgur.com/VqnTwoR.png
Obviously the shape shouldn't be as roughly drawn as that :)
Thanks for your time,
Cam
EDIT: The code used to draw the rectangle is as follows:
context.fillStyle = "#000033";
context.globalAlpha = checkLight(gameData.worldData.time);
context.fillRect(0, 0, 512, 480);
//This is where you have to add the cut out triangles for light!
context.stroke();
Instead of drawing a rectangle over the scene to darken it when the "light" is on, instead draw an image with the "lit" area completely transparent and the rest of the "dark" area more opaque.
One way is to use declare a triangular clipping area and draw your revealed scene. The scene would display only inside the defined clipping area.
Example code and a Demo:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var offset = 50;
var img = new Image();
img.onload = function() {
knockoutAndRefill(50,100,300,50,75,350);
};
img.src = 'http://guideimg.alibaba.com/images/trip/1/03/18/7/landscape-arch_68367.jpg';
function knockoutAndRefill(x0,y0,x1,y1,x2,y2){
context.save();
context.fillStyle='black';
context.fillRect(0,0,canvas.width,canvas.height);
context.beginPath();
context.moveTo(x0,y0);
context.lineTo(x1,y1);
context.lineTo(x2,y2);
context.closePath();
context.clip();
context.drawImage(img,0,0);
context.restore();
}
<canvas id=myCanvas width=500 height=400>
I need to draw a dynamic donut chart - something similar to -
http://194.90.28.56/~dev1/t.jpg
The green part indicates the percentage (in this case 27%) - it must be dynamic.
I think I need to do something like - Android - How to draw an arc based gradient
But with JS..
Thanks.
Great question. Gradients along paths in canvas are hard. The easiest way is to fudge it.
Instead of thinking of your image as a gradient that follows a circular path, think of it as two linear gradients.
One on the left side, going from green to gray, top to bottom.
The other on the right side, going from white to gray, top to bottom.
Imagine a square made of those two gradients:
Now imagine a circle cutting through:
That's all you gotta do.
To "cut" through like that its easiest to use clipping regions, so I've made an example doing that.
Here's the live example: http://jsfiddle.net/simonsarris/Msdkv/
Code below! Hope that helps.
var greenPart = ctx.createLinearGradient(0,0,0,100);
greenPart.addColorStop(0, 'palegreen');
greenPart.addColorStop(1, 'lightgray');
var whitePart = ctx.createLinearGradient(0,0,0,100);
whitePart.addColorStop(0, 'white');
whitePart.addColorStop(1, 'lightgray');
var width = 20;
ctx.lineWidth = width;
// First we make a clipping region for the left half
ctx.save();
ctx.beginPath();
ctx.rect(-width, -width, 50+width, 100 + width*2);
ctx.clip();
// Then we draw the left half
ctx.strokeStyle = greenPart;
ctx.beginPath();
ctx.arc(50,50,50,0,Math.PI*2, false);
ctx.stroke();
ctx.restore(); // restore clipping region to default
// Then we make a clipping region for the right half
ctx.save();
ctx.beginPath();
ctx.rect(50, -width, 50+width, 100 + width*2);
ctx.clip();
// Then we draw the right half
ctx.strokeStyle = whitePart;
ctx.beginPath();
ctx.arc(50,50,50,0,Math.PI*2, false);
ctx.stroke();
ctx.restore(); // restore clipping region to default