How to prevent randomly positioned images from overlapping using Angular - javascript

I have an Angular application that loads multiple images on to the page at random locations by utilizing the following code:
HTML:
<div ng-repeat="s in selectedImages" class="container">
<img ng-src="{{s.img}}" class="sImage" ng-style="s.pos"/>
</div>
CSS:
.wordImage {
position:absolute;
width:100px;
}
JS Controller:
function loadImages() {
$scope.myImages = ['img1.png', 'img2.png', 'img3.png', 'img4.png', 'img5.png']
$scope.selectedImages = [];
for (i in $scope.myImages) {
$scope.selectedImages.push(addRandomLocationToImage($scope.myImages[i]));
}
}
function addRandomLocationToImage(image) {
image.pos = {};
var preTop = getRandomHeight(); // get Height for this image
var preLeft = getRandomWidth(); // get Width for this image
image.pos = {top:preTop,
left:preLeft};
return image; // returns the same image object but contains pos{} for ng-style
}
function getRandomHeight() {
var imgHeight = 100;
var winHeight = $(window).height();
var randomH = Math.random() * (winHeight - 100); // subtract 100 for the header. and also footer padding
if (randomH < 150) {
randomH += 150; // add to keep it out of the header
}
if(winHeight - randomH < 100) { // if image will be on bottom edge of page
randomW -= imgHeight; // subtract 100 because that is the height of the images, this will prevent them from being partially off the page
}
return randomH;
}
function getRandomWidth() {
var imgWidth = 100;
var winWidth = $(window).width();
var randomW = Math.random() * winWidth;
if (randomW < 0) { // make sure it is not less than zero, then assign new number until it is greater than zero
while (randomW < 0) {
randomW = Math.random() * winWidth;
}
}
if (winWidth - randomW < 100) { // if image will be on right edge of page
randomW -= imgWidth; // subtract 100 because that is the width of the images, this will prevent them from being partially off the page
}
return randomW;
}
loadImages();
This definitely generates random images on a page...but they overlap very easily. My question is, how can I prevent them from overlapping? Here is some code that I have been working on.
var newLeft = currentImage.pos.left;
var newTop = currentImage.pos.top;
for (i in $scope.selectedImages) {
var originalLeft = $scope.selectedImages[i].pos.left;
var originalTop = $scope.selectedImages[i].pos.top;
if ((originalLeft - newLeft < 100 && originalLeft - newLeft > -100) && // could overlap horizontally
(originalTop - newTop < 100 && originalTop - newTop > -100)) { // could overlap vertically
//do something to select a new random location.
}
}

Basically you have to check a image position with every other image. You can use Array.some for this:
Considering that you store the image position in the image object as
x and y properties
function checkCollision(testImage) {
return $scope.myImages.some(function(img) {
if (img == testImage)
return false;
if (!img.x || !img.y) // Image has no position yet
return false;
return
testImage.x < img.x + imgWidth &&
testImage.x + imgWidth > img.x &&
testImage.y < img.y + imgHeight &&
testImage.y + imgHeight > img.y;
});
}
You have to be aware that depending of the available space and image sizes there might be a situation where is not possible to find a suitable position for a image.
I made a functional example.

Related

Resize window with smooth transition for different height sizes

