How to apply cropping to a zoomed image in JavaScript - javascript

I wrote a class for image cropping. It works fine with non-zoomed images (images in original dimensions), but if I want to apply the cropping to a zoomed image, it goes totally wrong.
Here is the cropping class:
var cropFlag = false; //false = disable cropping | true = enables cropping
function Cropper() {
this.flag1X, this.flag1Y; //startpoint (upper left corner) for rectangle
this.flag2X, this.flag2Y; //endpoint (lower right corner) for rectangle
this.mouseDownFlag = false; // true, if mouse is pressed
};
//gets the startposition of the rectangle
Cropper.prototype.handleMouseDown = function (e) {
if (cropFlag) {
var self = this;
//start of the rectangle
this.flag1X = e.clientX;
this.flag1Y = e.clientY;
this.mouseDownFlag = true;
};
};
//gets the endpoint of the rectangle
Cropper.prototype.handleMouseMove = function (e) {
var self = this;
if (this.mouseDownFlag) {
//end of the rectangle
this.flag2X = e.clientX;
this.flag2Y = e.clientY;
//calculate the position to draw the moved and scaled image
var imgDrawPositionX = (calcedPositionX * scale) + pointX;
var imgDrawPositionY = (calcedPositionY * scale) + pointY;
//redraw the image when rectangles size is changing to avoid multiple rectangles
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, imgDrawPositionX, imgDrawPositionY, width, height);
//draw the rectangle shape
ctx.beginPath();
ctx.lineWidth = "5"; //thickness
ctx.strokeStyle = "red"; //color
ctx.rect(this.flag1X, this.flag1Y, this.flag2X - this.flag1X, this.flag2Y - this.flag1Y);
ctx.stroke();
var draw = function () {
self.mouseDownFlag = false;
//calculate length and height of the clipped image
var clippedLength = width - (width - (self.flag2X - calcedPositionX) + (self.flag1X - calcedPositionX));
var clippedHeight = height - (height - (self.flag2Y - calcedPositionY) + (self.flag1Y - calcedPositionY));
console.log("clippedLength: " + clippedLength, "clippedHeight: " + clippedHeight);
//calculate the start coordinates of the clipping image
var startClippingX = self.flag1X - calcedPositionX;
var startClippingY = self.flag1Y - calcedPositionY;
console.log("startClippingX: " + startClippingX, "startClippingY: " + startClippingY);
//calculate the coordinates to draw the image in the center of the canvas
var centralDrawPosX = (canvas.width / 2) - (clippedLength / 2);
var centralDrawPosY = (canvas.height / 2) - (clippedHeight / 2);
console.log("centralDrawPosX: " + centralDrawPosX, "centralDrawPosY" + centralDrawPosY);
//clear the canvas and draw the clipped image
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, startClippingX, startClippingY, clippedLength, clippedHeight, centralDrawPosX, centralDrawPosY, clippedLength, clippedHeight);
canvas.removeEventListener('mouseup', draw);
};
//draws the rectangle and refreshs the whole canvas
canvas.addEventListener('mouseup', draw);
};
};
//initialize listeners and get button object
Cropper.prototype.initCropper = function () {
var self = this;
var button = document.getElementById('crop-button');
button.addEventListener('click', function () { cropFlag = true; moveFlag = false; });
canvas.addEventListener('mousedown', function (e) { self.handleMouseDown(e); });
canvas.addEventListener('mousemove', function (e) { self.handleMouseMove(e); });
};
var imageCropper = new Cropper();

Related

How can I embed use a file selector in this code instead of specifying the image source?

