/*
"mouse:wheel" event is where zooms are handled
"mouse:move" event is where panning is handled
*/
// create Fabric JS canvas'
var labelsCanvas = new fabric.Canvas("labelsCanvas");
var specimenCanvas = new fabric.Canvas("specimenCanvas");
//set defaults
var startingPositionForLine = 100;
const noZoom = 1;
var wasPanned = false;
var panY2 = startingPositionForLine;
var panX2 = startingPositionForLine;
var zoomY2 = startingPositionForLine;
var zoomX2 = startingPositionForLine;
// set starting zoom for specimen canvas
var specimenZoom = noZoom;
/*
Add pointer, label and background image into canvas
*/
// create a pointer line
var line = new fabric.Line([150, 35, panX2, panY2], {
fill: "red",
stroke: "red",
strokeWidth: 3,
strokeDashArray: [5, 2],
// selectable: false,
evented: false
});
// create text label
var text = new fabric.Text("Label 1", {
left: 100,
top: 0,
// selectable: false,
evented: false,
backgroundColor: "red"
});
// add both into "Labels" canvas
labelsCanvas.add(text);
labelsCanvas.add(line);
// add a background image into Specimen canvas
fabric.Image.fromURL(
"https://upload.wikimedia.org/wikipedia/commons/c/cb/Skull_brain_human_normal.svg",
function(oImg) {
oImg.left = 0;
oImg.top = 0;
oImg.scaleToWidth(300);
oImg.scaleToHeight(300);
specimenCanvas.add(oImg);
}
);
/*
Handle mouse events
*/
// zoom the specimen image canvas via a mouse scroll-wheel event
labelsCanvas.on("mouse:wheel", function(opt) {
// scroll value e.g. 5, 6 -1, -18
var delta = opt.e.deltaY;
// zoom level in specimen
var zoom = specimenCanvas.getZoom();
console.log("zoom ", zoom);
// make zoom smaller
zoom = zoom + delta / 200;
// use sane defaults for zoom
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
// create new zoom value
zoomX2 = panX2 * zoom;
zoomY2 = panY2 * zoom;
// save the zoom
specimenZoom = zoom;
// set the specimen canvas zoom
specimenCanvas.setZoom(zoom);
// move line to sync it with the zoomed image
line.set({
x2: zoomX2,
y2: zoomY2
});
console.log("zoomed line ", line.x2);
// render the changes
this.requestRenderAll();
// block default mouse behaviour
opt.e.preventDefault();
opt.e.stopPropagation();
console.log(labelsCanvas.viewportTransform[4]);
// stuff I've tried to fix errors
line.setCoords();
specimenCanvas.calcOffset();
});
// pan the canvas
labelsCanvas.on("mouse:move", function(opt) {
if (this.isDragging) {
// pick up the click and drag event
var e = opt.e;
// sync the label position with the panning
text.left = text.left + (e.clientX - this.lastPosX);
var x2ToUse;
var y2ToUse;
// UNZOOMED canvas is being panned
if (specimenZoom === noZoom) {
x2ToUse = panX2;
y2ToUse = panY2;
// move the image using the difference between
// the current position and last known position
line.set({
x1: line.x1 + (e.clientX - this.lastPosX),
y1: line.y1,
x2: x2ToUse + (e.clientX - this.lastPosX),
y2: y2ToUse + (e.clientY - this.lastPosY)
});
// set the new panning value
panX2 = line.x2;
panY2 = line.y2;
// stuff I've tried
// zoomX2 = line.x2;
// zoomY2 = line.y2;
}
// ZOOMED canvas is being panned
else
{
x2ToUse = zoomX2;
y2ToUse = zoomY2;
// stuff I've tried
// x2ToUse = panX2;
// y2ToUse = panY2;
// move the image using the difference between
// the current position and last known ZOOMED position
line.set({
x1: line.x1 + (e.clientX - this.lastPosX),
y1: line.y1,
x2: x2ToUse + (e.clientX - this.lastPosX),
y2: y2ToUse + (e.clientY - this.lastPosY)
});
zoomX2 = line.x2;
zoomY2 = line.y2;
}
// hide label/pointer when it is out of view
if (text.left < 0 || line.y2 < 35) {
text.animate("opacity", "0", {
duration: 15,
onChange: labelsCanvas.renderAll.bind(labelsCanvas)
});
line.animate("opacity", "0", {
duration: 15,
onChange: labelsCanvas.renderAll.bind(labelsCanvas)
});
}
// show label/pointer when it is in view
else
{
text.animate("opacity", "1", {
duration: 25,
onChange: labelsCanvas.renderAll.bind(labelsCanvas)
});
line.animate("opacity", "1", {
duration: 25,
onChange: labelsCanvas.renderAll.bind(labelsCanvas)
});
}
specimenCanvas.viewportTransform[4] += e.clientX - this.lastPosX;
specimenCanvas.viewportTransform[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
specimenCanvas.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
console.log(line.x2);
wasPanned = true;
});
labelsCanvas.on("mouse:down", function(opt) {
var evt = opt.e;
if (evt.altKey === true) {
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
});
labelsCanvas.on("mouse:up", function(opt) {
this.isDragging = false;
this.selection = true;
});
.canvas-container {
position: absolute!important;
left: 0!important;
top: 0!important;
}
.canvas {
position: absolute;
top: 0;
right: 0;
border: solid red 1px;
}
.label-canvas {
z-index: 2;
}
.specimen-canvas {
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<h1>
Dual canvas test
</h1>
<div style="position: relative; height: 300px">
<canvas class="canvas specimen-canvas" id="specimenCanvas" width="300" height="300"></canvas>
<canvas class="canvas label-canvas" id="labelsCanvas" width="300" height="300"></canvas>
</div>