I have an image uploader that I'm building that allows the user to remove images/ image previews prior to form submission. I seem to have a come across a side effect that a) I don't know what is causing it, and b) how to fix it.
When an image is deleted from the preview the image is removed via a click event and the remove() method on the image's parent figure element.
If a user then re-selects the same image (that has just been removed) from their computer with the file picker / input the image doesn't show on the preview the second time around? But, even more confusingly, if a completely different image is attached, and then the user tries to re-attach the original image that previously didn't show the second time, that image does then show again (I hope this makes sense).
I have no idea what is going on here?
Codepen: https://codepen.io/thechewy/pen/qBYYMYV
let dropZone = document.getElementById("zone"),
showSelectedImages = document.getElementById("show-selected-images"),
fileUploader = document.getElementById("upload-files");
dropZone.addEventListener("click", () => {
// assigns the dropzone to the hidden input element, when you click 'select files' it brings up a file picker window
fileUploader.click();
});
// Prevent browser default when draging over
dropZone.addEventListener("dragover", (e) => e.preventDefault());
// Prevent browser default when draging over
dropZone.addEventListener("drop", (e) => e.preventDefault());
fileUploader.addEventListener("change", (e) => {
// this function is further down but declared here and shows a thumbnail of the image
[...fileUploader.files].forEach(updateThumbnail);
console.log("fileUploader.files is: ", [...fileUploader.files]);
});
// updateThumbnail function
function updateThumbnail(file) {
if (file.type.startsWith("image/")) {
let uploadImageWrapper = document.createElement("figure"),
thumbnail = new Image(),
removeImage = `
<div class="remove-image jc-center flex"> Delete </div>
`;
// image thumbnail
thumbnail.classList.add("thumbnail");
thumbnail.src = URL.createObjectURL(file);
// appending elements
showSelectedImages.append(uploadImageWrapper); // <figure> element
uploadImageWrapper.append(thumbnail); // image thumbnail
uploadImageWrapper.insertAdjacentHTML("afterbegin", removeImage); // 'x' to remove image
// get the original width and height values of the thumbnail using the decode() method
thumbnail
.decode()
.then((response) => {
thumbWidth = thumbnail.naturalWidth;
thumbHeight = thumbnail.naturalHeight;
// typical front end image validations
if (thumbWidth * thumbHeight < 4000000) {
// output the error message
}
})
.catch((encodingError) => {
// Do something with the error.
});
// Delete images from the preview
document
.querySelectorAll("#show-selected-images .remove-image")
.forEach((i) => {
i.addEventListener("click", (e) => {
if (e.target) {
var deleteFigureEl = e.target.closest("figure");
// removes the image via removing it's parent element
deleteFigureEl.remove();
}
});
});
}
} // end of 'updateThumbnail' function
body {
margin: 0;
display: flex;
justify-content: center;
font-family: arial;
}
form {
width: 50%;
max-width: 600px;
}
.select-files {
padding: 1rem;
background: red;
cursor: pointer;
color: #fff;
font-weight: bold;
}
#show-selected-images {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 2rem;
}
figure {
width: 100%;
margin: 0;
}
img {
display: block;
width: 100%;
height: auto;
}
.remove-image {
cursor: pointer;
padding: 1rem;
background: lightgrey;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
<h1>Upload Your Images</h1>
<div id="zone">
<p class="select-files">SELECT FILES</p>
</div>
<div class="inner-wrapper">
<div class="upload-label-wrapper">
<input id="upload-files" style="display:none;" type="file" name="upload-files[]" multiple>
</div>
<button id="submit-images" oninput="updateThumbnail(this.files)">SUBMIT</button>
</div>
<div id="show-selected-images"></div>
</form>
let dropZone = document.getElementById("zone"),
showSelectedImages = document.getElementById("show-selected-images"),
fileUploader = document.getElementById("upload-files"),
files = [],
filesIndexes = new Set();
dropZone.addEventListener("click", () => {
// assigns the dropzone to the hidden input element, when you click 'select files' it brings up a file picker window
fileUploader.click();
});
// Prevent browser default when draging over
dropZone.addEventListener("dragover", (e) => e.preventDefault());
// Prevent browser default when draging over
dropZone.addEventListener("drop", (e) => e.preventDefault());
fileUploader.addEventListener("change", (e) => {
// this function is further down but declared here and shows a thumbnail of the image
[...fileUploader.files].forEach((file) => {
updateThumbnail(file);
let i = files.length;
while (filesIndexes.has(i)) {
i++;
}
files.push({ file, index: i });
filesIndexes.add(i);
});
fileUploader.value = "";
console.log("fileUploader.files is: ", [...fileUploader.files]);
});
// updateThumbnail function
function updateThumbnail(file) {
if (file.type.startsWith("image/")) {
let uploadImageWrapper = document.createElement("figure"),
thumbnail = new Image(),
removeImage = `
<div class="remove-image jc-center flex" index="${files.length}"> Delete </div>
`;
// image thumbnail
thumbnail.classList.add("thumbnail");
thumbnail.src = URL.createObjectURL(file);
// appending elements
showSelectedImages.append(uploadImageWrapper); // <figure> element
uploadImageWrapper.append(thumbnail); // image thumbnail
uploadImageWrapper.insertAdjacentHTML("afterbegin", removeImage); // 'x' to remove image
// get the original width and height values of the thumbnail using the decode() method
thumbnail
.decode()
.then((response) => {
thumbWidth = thumbnail.naturalWidth;
thumbHeight = thumbnail.naturalHeight;
// typical front end image validations
if (thumbWidth * thumbHeight < 4000000) {
// output the error message
}
})
.catch((encodingError) => {
// Do something with the error.
});
// Delete images from the preview
document
.querySelectorAll("#show-selected-images .remove-image")
.forEach((i) => {
i.onclick = (e) => {
console.log(e.currentTarget);
if (e.target) {
var deleteFigureEl = e.target.closest("figure");
let index = e.currentTarget.getAttribute("index");
files.forEach((obj, i) => {
if (obj.index == index) {
files.splice(i, 1);
filesIndexes.delete(Number(index));
}
});
// removes the image via removing it's parent element
deleteFigureEl.remove();
}
};
});
}
} // end of 'updateThumbnail' function
And then you should upload files like this
function upload(){
let formData = new FormData()
for (let index = 0; index < files.length; index++) {
formData.append(`file${files[index].index}`, files[index].file)
}
fetch("url", {method: "POST", body: formData})
}
Related
I have a file uploader that shows preview images and it is currently set so if you click an image the image preview is deleted and the image is also effectively deleted from the FileList array before the form submission by creating a second array and setting the FileList to hold these values. All of this works OK.
The Context
Whilst setting this up and posting this as a question on StackOverflow in order to (theortically) keep the code simpler I removed the 'remove image' button and set it so the image was deleted both visually and from the FileList if you clicked the image itself. I'm now struggling to work out how to transfer this functionality so when the 'x' is clicked the same functionality happens.
In the current code if you click the image you get the expected behaviour.
I've now included code so that the image preview for each individual image is wrapped in a parent <figure> element with the 'x' .remove-image element included in this too. I've also included some commented out code at the bottom that if uncommented removes the <figure> element containing the image when the 'x' is clicked.
The Question
How do I get it so that instead of when the <img> is clicked the required functionality only happens when the 'x' is clicked?
I would think I need to somehow have the click event on .remove-image (the 'x') that uses the .closest method to go up to the figure element and down to the image i.e. removeImage.closest('figure').querySelector('.img') but I only want the required functionality when the 'x' is clicked, and not when either the 'x' or the image are clicked, which would be simple to fix.
Any help greatly appreciated.
Codepen: https://codepen.io/thechewy/pen/oNdrzjz
let attachFiles = document.getElementById("attach-files");
let previewWrapper = document.getElementById("show-selected-images");
let form = document.getElementById("upload-images-form");
let submitData = new DataTransfer();
attachFiles.addEventListener("change", (e) => {
const currentSubmitData = Array.from(submitData.files);
// For each addded file, add it to submitData if not already present
[...e.target.files].forEach((file) => {
if (currentSubmitData.every((currFile) => currFile.name !== file.name)) {
submitData.items.add(file);
}
});
// Sync attachFiles FileList with submitData FileList
attachFiles.files = submitData.files;
// Clear the previewWrapper before generating new previews
previewWrapper.replaceChildren();
// Generate a preview <img> for each selected file
[...submitData.files].forEach(showFiles);
});
function showFiles(file) {
let uploadImageWrapper = document.createElement("figure");
let previewImage = new Image();
let removeImage = `<div class="remove-image"> X </div>`;
// Set relevant <img> attributes
previewImage.dataset.name = file.name;
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
// Adds click event listener to <img> preview (this needs moving to the .remove-image element)
previewImage.addEventListener("click", (e) => {
const target = e.currentTarget;
const name = target.dataset.name;
// Remove the clicked file from the submitData
[...submitData.files].forEach((file, idx) => {
if (file.name === name) {
submitData.items.remove(idx);
}
});
// Reset the attachFiles FileList
attachFiles.files = submitData.files;
// Remove the <img> node from the DOM
target.remove();
});
// Append <figure> and <img> preview node to DOM
previewWrapper.append(uploadImageWrapper); // <figure> element
uploadImageWrapper.append(previewImage); // <img>
uploadImageWrapper.insertAdjacentHTML('afterbegin', removeImage); // 'x' to remove the image
// // ===== Delete figure element that wraps the image =====
// document.querySelectorAll('#show-selected-images .remove-image').forEach(i => {
// i.addEventListener('click', (e) => {
// if (e.target) {
// let deleteFigureEl = e.target.closest('figure');
// // removes the image via removing it's parent element
// deleteFigureEl.remove();
// }
// })
// })
}
* {
position: relative;
}
form {
padding: 1rem 2rem;
width: 50%;
border: 1px solid;
}
input,
button {
display: block;
margin: 2rem 0;
}
.remove-image {
background: #000;
width: 30px;
height: 30px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
top: 10px;
left: -10px;
position: absolute;
z-index: 2;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
<form enctype="multipart/form-data" method="post" id="upload-images-form">
<input id="attach-files" type="file" name="attach-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="show-selected-images"></div>
</form>
The two dynamic values in the click listener are the target (which is the previewImage itself) and the name (which is the same as the file.name already in scope). So, all you'd really need to do is change those variable references inside a removeImage event listener (and make removeImage an actual element, not just a string, so that .addEventListener can be called on it).
const removeImage = document.createElement('div');
removeImage.className = 'remove-image';
removeImage.textContent = ' X ';
removeImage.addEventListener('click', () => previewImage.click());
removeImage.addEventListener("click", () => {
const name = file.name;
[...submitData.files].forEach((file, idx) => {
if (file.name === name) {
submitData.items.remove(idx);
}
});
attachFiles.files = submitData.files;
previewImage.remove();
removeImage.remove();
});
let attachFiles = document.getElementById("attach-files");
let previewWrapper = document.getElementById("show-selected-images");
let form = document.getElementById("upload-images-form");
let submitData = new DataTransfer();
attachFiles.addEventListener("change", (e) => {
const currentSubmitData = Array.from(submitData.files);
// For each addded file, add it to submitData if not already present
[...e.target.files].forEach((file) => {
if (currentSubmitData.every((currFile) => currFile.name !== file.name)) {
submitData.items.add(file);
}
});
// Sync attachFiles FileList with submitData FileList
attachFiles.files = submitData.files;
// Clear the previewWrapper before generating new previews
previewWrapper.replaceChildren();
// Generate a preview <img> for each selected file
[...submitData.files].forEach(showFiles);
});
function showFiles(file) {
let uploadImageWrapper = document.createElement("figure");
let previewImage = new Image();
const removeImage = document.createElement('div');
removeImage.className = 'remove-image';
removeImage.textContent = ' X ';
removeImage.addEventListener('click', () => previewImage.click());
removeImage.addEventListener("click", () => {
const name = file.name;
[...submitData.files].forEach((file, idx) => {
if (file.name === name) {
submitData.items.remove(idx);
}
});
attachFiles.files = submitData.files;
previewImage.remove();
removeImage.remove();
});
// Set relevant <img> attributes
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
// Append <figure> and <img> preview node to DOM
previewWrapper.append(uploadImageWrapper); // <figure> element
uploadImageWrapper.append(previewImage); // <img>
uploadImageWrapper.insertAdjacentElement('afterbegin', removeImage); // 'x' to remove the image
}
* {
position: relative;
}
form {
padding: 1rem 2rem;
width: 50%;
border: 1px solid;
}
input,
button {
display: block;
margin: 2rem 0;
}
.remove-image {
background: #000;
width: 30px;
height: 30px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
top: 10px;
left: -10px;
position: absolute;
z-index: 2;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
<form enctype="multipart/form-data" method="post" id="upload-images-form">
<input id="attach-files" type="file" name="attach-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="show-selected-images"></div>
</form>
I've built a file uploader (that runs on php in the backend) that previews an image file prior to upload.
The problem I'm having is I can't get it work with multiple files.
It's based on a tutorial I watched and the crux of the issue is in the updateThumbnail function. When this function is called for multiple file uploads I think I need to change the second parameter from fileUploader.files[0] to fileUploader.files, but I'm struggling with the actual function itself.
I clearly need to run a foreach loop (or similar) in the updateThumbnail function but I can't get it to play ball.
Note: It seems CodePen doesn't allow drag & drop functionality, but there is an input file element that is also assigned to the drop-zone that is hidden in the HTML with display:none. This uses a click event listener and fileUploader.click() so when you click the drop-zone you can bring up the file picker window.
Codepen: https://codepen.io/pauljohnknight/pen/JjNNyzO
// hidden on the form, but has drag & drop files assigned to it
var fileUploader = document.getElementById("standard-upload-files");
var dropZone = document.getElementById("drop-zone");
var showSelectedImages = document.getElementById("show-selected-images");
dropZone.addEventListener("click", (e) => {
//assigns the dropzone to the hidden input element so when you click 'select files' it brings up a file picker window
fileUploader.click();
});
fileUploader.addEventListener("change", (e) => {
if (fileUploader.files.length) {
// this function is further down but declared here and shows a thumbnail of the image
updateThumbnail(dropZone, fileUploader.files[0]);
}
});
dropZone.addEventListener('dragover', e => {
e.preventDefault()
})
dropZone.addEventListener('dragend', e => {
e.preventDefault()
})
// When the files are dropped in the 'drop-zone'
dropZone.addEventListener("drop", (e) => {
e.preventDefault();
// assign dropped files to the hidden input element
if (e.dataTransfer.files.length) {
fileUploader.files = e.dataTransfer.files;
}
// function is declared here but written further down
updateThumbnail(dropZone, e.dataTransfer.files[0]);
});
// updateThumbnail function that needs to be able to handle multiple files
function updateThumbnail(dropZone, file) {
var thumbnailElement = document.querySelector(".drop-zone__thumb");
if (!thumbnailElement) {
thumbnailElement = document.createElement("img");
thumbnailElement.classList.add("drop-zone__thumb");
// append to showSelectedImages div
showSelectedImages.appendChild(thumbnailElement);
}
if (file.type.startsWith("image/")) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
thumbnailElement.src = reader.result;
};
} else {
thumbnailElement.src = null;
}
} // end of 'updateThumbnail' function
body {
margin: 0;
display: flex;
justify-content: center;
width: 100%;
}
form {
width: 30%;
}
#drop-zone {
border: 1px dashed;
width: 100%;
padding: 1rem;
margin-bottom: 1rem;
}
.select-files {
text-decoration: underline;
cursor: pointer;
}
/* image that is preview prior to form submit*/
.drop-zone__thumb {
width: 200px;
height: auto;
display: block;
}
#submit-images {
margin-top: 1rem;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
<h1>Upload Your Images</h1>
<div id="drop-zone" class="drop-zone flex">
<p class="td text-center">DRAG AND DROP IMAGES HERE</p>
<p>Or</p>
<p class="select-files">Select Files</p>
</div>
<div id="show-selected-images"></div>
<div class="inner-input-wrapper">
<div class="upload-label-wrapper">
<input id="standard-upload-files" style="display:none" type="file" name="standard-upload-files[]" multiple>
</div>
<input type="submit" name="submit-images" id="submit-images" value="SUBMIT IMAGES">
</div>
</form>
I did quick Codesandbox example from your Codepen
Yes, you just need to iterate over your files and for each file add a preview. You can use for loop or just use Array.from and then .forEach (because FileList is not really an array, you need to convert it to array first to be able to use array inbuilt methods)
Array.from(fileUploader.files).forEach((file) => {
updateThumbnail(dropZone, file);
});
As for previews and updateThumbnail function - it all depends on how you want to use it. If you want users to be able to add more files after first selection then you can just append new previews. If you want to clear the old ones if the user select new ones then you would need to delete old previews. Or maybe you could add "Delete" button for each preview so the user could delete one of them after adding.
Here is the variant when you just want to append new previews:
function updateThumbnail(dropZone, file) {
if (file.type.startsWith('image/')) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
var thumbnailElement = document.createElement('img');
thumbnailElement.classList.add('drop-zone__thumb');
thumbnailElement.src = reader.result;
showSelectedImages.appendChild(thumbnailElement);
};
}
}
For drop you basically do the same:
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
// .. do whatever you want or need here
Array.from(e.dataTransfer.files).forEach((file) => {
updateThumbnail(dropZone, file);
});
});
As you can see functions for handling drop and select are quite similar, you can even make separate function which accepts fileList and then do something with it, so would not need to duplicate your code for both cases.
Made some minor changes to #Danila's version
Most notable differences is the use of es6 and a way to load image faster using URL.createObjectURL. The File reader is pretty much a legecy thing now when there is object urls + new promise based read methods on the prototype itself. Using bae64 is a waste of time decoding/encoding to/from base64
https://codesandbox.io/s/httpsstackoverflowcomquestions68416563-forked-o5spy?file=/src/index.js
import "./styles.css";
// Query all needed elements in one go
const [dropZone, showSelectedImages, fileUploader] = document.querySelectorAll(
"#standard-upload-files, #drop-zone, #show-selected-images"
);
dropZone.addEventListener("click", (evt) => {
// assigns the dropzone to the hidden input element so when you click 'select files' it brings up a file picker window
fileUploader.click();
});
// Prevent browser default when draging over
dropZone.addEventListener("dragover", (evt) => {
evt.preventDefault();
});
fileUploader.addEventListener("change", (evt) => {
// Clear the already selected images
showSelectedImages.innerHTML = "";
// this function is further down but declared here and shows a thumbnail of the image
[...fileUploader.files].forEach(updateThumbnail);
});
dropZone.addEventListener("drop", (evt) => {
evt.preventDefault();
// Clear the already selected images
showSelectedImages.innerHTML = "";
// assign dropped files to the hidden input element
if (evt.dataTransfer.files.length) {
fileUploader.files = evt.dataTransfer.files;
}
// function is declared here but written further down
[...evt.dataTransfer.files].forEach(updateThumbnail);
});
// updateThumbnail function that needs to be able to handle multiple files
function updateThumbnail(file) {
if (file.type.startsWith("image/")) {
const thumbnailElement = new Image();
thumbnailElement.classList.add("drop-zone__thumb");
thumbnailElement.src = URL.createObjectURL(file);
showSelectedImages.append(thumbnailElement);
}
} // end of 'updateThumbnail' function
I can manage to get dcm image from a url to display and work with cornerstone tools
as shown in the snippet below. I have managed to get it to upload and display a dcm image from my machine the code snippet is also attached. But when I upload the dcm images from my machine the some of the dicom tools like brightness and invert seem to work but others don't work
// Setup image loader
cornerstoneWebImageLoader.external.cornerstone = cornerstone;
cornerstone.registerImageLoader('http', cornerstoneWebImageLoader.loadImage)
cornerstone.registerImageLoader('https', cornerstoneWebImageLoader.loadImage)
// Setup tools
const csTools = cornerstoneTools.init();
// Enable Element
const element = document.querySelector('.cornerstone-element');
cornerstone.enable(element);
// Display an image
const imageId = 'https://www.asteris.biz/Keystone/ImageDownload.aspx?ClinicCode=TESTKEYSTONE&ImageId=01b1755e-33d1-4b24-b9af-a4a019689d5f&ImageType=PreviewImage&FrameIndex=0';
cornerstone.loadImage(imageId).then(function (image) {
cornerstone.displayImage(element, image);
});
// Add event handlers to flip or rotate the image
document.getElementById('hFlip').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.hflip = !viewport.hflip;
cornerstone.setViewport(element, viewport);
});
.cornerstone-element-wrapper,
.cornerstone-element {
width: 512px;
height: 512px;
margin: 0 auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://unpkg.com/cornerstone-core#2.2.6/dist/cornerstone.js"></script>
<script src="https://unpkg.com/cornerstone-math#0.1.6/dist/cornerstoneMath.js"></script>
<script src="https://unpkg.com/cornerstone-web-image-loader#2.1.0/dist/cornerstoneWebImageLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cornerstone-tools#3.0.0-b.717/dist/cornerstoneTools.js"></script>
<button id="hFlip" type="button" class="btn btn-default">HFlip</button>
<div class="cornerstone-element-wrapper">
<div class="cornerstone-element" data-index="0" oncontextmenu="return false"></div>
</div>
But when I try to get it to upload an image from my computer the tools fail to work
below is my code
ngOnInit(): void {
// Setup image loader
// Init Cornerstone Tools
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.init({
globalToolSyncEnabled: true
});
// Setup Tools
cornerstoneTools.addTool(cornerstoneTools.WwwcTool);
cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 1 });
cornerstoneTools.addTool(cornerstoneTools.ZoomTool);
cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 2 });
cornerstoneTools.addTool(cornerstoneTools.PanTool);
cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 4 });
// Image Loader
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneWADOImageLoader.webWorkerManager.initialize({
maxWebWorkers: navigator.hardwareConcurrency || 1,
startWebWorkersOnDemand: true,
taskConfiguration: {
decodeTask: {
initializeCodecsOnStartup: false,
usePDFJS: false,
strict: false
}
}
});
// Enable element
const element = document.querySelector(".cornerstone-element");
cornerstone.enable(element);
}
uploadNewImage(input) {
console.log("get file extension" + input.target.files[0].name.split(".").pop());
let file_extension = input.target.files[0].name.split(".").pop()
//Check file extension and do action accordingly
if (file_extension === 'dcm') {
console.log("we uploading a dcm file");
var self = this;
self.showResults = false;
this.file = input.target.files[0];
// Add the file to the cornerstoneFileImageLoader and get unique
// number for that file
const file = input.target.files[0];
// const imageId =
// "dicomweb:https://www.asteris.biz/Keystone/ImageDownload.aspx?ClinicCode=TESTKEYSTONE&ImageId=01b1755e-33d1-4b24-b9af-a4a019689d5f&ImageType=DicomImage&FrameIndex=0";
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
this.loadAndViewImage(imageId);
}
else {
console.log("we uploading a jpg or any other filer");
}
}
loadAndViewImage(imageId) {
// Enable element
const element = document.querySelector(".cornerstone-element");
cornerstone.enable(element);
// Display our image on the "enabled element"
cornerstone.loadImage(imageId).then(function (image) {
cornerstone.displayImage(element, image);
});
}
<input type="file" (change)="uploadNewImage($event)" id="sidebar-file-input"
accept="image/x-png, image/jpeg, .dcm" style="opacity: 0; width : 100%" #fileInp>Here
<div class="cornerstone-element-wrapper">
<div
class="cornerstone-element"
data-index="0"
oncontextmenu="return false"
></div>
</div>
So, I have four images that I put on the page from an array using a loop. Now I have the four images on the page, but I am looking for a way to allow the user to click on any of the images and display a large version of whichever one they click. I was thinking of using a new empty array, using push? to store the clicked image, but I don't know how to click on the images (because I 'm not using an img tag) and load the one that is clicked.
var arrayarray= [
"1.jpg",
"2.jpg",
"3.jpg",
"4.jpg"
];
var clicked =[];
function asdasd (){
for (var i = 0, j = arrayarray.length; i < j; i++) {
var fmg = document.createElement('img');
fmg.setAttribute("src", arrayarray[i]);
fmg.setAttribute("class", "fmss");
container.appendChild(fwfw);
if (??){
clicked.push(i);
}
}
}
You could add onClick event to an image node.
Selecting the image logic is handled by onClick function. In my example selectedImage variable stores the selected url.
See working example:
const images = [
"1.jpg",
"2.jpg",
"3.jpg",
"4.jpg",
];
let selectedImage = null;
const result = document.getElementById('result');
const container = document.getElementById('container');
const onClick = function() {
selectedImage = this['data-url']; // or this.src
// just for showing output in html
result.innerText = selectedImage;
};
// on Init
for (let i = 0; i < images.length; i++) {
const fmg = document.createElement('img');
fmg.setAttribute("src", images[i]);
fmg.setAttribute("class", "fmss");
fmg.setAttribute("alt", images[i]);
fmg.onclick = onClick;
fmg['data-url'] = images[i];
container.appendChild(fmg);
}
.fmss { border: 2px solid black; margin: 10px; }
.result { margin: 20px; }
Click me
<div id="container"></div>
<div id="result"></div>
No array needed. Just set the src of the big picture the to src of the clicked picture.
let main = document.getElementById("main"); // Get reference to main image
// Set up click event handler on thumbnail container
document.addEventListener("click", function(event){
// Check to see if the clicked element is a thumbnail
if(event.target.classList.contains("thumb")){
main.src = event.target.src; // Set main picture to match the thumbnail
}
});
.thumb { width:40px; }
#main { width:125px; }
<div id="picContainer">
<img src="https://spectator.imgix.net/content/uploads/2015/06/Emoji.jpg?auto=compress,enhance,format&crop=faces,entropy,edges&fit=crop&w=620&h=413" class="thumb">
<img src="https://i.pinimg.com/originals/43/7b/9b/437b9bbf3fde6d6a331b52bf6c422850.jpg" class="thumb">
<img src="https://cdn3.volusion.com/ghfyz.wgnwv/v/vspfiles/photos/LOF-A3-3650-2.gif" class="thumb">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQisqxRpIXDaOgpdYoy_4UgSKLjaFXM6qIEa4zAOjFIsh_Plp5R" class="thumb">
</div>
<img id="main" src="">
EDIT: 'mouseleave' event is constantly being triggered, although the mouse does not leave the element.
Code works as intended in: chrome, mozilla, edge, opera. But not safari!
I have a vanilla JavaScript solution that changes images every 1000ms when mouse hovered on parent element. There can be any amount of images inside wrapper and this should still work. To be more clear, javascript adds "hidden" class for every image and removes it from the one who's turn is to be displayed. (Code is in fiddle).
In safari it seems to be stuck swapping 2-3rd image. Am I using wrong dom-manipulation approach? How can I find the error?
Problem presentation: https://jsfiddle.net/pcwudrmc/65236/
let imageInt = 0;
let timeOut;
let imagesWrapper = document.querySelectorAll('.items-box__item');
// Events for when mouse enters/leaves
imagesWrapper.forEach(el => {
el.addEventListener('mouseenter', () => startAnim(el));
el.addEventListener('mouseleave', () => stopanim(el));
});
// DOM Manipulation functions
function changeImages(el) {
imageInt += 1;
if (imageInt === el.children[0].children.length) {
// reset to 0 after going through all images
imageInt = 0;
}
for (let i = 0; i < el.children[0].children.length; i++) {
// Adds "hidden" class to ALL of the images for a product
el.children[0].children[i].classList.add('hidden');
}
// Removes "hidden" class for one
el.children[0].children[imageInt].classList.remove('hidden');
// changeImage calls itself again after 1 second, if hovered
timeOut = setTimeout(changeImages.bind(null, el), 1000);
}
function changeBack(el) {
for (let i = 0; i < el.children[0].children.length; i++) {
// Adds "hidden" class to ALL of the images for a product
el.children[0].children[i].classList.add('hidden');
}
// Removes "hidden" class for the first image of the item
el.children[0].children[0].classList.remove('hidden');
}
startAnim = element => { changeImages(element) }
stopanim = element => {
changeBack(element);
clearTimeout(timeOut);
imageInt = 0;
}
.items-box__item {
width: 300px;
height: 300px;
}
.items-box__item--main-image {
object-fit: contain;
width: 90%;
height: 265px;
}
.hidden {
display: none;
}
<h3>Hover on pic and hold mouse</h3>
<div class="items-box__item">
<a href="/">
<img class="items-box__item--main-image" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/yrllszgndxzlydbycewc.jpg"/>
<img class="items-box__item--main-image hidden" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/e96i5zbvxxuxsdczbh9d.jpg"/>
<img class="items-box__item--main-image hidden" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948252/boaqfs3yuc4r7mvhsqqu.jpg"/>
</a>
</div>
You need to look at relatedTarget of mouseleave event, as both mouseenter and mouseleave happen every time the displayed image changes.
Also your code might be simplified. See the snippet below. Hope it helps.
const play = (box) => {
while (!box.classList.contains('items-box__item')) box = box.parentElement;
var img = box.querySelector('.show');
img.classList.remove('show');
(img.nextElementSibling || box.firstElementChild).classList.add('show');
}
const stop = ({target: box, relatedTarget: rt}) => {
while (!box.classList.contains('items-box__item')) box = box.parentElement;
while (rt != box && rt) rt = rt.parentElement;
if (rt === box) return;
box.querySelector('.show').classList.remove('show');
box.firstElementChild.classList.add('show');
box.play = clearInterval(box.play);
}
[...document.querySelectorAll('.items-box__item')]
.forEach((box) => {
box.addEventListener(
'mouseenter',
function() {
if (box.play) return;
play(box);
box.play = setInterval(() => play(box), 1000);
}
);
box.addEventListener('mouseleave', stop);
});
.items-box__item {
display: block;
width: 300px;
height: 300px;
}
.items-box__item img {
object-fit: contain;
width: 90%;
height: 265px;
display: none;
}
img.show {
display: initial
}
<h3>Hover on pic and hold mouse</h3>
<a class="items-box__item" href="/">
<img class="show" src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/yrllszgndxzlydbycewc.jpg">
<img src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948251/e96i5zbvxxuxsdczbh9d.jpg">
<img src="https://res.cloudinary.com/keystone-demo/image/upload/c_limit,h_300,w_300/v1525948252/boaqfs3yuc4r7mvhsqqu.jpg">
</a>