I found these two pieces of code and I'm quite new to Java. Essentially I'd like to be able to select the image from a file selector (like the first piece of code) instead of specifying the url of an image. Also, is there a way that I could output a list of all the coordinates to the console pr ideally create a txt file with the coords in?
I've left links to jsfiddle for both
thank you!!
http://jsfiddle.net/edprattt/m2a1j8yf/
https://jsfiddle.net/edprattt/8xqo71Lk/
##1
function showImage(src, target) {
var fr = new FileReader();
fr.onload = function(){
target.src = fr.result;
}
fr.readAsDataURL(src.files[0]);
}
function putImage() {
var src = document.getElementById("select_image");
var target = document.getElementById("target");
showImage(src, target);
}
##2
var canvas = document.getElementById('Canvas');
var context = canvas.getContext("2d");
var mapSprite = new Image();
mapSprite.src = "http://www.retrogameguide.com/images/screenshots/snes-legend-of-zelda-linkto-the-past-8.jpg";
var Marker = function () {
this.Sprite = new Image();
this.Sprite.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png"
this.Width = 12;
this.Height = 20;
this.XPos = 0;
this.YPos = 0;
}
var Markers = new Array();
var mouseClicked = function (mouse) {
// Get corrent mouse coords
var rect = canvas.getBoundingClientRect();
var mouseXPos = (mouse.x - rect.left);
var mouseYPos = (mouse.y - rect.top);
console.log("Marker added");
var marker = new Marker();
marker.XPos = mouseXPos - (marker.Width / 2);
marker.YPos = mouseYPos - marker.Height;
Markers.push(marker);
}
canvas.addEventListener("mousedown", mouseClicked, false);
var firstLoad = function () {
context.font = "15px Georgia";
context.textAlign = "center";
}
firstLoad();
var main = function () {
draw();
};
var draw = function () {
// Clear Canvas
context.fillStyle = "#000";
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw map
// Sprite, X location, Y location, Image width, Image height
// You can leave the image height and width off, if you do it will draw the image at default size
context.drawImage(mapSprite, 0, 0, 700, 700);
// Draw markers
for (var i = 0; i < Markers.length; i++) {
var tempMarker = Markers[i];
// Draw marker
context.drawImage(tempMarker.Sprite, tempMarker.XPos, tempMarker.YPos, tempMarker.Width, tempMarker.Height);
// Calculate postion text
var markerText = "Postion (X:" + tempMarker.XPos + ", Y:" + tempMarker.YPos;
// Draw a simple box so you can see the position
var textMeasurements = context.measureText(markerText);
context.fillStyle = "#666";
context.globalAlpha = 0.7;
context.fillRect(tempMarker.XPos - (textMeasurements.width / 2), tempMarker.YPos - 15, textMeasurements.width, 20);
context.globalAlpha = 1;
// Draw position above
context.fillStyle = "#000";
context.fillText(markerText, tempMarker.XPos, tempMarker.YPos);
}
};
setInterval(main, (1000 / 60)); // Refresh 60 times a second

How to draw rectangles onto a JavaScript video?

I am trying to allow users to upload their own video which will then be displayed into a canvas. From there on, they can draw rectangles onto the canvas (to annotate for object detection), and clear the rectangles when they want to. However, what I want is that when the users draw the rectangles and play the video, the rectangles will follow an object on the video. Also, when the user wants to re-draw the rectangles to reposition them, they will clear the rectangles on the canvas - but the previously-drawn rectangles will already be saved.
This is the current code I have:
function update(){
context.drawImage(video,0,0,1580,700);
requestAnimationFrame(update); // wait for the browser to be ready to present another animation fram.
}
function readyToPlayVideo(event){ // this is a referance to the video
// the video may not match the canvas size so find a scale to fit
videoContainer.scale = Math.min(
canvas.width / this.videoWidth,
canvas.height / this.videoHeight);
videoContainer.ready = true;
// the video can be played so hand it off to the display function
requestAnimationFrame(updateCanvas);
// add instruction
/*document.getElementById("playPause").textContent = "Click video to play/pause.";*/
document.querySelector(".mute").textContent = "Mute";
}
function updateCanvas(){
context.clearRect(0,0,canvas.width,canvas.height);
// only draw if loaded and ready
if(videoContainer !== undefined && videoContainer.ready){
// find the top left of the video on the canvas
video.muted = muted;
var scale = videoContainer.scale;
var vidH = videoContainer.video.videoHeight;
var vidW = videoContainer.video.videoWidth;
var top = canvas.height / 2 - (vidH /2 ) * scale;
var left = canvas.width / 2 - (vidW /2 ) * scale;
// now just draw the video the correct size
context.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
/*if(videoContainer.video.paused){ // if not playing show the paused screen
drawPayIcon();
}*/
}
// all done for display
// request the next frame in 1/60th of a second
requestAnimationFrame(updateCanvas);
}
var canvasOffset = $("#canvas2").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var isDrawing = false;
var startX;
var startY;
var mouseIsDown = true;
var mouseIsUp = true;
var startX;
var startY;
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
console.log(mouseX,mouseY);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
// Put your mousedown stuff here
if (mouseIsDown) {
console.log('1');
canvas2.style.cursor="crosshair";
mouseIsDown=false;
mouseIsUp=false;
console.log(mouseIsDown);
} else {
handleMouseUp();
}
mouseIsDown=false;
mouseIsUp=true;
}
function handleMouseUp(e) {
mouseIsDown=false;
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
if (mouseIsUp) {
console.log('2');
context2.beginPath();
context2.rect(startX,startY,mouseX-startX,mouseY-startY);
context2.strokeStyle="limegreen";
context2.lineWidth=2;
context2.stroke();
canvas2.style.cursor="default";
mouseIsUp=true;
}
}
$("#canvas2").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas2").mouseup(function (e) {
handleMouseUp(e);
});
function clearcanvas()
{
var canvas2 = document.getElementById('canvas2'),
context2 = canvas2.getContext("2d");
context2.clearRect(0, 0, canvas2.width, canvas2.height);
}
Any help is appreciated, thank you!

