How can I use HTML5 canvas to simply connect two dots with one line using mouse? where I would click on the first dot and drag the mouse creating a line until it connects to the second dot.
I have been using x/y offset to follow the mouse but drawing a line is where I need help in.
Data array is the two dots
$scope.data = [
[192,27]
,[183,55]
];
function drawDot(event) {
if(dragging){
context.lineTo(event.offsetX, event.offsetY);
context.stroke();
context.beginPath();
context.arc(event.offsetX, event.offsetY,5, 0, Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(event.offsetX, event.offsetY);
}
}
function engage(){
dragging = true;
drawDot(event);
}
function disengage(){
dragging = false;
context.beginPath();
}
function init(){
canvas.addEventListener("mousedown",engage);
canvas.addEventListener("mouseup",disengage);
canvas.addEventListener("mousemove",drawDot,false);
}
I am seeing a few things wrong here. Look at my example. I believe that is what you are looking for.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d")
var startX = 0;
var startY = 0;
function drawDot(event) {
if(dragging){
context.clearRect(0,0,canvas.width, canvas.height)
context.beginPath();
context.moveTo(startX, startY);
context.lineTo(event.offsetX, event.offsetY);
context.arc(event.offsetX, event.offsetY,5, 0, Math.PI*2);
context.stroke();
context.closePath();
}
}
function engage(event){
dragging = true;
startX = event.offsetX;
startY = event.offsetY;
}
function disengage(){
dragging = false;
}
canvas.addEventListener("mousedown",engage);
canvas.addEventListener("mouseup",disengage);
canvas.addEventListener("mousemove",drawDot,false);
<canvas id="canvas" style="margin: 10px; background: blue"></canvas>
Related
Currently working on a site that features some line drawing while hovering. How can I make the line recede naturally as you draw more? Right now I've figured out how to draw a continual line.
var canvas;
var button;
function windowResized() {
console.log('resized');
resizeCanvas(windowWidth, windowHeight);
}
function setup () {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0,0);
canvas.style('z-index', '-1')
background(175);
// button = createButton("Start Your Walk");
}
function draw () {
strokeWeight(4);
console.log('button')
line(pmouseX, pmouseY, mouseX, mouseY)
}
You may store the values of your mouse position in an array and then draw the points of the array in order. When the array is updated, if it is full, you will have to erase the last point of the array, move all the points one position backwards and add the new point. The following would be an example code. I recomend you to consult this page for documentation and also the p5 reference.
var mousePositions = [];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
v = createVector(mouseX, mouseY);
mousePositions.push(v);
noFill();
beginShape();
for(var i = 0; i < mousePositions.length; i++){
vertex(mousePositions[i].x, mousePositions[i].y);
}
endShape();
if(mousePositions.length > 25){
mousePositions.shift();
}
}
The following code makes use of the p5dom add-on to position the canvas in the centre of the window. To dynamically resize the canvas I'm using the windowResized() function. I want to keep the background function in setup. How do I prevent the background colour from clearing when I resize the window? Many thanks.
var cnv;
function centerCanvas() {
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
}
function setup() {
cnv = createCanvas(windowWidth,windowHeight);
centerCanvas();
background(255, 0, 200);
}
function draw(){
}
function windowResized() {
centerCanvas();
resizeCanvas(windowWidth,windowHeight)
}
One thing you might do is draw everything to a buffer instead of directly to the screen. The createGraphics() function is your friend here. From the P5.js reference:
var pg;
function setup() {
createCanvas(100, 100);
pg = createGraphics(100, 100);
}
function draw() {
background(200);
pg.background(100);
pg.noStroke();
pg.ellipse(pg.width/2, pg.height/2, 50, 50);
image(pg, 50, 50);
image(pg, 0, 0, 50, 50);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
You would want to draw everything to a buffer, and then when the screen is resized, redraw that buffer.
Simply by adding the background function to the draw one too.
Try this:
var cnv;
function centerCanvas() {
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
}
function setup() {
cnv = createCanvas(windowWidth,windowHeight);
centerCanvas();
background(255, 0, 200);
}
function draw(){
//HERE:
background(255, 0, 200);
}
function windowResized() {
//(you can add it here too...)
centerCanvas();
resizeCanvas(windowWidth,windowHeight);
}
I would simply set the background in the windowResized function.
function windowResized() {
centerCanvas();
resizeCanvas(windowWidth,windowHeight)
background(255, 0, 200);
}
For an alternative method, you could use CSS to edit the dimensions using something similar to the following:
<style>
canvas {
width: 100%;
height: 100%;
}
</style>
Is it possible to call the function draw(){} in a p5 js sketch when clicking on the canvas?
I would like everything under the draw function to be called when clicking anywhere on the canvas, and not before.
function setup() {
createCanvas(500, 500);
frameRate(65);
background('#ff0a0a');
textSize(60);
text("ART", 370, 250);
};
function draw() {
noFill();
var red = random(100);
var green = random(200);
var blue =random(230);
var h = random(height);
stroke(red,green,blue);
strokeWeight(8);
rect(frameCount,h,300,20+(frameCount));
ellipse(frameCount,h ,300,20+(frameCount));
triangle(frameCount,h ,300,20+(frameCount));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
This works fine for me:
function setup() {
createCanvas(500, 500);
frameRate(65);
background('#ff0a0a');
textSize(60);
text("ART", 370, 250);
};
function mousePressed() {
noFill();
var red = random(100);
var green = random(200);
var blue =random(230);
var h = random(height);
stroke(red,green,blue);
strokeWeight(8);
rect(frameCount,h,300,20+(frameCount));
ellipse(frameCount,h ,300,20+(frameCount));
triangle(frameCount,h ,300,20+(frameCount));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
Just to mention another way and to address your question in Kevin's answer above, you can do something like this to draw continuously when the mouse is clicked once and stop when it is clicked again. This would work like a toggle switch for drawing :-
var drawThings;
function setup() {
createCanvas(500, 500);
frameRate(65);
background('#ff0a0a');
textSize(60);
text("ART", 370, 250);
}
function draw() {
if (drawThings) {
noFill();
var red = random(100);
var green = random(200);
var blue = random(230);
var h = random(height);
stroke(red, green, blue);
strokeWeight(8);
rect(frameCount, h, 300, 20 + (frameCount));
ellipse(frameCount, h, 300, 20 + (frameCount));
triangle(frameCount, h, 300, 20 + (frameCount));
}
}
function mouseClicked() {
drawThings = !drawThings;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
I'm drawing some colored lines in the main big canvas. 3 colors are possible : red, green, blue. For further uses, I have 3 little canvasses (called #canvasR #canvasG and #canvasB) where I draw each line depending its color, for ex. all (and only) the red one in #canvasR. Everything is working perfectly except a big mystery for me : when I'm drawing say a first blue line in main canvas (onmousemove > onmouseup), the second blue line appears in #canvasB... all is correct. But when I want to draw a second blue line somewhere else (second onmousemove > onmouseup sequence) everything is OK in the main canvas but not in the #canvasB: a unwanted new blue line joins the first one and the new one, just like if the first onmouseup was ignored... screenshot:
http://e-vdn.com/4canvas.png
canvas.mousemove(function(e) {
cursorX = (e.pageX - this.offsetLeft);
cursorY = (e.pageY - this.offsetTop);
drawLine();
});
function drawLine() {
// in main canvas:
context.lineTo(cursorX, cursorY);
context.strokeStyle = color;
context.lineWidth = width_brush;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = width_brush*1.5;
context.shadowColor = color;
context.stroke();
// in small canvas:
if (color=='#f00') { ctx = ctxR; }
if (color=='#9f0') { ctx = ctxV; }
if (color=='#00f') { ctx = ctxB; }
ctx.lineTo( (cursorX/4), (cursorY/4) );
ctx.strokeStyle = color;
ctx.lineWidth = width_brush;
ctx.stroke();
}
You have to do context.beginPath with each new stroke or else all previous lines on that context will be redrawn along with your current stroke.
So, for example, assume you do (1) a red stroke and then (2) a blue stroke. Without context.beginPath your red stroke will be redrawn using the current blue pen.
Here's an untested refactoring of your code:
var lastX,lastY;
var lastRedX,lastRedY,lastGreenX,lastGreenY,lastBlueX,lastBlueY;
// in main canvas:
if(lastX){
context.beginPath();
context.moveTo(lastX,lastY);
context.lineTo(cursorX, cursorY);
context.strokeStyle = color;
context.lineWidth = width_brush;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = width_brush*1.5;
context.shadowColor = color;
context.stroke();
}
lastX=cursorX;
lastY=cursorY;
// in small red canvas:
if (color=='#f00')
if(lastRedX){
addLine(ctxR,lastRedX,lastRedY,cursorX,cursorY);
}
lastRedX=cursorX;
lastRedY=cursorY;
}
// in small V canvas:
if (color=='#9f0')
if(lastGreenX){
addLine(ctxV,lastGreenX,lastGreenY,cursorX,cursorY);
}
lastGreenX=cursorX;
lastGreenY=cursorY;
}
// in small Blue canvas:
if (color=='#00f')
if(lastBlueX){
addLine(ctxB,lastBlueX,lastBlueY,cursorX,cursorY);
}
lastBlueX=cursorX;
lastBlueY=cursorY;
}
function addLine(ctx,lastX,lastY,cursorX,cursorY){
ctx.beginPath();
ctx.moveTo( lastX,lastY );
ctx.lineTo( (cursorX/4), (cursorY/4) );
ctx.strokeStyle = color;
ctx.lineWidth = width_brush;
ctx.stroke();
}
I have it so that you can draw under the image, but you must start drawing outside of the image border and move under the image. So you can't start right on the image. How do I fix this?
My html is just:
<canvas id="canvas"></canvas>
<img id="html5" src="http://i.imgur.com/Wpx3Vum.png" style="position:absolute;left:100px;top:15px;" />
You can use two canvas elements instead:
Put two canvas elements on top of each other
Draw the image you want to superimpose on the top canvas
Add mouse event listener to the top canvas
When drawing read the positions from top canvas but draw the lines to the bottom one using the bottom canvas' context
(links just meant as examples)
An example of this could be including a simple basic draw function:
Online demo
HTML:
<div id="cont">
<canvas id="canvasBottom" width=400 height=400></canvas>
<canvas id="canvasTop" width=400 height=400></canvas>
</div>
CSS:
#cont {
position:relative;
border:1px solid #777;
height:400px;
}
#cont > canvas {
position:absolute;
left:0;
top:0;
cursor:crosshair;
}
JavaScript:
Load and set the image to top layer:
var img = new Image,
canvas = document.getElementById('canvasBottom'),
canvasTop = document.getElementById('canvasTop'),
ctx = canvas.getContext('2d'),
ctxMouse = canvasTop.getContext('2d');
img.onload = setup;
img.src = 'http://i.imgur.com/HNiER0v.png';
ctx.lineWidth = 5;
ctx.strokeStyle = 'rgb(0, 100, 255)';
function setup() {
ctxMouse.drawImage(this, 0, 0);
}
Handle mouse:
var px, py, isDown = false;
canvasTop.onmousedown = function (e) {
var pos = getXY(e);
px = pos.x;
py = pos.y;
isDown = true;
}
canvasTop.onmouseup = function () {
isDown = false;
}
canvasTop.onmousemove = function (e) {
if (isDown) {
var pos = getXY(e);
ctx.beginPath();
ctx.moveTo(px, py);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
px = pos.x;
py = pos.y;
}
}
function getXY(e) {
var rect = canvasTop.getBoundingClientRect();
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
}
As you can see you can now draw behind the initial drawing:
(Now, if that is not a master piece than I don't know what a master piece is..!)