275 lines
12 KiB
Plaintext
275 lines
12 KiB
Plaintext
|
|
(function($) {
|
|
$.fn.annotatorPNG = function(options) {
|
|
var settings = $.extend({
|
|
heightCanvas: "600px",
|
|
widthCanvas: "800px",
|
|
textButtonSave: "Save Image",
|
|
}, options);
|
|
|
|
|
|
function getCanvas() {
|
|
let $annotatorPNG = $(document).find("." + flagAnnotatorPNG);
|
|
let $canvasAnnotation = $($annotatorPNG.find("canvas." + flagCanvasAnnotation)[0]);
|
|
let canvas = $canvasAnnotation.data(keyFabric);
|
|
return canvas;
|
|
}
|
|
|
|
function deleteSelectedObjects() {
|
|
let canvas = getCanvas();
|
|
const activeObject = canvas.getActiveObject();
|
|
if (activeObject) {
|
|
console.log("active object type:", activeObject.type);
|
|
if (activeObject.type === 'activeSelection') {
|
|
activeObject.forEachObject(function(obj) {
|
|
canvas.remove(obj);
|
|
});
|
|
canvas.discardActiveObject();
|
|
} else {
|
|
canvas.remove(activeObject);
|
|
}
|
|
canvas.requestRenderAll();
|
|
}
|
|
}
|
|
|
|
return this.each(function() {
|
|
let $annotatorPNG = $(this);
|
|
let $toolbox = $annotatorPNG.find("." + flagToolbox);
|
|
let $inputUploadImage = $toolbox.find("." + flagUploadImage);
|
|
let $buttonAddArrow = $toolbox.find("." + flagAddArrow);
|
|
let $buttonAddTextbox = $toolbox.find("." + flagAddTextbox);
|
|
let $selectAddSymbol = $toolbox.find("." + flagAddSymbol);
|
|
let $inputColourPicker = $toolbox.find("." + flagColourPicker);
|
|
let $buttonEraseMode = $toolbox.find("." + flagEraseMode);
|
|
let $buttonSaveImage = $toolbox.find("." + flagSaveImage);
|
|
let $containerAnnotation = $annotatorPNG.find("." + flagContainerAnnotation);
|
|
let $canvasAnnotation = $containerAnnotation.find("." + flagCanvasAnnotation);
|
|
|
|
// Default values
|
|
$inputUploadImage.val('');
|
|
|
|
const symbols = ['Orange Arrow.png'];
|
|
symbols.forEach(symbol => {
|
|
$selectAddSymbol.append($("<option>", {
|
|
value: symbol,
|
|
text: symbol.replace('.png', ''),
|
|
}));
|
|
});
|
|
|
|
$inputColourPicker.val('#ff0000');
|
|
|
|
$buttonEraseMode.textContent = "Erase Mode";
|
|
$annotatorPNG.data(keyIsEraseMode, false);
|
|
|
|
$buttonSaveImage.text(settings.textButtonSave);
|
|
|
|
$canvasAnnotation.css({
|
|
height: settings.heightCanvas,
|
|
width: settings.widthCanvas,
|
|
});
|
|
console.log("canvas: ", $canvasAnnotation[0]);
|
|
var canvas = new fabric.Canvas($canvasAnnotation[0], {
|
|
// containerClass: flagContainerAnnotation,
|
|
});
|
|
canvas.clear();
|
|
canvas.selection = true;
|
|
$canvasAnnotation.data(keyFabric, canvas);
|
|
|
|
// Triggers
|
|
if (!$inputUploadImage.hasClass(flagInitialised)) {
|
|
$inputUploadImage.addClass(flagInitialised);
|
|
$inputUploadImage.on("change", function(event) {
|
|
console.log("File uploaded:", event.target.files[0]);
|
|
const file = event.target.files[0];
|
|
if (!file) {
|
|
return;
|
|
}
|
|
if (!(file.type == 'image/png')) {
|
|
alert("Please upload a PNG file.");
|
|
throw new Error("Invalid file type.");
|
|
return;
|
|
}
|
|
const reader = new FileReader();
|
|
let canvas = getCanvas();
|
|
reader.onload = function(eventReader) {
|
|
fabric.Image.fromURL(eventReader.target.result, function(image) {
|
|
canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas), {
|
|
scaleX: settings.widthCanvas.replace('px', '') / image.width,
|
|
scaleY: settings.heightCanvas.replace('px', '') / image.height,
|
|
});
|
|
});
|
|
};
|
|
reader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|
|
if (!$buttonAddArrow.hasClass(flagInitialised)) {
|
|
$buttonAddArrow.addClass(flagInitialised);
|
|
$buttonAddArrow.on("click", function() {
|
|
console.log("Add Arrow clicked");
|
|
let canvas = getCanvas();
|
|
const arrow = new fabric.Path('M 0 0 L 200 100', {
|
|
fill: $inputColourPicker.val(),
|
|
stroke: $inputColourPicker.val(),
|
|
strokeWidth: 2,
|
|
left: 100,
|
|
top: 100,
|
|
selectable: true,
|
|
});
|
|
canvas.add(arrow);
|
|
canvas.renderAll();
|
|
});
|
|
}
|
|
|
|
if (!$buttonAddTextbox.hasClass(flagInitialised)) {
|
|
$buttonAddTextbox.addClass(flagInitialised);
|
|
$buttonAddTextbox.on("click", function() {
|
|
console.log("Add Textbox clicked");
|
|
let canvas = getCanvas();
|
|
const textbox = new fabric.Textbox('Type here', {
|
|
left: 100,
|
|
top: 100,
|
|
width: 150,
|
|
fontSize: 20,
|
|
fill: $inputColourPicker.val(),
|
|
selectable: true,
|
|
});
|
|
canvas.add(textbox);
|
|
canvas.renderAll();
|
|
});
|
|
}
|
|
|
|
if (!$selectAddSymbol.hasClass(flagInitialised)) {
|
|
$selectAddSymbol.addClass(flagInitialised);
|
|
$selectAddSymbol.on("change", function() {
|
|
console.log("Add Symbol changed:", this.value);
|
|
if (this.value) {
|
|
let canvas = getCanvas();
|
|
fabric.Image.fromURL(`symbols/${this.value}`, function(image) {
|
|
image.set({
|
|
left: 100,
|
|
top: 100,
|
|
scaleX: 0.5,
|
|
scaleY: 0.5,
|
|
});
|
|
canvas.add(image);
|
|
});
|
|
this.value = '';
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!$inputColourPicker.hasClass(flagInitialised)) {
|
|
$inputColourPicker.addClass(flagInitialised);
|
|
$inputColourPicker.on("change", function() {
|
|
console.log("Colour Picker changed:", this.value);
|
|
let canvas = getCanvas();
|
|
canvas.renderAll();
|
|
const activeObject = canvas.getActiveObject();
|
|
if (activeObject) {
|
|
if (activeObject.type === 'textbox') {
|
|
activeObject.set('fill', this.value);
|
|
} else {
|
|
activeObject.set('fill', this.value);
|
|
activeObject.set('stroke', this.value);
|
|
}
|
|
canvas.renderAll();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!$buttonEraseMode.hasClass(flagInitialised)) {
|
|
$buttonEraseMode.addClass(flagInitialised);
|
|
$buttonEraseMode.data(keyIsEraseMode, false);
|
|
$buttonEraseMode.on("click", function() {
|
|
console.log("Erase Mode clicked");
|
|
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
|
|
isEraseMode = !isEraseMode;
|
|
$annotatorPNG.data(keyIsEraseMode, isEraseMode);
|
|
console.log("Erase Mode:", isEraseMode);
|
|
this.textContent = isEraseMode ? 'Exit Erase Mode' : 'Erase Mode';
|
|
|
|
if (isEraseMode) {
|
|
deleteSelectedObjects();
|
|
|
|
canvas.selection = false;
|
|
canvas.isDrawingMode = false;
|
|
|
|
canvas.defaultCursor = 'crosshair';
|
|
canvas.hoverCursor = 'crosshair';
|
|
} else {
|
|
canvas.selection = true;
|
|
canvas.defaultCursor = 'default';
|
|
canvas.hoverCursor = 'move';
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
if (!$canvasAnnotation.hasClass(flagInitialised)) {
|
|
$canvasAnnotation.addClass(flagInitialised);
|
|
// Object selection in erase mode
|
|
$canvasAnnotation.on('selection:created', function() {
|
|
console.log("Selection created");
|
|
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
|
|
if (isEraseMode) {
|
|
deleteSelectedObjects();
|
|
}
|
|
});
|
|
|
|
// Object click in erase mode
|
|
$canvasAnnotation.on('mouse:down', function(event) {
|
|
console.log("Canvas mouse down:", event);
|
|
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
|
|
if (isEraseMode && event.target) {
|
|
let canvas = getCanvas();
|
|
canvas.remove(event.target);
|
|
canvas.requestRenderAll();
|
|
}
|
|
});
|
|
|
|
// Prevent dragging in erase mode
|
|
$canvasAnnotation.on('object:moving', function(event) {
|
|
console.log("Canvas object moving:", event);
|
|
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
|
|
if (isEraseMode) {
|
|
let canvas = getCanvas();
|
|
event.target.setCoords();
|
|
canvas.remove(event.target);
|
|
canvas.requestRenderAll();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!$buttonSaveImage.hasClass(flagInitialised)) {
|
|
$buttonSaveImage.addClass(flagInitialised);
|
|
$buttonSaveImage.on("click", function() {
|
|
let canvas = getCanvas();
|
|
if (window.confirm("Please ensure there is no sensitive information or PII in your annotations. Do you want to proceed with saving?")) {
|
|
const dataURL = canvas.toDataURL({
|
|
format: 'png',
|
|
quality: 1
|
|
});
|
|
|
|
// Output
|
|
console.log("Base64 string:", dataURL);
|
|
|
|
let a = document.createElement('a');
|
|
a.style.display = 'none';
|
|
a.href = dataURL;
|
|
a.download = settings.fileName;
|
|
|
|
/* Download image
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
*/
|
|
|
|
alert("Image saved as Base64 string. Check the console for the output.");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
}(jQuery));
|