Canvas Drag Resize Shapes
by northcoder
HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Example</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
<img id="source" alt="taverna" style="display: none;" src="https://user-images.githubusercontent.com/56733719/141156687-8bbb9eec-4752-4169-b108-50e397e4a8b7.png">
<div class="imgmap_centered">
<button id="rect" class="imgmap_shapes">New ⬜</button>
<button id="circle" class="imgmap_shapes">New ◯</button>
</div>
<div id="container" style="margin: auto; border:1px solid #d3d3d3;">
<canvas id="canvas"></canvas>
</div>
<div class="imgmap" style="padding: 10px;">
<table>
<thead>
<tr>
<th>ID</th>
<th>Shape</th>
<th>Coordinates</th>
<th></th>
</tr>
</thead>
<tbody id="shapesRows">
</tbody>
</table>
</div>
</body>
</html>
CSS
imgmap_centered {
text-align: center;
}
button.imgmap_shapes {
display: inline-block;
padding: 5px;
margin: 10px;
}
div.imgmap table {
margin: 5px auto;
border-collapse: collapse;
width: 50%;
}
div.imgmap th {
text-align: left;
}
div.imgmap tr {
border-bottom: 1px solid #ccc;
}
div.imgmap table td>button {
padding: 5px;
margin: 5px;
}
JavaScript
window.onload = function() {
// inspired by https://stackoverflow.com/a/28285879/12567365
// extended to support resizing, handling of one shape at
// a time, scrolling/resizing for the viewport, and deletion
// of shapes.
// load image onto canvas
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = document.getElementById('source');
const container = document.getElementById('container');
container.style.width = '' + (img.naturalWidth + 2) + 'px';
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 1, 1);
// get canvas related references
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
// an array of objects that define different shapes:
var shapes = [];
// each shape has one handle, for resizing the shape:
var handles = [];
// indexes into shapes[] and handles[]
var dragIdx = -1;
var resizeIdx = -1;
//drag/resize related variables
var startX;
var startY;
let fillStyle = 'rgba(255, 255, 255, 0.6)';
let strokeStyle = 'red';
$('button#rect').on('click', function() {
drawNewRect();
})
$('button#circle').on('click', function() {
drawNewCircle();
})
$('#shapesRows').on('click', 'button', function() {
deleteShape(this);
})
// listen for global mouse events
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
canvas.onmousemove = myMove;
// call to draw the scene
draw();
function drawNewRect() {
let newIdx = shapes.length;
// define a rectangle
shapes.push({
idx: newIdx,
type: "rect",
x: 10,
y: 10,
width: 50,
height: 40,
fill: fillStyle,
stroke: strokeStyle
});
var s = shapes[newIdx];
handles.push({
idx: newIdx,
type: "rect",
x: s.x + s.width - 5,
y: s.y + s.height - 5,
width: 5,
height: 5,
fill: fillStyle,
stroke: strokeStyle
});
draw();
...