I'm really pretty new to code. I'm trying to make a paint app that will work on desktop and mobile. I had it working fine on desktop using JavaScript but then to get it to work on mobile it seemed like JQuery mobile was a recommended method. I'm converting it to JQuery and had the maint working with .mousedown, .mouseup, etc. but when I changed to to .vmousedown, .vmouseup, etc. to have it work with touch I get an error which I can't seem to resolve.
Uncaught TypeError: Object [object Object] has no method 'vmousedown'
I've seen other people with similar issues but I'm having a hard time making it work for me.
JSFiddle - http://jsfiddle.net/mquickel/dehAD/79/
HTML Snippet
<html>
<head>
<link rel="stylesheet" type="text/css" href="colorCSS2.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<body data-role="page">
<div id="container">
<div id="sketch" data-role="content">
<canvas id="paint" style="z-index: 0; position:absolute;" height="600px" width="600px"></canvas>
<canvas id="layer2" style="z-index: 1; position:absolute;" height="600px" width="600px"></canvas>
</div>
JS Snippet
document.getElementById( "container" ).onmousedown = function(event){
event.preventDefault();
}
var layer2 = document.getElementById("layer2");
var ctx2 = layer2.getContext("2d");
var imageObj = new Image();
/* Loading the Image*/
imageObj.onload = function() {
ctx2.drawImage(imageObj, 0, 0);
};
imageObj.src = 'https://lh5.googleusercontent.com/-P5ucC3TjCLU/UjHE0rENTaI/AAAAAAAAAts/mH2A_OORkQY/s800/color.png';
(function() {
var canvas = document.getElementById('paint');
var ctx = canvas.getContext('2d');
var imageObj = new Image();
var cont = document.getElementById('container');
var mouse = {x: 0, y: 0};
var last_mouse = {x: 0, y: 0};
/* Mouse Capturing Work */
$(cont).mousemove (function(e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
});
/* Drawing on Paint App */
ctx.lineWidth = 20;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = brushColor;
$(cont).vmousedown(function(e) {
console.log("hi");
$(cont).vmousemove (onPaint);
});
$(cont).vmouseup (function() {
console.log("up");
$(cont).unbind ('vmousemove', onPaint);
});
var onPaint = function() {
ctx.beginPath();
ctx.moveTo(last_mouse.x, last_mouse.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.closePath();
ctx.stroke();
};
}());
Related
I have been able to make a drawing application with html canvas and javascript. The only issue I now have is that I want the drawings to reappear when I reload the site. How can I do that?
My HTML-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DayMaker- Welcome</title>
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pa~trick+Hand&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght#-1,600&display=swap" rel="stylesheet">
</head>
<body>
<div class="colone">
<canvas id="canvas">
</canvas>
</div>
<div class="coltwo">
<div class="ctrlpanel">
<div id="toolbar">
<label for="Thickness"></label>
<input type="range" min="1" max="9" value="2" id="Thickness">
<input type="button" value="brushBtn" id="brushBtn">
<input type="button" value="eraserBtn" id="eraserBtn">
</div>
</div>
</div>
<script src="JS/canvas.js"></script>
</body>
</html>
My JS-
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const brushButton = document.getElementById("brushBtn")
const eraserButton = document.getElementById("eraserBtn")
const Thickness = document.getElementById("Thickness");
window.onresize = function(){ location.reload(); }
let vw = window.innerWidth / 100;
let vh = window.innerHeight / 100;
canvas.width = vw * 68;
canvas.height = vh * 94;
let painting = false;
let erase = false;
brushButton.onclick = function (){
canvas.addEventListener("mouseup", function() {
painting = false;
erase = false;
});
canvas.addEventListener("mousemove", function(e) {
if (painting) {
let x = e.clientX - canvas.offsetLeft;
let y = e.clientY - canvas.offsetTop;
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x, y);
ctx.strokeStyle = "#002276"
ctx.stroke();
prevX = x;
prevY = y;
}
Thickness.on = function (){
ctx.lineWidth = "2";
}
Thickness.oninput = function() {
ctx.lineWidth = this.value;
}
});
let prevX = 0;
let prevY = 0;
canvas.addEventListener("mousedown", function(e) {
painting = true;
erase = false;
prevX = e.clientX - canvas.offsetLeft;
prevY = e.clientY - canvas.offsetTop;
});
}
eraserButton.onclick = function (){
canvas.addEventListener("mouseup", function() {
painting = false;
});
canvas.addEventListener("mousemove", function(e) {
if (erase) {
ctx.clearRect(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop, 32, 32)
}
});
let prevX = 0;
let prevY = 0;
canvas.addEventListener("mousedown", function(e) {
erase = true;
painting = false;
prevX = e.clientX - canvas.offsetLeft;
prevY = e.clientY - canvas.offsetTop;
});
}
I am a big noob when it comes to writing javascript. So, please kindly elaborate on where I was wrong, and how I can fix it.
Thanking you in advance.
I tried to use dataURL(). But it did not work for me. Either I am doing something wrong or I don't know what I am doing. Please help me!
I Have build some code related to canvas but code is working on TRYIT but code is not working locally when i have copied all code to file and tried to run it .
This is what this code is doing , it takes an image and set the width and height of canvas with respect to that image and draw a filled circle with text in it on that image(canvas).
Here is code
<head>
<meta charset=utf-8 />
<title>Draw a circle</title>
</head>
<body onload="draw();">
<canvas id="circle"></canvas>
</body>
<script>
var canvas = document.getElementById('circle'),
context = canvas.getContext('2d');
function draw()
{
base_image = new Image();
base_image.src = 'http://sst-system.com/old/Planos/C21E34.JPG';
var canvas = document.getElementById('circle');
if (canvas.getContext)
{
base_image = new Image();
base_image.src = 'http://sst-system.com/old/Planos/C21E34.JPG';
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.canvas.width = base_image.width;
ctx.canvas.height = base_image.height;
var X = 500;
var Y = 229;
var R = 6.4;
ctx.font = "15px Arial bold";
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 12;
ctx.strokeStyle = '#FF0000';
ctx.drawImage(base_image, 0, 0)
ctx.stroke();
ctx.fillText("TT", X-9, Y+5);
}
}
</script>
There are no errors on console , but it shows these warnings in console :
As #DBS mentioned, it was a speed thing. You weren't waiting for the image to load before working with it.
The fix is to attach a listener to the load event of the image, either using image.addEventListener('load', () => { or the deprecated-but-still-works style of image.onload = () => {, which I have used below.
The reason that it works in the TryIt example is that the image is cached by the browser from the second load onwards, so it is available immediately and you don't need to wait for it to load.
I suspect that when you run it locally, if you have Devtools open, the cache is disabled due to an option in Devtools settings called "Disable cache (while DevTools is open)". So it will never be pulled from the cache, and thus never work.
The following code works:
<html>
<head>
<meta charset=utf-8 />
<title>Draw a circle</title>
</head>
<body onload="draw();">
<canvas id="circle"></canvas>
</body>
<script>
var canvas = document.getElementById('circle'),
context = canvas.getContext('2d');
function draw() {
base_image = new Image();
base_image.src = 'http://sst-system.com/old/Planos/C21E34.JPG';
var canvas = document.getElementById('circle');
if (canvas.getContext) {
base_image = new Image();
base_image.src = 'http://sst-system.com/old/Planos/C21E34.JPG';
// The key change: put the rest of the code inside the onload callback
// to wait for the image to load before using it.
base_image.onload = function() {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.canvas.width = base_image.width;
ctx.canvas.height = base_image.height;
var X = 500;
var Y = 229;
var R = 6.4;
ctx.font = "15px Arial bold";
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 12;
ctx.strokeStyle = '#FF0000';
ctx.drawImage(base_image, 0, 0)
ctx.stroke();
ctx.fillText("TT", X - 9, Y + 5);
};
}
}
</script>
</html>
I have a drawing app which consists of a container with a background image in grayscale and over it, there's another image (the same but not in grayscale).
When I draw on my image, I would to erase where I drawn or turn in grayscale (to reproduce the image in background).
How can I achieve that ?
Here is my code :
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#wrapper {
width: 600px;
height: 400px;
border: 1px solid black;
margin: 0 auto;
background-image: url('elephant-nb-400.jpg');
}
</style>
</head>
<body>
<div id="wrapper">
<canvas width="600" height="400"></canvas>
</div>
<script>
window.onload = function() {
var wrapper = document.querySelector("#wrapper");
var canvas = document.querySelector("#wrapper canvas");
var context = canvas.getContext("2d");
var image = document.createElement("img");
image.setAttribute("src", "elephant-400.jpg");
image.onload = function() {
context.drawImage(image, 0, 0, 600, 400);
};
var positionsX = new Array();
var positionsY = new Array();
var movements = new Array();
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var isErasing;
canvas.addEventListener("mousedown", function(e) {
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
isErasing = true;
addPositions(mouseX, mouseY);
draw();
});
canvas.addEventListener("mousemove", function(e) {
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
if(isErasing) {
addPositions(mouseX, mouseY, true);
draw();
}
});
canvas.addEventListener("mouseup", function(e) {
isErasing = false;
});
var addPositions = function(x, y, isMoving) {
positionsX.push(x);
positionsY.push(y);
movements.push(isMoving);
}
var draw = function(){
//context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clears the canvas
for(var i=0; i < positionsX.length; i++) {
context.beginPath();
if(movements[i] && i){
}else{
}
context.lineTo(positionsX[i], positionsY[i]);
context.closePath();
context.stroke();
}
}
}
</script>
</body>
My problem is solved.
You need to get the image data : var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
In function draw(), you need to add : context.putImageData(imageData, 0, 0, positionsX[i]-1, positionsY[i], 20, 20); after context.moveTo(positionsX[i-1], positionsY[i-1]);and context.moveTo(positionsX[i]-1, positionsY[i]);
I currently have a code that simply draws circles onto a canvas. However, I want those circles to be able to direct the user to a given link if he or she chooses to click on the circle again. I'm not entirely sure how to implement this though. Simply put, can drawn objects be used as a click event to direct user to another webpage?
http://jsfiddle.net/PTDy9/
<head>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
</head>
<body>
<img id="graph" style=display:none src="http://i47.tinypic.com/29zr14o.jpg" alt="graph" >
<canvas id="myCanvas" width="700" height="400" style="border:1px solid #FFFFF;">
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("graph");
ctx.drawImage(img,0,0);
var color_list = ["#FFC0CB", "#00ffff", "#DA70D6", "#90EE90", "#FF8C00", "#CD853F"];
var color_iter = 0;
var bullet_y = 450;
var width = img.naturalWidth;
var height = img.naturalHeight;
jQuery(document).ready(function(){
$("#myCanvas").click(function(e){
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
if (x < width && y < height) {
var ctx= this.getContext("2d");
ctx.beginPath();
ctx.arc(x, y, 10,0, 2*Math.PI);
color = color_list[color_iter];
ctx.strokeStyle = color;
ctx.fillStyle = color;
if (color_iter == color_list.length-1) {
color_iter = 0;
}
else {color_iter = color_iter + 1;}
ctx.fillStyle = color;
ctx.globalAlpha = .4;
ctx.fill();
ctx.stroke();
var a = document.createElement('a');
}
});
})
</script>
</body>
Here's one way let the user click on a circle to open a specified url in a new browser tab.
First create 1+ link objects specifying the click area on the canvas and the desired url:
var links=[];
addLink(75,75,30,"Google","http://www.google.com");
addLink(150,150,30,"CNN","http://www.cnn.com");
function addLink(x,y,radius,label,url){
links.push({
cx:x,
cy:y,
radius:radius,
label:label,
link:url
});
}
Then listen for mouse clicks and test if any link area was clicked.
If any specific link area was clicked, then open up the corresponding url in a new browser tab:
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<links.length;i++){
var link=links[i];
var dx=link.cx-mx;
var dy=link.cy-my;
if(dx*dx+dy*dy<link.radius*link.radius){
window.open(link.link,'_blank');
}
}
}
Full Example Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var links=[];
addLink(75,75,30,"Google","http://www.google.com");
addLink(150,150,30,"CNN","http://www.cnn.com");
drawLinks();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function addLink(x,y,radius,label,url){
links.push({
cx:x,
cy:y,
radius:radius,
label:label,
link:url
});
}
function drawLinks(){
ctx.save();
ctx.fillStyle="green";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.font="14px verdana";
ctx.textAlign="center";
ctx.textBaseline="middle";
for(var i=0;i<links.length;i++){
var link=links[i];
ctx.beginPath();
ctx.arc(link.cx,link.cy,link.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="blue";
ctx.fill();
ctx.fillStyle="white";
ctx.fillText(link.label,link.cx,link.cy);
}
ctx.restore();
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<links.length;i++){
var link=links[i];
var dx=link.cx-mx;
var dy=link.cy-my;
if(dx*dx+dy*dy<link.radius*link.radius){
window.open(link.link,'_blank');
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I wrote a simple script to draw a path on HTML5 canvas, however when running the javascript in chrome:
The longer the path grows (as I draw it), the less responsive the page is, and eventually the javascript console is totally stuck, and I noticed the CPU is almost 100% busy. Could you please give me some hints?
Here is my code:
<!DOCTYPE html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
var context;
window.onload =function(){init();};
function init(){
context = document.getElementById("surface").getContext("2d");
$('#surface').mousedown(function(e){
var touchX = e.pageX - this.offsetLeft;
var touchY = e.pageY - this.offsetTop;
paint = true;
addClick(touchX, touchY);
redraw();
});
$('#surface').mousemove(function(e){
if(paint){
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
};
function addClick(x, y){
clickX.push(x);
clickY.push(y);
}
function redraw(){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.beginPath();
for(var i=0; i<clickX.length;i++){
context.lineTo(clickX[i], clickY[i]);
console.log(clickX[i]+", "+clickY[i]);
context.stroke();
}
context.closePath();
}
</script>
</head>
<body>
<canvas id="surface" style="border:1px solid #000000;" width="800" height ="600"></canvas>
</body>
Here are some issues I noticed:
A Demo after refactoring some of your code: http://jsfiddle.net/m1erickson/LStXc/
You have a typo in redraw (strokeStype s/b strokeStyle)
If your project doesn't require saving/reusing the user's polyline then you don't need to save the mouse positions in an array. You can just continuously draw the line by adding a .lineTo with each mousemove event.
Some performance issues:
Calling external functions (as your addClick) are slower than inline commands so consider moving the addClick code into the mousemove handler.
If your canvas is not being repositioned, you can calculate the offsets once before sketching begins.
Setting context state (.strokeStyle, .lineJoin, .lineWidth) are relative expensive when repeated in a very active function like a mouse handler. If your state does not change during the sketch then set these once before sketching begins
Example Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("surface");
var context=canvas.getContext("2d");
var canvasOffset=$("#surface").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
var context;
$('#surface').mousedown(function(e){
var touchX = e.clientX - offsetX;
var touchY = e.clientY - offsetY;
paint = true;
clickX.push(e.clientX-offsetX);
clickY.push(e.clientY-offsetY);
lastX=touchX;
lastY=touchY;
});
$('#surface').mousemove(function(e){
if(paint){
var x=e.clientX-offsetX;
var y=e.clientY-offsetY;
clickX.push(x);
clickY.push(y);
context.beginPath();
context.moveTo(lastX,lastY)
context.lineTo(x,y);
context.stroke();
context.closePath();
lastX=x;
lastY=y;
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="surface" width=300 height=300></canvas>
</body>
</html>
You can try with this redraw function:
var actClick = 0;
function redraw(){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.beginPath();
actClick = actClick - 2;
for( ; actClick < clickX.length ; actClick++ ){
context.lineTo(clickX[actClick], clickY[actClick]);
context.stroke();
}
context.closePath();
}
You can find the jsFiddle
The problem is that you redraw the wole image every new point, so every new point it will become slower.
Try the below code. Hope this will work for you
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var paint;
var context;
window.onload =function(){init();};
function init(){
context = document.getElementById("surface").getContext("2d");
$('#surface').mousedown(function(e){
var touchX = e.pageX; //e.pageX - this.offsetLeft;
var touchY = e.pageY; //e.pageY - this.offsetTop;
paint = true;
context.beginPath();
redraw(touchX, touchY);
});
$('#surface').mousemove(function(e){
if(paint){
var touchX = e.pageX; //e.pageX - this.offsetLeft;
var touchY = e.pageY; //e.pageY - this.offsetTop;
redraw(touchX, touchY);
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
};
function redraw(nextX,nextY){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.lineTo(nextX, nextY);
console.log(nextX+", "+nextY);
context.stroke();
//context.closePath();
}
</script>
</head>
<body>
<canvas id="surface" style="border:1px solid #000000;" width="800" height ="600"></canvas>
</body>