why don't my javascript marquee move smoothly? - javascript

I have created a marquee using javascript. It will move from right to left of the screen displaying a number of images. The images don't move smoothly like in a marquee but jerks as if in an automated slide slow.
const slideContainer = document.querySelector('.container');
const slide = document.querySelector('.slides');
const interval = 1000;
let slides = document.querySelectorAll('.slide');
let index = 1;
const firstClone = slides[0].cloneNode(true);
const lastClone = slides[slides.length-1].cloneNode(true);
firstClone.id = 'first-clone';
lastClone.id = 'last-clone';
slide.append(firstClone);
slide.prepend(lastClone);
const slidewidth = slides[index].clientWidth;
slide.style.transform = `translateX(${-slidewidth * index}px, 0)`;
slide.style.transition = `.7s`;
const startSlide = ()=>{
setInterval(() => {
index++;
slide.style.transform = `translateX(${-slidewidth * index}px)`;
slide.style.transition = `.7s`;
}, interval);
};
slide.addEventListener('transitionend', ()=>{
slides = document.querySelectorAll('.slide');
console.log(index);
if (slides[index].id===firstClone.id) {
slide.style.transition = `none`;
index = 1;
slide.style.transform = `translateX(${-slidewidth * index}px)`;
}
});
startSlide();
.{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container{
margin: 0 auto;
width:40vw;
height: 85vh;
border: 2px solid #8e6c5e;
border-radius: 10px;
position: relative;
overflow: hidden;
}
.container.hide{
display: none;
}
.slides{
display: flex;
height: 100%;
}
.slide{
/*object-fit: contain;*/
min-width: 100%
}
.slide img{
width: 100%;
height: 100%;
display: flex;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>cards of fate</title>
</head>
<body>
<div class="container">
<div class="slides">
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/31/virgin-759376_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/32/bull-759381_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/30/twins-759375_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/30/lion-759374_960_720.jpg" alt="">
</div>
</div>
</div>
<script src="main_v1.js"></script>
</body>
</html>
I tried playing around the transition interval and speed but to no avail. I am little new around this so please help me out

Related

how can fixed this prve button for slide show

I want to create one slide show with Array. I created the "next" button and this works good.
I tried to fix the "prv" button but I can't. What to do? I tried imgIndex--; but its not working.
let downimgs = document.querySelectorAll('.down-imgs img')
let topimg = document.querySelector('.top-img img')
let myImg = document.getElementById('mainimge')
let imgArray = ["img/3-kid.jpeg", "img/men-1.jpg", "img/woamn-1.jpeg", "img/woman-2.jpg"]
let imgIndex = 0;
downimgs.forEach(imgs => {
imgs.addEventListener('click', () => {
topimg.src = imgs.src
})
});
function next() {
myImg.setAttribute("src", imgArray[imgIndex]);
imgIndex++;
if (imgIndex >= imgArray.length) {
imgIndex = 0
}
}
// my proplem here ..
function prv() {
myImg.setAttribute("src", imgArray[imgIndex - 1]);
imgIndex--;
if (imgIndex >= imgArray.length) {
imgIndex = 3
}
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
img {
height: 300px;
}
.top-img img {
width: 100%;
object-fit: cover;
position: relative;
}
.next,
.prv {
display: inline-block;
width: 150px;
height: 150px;
left: 100%;
position: absolute;
padding: 15px;
font-size: 50px;
color: red;
cursor: pointer;
}
.next {
transform: translate(-150px, -50px);
}
.prv {
left: 0;
transform: translate(150px, -50px);
}
.down-imgs img {
width: 150px;
height: 150px;
}
.full-parent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="s.css">
</head>
<body>
<section class="full-parent">
<figure class="top-img">
<img src="img/3-kid.jpeg" alt="" id="mainimge">
</figure>
<div class="down-imgs">
<img src="img/3-kid.jpeg" class="slide">
<img src="img/men-1.jpg" alt="" class="slide">
<img src="img/woamn-1.jpeg" alt="" class="slide">
<img src="img/woman-2.jpg" alt="" class="slide">
</div>
<span class="next" onclick="next()">&#10095</span>
<span class="prv" onclick="prv()">&#10094</span>
</section>
<script src="s.js"></script>
</body>
</html>
There is a defect in your prv function. You are decrementing imgIndex, but then checking that imgIndex is greater than or equal to the array length. Instead, you want to check that imgIndex is less than 0, then adjust accordingly. You will also want to change the order of the boundary check, otherwise you have potential to go out of bounds with imgArray[imgIndex-1].
Based on your code, I believe you want something like:
function prv(){
if (--imgIndex<0){ // if imgIndex leaves imgArray lower bound
imgIndex = imgArray.length-1; // wrap imgIndex around to the upper bound of the array
}
myImg.setAttribute("src" , imgArray[imgIndex]);
}

How to decouple functions according to what they do, not what they are in JavaScript?

I have the following code below:
https://codesandbox.io/s/dropdown-forked-pojgt?file=/src/index.js
In this example, I currently have these 2 lines embedded in the buildOptions function:
const allOptions = document.querySelectorAll(".option");
allOptions.forEach((op) => op.addEventListener("click", selectOptions));
Now the selectOptions will be activated upon clicking. However, since I'm interested in functional programming, is there a way for me to decouple that logic from the buildOptions function?
Furthermore, from a code perspective, is the code in the codesandbox above a good way to organize my code?
Edit:
HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
</head>
<body>
<div id="root">
<div class="optionBox">Select an option</div>
</div>
<div id="result"></div>
<hr />
<div id="details">
<p>What we're building</p>
<div style="display: flex; align-items: flex-start;">
<img src="https://i.imgur.com/AXoKKc5.png" width="122" />
<img src="https://i.imgur.com/mZwI3g0.png" width="123" />
<img src="https://i.imgur.com/S1LU4yf.png" width="106" />
</div>
<ul>
<li>A dropdown can have multiple options</li>
<li>
You must be able to handle the dropdown changing to a new value and
display it somewhere
</li>
<li>
you may change public/index.html if you wish to start with specific
markup
</li>
</ul>
</div>
</body>
</html>
JS:
import "./index.css";
// Assertions
// #root exists in the DOM as a node you can access
function optionBox(node, options = {}) {
let curr = 0;
node.addEventListener("click", buildOptions);
let optionsWrapped = null;
//buildOptions
function buildOptions() {
optionsWrapped = document.createElement("div");
optionsWrapped.classList.add("optionsWrapped");
curr = curr + 1;
if (curr % 2 === 1) {
for (let option in options) {
const optVal = options[option];
const optionDiv = document.createElement("div");
optionDiv.classList.add("option");
optionDiv.textContent = optVal;
optionsWrapped.appendChild(optionDiv);
}
node.appendChild(optionsWrapped);
const allOptions = document.querySelectorAll(".option");
allOptions.forEach((op) => op.addEventListener("click", selectOptions));
} else {
node.removeChild(node.childNodes[1]);
}
}
function selectOptions(e) {
const replacedNode = document.createElement("div");
replacedNode.textContent = e.target.textContent;
replacedNode.classList.add("replacedNode");
node.replaceWith(replacedNode);
}
return node;
}
optionBox(document.querySelector(".optionBox"), {
op1: "option 1",
op2: "option 2",
op3: "option 3"
});
CSS:
.optionBox {
border: 1px solid black;
width: 200px;
height: 30px;
margin-bottom: 100px;
}
.optionsWrapped {
border: 1px solid blue;
width: 100px;
height: 80px;
margin-top: 10px;
}
.replacedNode {
border: 1px solid black;
width: 100px;
height: 30px;
text-align: center;
line-height: 30px;
}

How can i go to the next/previous image lightbox using ev.target.nextElementSibling ev.targetprevElementSibling?

I am beginner to web development
I have a problem with my lightbox, i need to use ev.target.nextElementSibling and ev.target.prevElementSibling to go to the next/previous image by clicking at the next arrow.png (img)/ prev arrow.png(img), i have tried everything but i don't know how. When i'm clicking at the image it's zoom in (that's ok) but when i click on the arrow the image is hidding but i want to go to the next/prev image.
const imgs = document.querySelectorAll('.gallery img');
const lightbox = document.querySelector('.lightbox');
const arrowNext = document.querySelector('.arrowNext');
for (let index = 0; index < imgs.length; index++) {
const img = imgs[index];
img.addEventListener('click', showLightbox);
}
function showLightbox(ev) {
const prevEl = ev.target.prevElementSibling;
const nextEl = ev.target.nextElementSibling;
console.log(ev)
const lightbox = document.querySelector('.lightbox');
const img = document.querySelector('.lightbox img');
const imgUrl = ev.target.src;
img.src = imgUrl;
lightbox.classList.add('visible');
}
lightbox.addEventListener('click', hideLightbox);
function hideLightbox() {
lightbox.classList.remove('visible');
}
arrowNext.addEventListener('click', nextPhoto);
function nextPhoto(ev) {
const arrowNext = document.querySelector('.arrowNext');
const img = document.querySelector('.arrowNext img');
const imgUrl = ev.target.src;
img.src = imgUrl;
const next = ev.target.nextElementSibling;
}
body {
background: #eee;
}
.lightbox {
position: absolute;
z-index: 100;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
top: 0;
left: 0;
justify-content: center;
align-items: center;
display: flex;
transition: all 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
transform: scale(0);
}
.visible {
transform: scale(1);
}
.lightbox img {
max-width: 80%;
max-height: 80%;
}
.arrowNext {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lightbox</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="gallery">
<img src="/img/img1.jpg" alt="photo1">
<img src="/img/img2.jpg" alt="photo2">
<img src="/img/img3.jpg" alt="photo3">
<img src="/img/img4.jpg" alt="photo4">
</section>
<div class="lightbox">
<div class="arrowPrev">
<img src="/img/prev arrow.png" alt="">
</div>
<img src="/img/img5.jp" alt="">
<div class="arrowNext">
<img src="/img/next arrow.png" alt="">
</div>
</div>
<script src="main.js" type="text/javascript"></script>
</body>
</html>
Be aware that ev.target is the the element the mouse clicks on, in your case the arrow. You're looking to get the next image, not the next arrow.
I'd advise using an index variable to get which image is presented and then doing document.querySelectorAll('img')[index+1] to get the next image.
With what your code could give:
(Be aware that ev.stopPropagation() is needed to prevent closing the lightbox when the arrow is clicked.)
const imgs = document.querySelectorAll('.gallery img');
const lightbox = document.querySelector('.lightbox');
const arrowNext = document.querySelector('.arrowNext');
var index = 0;
for (let index = 0; index < imgs.length; index++) {
const img = imgs[index];
img.addEventListener('click', (e) => {showLightbox(e, index)});
}
function showLightbox(ev, i) {
const prevEl = ev.target.prevElementSibling;
const nextEl = ev.target.nextElementSibling;
const lightbox = document.querySelector('.lightbox');
const img = document.querySelector('.lightbox img');
const imgUrl = ev.target.src;
img.src = imgUrl;
index = i;
lightbox.classList.add('visible');
}
lightbox.addEventListener('click', hideLightbox);
function hideLightbox() {
lightbox.classList.remove('visible');
}
arrowNext.addEventListener('click', nextPhoto);
function nextPhoto(ev) {
ev.stopPropagation();
index++;
const arrowNext = document.querySelector('.arrowNext');
const img = document.querySelector('.arrowNext img');
const imgUrl = imgs[index].src;
img.src = imgUrl;
}
body {
background: #eee;
}
.lightbox {
position: absolute;
z-index: 100;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
top: 0;
left: 0;
justify-content: center;
align-items: center;
display: flex;
transition: all 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
transform: scale(0);
}
.visible {
transform: scale(1);
}
.lightbox img {
max-width: 80%;
max-height: 80%;
}
.arrowNext {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lightbox</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="gallery">
<img src="/img/img1.jpg" alt="photo1">
<img src="/img/img2.jpg" alt="photo2">
<img src="/img/img3.jpg" alt="photo3">
<img src="/img/img4.jpg" alt="photo4">
</section>
<div class="lightbox">
<div class="arrowPrev">
<img src="/img/prev arrow.png" alt="">
</div>
<img src="/img/img5.jp" alt="">
<div class="arrowNext">
<img src="/img/next arrow.png" alt="" style="background:red;padding:20px">
</div>
</div>
<script src="main.js" type="text/javascript"></script>
</body>
</html>

How to capture data from div by click

I would like to capture data from selected div(ie. name of country) by click and put in span , additionaly i want to find some way to mark selected divs, but also unmark others div which were selected previously.
https://codepen.io/tatasek/pen/PoojNGL
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="div div__first"></div>
<div class="div div__second"></div>
<div class="div div__third"></div>
<p>I have selected:<span class="selectedCountry"></span></p>
<script src="app.js"></script>
</body>
</html>
CSS
body{
display: flex;
height: 100vh;
justify-content: center;
align-items: center;;
}
.div{
margin-left: 10px;
padding: 3px;
border: 2px solid black;
background-color: skyblue;
cursor: pointer;
}
p{
margin-left: 10px;;
}
.active{
background-color: yellow;
}
JS
const countries = ['Lithuania', 'Latvia', 'Estonia'];
const divList = document.querySelectorAll('.div');
divList.forEach(function(div, index){
div.textContent = countries[index];
})
Thanks for your time!
Michal
Building on what you've done so far, I just added some event listeners to check for changes and add the selected items to the list. Let me know if you need any further clarification.
const countries = ['Lithuania', 'Latvia', 'Estonia'];
const divList = document.querySelectorAll('.div');
divList.forEach(function(div, index){
div.textContent = countries[index];
div.addEventListener('click', function(){
divList.forEach(function(el, i) {
el.classList.remove('active')
})
this.classList.toggle('active');
})
})
var choices = document.getElementsByTagName('div')
for(var i = 0; i < choices.length; i++) {
choices[i].addEventListener('click', function() {
document.getElementsByClassName('selectedCountry')[0].innerText =
document.getElementsByClassName('active')[0].innerText;
})
}
body{
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
.div{
margin-left: 10px;
padding: 15px;
border: 2px solid black;
background-color: skyblue;
cursor: pointer;
}
p{
margin-left: 10px;
}
.active{
background-color: yellow;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="div div__first"></div>
<div class="div div__second"></div>
<div class="div div__third"></div>
<p>I have selected:<span class="selectedCountry"></span></p>
<script src="app.js"></script>
</body>
</html>
Try
for (let i = 0; i < document.getElementsByClassName('div').length; i++) {
document.getElementsByClassName('div')[i].addEventListener('click', appendToSpan, false);
}
function appendToSpan(e) {
document.getElementsByClassName('selectedCountry')[0].innerText += e.target.innerText;
}
Edit:
Change to:
const countries = ['Lithuania', 'Latvia', 'Estonia'];
const divList = document.querySelectorAll('.div');
divList.forEach(function(div, index){
div.textContent = countries[index];
div.addEventListener('click', function() {
this.classList.toggle('active');
if (this.classList.contains('active')) {
document.getElementsByClassName('selectedCountry')[0].classList.add(this.innerText);
} else {
document.getElementsByClassName('selectedCountry')[0].classList.remove(this.innerText);
}
let classes = document.getElementsByClassName('selectedCountry')[0].getAttribute('class').split(' ');
document.getElementsByClassName('selectedCountry')[0].innerText = '';
for (let i = 1; i < classes.length; i++) {
document.getElementsByClassName('selectedCountry')[0].innerText += classes[i]
}
})
})
I've used addEventListener on click event on each div. Also I've created selected variable which is an array and keeps selected items. On click I check if the selected value is in selected variable by indexOf() function which returns -1 if there is not. Then I push() value to the array if it's not selected yet or delete it by splice() and index of value.
Array is printed by join() function which concats each value of array,
const divList = document.querySelectorAll('.div');
const output = document.querySelector('.selectedCountry');
const countries = ['Lithuania', 'Latvia', 'Estonia'];
let selected = [];
divList.forEach((div, index) => {
div.textContent = countries[index];
div.addEventListener('click',()=> {
var indexOfDiv = selected.indexOf(countries[index]);
(indexOfDiv >= 0)
? (selected.splice(indexOfDiv,1) && div.classList.remove('selected'))
: (selected.push(div.textContent) && div.classList.add('selected'))
output.textContent = selected.join(', ');
});
});
.div { border: 1px solid lightgray; margin: 0.5rem; padding: 0.25rem 0.4rem; }
.div.selected { border-color: lightgreen; }
<div class="div div__first"></div>
<div class="div div__second"></div>
<div class="div div__third"></div>
<p>I have selected:<span class="selectedCountry"></span></p>
const countries = ['Lithuania', 'Latvia', 'Estonia'];
const divList = document.querySelectorAll('.div');
const selectedCountry = document.getElementsByClassName('selectedCountry')[0];
function clearSelection() {
divList.forEach(function(div) {
div.classList.remove('active');
})
}
divList.forEach(function(div, index){
div.textContent = countries[index];
div.addEventListener('click', function() {
clearSelection();
this.classList.add('active');
selectedCountry.innerText = document.getElementsByClassName('active')[0].innerText;
})
})
body{
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
.div{
margin-left: 10px;
padding: 15px;
border: 2px solid black;
background-color: skyblue;
cursor: pointer;
}
p{
margin-left: 10px;
}
.active{
background-color: yellow;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="div"></div>
<div class="div"></div>
<div class="div"></div>
<p>I have selected:<span class="selectedCountry"></span></p>
<script src="app.js"></script>
</body>
</html>

How to display (x1,y1,) and (x2,y2) of croped image

This is the used for upload,crop,cut then display image,
but I want to display cropped image and (x1,y1,), (x2,y2) coordinates of cropped image.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Cropper.js</title>
<link rel="stylesheet" href="css/style.css" />
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro|Open+Sans+Condensed:300|Raleway' rel='stylesheet' type='text/css'>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="
https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.4/cropper.min.css
">
<style>
.page {
margin: 1em auto;
max-width: 768px;
display: flex;
align-items: flex-start;
flex-wrap: wrap;
height: 100%;
}
.box {
padding: 0.5em;
width: 100%;
margin:0.5em;
}
.box-2 {
padding: 0.5em;
width: calc(100%/2 - 1em);
}
.options label,
.options input{
width:4em;
padding:0.5em 1em;
}
.btn{
background:white;
color:black;
border:1px solid black;
padding: 0.5em 1em;
text-decoration:none;
margin:0.8em 0.3em;
display:inline-block;
cursor:pointer;
}
.hide {
display: none;
}
img {
max-width: 100%;
}
</style>
</head>
<body>
<div class="container">
<h1>Cropper with a range of aspect ratio</h1>
<div>
<main class="page">
<h2>Upload ,Crop and save.</h2>
<!-- input file -->
<div class="box">
<input type="file" id="file-input">
</div>
<!-- leftbox -->
<div class="box-2">
<div class="result" id="image"></div>
</div>
<!--rightbox-->
<div class="box-2 img-result hide">
<form><img alt="" class="cropped" src=""></form>
</div>
<!-- input file -->
<div class="box">
<div class="options hide">
<label> Width</label>
<input type="number" class="img-w" value="300" min="100" max="1200" />
</div>
<!-- save btn -->
<button class="btn save hide" >Save</button>
<!-- download btn -->
</div>
</main>
</div>
</div><br><br><br><br><br>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/0.8.1/cropper.min.js
"></script>
<script>
// vars
let result = document.querySelector('.result'),
img_result = document.querySelector('.img-result'),
img_w = document.querySelector('.img-w'),
img_h = document.querySelector('.img-h'),
options = document.querySelector('.options'),
save = document.querySelector('.save'),
cropped = document.querySelector('.cropped'),
dwn = document.querySelector('.download'),
upload = document.querySelector('#file-input'),
cropper = '';
// on change show image with crop options
upload.addEventListener('change', (e) => {
if (e.target.files.length) {
// start file reader
const reader = new FileReader();
reader.onload = (e)=> {
if(e.target.result){
// create new image
let img = document.createElement('img');
img.id = 'image';
img.src = e.target.result
// clean result before
result.innerHTML = '';
// append new image
result.appendChild(img);
// show save btn and options
save.classList.remove('hide');
options.classList.remove('hide');
// init cropper
cropper = new Cropper(img);
// cropped value
}
};
reader.readAsDataURL(e.target.files[0]);
}
});
// save on click
save.addEventListener('click',(e)=>{
e.preventDefault();
// get result to data uri
let imgSrc = cropper.getCroppedCanvas({
width: img_w.value // input value
}).toDataURL();
// remove hide class of img
cropped.classList.remove('hide');
img_result.classList.remove('hide');
// show image cropped
cropped.src = imgSrc;
dwn.classList.remove('hide');
dwn.download = 'imagename.png';
dwn.setAttribute('value',imgSrc);
});
</script>
</body>
</html>
Please can anyone help me? How do I find (x1,y1,), (x2,y2) coordinates of cropped image? I have some idea about that: First find (x1,y1,) and width and height of cropped image then x2=x1+width , y2=y1+width, but I don't know how to apply. Please help me with how apply this to Javascript or jQuery.
Working example with both: absolute canvas coordinates and relative image coordinates:
// vars
let result = document.querySelector('.result'),
img_result = document.querySelector('.img-result'),
img_w = document.querySelector('.img-w'),
img_h = document.querySelector('.img-h'),
options = document.querySelector('.options'),
save = document.querySelector('.save'),
cropped = document.querySelector('.cropped'),
dwn = document.querySelector('.download'),
upload = document.querySelector('#file-input'),
cropper = '';
// on change show image with crop options
upload.addEventListener('change', (e) => {
if (e.target.files.length) {
// start file reader
const reader = new FileReader();
reader.onload = (e) => {
if (e.target.result) {
// create new image
let img = document.createElement('img');
img.id = 'image';
img.src = e.target.result
// clean result before
result.innerHTML = '';
// append new image
result.appendChild(img);
// show save btn and options
save.classList.remove('hide');
options.classList.remove('hide');
// init cropper
cropper = new Cropper(img);
// cropped value
}
};
reader.readAsDataURL(e.target.files[0]);
}
});
// save on click
save.addEventListener('click', (e) => {
let cropLeft = cropper.cropBoxData.left;
let cropTop = cropper.cropBoxData.top;
let cropRight = cropLeft + cropper.cropBoxData.width;
let cropBottom = cropTop + cropper.cropBoxData.height;
let info = "Crop region (absolute canvas coordinates):\n" +
"(x1, y1) = (" + cropLeft + ", " + cropTop + ")\n" +
"(x2, y2) = (" + cropRight + ", " + cropBottom + ")\n";
let zoom = cropper.image.offsetHeight / cropper.image.naturalHeight;
let naturalWidth = (cropRight - cropLeft) / zoom;
let naturalHeight = (cropBottom - cropTop) / zoom;
let relativeLeft = (cropper.cropBoxData.left - cropper.canvasData.left);
let relativeTop = (cropper.cropBoxData.top - cropper.canvasData.top);
let naturalLeft = relativeLeft / zoom;
let naturalTop = relativeTop / zoom;
let naturalRight = naturalLeft + naturalWidth;
let naturalBottom = naturalTop + naturalHeight;
info += "\nCrop region (image coordinates):\n" +
"(x1, y1) = (" + naturalLeft + ", " + naturalTop + ")\n" +
"(x2, y2) = (" + naturalRight + ", " + naturalBottom + ")\n";
alert(info);
e.preventDefault();
// get result to data uri
let croppedImg = cropper.getCroppedCanvas({
width: img_w.value // input value
});
let imgSrc = croppedImg.toDataURL();
// remove hide class of img
cropped.classList.remove('hide');
img_result.classList.remove('hide');
// show image cropped
cropped.src = imgSrc;
});
.page {
margin: 1em auto;
max-width: 768px;
display: flex;
align-items: flex-start;
flex-wrap: wrap;
height: 100%;
}
.box {
padding: 0.5em;
width: 100%;
margin: 0.5em;
}
.box-2 {
padding: 0.5em;
width: calc(100%/2 - 1em);
}
.options label,
.options input {
width: 4em;
padding: 0.5em 1em;
}
.btn {
background: white;
color: black;
border: 1px solid black;
padding: 0.5em 1em;
text-decoration: none;
margin: 0.8em 0.3em;
display: inline-block;
cursor: pointer;
}
.hide {
display: none;
}
img {
max-width: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Cropper.js</title>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro|Open+Sans+Condensed:300|Raleway' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="
https://cdnjs.cloudflare.com/ajax/libs/cropper/2.3.4/cropper.min.css
">
</head>
<body>
<div class="container">
<h1>Cropper with a range of aspect ratio</h1>
<div>
<main class="page">
<h2>Upload ,Crop and save.</h2>
<!-- input file -->
<div class="box">
<input type="file" id="file-input">
</div>
<!-- leftbox -->
<div class="box-2">
<div class="result" id="image"></div>
</div>
<!--rightbox-->
<div class="box-2 img-result hide">
<form><img alt="" class="cropped" src=""></form>
</div>
<!-- input file -->
<div class="box">
<div class="options hide">
<label> Width</label>
<input type="number" class="img-w" value="300" min="100" max="1200" />
</div>
<!-- save btn -->
<button class="btn save hide">Save</button>
<!-- download btn -->
</div>
</main>
</div>
</div><br><br><br><br><br>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/0.8.1/cropper.min.js
"></script>
</body>
</html>

Categories

Resources