Drawing on canvas, offset is 100px off - javascript

I know it´s not well seen, that you post a link to a code, but I followed this tutorial of making a html drawing canvas app and implemented the source to my wordpress site and everything works fine, except, that all the mouse-click-events seems offset to the left by 100px.
If I open the example html, everything works fine, so I think it has something to do with the parent container css´s or something.
Since I am not very well in js, I thought maybe you can help me figure it out, since I try since a few days now.
This is the tutorial and source code and this is the code of the js file
var drawingApp = (function () {
"use strict";
var canvas,
context,
canvasWidth = 490,
canvasHeight = 220,
colorPurple = "#cb3594",
colorGreen = "#659b41",
colorYellow = "#ffcf33",
colorBrown = "#986928",
outlineImage = new Image(),
crayonImage = new Image(),
markerImage = new Image(),
eraserImage = new Image(),
crayonBackgroundImage = new Image(),
markerBackgroundImage = new Image(),
eraserBackgroundImage = new Image(),
crayonTextureImage = new Image(),
clickX = [],
clickY = [],
clickColor = [],
clickTool = [],
clickSize = [],
clickDrag = [],
paint = false,
curColor = colorPurple,
curTool = "crayon",
curSize = "normal",
mediumStartX = 18,
mediumStartY = 19,
mediumImageWidth = 93,
mediumImageHeight = 46,
drawingAreaX = 111,
drawingAreaY = 11,
drawingAreaWidth = 267,
drawingAreaHeight = 200,
toolHotspotStartY = 23,
toolHotspotHeight = 38,
sizeHotspotStartY = 157,
sizeHotspotHeight = 36,
totalLoadResources = 8,
curLoadResNum = 0,
sizeHotspotWidthObject = {
huge: 39,
large: 25,
normal: 18,
small: 16
},
// Clears the canvas.
clearCanvas = function () {
context.clearRect(0, 0, canvasWidth, canvasHeight);
},
// Redraws the canvas.
redraw = function () {
var locX,
locY,
radius,
i,
selected,
drawCrayon = function (x, y, color, selected) {
context.beginPath();
context.moveTo(x + 41, y + 11);
context.lineTo(x + 41, y + 35);
context.lineTo(x + 29, y + 35);
context.lineTo(x + 29, y + 33);
context.lineTo(x + 11, y + 27);
context.lineTo(x + 11, y + 19);
context.lineTo(x + 29, y + 13);
context.lineTo(x + 29, y + 11);
context.lineTo(x + 41, y + 11);
context.closePath();
context.fillStyle = color;
context.fill();
if (selected) {
context.drawImage(crayonImage, x, y, mediumImageWidth, mediumImageHeight);
} else {
context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, x, y, 59, mediumImageHeight);
}
},
drawMarker = function (x, y, color, selected) {
context.beginPath();
context.moveTo(x + 10, y + 24);
context.lineTo(x + 10, y + 24);
context.lineTo(x + 22, y + 16);
context.lineTo(x + 22, y + 31);
context.closePath();
context.fillStyle = color;
context.fill();
if (selected) {
context.drawImage(markerImage, x, y, mediumImageWidth, mediumImageHeight);
} else {
context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, x, y, 59, mediumImageHeight);
}
};
// Make sure required resources are loaded before redrawing
if (curLoadResNum < totalLoadResources) {
return;
}
clearCanvas();
if (curTool === "crayon") {
// Draw the crayon tool background
context.drawImage(crayonBackgroundImage, 0, 0, canvasWidth, canvasHeight);
// Draw purple crayon
selected = (curColor === colorPurple);
locX = selected ? 18 : 52;
locY = 19;
drawCrayon(locX, locY, colorPurple, selected);
// Draw green crayon
selected = (curColor === colorGreen);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorGreen, selected);
// Draw yellow crayon
selected = (curColor === colorYellow);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorYellow, selected);
// Draw brown crayon
selected = (curColor === colorBrown);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorBrown, selected);
} else if (curTool === "marker") {
// Draw the marker tool background
context.drawImage(markerBackgroundImage, 0, 0, canvasWidth, canvasHeight);
// Draw purple marker
selected = (curColor === colorPurple);
locX = selected ? 18 : 52;
locY = 19;
drawMarker(locX, locY, colorPurple, selected);
// Draw green marker
selected = (curColor === colorGreen);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorGreen, selected);
// Draw yellow marker
selected = (curColor === colorYellow);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorYellow, selected);
// Draw brown marker
selected = (curColor === colorBrown);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorBrown, selected);
} else if (curTool === "eraser") {
context.drawImage(eraserBackgroundImage, 0, 0, canvasWidth, canvasHeight);
context.drawImage(eraserImage, 18, 19, mediumImageWidth, mediumImageHeight);
}
// Draw line on ruler to indicate size
switch (curSize) {
case "small":
locX = 467;
break;
case "normal":
locX = 450;
break;
case "large":
locX = 428;
break;
case "huge":
locX = 399;
break;
default:
break;
}
locY = 189;
context.beginPath();
context.rect(locX, locY, 2, 12);
context.closePath();
context.fillStyle = '#333333';
context.fill();
// Keep the drawing in the drawing area
context.save();
context.beginPath();
context.rect(drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
context.clip();
// For each point drawn
for (i = 0; i < clickX.length; i += 1) {
// Set the drawing radius
switch (clickSize[i]) {
case "small":
radius = 2;
break;
case "normal":
radius = 5;
break;
case "large":
radius = 10;
break;
case "huge":
radius = 20;
break;
default:
break;
}
// Set the drawing path
context.beginPath();
// If dragging then draw a line between the two points
if (clickDrag[i] && i) {
context.moveTo(clickX[i - 1], clickY[i - 1]);
} else {
// The x position is moved over one pixel so a circle even if not dragging
context.moveTo(clickX[i] - 1, clickY[i]);
}
context.lineTo(clickX[i], clickY[i]);
// Set the drawing color
if (clickTool[i] === "eraser") {
//context.globalCompositeOperation = "destination-out"; // To erase instead of draw over with white
context.strokeStyle = 'white';
} else {
//context.globalCompositeOperation = "source-over"; // To erase instead of draw over with white
context.strokeStyle = clickColor[i];
}
context.lineCap = "round";
context.lineJoin = "round";
context.lineWidth = radius;
context.stroke();
}
context.closePath();
//context.globalCompositeOperation = "source-over";// To erase instead of draw over with white
context.restore();
// Overlay a crayon texture (if the current tool is crayon)
if (curTool === "crayon") {
context.globalAlpha = 0.4; // No IE support
context.drawImage(crayonTextureImage, 0, 0, canvasWidth, canvasHeight);
}
context.globalAlpha = 1; // No IE support
// Draw the outline image
context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
},
// Adds a point to the drawing array.
// #param x
// #param y
// #param dragging
addClick = function (x, y, dragging) {
clickX.push(x);
clickY.push(y);
clickTool.push(curTool);
clickColor.push(curColor);
clickSize.push(curSize);
clickDrag.push(dragging);
},
// Add mouse and touch event listeners to the canvas
createUserEvents = function () {
var press = function (e) {
// Mouse down location
var sizeHotspotStartX,
mouseX = e.pageX - this.offsetLeft,
mouseY = e.pageY - this.offsetTop;
if (mouseX < drawingAreaX) { // Left of the drawing area
if (mouseX > mediumStartX) {
if (mouseY > mediumStartY && mouseY < mediumStartY + mediumImageHeight) {
curColor = colorPurple;
} else if (mouseY > mediumStartY + mediumImageHeight && mouseY < mediumStartY + mediumImageHeight * 2) {
curColor = colorGreen;
} else if (mouseY > mediumStartY + mediumImageHeight * 2 && mouseY < mediumStartY + mediumImageHeight * 3) {
curColor = colorYellow;
} else if (mouseY > mediumStartY + mediumImageHeight * 3 && mouseY < mediumStartY + mediumImageHeight * 4) {
curColor = colorBrown;
}
}
} else if (mouseX > drawingAreaX + drawingAreaWidth) { // Right of the drawing area
if (mouseY > toolHotspotStartY) {
if (mouseY > sizeHotspotStartY) {
sizeHotspotStartX = drawingAreaX + drawingAreaWidth;
if (mouseY < sizeHotspotStartY + sizeHotspotHeight && mouseX > sizeHotspotStartX) {
if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.huge) {
curSize = "huge";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "large";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "normal";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.small + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "small";
}
}
} else {
if (mouseY < toolHotspotStartY + toolHotspotHeight) {
curTool = "crayon";
} else if (mouseY < toolHotspotStartY + toolHotspotHeight * 2) {
curTool = "marker";
} else if (mouseY < toolHotspotStartY + toolHotspotHeight * 3) {
curTool = "eraser";
}
}
}
}
paint = true;
addClick(mouseX, mouseY, false);
redraw();
},
drag = function (e) {
if (paint) {
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
redraw();
}
// Prevent the whole page from dragging if on mobile
e.preventDefault();
},
release = function () {
paint = false;
redraw();
},
cancel = function () {
paint = false;
};
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
canvas.addEventListener("mousemove", drag, false);
canvas.addEventListener("mouseup", release);
canvas.addEventListener("mouseout", cancel, false);
// Add touch event listeners to canvas element
canvas.addEventListener("touchstart", press, false);
canvas.addEventListener("touchmove", drag, false);
canvas.addEventListener("touchend", release, false);
canvas.addEventListener("touchcancel", cancel, false);
},
// Calls the redraw function after all neccessary resources are loaded.
resourceLoaded = function () {
curLoadResNum += 1;
if (curLoadResNum === totalLoadResources) {
redraw();
createUserEvents();
}
},
// Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
init = function () {
// Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
canvas = document.createElement('canvas');
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
canvas.setAttribute('id', 'canvas');
document.getElementById('canvasDiv').appendChild(canvas);
if (typeof G_vmlCanvasManager !== "undefined") {
canvas = G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d"); // Grab the 2d canvas context
// Note: The above code is a workaround for IE 8 and lower. Otherwise we could have used:
// context = document.getElementById('canvas').getContext("2d");
// Load images
crayonImage.onload = resourceLoaded;
crayonImage.src = cvtemplateDir+ "/images/crayon-outline.png";
markerImage.onload = resourceLoaded;
markerImage.src = cvtemplateDir+ "/images/marker-outline.png";
eraserImage.onload = resourceLoaded;
eraserImage.src = cvtemplateDir+ "/images/eraser-outline.png";
crayonBackgroundImage.onload = resourceLoaded;
crayonBackgroundImage.src = cvtemplateDir+ "/images/crayon-background.png";
markerBackgroundImage.onload = resourceLoaded;
markerBackgroundImage.src = cvtemplateDir+ "/images/marker-background.png";
eraserBackgroundImage.onload = resourceLoaded;
eraserBackgroundImage.src = cvtemplateDir+ "/images/eraser-background.png";
crayonTextureImage.onload = resourceLoaded;
crayonTextureImage.src = cvtemplateDir+ "/images/crayon-texture.png";
outlineImage.onload = resourceLoaded;
outlineImage.src = cvtemplateDir+ "/images/watermelon-duck-outline.png";
};
return {
init: init
};
}());
It´s being implemented on my website here
This is the code to initialize it, which is being called on the hook:
add_action( 'comment_form_before', 'canvas_comments');
function canvas_comments() {
?>
<div id="canvasDiv" style="width:490px;height:220px;"></div>
<script type="text/javascript">
drawingApp.init();
</script>
<?php
}
EDIT:
Just realized in Firefox it´s offsetting even more, I used chrome