Some context:
I'm working on a Chrome Extension where the user can launch it via default "popup.html", or if the user so desires this Extension can be detached from the top right corner and be used on a popup window via window.open
This question will also apply for situations where users create a Shortcut for the extension on Chrome via:
"..." > "More tools" > "Create Shortcut"
Problem:
So what I need is for those cases where users use the extension detached via window.open or through a shortcut, when navigating through different options, for the Height of the window to be resized smoothly.
I somewhat achieve this but the animation is clunky and also the final height is not always the same. Sometimes I need to click twice on the button to resize too because 1 click won't be enough. Another issue is there is also some twitching of the bottom text near the edge of the window when navigating.
Here's what I got so far:
(strWdif and strHdif are used to compensate for some issues with CSS setting proper sizes which I haven't figured out yet.)
const popup = window;
function resizeWindow(popup) {
setTimeout(function () {
var strW = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var height = window.innerHeight;
console.log("Window Height: ", height, "CSS Height: ", bodyTargetHeight);
var timer = setInterval(function () {
if (height < bodyTargetHeight) {
popup.resizeTo(bodyTargetWidth, height += 5);
if (height >= bodyTargetHeight) {
clearInterval(timer);
}
} else if (height > bodyTargetHeight) {
popup.resizeTo(bodyTargetWidth, height -= 5);
if (height <= bodyTargetHeight) {
clearInterval(timer);
}
} else {
clearInterval(timer);
}
}, 0);
}, 0400);
}
Question:
Is there a way to make this more responsive, and smooth and eliminate all the twitching and clunkiness?
I guess the issue might be that I am increasing/diminishing by 5 pixels at a time but that is the speed I need. Maybe there is another way to increase/decrease by 1px at a faster rate? Could this be the cause of the twitching and clunkiness?
Also, I should add that troubleshooting this is difficult because the browser keeps crashing so there is also a performance issue sometimes when trying different things.
EDIT:
Another option using resizeBy:
function animateClose(time) {
setTimeout(function () {
var strW = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var w = window.innerWidth; //Get window width
var h = window.innerHeight; //Get window height
var loops = time * 0.1; //Get nb of loops
var widthPercentageMinus = (w / loops) * -0;
var heightPercentageMinus = (h / loops) * -1;
var widthPercentagePlus = (w / loops) * +0;
var heightPercentagePlus = (h / loops) * +1;
console.log("Window Height: ", h, "CSS Height: ", bodyTargetHeight);
var loopInterval = setInterval(function () {
if (h > bodyTargetHeight) {
window.resizeBy(widthPercentageMinus, heightDecrheightPercentageMinuseasePercentageMinus);
} else if (h < bodyTargetHeight) {
window.resizeBy(widthPercentagePlus, heightPercentagePlus);
} else {
clearInterval(loopInterval);
}
}, 1);
}, 0400);
}
This one is a bit more smooth but I can't make it stop at the desired Height. It also is not differentiating between resizing up or down, also crashes the browser sometimes.
maybe with requestAnimationFrame
try something like this (not tested):
function resizeWindow(popup) {
var gcs = getComputedStyle(window.document.querySelector(".body_zero"));
var strW = gcs.getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = gcs.getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var height = window.innerHeight;
console.log("Window Height: ", height, "CSS Height: ", bodyTargetHeight);
window.myRequestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var hStep = 2; //choose the step. Must be an integer
function internalFunc() {
if (Math.abs(height - bodyTargetHeight) > hStep) {
if (height < bodyTargetHeight)
hStep *= 1;
else if (height > bodyTargetHeight)
hStep *= -1;
popup.resizeBy(0, hStep);
height += hStep;
window.myRequestAnimationFrame(internalFunc)
} else
popup.resizeBy(0, bodyTargetHeight - height)
}
popup.resizeTo(bodyTargetWidth, height);
window.myRequestAnimationFrame(internalFunc)
}
<html>
<head>
<script>
const bodyTargetWidth = 150;
const bodyTargetHeight = 250; //target height
var height; //height at beginning
window.myRequestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
var hStep = 5; //choose the step. Must be an integer
var dir;
var myPopup;
function doResize() {
function internalFunc() {
console.log('height: ', height) ;
if (Math.abs(height - bodyTargetHeight) > hStep) {
dir = Math.sign(bodyTargetHeight - height);
myPopup.resizeBy(0, dir * hStep);
height += dir * hStep;
window.myRequestAnimationFrame(internalFunc)
} else
myPopup.resizeBy(0, bodyTargetHeight - height)
}
if (!myPopup || myPopup?.closed) {
myPopup = window.open("about:blank", "hello", "left=200,top=200,menubar=no,status=no,location=no,toolbar=no");
height = 150;
myPopup.resizeTo(bodyTargetWidth, height);
} else {
myPopup.focus();
height = myPopup.outerHeight
}
myPopup.resizeTo(bodyTargetWidth, height);
window.myRequestAnimationFrame(internalFunc)
}
document.addEventListener('DOMContentLoaded', _ => document.getElementById('myBtn').addEventListener('click', doResize))
</script>
</head>
<body>
<button type="button" id="myBtn">Create popup<br>\<br>Reset popup height</button><br>
<p>First create the popup, then change popup height and click the button above again</p>
</body>
</html>

How to start function at specific scroll position on page?

I'm experimenting with the following code where images flip through in a canvas.
If I put the canvas, let's say at the middle of my page, I was wondering if there's a way to only make the images flip through once the viewer gets to that specific section of the page.
Right now, from the looks of it, the images start flipping through right at the top of the page, immediately when you scroll down. By the time you get to the middle of the page where the actual canvas is, the images have already finished flipping through, and it's stopped on the last frame.
I assume I have to set the function to only trigger after the user scrolls to a specific number of pixels on the Y-axis? What's the best way to do so?
Please see code below.
Thanks!
var images = new Array();
var currentLocation = 0;
var totalImages = 200;
for (var i = 1; i < totalImages; i++) {
var img = new Image;
var slug = '000' + i;
img.src = 'https://s3.amazonaws.com/clearmotion/hero/high-min/frame' + slug.slice(-3) + '-low.jpg'
images.push(img);
}
var c = document.getElementById("background");
var ctx = c.getContext("2d");
var mouseWheel = function() {
var newLocation = null;
window.addEventListener('wheel', function(e) {
e.preventDefault(); // No scroll
// update our variable at high frequency
var delta = Math.max(-1, Math.min(1, e.deltaY));
if (delta == -1) currentLocation += 1;
if (delta == 1) currentLocation -= 1;
if (currentLocation < 0) currentLocation = 0;
if (currentLocation >= (totalImages - 1)) currentLocation = (totalImages - 1);
if (newLocation === null) { // if set, we already are waiting to draw
requestAnimationFrame(setImage);
}
newLocation = currentLocation;
});
function setImage() {
if (images[newLocation]) {
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[newLocation], 0, 0, 1000, 1000);
}
newLocation = null; // so the throttler knows we can draw again
}
}
images[0].onload = function() {
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[currentLocation], 0, 0, 1000, 1000);
mouseWheel();
};
<canvas id="background" width="1000" height="1000"></canvas>
You can actually start make the images flip through once the viewer gets to that specific section of the page by using The Intersection Observer API
So you have to detect when your element in the the viewport, the canvas in this case.
To do this you have multiple ways.
By using Observer API
const element = document.querySelector("#background")
const Ob = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) {
// Not in the viewport
} else {
// In the viewport
// You're code here
}
});
Ob.observe(element);
Or if you want to do it in you're own.
You can use this and adapt it if needed
function elementInViewport(el) {
var top = el.offsetTop
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
}
return (
top >= window.pageYOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight)
);
}

