Related
I am trying to solve a question which has been bugging me for a while, can someone explain to me how to make the *red rectangle face/aim towards my mouse and explain to me how it works it would be awesome!!!
Here is the Fiddle
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var player = {
x: 200,
y: 200,
}
drawPlayer = function(something) {
context.beginPath();
context.fillStyle = "blue";
context.arc(something.x, something.y, 30, 0, 2 * Math.PI);
context.fill();
context.fillStyle = "red";
context.fillRect(something.x, something.y - 10, 50, 20);
context.restore();
}
update = function() {
context.clearRect(0, 0, 500, 500)
drawPlayer(player);
}
setInterval(update, 20);
<canvas id="canvas" style="outline: 1px solid #ccc" width="500" height="500"></canvas>
Use context.translate to translate coordinates to the center of your player and then context.rotate to rotate the rectangle.
To find the angle between the mouse position and the center of the player you can use Math.atan2 function.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var player = {
x: 200,
y: 200,
}
drawPlayer = function(something, angle) {
context.clearRect(0, 0, 500, 500);
context.beginPath();
context.fillStyle = "blue";
context.arc(something.x, something.y, 30, 0, 2 * Math.PI);
context.fill();
// save the untranslated context
context.save();
context.beginPath();
// move the rotation point to the center of the player
context.translate(something.x, something.y);
context.rotate(angle);
context.fillStyle = "red";
// note that coordinates are translated,
// so 0 is player.x and -10 is player.y - 10
context.fillRect(0, - 10, 50, 20);
// restore the context to its untranslated state
context.restore();
}
drawPlayer(player, 0);
document.onmousemove = function(e) {
var angle = Math.atan2(e.pageY - player.y, e.pageX - player.x)
drawPlayer(player, angle);
}
<canvas id="canvas" style="outline: 1px solid #ccc" width="500" height="500"></canvas>
I am trying to make a screen following the player so that the player is in the middle of the screen. I have already made it in another game, but here it doesn't work. Here is my code :
var c = document.getElementById("main");
var ctx = c.getContext("2d");
var screen = document.getElementById("screen").getContext("2d");
var WhatUSeeWidth = document.getElementById("screen").width;
var WhatUSeeHeight = document.getElementById("screen").height;
ctx.beginPath();
for (i = 0; i < 100; i ++) {
if (i % 2) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "blue";
}
ctx.fillRect(0, i * 100, 500, 100);
}
var player = {
x : 700,
y : 800
}
setInterval(tick, 100);
function tick() {
screen.beginPath();
screen.drawImage(c, player.x - WhatUSeeWidth / 2, player.y - WhatUSeeHeight / 2, WhatUSeeWidth, WhatUSeeHeight, 0, 0, WhatUSeeWidth, WhatUSeeHeight);
}
canvas {
border: 2px solid black;
}
<canvas id="main" width="500" height="500"h></canvas>
<canvas id="screen" width="500" height="500"></canvas>
I want to draw The Blue and red canvas in The "screen" canvas Using drawImage
Ok , from your comment I understood what you are looking for. But the problem is that you probably start by an example without having understood. I try to give you my interpretation of what you do , but you should look for a good guide that starts with the basics and deepen animations (for example this: http://www.html5canvastutorials.com/).
HTML
<canvas id="canvasLayer" width="500" height="500"></canvas>
Javascript
var canvas = document.getElementById("canvasLayer");
var context = canvas.getContext("2d");
var WhatUSeeWidth = document.getElementById("canvasLayer").width;
var WhatUSeeHeight = document.getElementById("canvasLayer").height;
var player = {
x : 0,
y : 0
}
function drawBackground() {
for (i = 0; i < 100; i ++) {
if (i % 2) {
context.fillStyle = "red";
}
else {
context.fillStyle = "blue";
}
context.fillRect(0, i * 100, 500, 100);
}
}
function playerMove() {
context.beginPath();
var radius = 5;
context.arc(player.x, player.y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();
}
setInterval(tick, 100);
function tick() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBackground();
player.x++;
player.y++;
playerMove();
}
This is the JSFiddle.
EDIT WITH THE CORRECT ANSWER
The error is in the position of the object "player". It is located outside of the canvas, width:500 height:500 and the "player" is in position x:700 y:800.
Changing the position of the player your copy will appear.
var player = {
x : 50,
y : 50
}
Here the jsfiddle example.
I made a cylinder gauge, very similar to this one:
It is drawn using about 7 or so functions... mine is a little different. It is very fleixble in that I can set the colors, transparency, height, width, whether there is % text shown and a host of other options. But now I have a need for the same thing, but all rotated 90 deg so that I can set the height long and the width low to generate something more like this:
I found ctx.rotate, but no mater where it goes all the shapes fall apart.. ctx.save/restore appears to do nothing, I tried putting that in each shape drawing function. I tried modifying, for example, the drawOval function so that it would first rotate the canvas if horizontal was set to one; but it appeared to rotate it every single iteration, even with save/restore... so the top cylinder would rotate and the bottom would rotate twice or something. Very tough to tell what is really happening. What am I doing wrong? I don't want to duplicate all this code and spend hours customizing it, just to produce something I already have but turned horizontal. Erg! Help.
Option 1
To rotate everything just apply a transform to the element itself:
canvas.style.transform = "rotate(90deg)"; // or -90 depending on need
canvas.style.webkitTransform = "rotate(90deg)";
Option 2
Rotate context before drawing anything and before using any save(). Unlike the CSS version you will first need to translate to center, then rotate, and finally translate back.
You will need to make sure width and height of canvas is swapped before this is performed.
ctx.translate(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5); // center
ctx.rotate(Math.PI * 0.5); // 90°
ctx.translate(-ctx.canvas.width * 0.5, -ctx.canvas.height * 0.5);
And of course, as an option 3, you can recalculate all your values to go along the other axis.
Look at the rotate function in this example. You want to do a translation to the point you want to rotate around.
example1();
example2();
function rotate(ctx, degrees, x, y, fn) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees * (Math.PI / 180));
fn();
ctx.restore();
}
function rad(deg) {
return deg * (Math.PI / 180);
}
function example2() {
var can = document.getElementById("can2");
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
function drawBattery() {
var percent = 60;
ctx.beginPath();
ctx.arc(35,50, 25,0,rad(360));
ctx.moveTo(35+percent+25,50);
ctx.arc(35+percent,50,25,0,rad(360));
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgba(0,255,0,.5)";
ctx.arc(35,50,25,0,rad(360));
ctx.arc(35+percent,50,25,0,rad(360));
ctx.rect(35,25,percent,50);
ctx.fill();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "#666666";
ctx.moveTo(135,25);
ctx.arc(135,50,25, rad(270), rad(269.9999));
//ctx.moveTo(35,75);
ctx.arc(35,50,25,rad(270),rad(90), true);
ctx.lineTo(135,75);
ctx.stroke();
}
drawBattery();
can = document.getElementById("can3");
ctx = can.getContext('2d');
w = can.width;
h = can.height;
rotate(ctx, -90, 0, h, drawBattery);
}
function example1() {
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var color1 = "#FFFFFF";
var color2 = "#FFFF00";
var color3 = "rgba(0,155,255,.5)"
var text = 0;
function fillBox() {
ctx.save();
ctx.fillStyle = color3;
ctx.fillRect(0, 0, can.width / 2, can.height);
ctx.restore();
}
function drawBox() {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = ctx.fillStyle = color1;
ctx.rect(10, 10, 50, 180);
ctx.font = "30px Arial";
ctx.fillText(text, 25, 45);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = color2;
ctx.lineWidth = 10;
ctx.moveTo(10, 10);
ctx.lineTo(60, 10);
ctx.stroke();
ctx.restore();
}
fillBox();
rotate(ctx, 90, can.width, 0, fillBox);
text = "A";
drawBox();
color1 = "#00FFFF";
color2 = "#FF00FF";
text = "B";
rotate(ctx, 90, can.width, 0, drawBox);
centerRotatedBox()
function centerRotatedBox() {
ctx.translate(can.width / 2, can.height / 2);
for (var i = 0; i <= 90; i += 10) {
var radians = i * (Math.PI / 180);
ctx.save();
ctx.rotate(radians);
ctx.beginPath();
ctx.strokeStyle = "#333333";
ctx.rect(0, 0, 50, 50)
ctx.stroke();
ctx.restore();
}
}
}
#can,
#can2,
#can3 {
border: 1px solid #333333
}
<canvas id="can" width="200" height="200"></canvas>
<canvas id="can2" width="200" height="100"></canvas>
<canvas id="can3" width="100" height="200"></canvas>
I've got some code which draws a rectangle on a canvas, but I want that rectangle to change color when I hover the mouse over it.
The problem is after I've drawn the rectangle I'm not sure how I select it again to make the adjustment.
What I want to do:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
$('c.[rectangle]').hover(function(this){
this.fillStyle = 'red';
this.fill();
});
You can't do this out-of-the-box with canvas. Canvas is just a bitmap, so the hover logic has to be implemented manually.
Here is how:
Store all the rectangles you want as simple object
For each mouse move on the canvas element:
Get mouse position
Iterate through the list of objects
use isPointInPath() to detect a "hover"
Redraw both states
Example
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
rects = [
{x: 10, y: 10, w: 200, h: 50},
{x: 50, y: 70, w: 150, h: 30} // etc.
], i = 0, r;
// render initial rects.
while(r = rects[i++]) ctx.rect(r.x, r.y, r.w, r.h);
ctx.fillStyle = "blue"; ctx.fill();
canvas.onmousemove = function(e) {
// important: correct mouse position:
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0, r;
ctx.clearRect(0, 0, canvas.width, canvas.height); // for demo
while(r = rects[i++]) {
// add a single rect to path:
ctx.beginPath();
ctx.rect(r.x, r.y, r.w, r.h);
// check if we hover it, fill red, if not fill it blue
ctx.fillStyle = ctx.isPointInPath(x, y) ? "red" : "blue";
ctx.fill();
}
};
<canvas/>
This is a stable code in base of #K3N answer. The basic problem of his code is because when one box is over the another the two may get mouse hover at same time. My answer perfectly solves that adding a 'DESC' to 'ASC' loop.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
var map = [
{x: 20, y: 20, w: 60, h: 60},
{x: 30, y: 50, w: 76, h: 60}
];
var hover = false, id;
var _i, _b;
function renderMap() {
for(_i = 0; _b = map[_i]; _i ++) {
ctx.fillStyle = (hover && id === _i) ? "red" : "blue";
ctx.fillRect(_b.x, _b.y, _b.w, _b.h);
}
}
// Render everything
renderMap();
canvas.onmousemove = function(e) {
// Get the current mouse position
var r = canvas.getBoundingClientRect(),
x = e.clientX - r.left, y = e.clientY - r.top;
hover = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = map.length - 1, b; b = map[i]; i--) {
if(x >= b.x && x <= b.x + b.w &&
y >= b.y && y <= b.y + b.h) {
// The mouse honestly hits the rect
hover = true;
id = i;
break;
}
}
// Draw the rectangles by Z (ASC)
renderMap();
}
<canvas id="canvas"></canvas>
You may have to track the mouse on the canvas using JavaScript and see when it is over your rectangle and change the color then. See code below from my blog post
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="700" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var myRect={x:150, y:75, w:50, h:50, color:"red"};
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = myRect.color;
ctx.fillRect(myRect.x, myRect.y, myRect.w, myRect.h);
c.addEventListener("mousemove", function(e){
if ((e.clientX>=myRect.x)&(e.clientX<=myRect.x+myRect.w)&(e.clientY>=myRect.y)&(e.clientY<=myRect.y+myRect.h)){
myRect.color = "green";}
else{
myRect.color = "red";}
updateCanvas();
}, false);
function updateCanvas(){
ctx.fillStyle = myRect.color;
ctx.fillRect(myRect.x, myRect.y, myRect.w, myRect.h);
}
</script>
</body>
</html>
I believe this is a slightly more in-depth answer that would work better for you, especially if you are interested in game design with the canvas element.
The main reason this would work better for you is because it focuses more on an OOP (object orientated programming) approach. This allows for objects to be defined, tracked and altered at a later time via some event or circumstance. It also allows for easy scaling of your code and in my opinion is just more readable and organized.
Essentially what you have here is two shapes colliding. The cursor and the individual point / object it hovers over. With basic squares, rectangles or circles this isn't too bad. But, if you are comparing two more unique shapes, you'll need to read up more on Separating Axis Theorem (SAT) and other collision techniques. At that point optimizing and performance will become a concern, but for now I think this is the optimal approach.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
const cx = width / 2;
const cy = height / 2;
const twoPie = Math.PI * 2;
const points = []; // This will be the array we store our hover points in later
class Point {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r || 0;
}
}
class HoverPoint extends Point {
constructor(x, y, r, color, hoverColor) {
super(x, y, r);
this.color = color;
this.hoverColor = hoverColor;
this.hovered = false;
this.path = new Path2D();
}
draw() {
this.hovered ? ctx.fillStyle = this.hoverColor : ctx.fillStyle = this.color;
this.path.arc(this.x, this.y, this.r, 0, twoPie);
ctx.fill(this.path);
}
}
class Cursor extends Point {
constructor(x, y, r) {
super(x, y, r);
}
collisionCheck(points) {
// This is the method that will be called during the animate function that
// will check the cursors position against each of our objects in the points array.
document.body.style.cursor = "default";
points.forEach(point => {
point.hovered = false;
if (ctx.isPointInPath(point.path, this.x, this.y)) {
document.body.style.cursor = "pointer";
point.hovered = true;
}
});
}
}
function createPoints() {
// Create your points and add them to the points array.
points.push(new HoverPoint(cx, cy, 100, 'red', 'coral'));
points.push(new HoverPoint(cx + 250, cy - 100, 50, 'teal', 'skyBlue'));
// ....
}
function update() {
ctx.clearRect(0, 0, width, height);
points.forEach(point => point.draw());
}
function animate(e) {
const cursor = new Cursor(e.offsetX, e.offsetY);
update();
cursor.collisionCheck(points);
}
createPoints();
update();
canvas.onmousemove = animate;
There is one more thing that I would like to suggest. I haven't done tests on this yet but I suspect that using some simple trigonometry to detect if our circular objects collide would preform better over the ctx.IsPointInPath() method.
However if you are using more complex paths and shapes, then the ctx.IsPointInPath() method would most likely be the way to go. if not some other more extensive form of collision detection as I mentioned earlier.
The resulting change would look like this...
class Cursor extends Point {
constructor(x, y, r) {
super(x, y, r);
}
collisionCheck(points) {
document.body.style.cursor = "default";
points.forEach(point => {
let dx = point.x - this.x;
let dy = point.y - this.y;
let distance = Math.hypot(dx, dy);
let dr = point.r + this.r;
point.hovered = false;
// If the distance between the two objects is less then their combined radius
// then they must be touching.
if (distance < dr) {
document.body.style.cursor = "pointer";
point.hovered = true;
}
});
}
}
here is a link containing examples an other links related to collision detection
I hope you can see how easily something like this can be modified and used in games and whatever else. Hope this helps.
Below code adds shadow to canvas circle on hovering it.
<html>
<body>
<canvas id="myCanvas" width="1000" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
<script>
var canvas = document.getElementById("myCanvas"),
ctx = canvas.getContext("2d"),
circle = [{
x: 60,
y: 50,
r: 40,
},
{
x: 100,
y: 150,
r: 50,
} // etc.
];
// render initial rects.
for (var i = 0; i < circle.length; i++) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}
canvas.onmousemove = function(e) {
var x = e.pageX,
y = e.pageY,
i = 0,
r;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < circle.length; i++) {
if ((x > circle[i].x - circle[i].r) && (y > circle[i].y - circle[i].r) && (x < circle[i].x + circle[i].r) && (y < circle[i].y + circle[i].r)) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowBlur = 10;
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgb(255,255,255)';
ctx.shadowColor = 'grey';
ctx.stroke();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
} else {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
}
}
};
</script>
</html>
I know this is old, but I am surprised no one has mentioned JCanvas. It adds to the simplicity of animating canvas on events. More documentation here https://projects.calebevans.me/jcanvas/docs/mouseEvents/
<html lang="en">
<head>
<!-- css and other -->
</head>
<body onload="draw();">
<canvas id = "canvas" width="500" height="500" style= border:1px solid #000000;"> </canvas>
<script>
function draw() {
$('canvas').drawRect({
layer: true,
fillStyle:'#333',
x:100, y: 200,
width: 600,
height: 400,
mouseover: function(layer) {
$(this).animateLayer(layer, {
fillStyle: 'green'
}, 1000, 'swing');
}
});
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jcanvas/21.0.1/jcanvas.js" crossorigin="anonymous"></script>
</body>
</html>
Consider this following code:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
c.addEventListener("mouseover", doMouseOver, false);//added event to canvas
function doMouseOver(e){
ctx.fillStyle = 'red';
ctx.fill();
}
DEMO
You could use canvas.addEventListener
var canvas = document.getElementById('canvas0');
canvas.addEventListener('mouseover', function() { /*your code*/ }, false);
It worked on google chrome
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(20,20,150,100);
ctx.stroke();
$(c).hover(function(e){
ctx.fillStyle = 'red';
ctx.fill();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="myCanvas"/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
#map{border: 2px solid black}
</style>
<script>
window.onload = function(){
var canvas = document.getElementById("map"),
c = canvas.getContext("2d");
c.fillStyle = "white";
c.fillRect(0, 0, canvas.width, canvas.height);
/*aisles*/
c.fillStyle = "#009900";
c.fillRect (20,90,20,250);
c.fillRect (70,90,20,250);
c.fillRect (120,90,20,250);
c.fillRect (170,90,20,250);
c.fillRect (220,90,20,250);
c.fillRect (270,90,20,250);
c.fillRect (470,90,20,250);
c.fillRect (520,90,20,250);
c.fillRect (570,90,20,250);
c.fillRect (620,90,20,250);
c.fillRect (670,90,20,250);
c.fillRect (720,90,20,250);
c.fillRect (770,90,20,250);
c.fillStyle = "#0066cc";
c.fillRect (320,90,20,250);
c.fillRect (370,90,20,250);
c.fillRect (420,90,20,250);
/*sections*/
c.fillStyle = "#009900";
c.fillRect (700, 400,200,50);
c.fillRect (850,0,50,300);
c.fillRect (850, 365, 50, 85);
c.fillRect (175,0,555,50);
c.fillRect (0,0,150,50 );
/*section names*/
c.fillStyle = "white";
c.font = "25px Arial";
c.fillText("Dairy" ,45,30);
c.fillText("-----Meat------", 375, 30);
c.fillText("Produce",750, 435);
c.fillText("B", 865, 90);
c.fillText("a", 865, 115);
c.fillText("k", 865, 140);
c.fillText("e", 865, 165);
c.fillText("r", 865, 190);
c.fillText("y", 865,215);
/*aisle numbers*/
c.fillStyle = "white";
c.font = "12px Arial";
c.fillText("16", 22, 210);
c.fillText("15", 72, 210);
c.fillText("14", 122, 210);
c.fillText("13", 172, 210);
c.fillText("12", 222, 210);
c.fillText("11", 272, 210);
c.fillText("10", 322, 210);
c.fillText("9", 376, 210);
c.fillText("8", 426, 210);
c.fillText("7", 476, 210);
c.fillText("6", 526, 210);
c.fillText("5", 576, 210);
c.fillText("4", 626, 210);
c.fillText("3", 676, 210);
c.fillText("2", 726, 210);
c.fillText("1", 776, 210);
c.beginPath();
c.fillStyle = "#009900";
c.arc(550,450,50,0,2,true);
c.fill();
c.beginPath();
c.fillStyle = "#009900";
c.arc(200,450,50,0,2,true);
c.fill();
/*animation sequence*/
var posX = 550;
var posY = 450;
setInterval(function(){
posX += 1;
if(posX >= 540){
posY += -1;
}
c.fillStyle = "red";
c.beginPath();
c.arc(posX,posY, 5, 0, Math.PI*2, false);
c.fill();
},30);
};
</script>
<title>Canvas Map</title>
</head>
<body>
<canvas id="map" width="900" height="450">
<img src="images/sad dinosaur.jpg" />
You will need an updated browser to view this page!
(Chrome,Firefox, etc...)
</canvas>
</body>
</html>
I am trying to make an animation where the red circle will go up and down the aisles(like a maze) without painting over them. I have been trying to use an if/else statement to enforce the directions of the animation. However, when I try and use a second if statement to alter the circles course it starts my circle off at that coordinate point.
This is one way:
Make an array of line coordinates that you wish to animate along.
Calculate waypoints along those lines where you want your circle to visit and save them in an array.
Create an animation loop.
Inside the loop, (1) clear the canvas, (2) draw the isles, (3) draw the circle at the next point in the array.
Here's example code and a Demo:
// canvas and context references
var canvas = document.getElementById("map");
var c = canvas.getContext("2d");
// set some context styles
c.fillStyle = "white";
c.fillRect(0, 0, canvas.width, canvas.height);
c.fillStyle = 'red';
var startTime;
var interval = 50;
// define lines that go up/down the isles
var lines = []
lines.push({
x: 553,
y: 454
});
lines.push({
x: 672,
y: 378
});
lines.push({
x: 815,
y: 368
});
lines.push({
x: 812,
y: 70
});
lines.push({
x: 752,
y: 71
});
lines.push({
x: 761,
y: 365
});
lines.push({
x: 708,
y: 364
});
lines.push({
x: 703,
y: 76
});
lines.push({
x: 204,
y: 72
});
lines.push({
x: 200,
y: 454
});
// calculate points at intervals along each line
// put all the calculated points in a points[] array
var points = [];
var pointIndex = 0;
for (var i = 1; i < lines.length; i++) {
var line0 = lines[i - 1];
var line1 = lines[i];
for (var j = 0; j < 100; j++) {
var dx = line1.x - line0.x;
var dy = line1.y - line0.y;
var x = line0.x + dx * j / 100;
var y = line0.y + dy * j / 100;
points.push({
x: x,
y: y
});
}
}
var img = new Image();
img.onload = start;
img.src = "https://dl.dropboxusercontent.com/u/139992952/multple/isles.png";
function start() {
requestAnimationFrame(animate);
}
function animate(time) {
// continue animating until we've reach the last point in points[]
if (pointIndex < points.length - 1) {
requestAnimationFrame(animate);
}
// get the current point
var p = points[pointIndex];
// clear the canvas
c.clearRect(0, 0, canvas.width, canvas.height);
// draw the isles
c.drawImage(img, 0, 0);
// draw the circle at the current waypoint
c.beginPath();
c.arc(p.x, p.y, 5, 0, Math.PI * 2);
c.closePath();
c.fill();
// increment the pointIndex for the next animation loop
pointIndex++;
}
<canvas id="map" width="900" height="450">
<img src="images/sad dinosaur.jpg" />
You will need an updated browser to view this page!
(Chrome,Firefox, etc...)
</canvas>
It looks to me like what you need is a state machine.
Currently, your shopper keeps track of two variables, which, between them, tell them where it is on the canvas. A state machine essentially introduces a set of tasks that the shopper has to perform, and then the shopper remembers which task it's performing at the moment. The simplest way to handle this would be with a switch statement in your animation callback. An abbreviated version might look like this:
/*animation sequence*/
var posX = 550;
var posY = 450;
var state = "enter";
setInterval(function () {
switch(state) {
case "enter":
if (posY > 390) {
posY -= 1;
} else {
state = "seekProduce";
}
break;
case "seekProduce":
if (posX < 840) {
posX += 1;
} else {
state = "seekBakery";
}
break;
/* ... */
}
}, 4);
I've set up a jsFiddle with something like what you're aiming for. In this case, the shopper has seven tasks, but is only ever doing one of them at a time.
Enter the store (just go up a little bit; when you're done, seek the produce section)
Seek the produce section (go right until you're close to the section; when done, seek the bakery)
Seek the bakery (go up quite a way, then seek the next aisle)
Seek the next aisle (go left a bit, then, if you're high up, go down the aisle, otherwise go up the aisle)
Go up an aisle (go up until you're out of the aisle, then seek the next aisle)
Go down an aisle (go down until you're out of the aisle; if there are no more aisles then seek the exit, otherwise seek the next aisle)
Seek the exit (go down and left until you're at the right spot, then we're done).
Except for leaving the store, each task is set up to go to another task when finished. I use a switch statement to decide how to move, given whatever task is current. My implementation is pretty crude -there's lots of room to improve the code- but it should demonstrate the general idea.