Did you try to get offsetTop and offsetLeft explicitly from the canvas?
You are now accessing offsetTop by this in a listener-function. Are you sure that this points to your canvas and not to something else?

I finally fixed with treeno´s suggestion to use canvas.getBoundingClientRect();
I inserted it at the end of the createUserEvents-function like this:
cancel = function () {
......
var rect = canvas.getBoundingClientRect();
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
.....
},
And finally i replaced every this.OffsetLeft and this.OffsetTop with rect.left and rect.top
Works like a charm!

Related

Canvas collision

I am a new in javascript and trying to find out how to make a collision with ball and plank which will stop the game and alert player with something like "You lost". But I only want red balls to hit the plank and blue to pass on without touching. Here is code that I am working on. (I dont mind if you could help to do collision only with both balls)
var spawnRate = 100;
var spawnRateOfDescent = 2;
var lastSpawn = -10;
var objects = [];
var startTime = Date.now();
function spawnRandomObject() {
var t;
if (Math.random() < 0.50) {
t = "red";
} else {
t = "blue";
}
var object = {
type: t,
x: Math.random() * (canvas.width - 30) + 15,
y: 0
}
objects.push(object);
}
function animate() {
var time = Date.now();
if (time > (lastSpawn + spawnRate)) {
lastSpawn = time;
spawnRandomObject();
}
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
object.y += spawnRateOfDescent;
ctx.beginPath();
ctx.arc(object.x, object.y, 8, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = object.type;
ctx.fill();
}
}
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var paddleHeight = 10;
var paddleWidth = 60;
var paddleY = 480
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;
var leftPressed = false;
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPaddle();
animate();
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 3;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 3;
}
}
setInterval(draw, 10);
Thanks!
If you have an object like this:
let ball = { type: 'red', x: 10, y: 10, width: 10, height: 10 };
You might want to consider adding a method to this to check if it overlaps any other rectangle:
ball.overlapsBall = function( otherBall ){
return !(
otherBall.x + otherBall.width < this.x
&& otherBall.y + otherBall.height < this.y
&& otherBall.y > this.y + this.height
&& otherBall.x > this.x + this.height
);
}
You do this by checking if it does not overlap, which is only true if one box is entirely outside of the other (have a read through the if statement and try to visualise it, its actually rather simple)
In your draw function you could now add a loop to see if any overlap occurs:
var overlap = objects.filter(function( ball ) { return paddle.overlapsBall( ball ) });
You could even place an if statement to check it's type! (The filter will take you entire array of balls and check the overlaps, and remove anything from the array that does not return true. Now you can use overlaps.forEach(function( ball ){ /* ... */}); to do something with all the balls that overlapped your paddle.)
One last thing, if you are planning on doing this with many objects you might want to consider using a simple class like this for every paddle or ball you make:
class Object2D {
constructor(x = 0, y = 0;, width = 1, height = 1){
this.x = x;
this.y = x;
this.width = width;
this.height = height;
}
overlaps( otherObject ){
!( otherObject.x + otherObject.width < this.x && otherObject.y + otherObject.height < this.y && otherObject.y > this.y + this.height && otherObject.x > this.x + this.height );
}
}
This allows you to this simple expression to create a new object that automatically has a method to check for overlaps with similar objects:
var paddle = new Object2D(0,0,20,10);
var ball = new Object2D(5,5,10,10);
paddle.overlaps( ball ); // true!
On top of that, you are ensured that any Object2D contains the values you will need for your calculations. You can check if this object is if the right type using paddle instanceof Object2D (which is true).
Note Please note, as #Janje so continuously points out in the comments below, that we are doing a rectangle overlap here and it might create some 'false positives' for all the pieces of rectangle that aren't the circle. This is good enough for most cases, but you can find the math for other overlaps and collisions easily ith a quick google search.
Update: Simple Implementation
See below for a very simple example of how overlaps work in action:
var paddle = { x: 50, y: 50, width: 60, height: 20 };
var box = { x: 5, y: 20, width: 20, height: 20 };
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
document.body.appendChild( canvas );
canvas.width = 300;
canvas.height = 300;
function overlaps( a, b ){
return !!( a.x + a.width > b.x && a.x < b.x + b.width
&& a.y + a.height > b.y && a.y < b.y + b.height );
}
function animate(){
ctx.clearRect( 0, 0, canvas.width, canvas.height );
ctx.fillStyle = overlaps( paddle, box ) ? "red" : "black";
ctx.fillRect( paddle.x, paddle.y, paddle.width, paddle.height );
ctx.fillRect( box.x, box.y, box.width, box.height );
window.requestAnimationFrame( animate );
}
canvas.addEventListener('mousemove', function(event){
paddle.x = event.clientX - paddle.width / 2;
paddle.y = event.clientY - paddle.height / 2;
})
animate();