I am trying to fit number of images in one div

What I am trying to do
I want to display multiple images in the same div of fixed size like the image. There will be multiple divs in the same page. The total size of the divs should not exceed the size of the screen.
function setupView(div, items, height, percentage) {
//get the height for the div
//var max_height = getPossibleHeight(div, items);
if(percentage){
$(div).css("height" , $(window).height() / 100 * height);
} else
$(div).css("height" , height+"px");
$(div).css("line-height",0);
//get the computed height and width
const div_height = $(div).height();
const div_width = $(div).width();
//Calculate the side of each image
const im_side = parseInt(getItemSize(div_width, div_height, items));
var count;
var dv = $(div);
for(count=0; count <= items; count++){
dv.append("<img style='height: "+ im_side +"px;"+" width: "+ im_side+"px" +"' src='../images/done.png'/>");
}
}
function getItemSize(x, y, n) {
var px = Math.ceil(Math.sqrt(n*x/y));
var sx,sy;
if(Math.floor((px*y)/x)*px < n){
sx = y/Math.ceil(px*y/x);
} else{
sx = x/px;
}
var py = Math.ceil(Math.sqrt((n*y)/x));
if(Math.floor((py*x)/y)*py<n){
sy = x/Math.ceil((x*py)/y);
}
else {
sy = y/py;
}
// alert("X="+sx + " Y="+sy);
// if(x>y)
return (sx>sy) ? sx : sy;
}
$(function() {
setupView(".panel-4",25000,"60",true);
// setupView(".panel-5",9000);
alert("Load complete!");
});
This is what is happening right now:
Current Situation
I have used the code provided on
C Code
I want to resize the images in such a way that they fill the div completely without leaving any space.