Display a cross from its center

The following code allows me to click on an image (canvas), have coordinates, and place a cross exactly where the click was done. The problem with the cross, that it will be represented from the corner (right-bottom) and i will have an offset between the click and the cross, that do not represent the exact coordinate. In other words, the center of the cross should be the origin of dislaying the coordinates.
How to do that ?
var canvas = document.getElementById('Canvas');
var context = canvas.getContext("2d");
// Map sprite
var mapSprite = new Image();
mapSprite.src = "image.png";
//Declare Marker sprite
var Marker = function () {
this.Sprite = new Image();
this.Sprite.src = "cross.png"
this.Width = 10;
this.Height = 10;
this.XPos = 0;
this.YPos = 0;
}
var Markers = new Array();
var mouseClicked = function (mouse) {
// Get corrent mouse coords
var rect = canvas.getBoundingClientRect();
var mouseXPos = Math.round(mouse.x - rect.left);
var mouseYPos = Math.round(mouse.y - rect.top);
console.log("Marker added");
// Move the marker when placed to a better location
var marker = new Marker();
marker.XPos = mouseXPos - (marker.Width / 2);
marker.YPos = mouseYPos - marker.Height;
marker.YPosNew = marker.YPos;
Markers.push(marker);
// Draw marker
context.drawImage(Markers[0].Sprite, Markers[0].XPos, Markers[0].YPos, Markers[0].Width, Markers[0].Height);
// Calculate postion text
var markerText = Markers[0].XPos + ", " + Markers[0].YPosNew;
// disable pointer after 1s
setTimeout( function(){
document.getElementById('Canvas').style.cursor="not-allowed"; } , 1000 );
}
// Add mouse click event listener to canvas
canvas.addEventListener("mousedown", mouseClicked, false);
var main = function () {
draw();
};
var draw = function () {
// Clear Canvas
context.fillStyle = "#000";
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw diagramme
context.drawImage(mapSprite, 0, 0, 954, 267);
//draw all precedent cross
cross = new Image();
cross.src = "cross.png";
}
mapSprite.addEventListener('load', main);
<div style="width : 75%;margin : auto;">
<canvas id="Canvas" width="954" height="267"></canvas>
</div>
var marker = new Marker();
marker.XPos = mouseXPos - (marker.Width / 2);
marker.YPos = mouseYPos - (marker.Height / 2);
marker.YPosNew = marker.YPos;
Markers.push(marker);
change your marker's Ypos , that's why its going up. in this case cross will position at middle of click.

Use Clip Function to with Gradient Effect with JavaScript on Canvas