How to create Blur Eraser and Blur Drawing effect in JQuery or Javascript?

I want to make blur erasing and blur drawing effect in JQuery or Javascript. I have written the code for erasing the blurred image when I hover it and to reveal the unblurred image. Here's the screenshot.
I am able to erase the blur image when I hover over the image, but I couldn't redraw the blurred image at the same position, may be like after 500ms. How do I redraw the blur again over where I hovered with my mouse?
Here's the code for reference:
<!DOCTYPE html>
<html>
<head>
<title>Blur Testing</title>
<meta name="content-type" content="text/html; charset=UTF-8">
<style>
body {
margin: 0;
}
#item {
background: url("http://i66.tinypic.com/2z6uq9f.jpg");
background-size: cover;
background-position: center;
}
</style>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
</head>
<body>
<canvas id="item"></canvas>
<script>
var canvas = document.getElementById('item');
var ctx = canvas.getContext('2d'),
img = new Image,
radius = 30;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
$('#item').css({
"-webkit-filter": "blur(0px)",
"filter": "blur(0px)"
});
$(img).on('load', function () {
$('#item').mouseover(function (e) {
erase(getXY(e));
}).mousemove(function (e) {
erase(getXY(e));
//setTimeout(redraw(getXY(e)), 400);
});
ctx.drawImage(img, 0, 0);
ctx.globalCompositeOperation = 'destination-out';
});
img.src = 'http://i64.tinypic.com/14mt7yx.jpg';
img.width = window.width;
img.height = window.height;
function getXY(e) {
var r = $('#item')[0].getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top};
}
// function redraw(pos) {
// ctx.globalCompositeOperation = 'source-in';
// ctx.beginPath();
// ctx.arc(pos.x, pos.y, radius, 0, 2 * Math.PI);
// ctx.closePath();
// ctx.fill();
// };
function erase(pos) {
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
</script>
</body>
</html>
The following is a quick modification on Alpha Mask Filter question. I have simply reversed the blur and sharp images. See the linked question for details.
The extra bit to fade out the blur mask
blurMaskFadeCounter += 1;
if((blurMaskFadeCounter % blurMaskFadeRate) === 0){
maskImage.ctx.globalCompositeOperation = "destination-out";
maskImage.ctx.fillStyle = "#000";
maskImage.ctx.globalAlpha = 0.1;
maskImage.ctx.fillRect(0,0,maskImage.width,maskImage.height);
maskImage.ctx.globalAlpha = 1;
maskImage.ctx.globalCompositeOperation = "source-over";
}
Simply draws over the mask with destination-out composition and alpha set low. It is timed to every so many frames to slow it down. If you set alpha below 0.1 you get some pixels that wont completely clear so the frame skipping give a slower response
var imageLoadedCount = 0;
var error = false;
var maskImage;
var flowerImage;
var flowerImageBlur;
/** ImageTools.js begin **/
var imageTools = (function () {
var tools = {
canvas : function (width, height) { // create a blank image (canvas)
var c = document.createElement("canvas");
c.width = width;
c.height = height;
return c;
},
createImage : function (width, height) {
var image = this.canvas(width, height);
image.ctx = image.getContext("2d");
return image;
},
loadImage : function (url, callback) {
var image = new Image();
image.src = url;
image.addEventListener('load', callback);
image.addEventListener('error', callback);
return image;
}
};
return tools;
})();
var mouse;
var demo = function(){
/** fullScreenCanvas.js begin **/
var canvas = (function(){
var canvas = document.getElementById("canv");
if(canvas !== null){
document.body.removeChild(canvas);
}
// creates a blank image with 2d context
canvas = document.createElement("canvas");
canvas.id = "canv";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.zIndex = 1000;
canvas.ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
return canvas;
})();
var ctx = canvas.ctx;
/** fullScreenCanvas.js end **/
/** MouseFull.js begin **/
if(typeof mouse !== "undefined"){ // if the mouse exists
if( mouse.removeMouse !== undefined){
mouse.removeMouse(); // remove previouse events
}
}else{
var mouse;
}
var canvasMouseCallBack = undefined; // if needed
mouse = (function(){
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false,
interfaceId : 0, buttonLastRaw : 0, buttonRaw : 0,
over : false, // mouse is over the element
bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
getInterfaceId : function () { return this.interfaceId++; }, // For UI functions
startMouse:undefined,
mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
function mouseMove(e) {
var t = e.type, m = mouse;
m.x = e.offsetX; m.y = e.offsetY;
if (m.x === undefined) { m.x = e.clientX; m.y = e.clientY; }
m.alt = e.altKey;m.shift = e.shiftKey;m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1];
} else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2];
} else if (t === "mouseout") { m.buttonRaw = 0; m.over = false;
} else if (t === "mouseover") { m.over = true;
} else if (t === "mousewheel") { m.w = e.wheelDelta;
} else if (t === "DOMMouseScroll") { m.w = -e.detail;}
if (canvasMouseCallBack) { canvasMouseCallBack(mouse); }
e.preventDefault();
}
function startMouse(element){
if(element === undefined){
element = document;
}
mouse.element = element;
mouse.mouseEvents.forEach(
function(n){
element.addEventListener(n, mouseMove);
}
);
element.addEventListener("contextmenu", function (e) {e.preventDefault();}, false);
}
mouse.removeMouse = function(){
if(mouse.element !== undefined){
mouse.mouseEvents.forEach(
function(n){
mouse.element.removeEventListener(n, mouseMove);
}
);
canvasMouseCallBack = undefined;
}
}
mouse.mouseStart = startMouse;
return mouse;
})();
if(typeof canvas !== "undefined"){
mouse.mouseStart(canvas);
}else{
mouse.mouseStart();
}
/** MouseFull.js end **/
// load the images and create the mask
if(imageLoadedCount === 0){
imageLoadedCount = 0;
error = false;
maskImage;
flowerImage = imageTools.loadImage("http://www.createjs.com/demos/_assets/art/flowers.jpg", function (event) {
if (event.type === "load") {
imageLoadedCount += 1;
} else {
error = true;
}
})
flowerImageBlur = imageTools.loadImage("http://i.stack.imgur.com/3S5m8.jpg", function () {
if (event.type === "load") {
maskImage = imageTools.createImage(this.width, this.height);
imageLoadedCount += 1;
} else {
error = true;
}
})
}
// set up the canvas
var w = canvas.width;
var h = canvas.height;
var cw = w / 2;
var ch = h / 2;
// calculate time to download image using the MS algorithum. As this code is a highly gaurded secret I have obsficated it for your personal safty.
var calculateTimeToGo= (function(){var b="# SecondQMinuteQHourQDayQWeekQMonthQMomentQTick#.,Some time soon,Maybe Tomorrow.".replace(/Q/g,"#.,# ").split(","),r=Math.random,f=Math.floor,lc=0,pc=0,lt=0,lp=0;var cttg=function(a){if(lc===0){lc=100+r(r()*60);lt=f(r()*40);if(pc===0||r()<(lp/b.length)-0.2){lp=f(r()*b.length);pc=1+f(r()*10)}else{pc-=1}}else{lc-=1}a=lt;if(lp===0){a=lt;if(r()<0.01){lt-=1}}var s=b[lp].replace("#",a);if(a===1){s=s.replace("#","")}else{s=s.replace("#","s")}return s};return cttg})();
// draws circle with gradient
function drawCircle(ctx, x, y, r) {
var gr = ctx.createRadialGradient(x, y, 0, x, y, r)
gr.addColorStop(1, "rgba(0,0,0,0)")
gr.addColorStop(0.5, "rgba(0,0,0,0.08)")
gr.addColorStop(0, "rgba(0,0,0,0.1)")
ctx.fillStyle = gr;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
// draw text
function drawText(ctx, text, size, x, y, c) {
ctx.fillStyle = c;
ctx.strokeStyle = "black";
ctx.lineWidth = 5;
ctx.lineJoin = "round";
ctx.font = size + "px Arial Black";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
if (c !== "black") {
ctx.strokeText(text, x, y + 1);
}
ctx.fillText(text, x, y);
}
// draw the image to fit the current canvas size
function drawImageCentered(ctx, image, x, y) {
var scale = Math.min(w / image.width, h / image.height);
ctx.setTransform(scale, 0, 0, scale, cw, ch);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
// how often to fade blur mask
var blurMaskFadeRate =8; // number of frames between fading mask out
var blurMaskFadeCounter = 0;
// points for filling gaps between mouse moves.
var lastMX,lastMY;
// update function will try 60fps but setting will slow this down.
function update(time){
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore transform
ctx.clearRect(0, 0, w, h); // clear rhe canvas
// have the images loaded???
if (imageLoadedCount === 2) {
// draw the unblured image that will appear at the top
ctx.globalCompositeOperation = "source-over";
drawImageCentered(ctx, flowerImageBlur, cw, ch);
drawText(ctx, "Move mouse over image to unblur.", 20 + Math.sin(time / 100), cw, ch - 30, "White");
// Mask out the parts when the mask image has pixels
ctx.globalCompositeOperation = "destination-out";
drawImageCentered(ctx, maskImage, cw, ch);
// draw the blured image only where the destination has been masked
ctx.globalCompositeOperation = "destination-atop";
drawImageCentered(ctx, flowerImage, cw, ch);
blurMaskFadeCounter += 1;
if((blurMaskFadeCounter % blurMaskFadeRate) === 0){
maskImage.ctx.globalCompositeOperation = "destination-out";
maskImage.ctx.fillStyle = "#000";
maskImage.ctx.globalAlpha = 0.1;
maskImage.ctx.fillRect(0,0,maskImage.width,maskImage.height);
maskImage.ctx.globalAlpha = 1;
maskImage.ctx.globalCompositeOperation = "source-over";
}
// because image has been scaled need to get mouse coords on image
var scale = Math.min(w / flowerImage.width, h / flowerImage.height);
var x = (mouse.x - (cw - (maskImage.width / 2) * scale)) / scale;
var y = (mouse.y - (ch - (maskImage.height / 2) * scale)) / scale;
// draw circle on mask
drawCircle(maskImage.ctx, x, y, 60);
// if mouse is draging then draw some points between to fill the gaps
if (lastMX !== undefined) {
drawCircle(maskImage.ctx, ((x + lastMX) / 2 + x) / 2, ((y + lastMY) / 2 + y) / 2, 60);
drawCircle(maskImage.ctx, (x + lastMX) / 2, (y + lastMY) / 2, 60);
drawCircle(maskImage.ctx, ((x + lastMX) / 2 + lastMX) / 2, ((y + lastMY) / 2 + lastMY) / 2, 60);
}
// save las mouse pos on image
lastMX = x;
lastMY = y;
} else {
// Laoding images so please wait.
drawText(ctx, "Please wait.", 40 + Math.sin(time / 100), cw, ch - 30, "White");
drawText(ctx, "loading images... ", 12, cw, ch, "black")
drawText(ctx, "ETA " + calculateTimeToGo(time), 14, cw, ch + 20, "black")
}
// if not restart the request animation frame
if(!STOP){
requestAnimationFrame(update);
}else{
var can = document.getElementById("canv");
if(can !== null){
document.body.removeChild(can);
}
STOP = false;
}
}
update();
}
var STOP = false; // flag to tell demo app to stop
function resizeEvent() {
var waitForStopped = function () {
if (!STOP) { // wait for stop to return to false
demo();
return;
}
setTimeout(waitForStopped, 200);
}
STOP = true;
setTimeout(waitForStopped, 100);
}
window.addEventListener("resize", resizeEvent);
demo();

"break" in line when drawing with lineTo

This is my first time working with Canvas in Javascript. I'm trying to draw lines, pretty much. Here's what I'm getting in some of the lines (image below). Sometimes the line appears correct, but most of the time like this. As you can see there's a little break in the line where it appears darker. I'm trying to figure out the cause of this but no luck.
Here's my code. It's not very clean as it's still in development:
var canvas = document.getElementById("canvas");
var Point = function(x, y) {
this.startX = x;
this.startY = y;
};
var Interval = function(x, y) {
this.jumpX = x;
this.jumpY = y;
};
var points = [
[
new Point(340, 130), // point start
new Point(220, 130), // end first line
new Point(220, 70), // end second line
new Interval(-10, -10),
],
[
new Point(560, 80), // point start
new Point(660, 80), // end first line
new Point(660, 20), // end second line
new Interval(10, -10),
],
[
new Point(620, 230), // point start
new Point(770, 230), // end first line
new Point(770, 150), // end second line
new Interval(10, -10),
],
[
new Point(620, 230), // point start
new Point(770, 230), // end first line
new Point(770, 150), // end second line
new Interval(10, -10),
],
];
var ctx = canvas.getContext('2d');
ctx.strokeStyle = "#DFC270";
var func = function(points, text, j1, j2) {
var startX = points[0].startX,
startY = points[0].startY,
tempX = startX,
tempY = startY,
line1X = points[1].startX,
line1Y = points[1].startY,
line2X = points[2].startX,
line2Y = points[2].startY;
ctx.lineWidth = 1;
ctx.beginPath();
var inter = function() {
ctx.moveTo(startX, startY);
// console.log(tempY + j1);
if (tempY == line1Y && tempX == line1X) {
if (startX !== line2X) {
startX += j2;
}
if (startY !== line2Y) {
startY += j2;
}
if (startY == line2Y && startX == line2X) {
ctx.beginPath();
ctx.lineWidth = 1;
ctx.arc(startX, startY-j2, 5, 0, 2*Math.PI);
ctx.fillStyle = "#DFC270";
ctx.fill();
ctx.closePath();
ctx.stroke();
clearInterval(inter);
return;
}
} else {
if (startX !== line1X && tempX !== line1X) {
startX += j1;
tempX = startX;
}
if (startY !== line1Y && tempY !== line1Y) {
startY += j1;
tempY = startY;
}
}
window.requestAnimationFrame(inter);
ctx.lineTo(startX, startY);
ctx.stroke();
};
window.requestAnimationFrame(inter);
};
for (var i = 0; i < points.length; ++i) {
var interval = points[i][points[i].length-1];
func(points[i], 'test', interval.jumpX, interval.jumpY);
};
Here's a fiddle I was able to recreate it on too
https://jsfiddle.net/e9vLoken/
This is due to calling beginPath() twice, remove the extra method call under your if-statement:
var func = function(points, text, j1, j2) {
...
ctx.beginPath(); // <-- Already called here
...
var inter = function() {
if (startY == line2Y && startX == line2X) {
//ctx.beginPath(); <-- Remove this
ctx.lineWidth = 1;
...
The trouble is that you never completed the final path stroke when the point where the circle is to be drawn.
at line 68 call the stroke function like this
if (startY == line2Y && startX == line2X ) {
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.arc(startX, startY-j2, 5, 0, 2*Math.PI);
ctx.fillStyle = "#DFC270";
ctx.fill();
ctx.closePath();
ctx.stroke();
clearInterval(inter);
return;

JavaScript stroke fill on click

I'm trying to to make it possible for an image on a canvas to have a box over it with low opacity, to make it be shown that it has been selected. So I need an onclick function, but i'm stuck on what to do. Any advice? I would aslo appreciate if someone could point me in the right direction on how to make the box also pulsate.
var image1 = new Kinetic.Image({
image: imageObj,
x: xposition,
y: yposition,
width: width,
height: height,
stroke: 'blue',
srokeFill: 'red',
strokeWidth: 5,
draggable: true,
dragBoundFunc: function (pos) {
if (pos.x < this.minX)
this.minX = pos.x;
return {
x: pos.x,
y: this.getAbsolutePosition().y
}
}
});
layer.on('mouseover', function (evt) {
var shape = evt.target;
document.body.style.cursor = 'pointer';
shape.strokeEnabled(true);
layer.draw();
});
layer.on('mouseout', function (evt) {
var shape = evt.target;
document.body.style.cursor = 'default';
shape.strokeEnabled(false);
layer.draw();
});
When making a clickable region on a canvas you need to.
- Create a redraw function.
- Find the mouse point inside of canvas.
- Do collision detection on the mouse point and region.
update: added multiple clickable regions.
// x1, y1, x2, y2, clicked
var boxes = [{
x1: 10,
y1: 10,
x2: 110,
y2: 110,
clicked: false
}, {
x1: 120,
y1: 10,
x2: 220,
y2: 110,
clicked: false
}];
function go() {
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
makeNoise(ctx);
var imageData = ctx.getImageData(0, 0, w, h);
var mx = 0;
var my = 0;
$('#can').mousemove(function(event) {
var offset = $(this).offset();
mx = event.pageX - offset.left;
my = event.pageY - offset.top;
redraw();
});
$('#can').click(function(event) {
var offset = $(this).offset();
mx = event.pageX - offset.left;
my = event.pageY - offset.top;
for (var i = 0, len = boxes.length; i < len; i++) {
var b = boxes[i];
if (hit(b.x1, b.y1, b.x2, b.y2)) {
b.clicked = !b.clicked;
}
}
redraw();
});
function redraw() {
// Draw the original image
ctx.putImageData(imageData, 0, 0);
// Draw the clickable region
for (var i = 0, len = boxes.length; i < len; i++) {
drawBox(boxes[i]);
}
// Draw the mouse. Probably only needed when testing
// mouse location.
drawMouse();
}
redraw();
// Collision dection of a square against mouse point.
// square points x1,y1 must be less than x2,y2
function hit(x1, y1, x2, y2) {
if (mx < x1 || my < y1 || mx > x2 || my > y2) return false;
return true;
}
function drawMouse() {
ctx.moveTo(mx, my);
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(mx, my, 5, 0, Math.PI * 360);
ctx.fill();
}
function drawBox(b) {
if (b.clicked) {
// Mouse clicked.
ctx.fillStyle = "rgba(255,0,255,.5)"
} else if (hit(b.x1, b.y1, b.x2, b.y2)) {
// Mouse Over
ctx.fillStyle = "rgba(255,255,255,.5)"
} else {
// Mouse Out
ctx.fillStyle = "red";
}
ctx.fillRect(b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
}
}
// Fill a canvas context with noise.
function makeNoise(ctx) {
var can = ctx.canvas;
var imageData = ctx.getImageData(0, 0, can.width, can.height);
var d = imageData.data;
for (var i = 0, len = d.length; i < len; i += 4) {
d[i] = d[i + 1] = d[i + 2] = (Math.random() * 8) << 4;
d[i + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
}
go();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="can" width="400" height="300"></canvas>

JS Function only runs if key is pressed

so I've put some simple collision detection code on a canvas: if my obstacle car sprites touch my user car sprite, the obstacle car stops. For some reason, when the cars are close, the collision is only detected if I am pressing the keys that my user car uses to move (up, down, left, and right arrow keys). How can I get this function to work all the time, regardless of if I am pressing down the keys to move?
collision detection code:
//Collide test
function firstObstaclecollideTest () {
if (Math.abs(x1 - (usercar.width / 2) - x) < usercar.width && Math.abs(y1 - (usercar.height / 2) - y) < usercar.height) {
mod1 = 0;
speed1 = 0;
}
requestAnimationFrame(firstObstaclecollideTest);
}
requestAnimationFrame(firstObstaclecollideTest);
function secondObstaclecollideTest () {
if (Math.abs(x2 - (usercar.width / 2) - x) < usercar.width && Math.abs(y2 - (usercar.height / 2) - y) < usercar.height) {
mod2 = 0;
speed2 = 0;
}
requestAnimationFrame(secondObstaclecollideTest);
}
requestAnimationFrame(secondObstaclecollideTest);
Full Code: http://jsbin.com/dofihiwize/1/edit?output
Your code is a bit messy i fear :
- You are triggering 4 animation loops : have only one loop to avoid headaches.
- You are duplicating quite some code : go for a Car class to clean things up.
- There are several confusion of concern : for instance, the function drawing the car is clearing the canvas, and also drawing the time elapsed. The function names are also misleading (gameStart is a game loop, ... ).
updated fiddle is here :
http://jsbin.com/bafulazose/1/edit?js,output
//Setting the canvas and context
var canvas = document.getElementById('background');
var context = canvas.getContext('2d');
//================
// CAR Class
//================
//Uploading obstacle car
var carImage = new Image();
carImage.src = "http://www.i2clipart.com/cliparts/f/e/3/a/128135fe3a51f073730a8d561282d05b4f35ab.png";
function Car(x, y, speed, mod, angle) {
this.x = x; // x center of car
this.y = y; // y center of car
this.speed = speed;
this.mod = mod;
this.angle = angle;
this.move = function () {
this.x += (this.speed * this.mod) * Math.cos(Math.PI / 180 * this.angle);
this.y += (this.speed * this.mod) * Math.sin(Math.PI / 180 * this.angle);
if (this.y > context.canvas.height + 150) {
this.y = -carImage.height;
this.x = Math.floor(Math.random() * canvas.width);
}
};
this.draw = function () {
context.save();
context.translate(this.x, this.y);
context.rotate(this.angle* Math.PI / 180);
context.drawImage(carImage, -(carImage.width / 2), -(carImage.height / 2));
context.strokeRect(-(carImage.width / 2), -(carImage.height / 2), carImage.width , carImage.height);
context.restore();
};
this.testCollision = function(other) {
var dx = Math.abs(this.x - other.x );
var dy = Math.abs(this.y - other.y );
if ( dx < carImage.width && dy < carImage.height) {
this.mod = 0;
this.speed = 0;
}
};
}
//================
//ENTER: USER CAR
//================
var userCar = new Car(450, 550, 10, -1, -90);
setupKeys(userCar);
//=====================
//ENTER: OBSTACLE CAR 1
//=====================
var obstacleCar1 ;
//======================
//ENTER: OBSTACLE CAR 2
//======================
var obstacleCar2 ;
function setupGame () {
obstacleCar1 = new Car(200, 5, 5, 1, 90);
obstacleCar2 = new Car(340, 5, 5, 1, 90);
gameOver = false;
startTime = Date.now();
score = 0;
}
//=========================
//Properties for score keep
//=========================
var score;
var startTime;
var gameOver;
var spaceBarPressed = false;
//=========================
// Launch the game
//=========================
setupGame () ;
var gameLoopInterval = setInterval(gameLoop, 30);
//===========================
//Draw Final and Elasped Time
//===========================
function drawElapsedTime() {
context.save();
context.fillStyle = "black";
context.font = "30px Verdana";
context.fillText(parseInt((Date.now() - startTime) / 1000) + " secs", canvas.width - 120, 40);
context.restore();
}
function drawFinalScore() {
context.save();
context.fillStyle = "black";
context.font = "30px Verdana";
context.fillText("Game Over: " + score + " secs", 100, 100);
context.font = "12px Verdana";
context.fillText("Press space to restart", 190, 150);
context.restore();
}
//========================
// Game loop
//========================
function gameLoop() {
context.clearRect(0, 0, canvas.width, canvas.height);
if (gameOver) {
drawFinalScore();
if (spaceBarPressed) {
setupGame ();
}
return;
}
obstacleCar1.move();
obstacleCar2.move();
obstacleCar1.testCollision(userCar);
obstacleCar2.testCollision(userCar);
if (obstacleCar1.speed===0 && obstacleCar2.speed===0) {
score = parseInt((Date.now() - startTime) / 1000);
gameOver = true;
spaceBarPressed = false;
}
obstacleCar1.draw();
obstacleCar2.draw();
userCar.draw();
drawElapsedTime();
}
//========================
// Keys handling
//========================
function setupKeys(target) {
var cancelledKeys = [32, 37, 38, 39, 40];
function keyUpHandler(event) {
if (event.keyCode == 38 || event.keyCode == 40) {
mod = 0;
}
}
function keyDownHandler(event) {
var keyCode = event.keyCode;
if (keyCode == 37) {
target.x -= target.speed;
}
if (keyCode == 39) {
target.x += target.speed;
}
if (keyCode == 32) {
spaceBarPressed = true;
}
// space and arrow keys
if (cancelledKeys.indexOf(keyCode) > -1) {
event.preventDefault();
}
}
//Event listeners for keys
window.addEventListener("keydown", keyDownHandler, false);
window.addEventListener("keyup", keyUpHandler, false);
}
Edit :
Morning coffee improvements (:-)) :
- moves are smooth ( requestAnimationFrame + position += speed * time elapsed)
- keys are handled properly
- cars have a clean spawn function
- cars are now in a 'scene graph' (an array) so we can test intersection
- road !! (with roadPos, roadSpeed)
http://jsbin.com/zujecerehe/1/edit?js,output

Categories

Resources