Algorithm - Best way to determine dimensions for an image size based off its height and width?

I have a bunch of images I am parsing and I have access to their url, height, and width.
I want to place these images in a photo grid that has three different objects of set height and width. I am trying to come up with a good way to place each image in each "class" of item based off its dimensions and which one it would "fit" best with so it is not stretched.
For example:
var imageSource = //source of image;
var imageHeight = //height of image;
var imageWidth = //width of image;
var imageClass = bestClass(imageHeight, imageWidth);
function bestClass(height, width){
var classes = ["250,500", "500,500", "300,400"];
//do some magic to determine which class is the best dimensions for this image in a photo grid.
}
I wanted to post this question to see if there was any magic built in that helped me out here before I dug into finding the mean difference between height, width and comparing it to the nearest "bin" or whatever...
As you have answers that technically achieve what you are after I thought I'd put it to you differently:
Is squeezing a 300x500 image into a 250x500 space really acceptable? There will still be distortions.
The ideal answer would be to restructure your data to put some constraints on image dimension ratio, either when images are inserted into the system or run some image processing to crop images to the correct ratio. Note that background-size: cover; may help here, and place the image into the background (background-size only works on background images, not <img /> elements). Even better than constraining resolution would be to constrain size to the exact sizes you want.
Ideally you'd probably want to change your presentation layer to work with your data (which is arbitrarily sized), but, if that is not an option, you have to try and manipulate your data to match how you want to present. Stretched or squeezed images are never going to look good.
Using the height/width ratio:
var func = function bestClass(height, width){
var classes = [{ Width: 250, Height: 500} , { Width: 500, Height: 500}, { Width: 300, Height: 400}];
var minDist = 1;
var ratio = height / width;
var index = 0;
for(var i = 0; i < 3; i++) {
var dist = Math.abs((classes[i].Height / classes[i].Width) - ratio);
if (dist < minDist) {
minDist = dist;
index = i;
}
}
return classes[index];
}
var result = func(100,100);
You can try using the ratio height/width.
var ratio = (imageHeight/imageWidth);
if ( Math.abs(ratio - 250/500) <= Math.abs(ratio - 500/500) && Math.abs(ratio - 250/500) <= Math.abs(ratio - 300/400){
console.log("best is 250/500")
}
else if ( Math.abs(ratio - 500/500) <= Math.abs(ratio - 250/500) && Math.abs(ratio - 500/500) <= Math.abs(ratio - 300/400){
console.log("best is 500/500")
}
else{console.log("best is 300/400")}
Update: If you dont want to be any distortions and just find the perfect size to fit the images in these classes use the image ratio and the differece between the class ratio like this:
var ratio = (imageHeight/imageWidth);
if ( Math.abs(ratio - 250/500) <= Math.abs(ratio - 500/500) && Math.abs(ratio - 250/500) <= Math.abs(ratio - 300/400){
var dif = ratio-0.5;
if(dif<=0){
var newImageWidth = 500;
var newImageHeight = 500*ratio
}
else{
var newImageWidth = 500 - (500*dif);
var newImageHeight = 250;
}
}
else if ( Math.abs(ratio - 500/500) <= Math.abs(ratio - 250/500) && Math.abs(ratio - 500/500) <= Math.abs(ratio - 300/400){
console.log("best is 500/500");
var dif = ratio-1;
if(dif<=0){
var newImageWidth = 500;
var newImageHeight = 500*ratio
}
else{
var newImageWidth = 500 - (500*dif);
var newImageHeight = 500;
}
}
else{console.log("best is 300/400")
var dif = ratio-0.75;
if(dif<=0){
var newImageWidth = 400;
var newImageHeight = 400*ratio
}
else{
var newImageWidth = 400 - (400*dif);
var newImageHeight = 300;
}
}

fengyuanchen Cropper - How to Fit Image into Canvas If Rotated?

I gone through documentation of cropper by fengyuanchen. I want the image to be fit by default into canvas if rotated. But I couldnt find a way to achieve this. Any idea how to achieve this functionality?
I want it to be like this to be default: link
Check issue demo here: link
I fixed this behavior but for my special needs. I just needed one rotate button which rotates an image in 90° steps. For other purposes you might extend/change my fix.
It works in "strict" mode by dynamically change the cropbox dimensions.
Here my function which is called, when I want to rotate an image. Ah and additionally the misplacement bug has also been fixed.
var $image;
function initCropper() {
$image = $('.imageUploadPreviewWrap > img').cropper({
autoCrop : true,
strict: true,
background: true,
autoCropArea: 1,
crop: function(e) {
}
});
}
function rotateImage() {
//get data
var data = $image.cropper('getCropBoxData');
var contData = $image.cropper('getContainerData');
var imageData = $image.cropper('getImageData');
//set data of cropbox to avoid unwanted behavior due to strict mode
data.width = 2;
data.height = 2;
data.top = 0;
var leftNew = (contData.width / 2) - 1;
data.left = leftNew;
$image.cropper('setCropBoxData',data);
//rotate
$image.cropper('rotate', 90);
//get canvas data
var canvData = $image.cropper('getCanvasData');
//calculate new height and width based on the container dimensions
var heightOld = canvData.height;
var heightNew = contData.height;
var koef = heightNew / heightOld;
var widthNew = canvData.width * koef;
canvData.height = heightNew;
canvData.width = widthNew;
canvData.top = 0;
if (canvData.width >= contData.width) {
canvData.left = 0;
}
else {
canvData.left = (contData.width - canvData.width) / 2;
}
$image.cropper('setCanvasData', canvData);
//and now set cropper "back" to full crop
data.left = 0;
data.top = 0;
data.width = canvData.width;
data.height = canvData.height;
$image.cropper('setCropBoxData',data);
}
This is my extended code provided by AlexanderZ to avoid cuttong wider images than container :)
var contData = $image.cropper('getContainerData');
$image.cropper('setCropBoxData',{
width: 2, height: 2, top: (contData.height/ 2) - 1, left: (contData.width / 2) - 1
});
$image.cropper('rotate', 90);
var canvData = $image.cropper('getCanvasData');
var newWidth = canvData.width * (contData.height / canvData.height);
if (newWidth >= contData.width) {
var newHeight = canvData.height * (contData.width / canvData.width);
var newCanvData = {
height: newHeight,
width: contData.width,
top: (contData.height - newHeight) / 2,
left: 0
};
} else {
var newCanvData = {
height: contData.height,
width: newWidth,
top: 0,
left: (contData.width - newWidth) / 2
};
}
$image.cropper('setCanvasData', newCanvData);
$image.cropper('setCropBoxData', newCanvData);
Not a direct answer to the question ... but i'm betting many people that use this plugin will find this helpfull..
Made this after picking up #AlexanderZ code to rotate the image.
So ... If you guys want to ROTATE or FLIP a image that has already a crop box defined and if you want that cropbox to rotate or flip with the image ... use these functions:
function flipImage(r, data) {
var old_cbox = $image.cropper('getCropBoxData');
var new_cbox = $image.cropper('getCropBoxData');
var canv = $image.cropper('getCanvasData');
if (data.method == "scaleX") {
if (old_cbox.left == canv.left) {
new_cbox.left = canv.left + canv.width - old_cbox.width;
} else {
new_cbox.left = 2 * canv.left + canv.width - old_cbox.left - old_cbox.width;
}
} else {
new_cbox.top = canv.height - old_cbox.top - old_cbox.height;
}
$image.cropper('setCropBoxData', new_cbox);
/* BUG: When rotated to a perpendicular position of the original position , the user perceived axis are now inverted.
Try it yourself: GO to the demo page, rotate 90 degrees then try to flip X axis, you'll notice the image flippped vertically ... but still ... it fliped in relation to its original axis*/
if ( r == 90 || r == 270 || r == -90 || r == -270 ) {
if ( data.method == "scaleX") {
$image.cropper("scaleY", data.option);
} else {
$image.cropper("scaleX", data.option);
}
} else {
$image.cropper(data.method, data.option);
}
$image.cropper(data.method, data.option);
}
function rotateImage(rotate) {
/* var img = $image.cropper('getImageData'); */
var old_cbox = $image.cropper('getCropBoxData');
var new_cbox = $image.cropper('getCropBoxData');
var old_canv = $image.cropper('getCanvasData');
var old_cont = $image.cropper('getContainerData');
$image.cropper('rotate', rotate);
var new_canv = $image.cropper('getCanvasData');
//calculate new height and width based on the container dimensions
var heightOld = new_canv.height;
var widthOld = new_canv.width;
var heightNew = old_cont.height;
var racio = heightNew / heightOld;
var widthNew = new_canv.width * racio;
new_canv.height = Math.round(heightNew);
new_canv.width = Math.round(widthNew);
new_canv.top = 0;
if (new_canv.width >= old_cont.width) {
new_canv.left = 0;
} else {
new_canv.left = Math.round((old_cont.width - new_canv.width) / 2);
}
$image.cropper('setCanvasData', new_canv);
if (rotate == 90) {
new_cbox.height = racio * old_cbox.width;
new_cbox.width = racio * old_cbox.height;
new_cbox.top = new_canv.top + racio * (old_cbox.left - old_canv.left);
new_cbox.left = new_canv.left + racio * (old_canv.height - old_cbox.height - old_cbox.top);
}
new_cbox.width = Math.round(new_cbox.width);
new_cbox.height = Math.round(new_cbox.height);
new_cbox.top = Math.round(new_cbox.top);
new_cbox.left = Math.round(new_cbox.left);
$image.cropper('setCropBoxData', new_cbox);
}
var photoToEdit = $('.photo_container img');
$( photoToEdit ).cropper({
autoCrop : true,
crop: function(e) {}
});
$("#rotate_left_btn").click( function () {
$( photoToEdit ).cropper('rotate', -90);
var containerHeightFactor = $(".photo_container").height() / $( photoToEdit).cropper('getCanvasData').height;
if ( containerHeightFactor < 1 ) { // if canvas height is greater than the photo container height, then scale (on both x and y
// axes to maintain aspect ratio) to make canvas height fit container height
$( photoToEdit).cropper('scale', containerHeightFactor, containerHeightFactor);
} else if ( $( photoToEdit).cropper('getData').scaleX != 1 || $( photoToEdit).cropper('getData').scaleY != 1 ) { // if canvas height
// is NOT greater than container height but image is already scaled, then revert the scaling cuz the current rotation will bring
// the image back to its original orientation (landscape/portrait)
$( photoToEdit).cropper('scale', 1, 1);
}
}
I Fixed this issue hope fully. i have added or changed the option to 0 (viewMode: 0,). Now its working well.
cropper = new Cropper(image, {
dragMode: 'none',
viewMode: 0,
width: 400,
height: 500,
zoomable: true,
rotatable: true,
crop: function(e) {
}
});
document.getElementById('rotateImg').addEventListener('click', function () {
cropper.rotate(90);
});

Categories

Resources