I'm trying to use the clip() function in canvas to create this effect, as pictured: there is a background image, and when your mouse hover on it, part of the image is shown. I got it to work as a circle, but I want this gradient effect you see the picture. How do I achieve that?
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/normalize.css">
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/style.css">
</head>
<body>
<canvas id="canvas" width="2000" height="1200"></canvas>
<script>
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
can.addEventListener('mousemove', function(e) {
var mouse = getMouse(e, can);
redraw(mouse);
}, false);
function redraw(mouse) {
console.log('a');
can.width = can.width;
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.drawImage(img, 0, 0);
ctx.beginPath();
ctx.rect(0,0,2000,1200);
ctx.arc(mouse.x, mouse.y, 200, 0, Math.PI*2, true)
ctx.clip();
ctx.fillRect(0,0,2000,1200);
}
var img = new Image();
img.onload = function() {
redraw({x: 0, y: 0})
}
img.src = 'http://placekitten.com/2000/1000';
function getMouse(e, canvas) {
var element = canvas,
offsetX = 0,
offsetY = 0,
mx, my;
// Compute the total offset. It's possible to cache this if you want
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {
x: mx,
y: my
};
}
</script>
USING a RADIAL gradient
There are many ways to do that but the simplest is a gradient with an alpha.
First you need to define the size of the circle you wish to show.
var cirRadius = 300;
Then the location (canvas coordinates) where this circle will be centered
var posX = 100;
var posY = 100;
Now define the rgb colour
var RGB = [0,0,0] ; // black
Then an array of alpha values to define what is transparent
var alphas = [0,0,0.2,0.5,1]; // zero is transparent;
Now all you do is render the background image
// assume ctx is context and image is loaded
ctx.drawImage(image, 0, 0, ctx.canvas.width, ctx.canvas.height); // fill the canvas
Then create the gradient with it centered at the position you want and the second circle at the radius you want. The first 3 numbers define the center and radius of the start of the gradient, the last 3 define the center and radius of the end
var grad = ctx.createRadialGradient(posX,posY,0,posX,posY,cirRadius);
Now add the colour stops using the CSS color string rgba(255,255,255,1) where the last is the alpha value from 0 to 1.
var len = alphas.length-1;
alphas.forEach((a,i) => {
grad.addColorStop(i/len,`rgba(${RGB[0]},${RGB[1]},${RGB[2]},${a})`);
});
or for legacy browsers that do not support arrow functions or template strings
var i,len = alphas.length;
for(i = 0; i < len; i++){
grad.addColorStop(i / (len - 1), "rgba(" + RGB[0] + "," + RGB[1] + "," + RGB[2] + "," + alphas[i] + ")");
}
Then set the fill style to the gradient
ctx.fillStyle = grad;
then just fill a rectangle covering the image
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);
And you are done.
By setting the position with via a mouse event and then doing the above steps 60times a second using window.requestAnimationFrame you can get the effect you are looking for in real time.
Here is an example
// create a full screen canvas
var canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.left = "0px";
canvas.style.top = "0px";
canvas.style.zIndex = 10;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
// var to hold context
var ctx;
// load an image
var image = new Image();
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";
// add resize event
var resize = function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext("2d");
}
// add mouse event. Because it is full screen no need to bother with offsets
var mouse = function(event){
posX = event.clientX;
posY = event.clientY;
}
// incase the canvas size is changed
window.addEventListener("resize",resize);
// listen to the mouse move
canvas.addEventListener("mousemove",mouse)
// Call resize as that gets our context
resize();
// define the gradient
var cirRadius = 300;
var posX = 100; // this will be set by the mouse
var posY = 100;
var RGB = [0,0,0] ; // black any values from 0 to 255
var alphas = [0,0,0.2,0.5,0.9,0.95,1]; // zero is transparent one is not
// the update function
var update = function(){
if(ctx){ // make sure all is in order..
if(image.complete){ // draw the image when it is ready
ctx.drawImage(image,0,0,canvas.width,canvas.height)
}else{ // while waiting for image clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
}
// create gradient
var grad = ctx.createRadialGradient(posX,posY,0,posX,posY,cirRadius);
// add colour stops
var len = alphas.length-1;
alphas.forEach((a,i) => {
grad.addColorStop(i/len,`rgba(${RGB[0]},${RGB[1]},${RGB[2]},${a})`);
});
// set fill style to gradient
ctx.fillStyle = grad;
// render that gradient
ctx.fillRect(0,0,canvas.width,canvas.height);
}
requestAnimationFrame(update); // keep doing it till cows come home.
}
// start it all happening;
requestAnimationFrame(update);

myContext.clearRect(0, 0, 500, 700); Not Clearing Canvas Correctly

I have an HTML5 Canvas that can be drawn on with the mouse. I would like to be able to clear the canvas so the user can make a new drawing. I do this with:
myContext.clearRect(0, 0, 500, 700);
The canvas appears clear but as soon as the user begins a new drawing the old drawing reappears. My JavaScript for the mouse drawing part is:
// Variables
var x1;
var y1;
var isPressed = false;
var myCanvas;
var myContext;
function startCanvas() {
// Canvas stuff
myCanvas = document.getElementById("can1");
myContext = myCanvas.getContext("2d");
// Specify a black background, and white lines that are 3 pixels thick.
myContext.fillStyle = '#000000';
myContext.strokeStyle = '#000000';
myContext.fillRect(0, 0, 500, 700);
myContext.lineWidth = 3;
myContext.fill();
}
function functionMouseDown(e) {
// Get coordinates
x1 = e.clientX - myCanvas.offsetLeft;
y1 = e.clientY - myCanvas.offsetTop;
isPressed = true;
}
function functionMouseMove(e) {
// If mouse is down and moved start drawing line
if (isPressed == true) {
drawLine(e);
}
}
function functionMouseUp() {
// Stop drawing line
isPressed = false;
}
function drawLine(e) {
// Draw line
var x = e.clientX - myCanvas.offsetLeft;
var y = e.clientY - myCanvas.offsetTop;
myContext.strokeStyle = '#ffffff';
myContext.lineWidth = 1;
myContext.moveTo(x1, y1);
myContext.lineTo(x, y);
myContext.stroke();
// Set start coordinates to current coordinates
x1 = x;
y1 = y;
}
startCanvas();
The HTML is:
<canvas id="can1" width="500" height="700"></canvas>
myContext.strokeStyle = '#000000';
myContext.beginPath();//<---- add this and read about this.
myContext.fillRect(0, 0, 500, 700);
myContext.lineWidth = 3; //why?
myContext.fill();

Categories