I want to implement the selecting feature by dragging, so if drag on the grid chart, the multiple cell in form of rectangle/square, but mine is not working properly - square should be formed while I moving the mouse. But now it draw a square when i drag it and move up the mouse.
I also want the cell is selecting by square in every direction of diagonals
How do I fix it?
function getSquare(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: 1 + (evt.clientX - rect.left) - (evt.clientX - rect.left)%10,
y: 1 + (evt.clientY - rect.top) - (evt.clientY - rect.top)%10
};
}
function drawBoard(context) {
for (var x = 0.5; x < 10001; x += 10) {
context.moveTo(x, 0);
context.lineTo(x, 10000);
}
for (var y = 0.5; y < 10001; y += 10) {
context.moveTo(0, y);
context.lineTo(10000, y);
}
context.strokeStyle = "#ddd";
context.stroke();
}
function fillSquare(context, x, y){
context.fillStyle = "#70B7B5"
context.fillRect(x,y,9,9);
}
var canvas = document.getElementById('myBoard');
var context = canvas.getContext('2d');
drawBoard(context);
var isDrag=false;
var previousPos = (-1,-1);
canvas.addEventListener('mousedown', function(evt) {
var mousePos = getSquare(canvas, evt);
isDrag=true;
fillSquare(context, mousePos.x, mousePos.y)
previousPos = mousePos;
}, false);
canvas.addEventListener('mousemove', function(evt) {
if (isDrag){
var mousePos = getSquare(canvas, evt);
if (mousePos.x-previousPos.x){
for (i=0; i<(mousePos.x-previousPos.x)/10;i++){
for(j=0; j<(mousePos.x-previousPos.x)/10;j++){
fillSquare(context, mousePos.x-(j*10), mousePos.y-(i*10));
}
}
}else{
for (i=0; i<(previousPos.x-mousePos.x)/10;i++){
for(j=0; j<(previousPos.x-mousePos.x)/10;j++){
fillSquare(context, mousePos.x+(j*10), mousePos.y-(i*10));
}
}
}
previousPos = mousePos;
}
}, false);
canvas.addEventListener('mouseup', function(evt) {
if (isDrag){
isDrag = false;
}
}, false);
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<canvas id="myBoard" width="10000" height="10000"></canvas>
<script type="text/javascript" src="myBoard2.js"></script>
</body>
you did everything well and i changed it a little as bellow: use this range function for selecting squares in every direction of diagonals
function range(start, end) {
var ans = [];
if (end > start) {
for (let i = start; i <= end; i += 10) {
ans.push(i);
}
} else {
emptySquare(context);
for (let i = start; i >= end; i -= 10) {
ans.push(i);
}}
return ans;
}
and emptySquare() to clear color of context rect as bellow:
function emptySquare(context) {
context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = "#ffffff"
context.fill();
context.strokeStyle = "#ddd";
context.stroke();
}
then u just need to rewrite mousemove handler like this:
canvas.addEventListener('mousemove', function(evt) {
if (isDrag) {
var mousePos = getSquare(canvas, evt);
var x_dist = range(previousPos.x, mousePos.x);
var y_dist = range(previousPos.y, mousePos.y);
for (x in x_dist) {
for (y in y_dist) {
fillSquare(context, x_dist[x], y_dist[y]);
}}}
}, false);
and call emptySquare(context); in mousedown handler too...
A little more readable design, and sped up a bit by throttling the mouse move logic.
const canvas = document.getElementById('board');
const context = canvas.getContext('2d');
let anchor = null;
let pos = null;
let lastPos = null;
// return x,y in grid coords from an event
function position(event) {
const rect = canvas.getBoundingClientRect();
return [
Math.floor((event.clientX-rect.left)/10),
Math.floor((event.clientY-rect.top)/10)
];
}
// color the rectangle with corners at posA, posB
function colorRegion(posA, posB, color) {
const minX = Math.min(posA[0], posB[0]);
const minY = Math.min(posA[1], posB[1]);
const maxX = Math.max(posA[0], posB[0]);
const maxY = Math.max(posA[1], posB[1]);
context.fillStyle = color
for (let i=minX; i<maxX; i++) {
const tenI = i*10+1
for (let j=minY; j<maxY; j++) {
context.fillRect(tenI,10*j+1,9,9);
}
}
}
// mouse down, set the anchor
canvas.addEventListener('mousedown', function(evt) {
anchor = position(evt);
lastPos = position(evt);
})
// mouse up, clear the anchor
canvas.addEventListener('mouseup', function(evt) {
anchor = null;
})
// mouse move, color the old rect white, color new rect green
// remember the last pos
function onmove() {
if (!anchor) return;
colorRegion(anchor, lastPos, 'white')
colorRegion(anchor, pos, '#70B7B5')
lastPos = pos;
}
// no need to run this on every pixel
// you could also measure absolute mouse move > 10x10 as a throttle
const throttledOnMove = _.throttle(onmove, 100);
canvas.addEventListener('mousemove', function(evt) {
pos = position(evt);
throttledOnMove()
})
.container {
height: 10000px;
width: 10000px;
}
.grid {
box-sizing: border-box;
margin: 0;
height: 100%;
width: 100%;
background-image: repeating-linear-gradient(0deg, transparent, transparent 9px, #ccc 9px, #ccc 10px), repeating-linear-gradient(-90deg, transparent, transparent 9px, #ccc 9px, #ccc 10px);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<div class="container">
<div class="grid">
<canvas id="board" width="10000" height="10000"></canvas>
</div>
</div>