get image size before upload in React - javascript

The desired results have been done in vanilla here
To be clear, I won't be using alert(), I'd like to place the dimensions in the state object.
How would I recreate this code in React under the OnChange() event handler?

React is still JavaScript, everything you do in regular js can be done in React. At a high level, React is just the framework that helps you create more modular reusable code.
With that being said, thinking as a React developer, you should create the upload process first get that to work in a separate class. The class could accept an image through its props. Then once that is working correctly you could create a Higher order component that wraps the upload component or rather receives the upload component as a parameter and checks the image size. At this point you can return an Invalid component or just process the image and upload.
You might want to look at a few tutorial on Getting started with React.
This is an excellent start egghead.io

I have a img src that looks something like this:
I was able to solve the problem with code like this
if (e.target.files && e.target.files[0]) {
var img = document.createElement("img");
this.state.backgroundImageFile = e.target.files[0];
img.onload = function () {
debugger;
console.log(this.width + " " + this.height);
});
var reader = new FileReader();
reader.onloadend = function (ended) {
img.src = ended.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}

Related

Image onload not being called in vue

I am trying to build a Vue App and I am new to Vue, I am trying to load an image at runtime in Js/Ts with the code below
console.log("code is being called");
let image = new Image();
image.onload = (event) => {
console.log("image loaded");
}
image.src = "static/prison_tileset.png";
The code works fine on a regular html file, in Vue however, the onload method isn't being called. The first console.log is being called. I am sure that the image is found because if I manipulate the path to something wrong on purpose I get an error that the file isn't being found. It's just that the onload event isn't being firied.
I'd be very happy if somebody could help me with that!
I've gotten it to work now! I will answer the question myself as best as I can. To use local assets in view you have to load them via Webpack like this:
const Logo = require("../assets/logo.png");
this.image.src = Logo;
If you also happen to use electron you have to set the webSecurity in your entry file to false for electron to be allowed to access local files.

Rendering image dynamically is so hard in React

After trying various ways for hours and checking every relatable link, I couldn't find any proper way to render image dynamically in React.
Here is what i am trying to do.
I have an array of objects in which each object has a attribute called name. I am using map function map to loop over this array and returning of array of img element like shown below.
<img className="img-thumbnail" src={require('../../public/images/'+item.name+'.png')}/>
where item.name is the name of image file I want to display, for which require is giving me error "cannot find module".
Moreover I need to implement some fallback option, where rather showing broken images incase image file does not exist, i want to display default image
Here are the things I have tried:
using try and catch block over require and calling this function from img element
setImage(data){
try{
return require( '../../public/images/'+data+'.png' ) //actual image
}catch(err){
console.log(err);
return require('../../public/images/fallback.png'); //fallback
}
<img className="img-thumbnail" src={this.setImage(item)}/>
using import, inside same function above, got error import cannot be called from inside of function
using react-image library. Turned out it does not support local images.
Any help ?
Here a tricky way to handle this. Use react state to check if there's error.
If true, show fallback, otherwise, show actual image.
setImage = (data) => {
const image = new Image();
image.src = '../../public/images/'+data+'.png';
this.setState({
hasError: false
})
image.onerror = () => {
this.setState({
hasError: true
})
}
return image.src;
}
// into render
this.state.hasError
? <img src="../../public/images/fallback.png" />
: <img className="img-thumbnail" src={this.setImage(item)}/>
Update: Example
var image = new Image();
image.src = 'fake.jpg';
image.onerror = () => {
console.log('image doesn t exist');
}
I dont know why you need required it could be done simply like this. You can import something like this. Import image like this
import fallback from '../../public/images/fallback.png';
and for dynamic image i would suggest either make some key value pair. For ex :
let data = {
image1 : ../../public/images/image1.png,
image2 : ../../public/images/image1.png
}
and import it normal
and something in render
it could be something like this.
render(){
return(
<img className="img-thumbnail" src={img?img[type]:fallback}/> //something its just refrence(where type is something which you want dynamically add image)
)
}
Requires are statically checked during compile time. The path of requires cannot be dynamic. Since you have static images in your bundle and the object maps to one of these you can follow a solution to something as follows
const images = {
image1: require('local/path/to/image1'),
image2: require('local/path/to/image2'),
image3: require('local/path/to/image3'),
}
const defaultImage = require('local/path/to/defaultImage');
const Img = ({ name }) => {
// here name is the name for the image you get from api..
// This should match with the keys listed the iages object
return <img src={images[name] ? images[name] : defaultImage}/>
}
Above all answers were helpful but unforutnaley none of the method worked for me. So again digging little deep I found that require was giving error "cannot find module" because after webpack bundles my code, require lost the context. Which means the given relative path was no longer valid.
What i needed to do was preserve context which I did by using require.context;
Here is the final code that worked.
//getting the context of image folder
const imageFolderContext = require.context('realtive/path/to/image/folder')
//function to check if image exist
checkFile(data){
try{
let pathToImage = './path/to/image/relative/to/image/folder/context
imageFolderContext(pathToImage) //will check if Image exist
return true //return true if exist
}catch(err){return false}
}
//rendering image element dynamically based on item name and if exist or not
<img src={this.checkFile(itemName)?imageFolderContext('path/to/image/relative/to/context'):imageFolderContext('default/image/path/) />
don't forget to bind checkFile function

Display shapefiles as layer in map with React 16

I'm using an old (2 years) leaflet plugin inside react to load a shape file ( a zip file that contains 4 files inside that when displayed on a map will draw a layer, commonly used on GIS)
While the plugin works (tested), I would like to eliminate the upload functionality. just call the zip file that I have inside my app and make it appear and disappear on the layers control menu in the top right of the map. That's it
Here is the https://codesandbox.io/s/34o825nz8m
I believe the trick is in here:
handleFile(e) {
var reader = new FileReader();
var file = e.target.files[0];
reader.onload = function(upload) {
this.readerLoad(upload);
}.bind(this);
reader.readAsArrayBuffer(file);
}
What I've tried so far:
replaced the var file for './protrac.zip' which is located here (https://www.data.boem.gov/Mapping/Files/protrac.zip)
got an error.
changed reader.readAsDataURL(file).
Since I've erased the input tag my intention is to run the handleFile function inside ComponentDidMount (). but I can't even console.log the zip that I have inside my app.
P.D. if you get a createLeafletElement () error, this can only be fixed on the node_modules folder by putting this line
ShapeFile.prototype.createLeafletElement = function createLeafletElement () {}

preload images on javascript (React, Jquery) app, images loaded twice

Please look at EDIT 3 below, as I figured out that it is not an issue with React but with the browser's chaching mechanism.
I'm trying to create an app that creates some simple carousel out of given array of images url. I've written a module that helps me to invoke a callback once all the images are loaded, this is how it look:
ImagesLoader.js
export default {
// a module that loads an array of images urls and when completes
// calls a callback with the images elements array
load(imagesUrlsArray, callback){
const imagesLoaded = [];
imagesUrlsArray.map((url) => {
const img = new Image();
img.onload = () => {
imagesLoaded.push(img);
if(imagesUrlsArray.length === imagesLoaded.length){
callback(imagesLoaded);
}
};
img.src = url;
});
}
}
I know I can use promises and resolve once all urls are loaded, and no check for errors right now.
Here is where my component updates the state with the images retriveed from the module above:
componentDidMount() {
ImagesLoader.load(this.props.images, (loadedImages) => {
const imagesStateData = this.calculateImagesStateData(loadedImages);
this.setState(Object.assign({},
imagesStateData,
{
loaded: true,
loadedImages: loadedImages
}
));
});
}
What happens is when I click the next or previous button (look at the screenshot below) each time the image loaded again, I can't understand why.
this is the first time I do such thing with reactjs, with jquery had no problems
Here is how I pass the images urls:
export default class App extends Component {
render() {
var images = [
"http://www.wallpapereast.com/static/images/excellent-love-quotes-wallpaper-hd.jpg",
"http://www.wallpapereast.com/static/images/My-Samsung-Galaxy-S3-Wallpaper-HD-Landscapes1.jpg",
"https://s-media-cache-ak0.pinimg.com/236x/58/01/02/5801020fea36221ffba33633f99a7d81.jpg",
"http://www.wallpapereast.com/static/images/pier_1080.jpg",
"http://www.wallpapereast.com/static/images/wallpaper-black-hd-hd-wallpapers.jpg",
"http://1.bp.blogspot.com/-dvg12YJKaKg/UnVfkMke7jI/AAAAAAAAUaU/O86x5FMgEuk/s1600/longcat.gif"
];
var settings = {
autoPlay: true,
arrows: true
};
return (
<Layout>
<ReactCarousel images={images} width={500} height={300} settings={settings}/>
</Layout>
);
}
}
EDIT:
managed to give a short example. http://codepen.io/anon/pen/ObyRPX , what I could see from building this example is if I don't use the ImageItem component and render a simple <img src='image.src'/> element it works good, so I guess my problem is with the ImageItem component.
EDIT 2:
this is pretty weird http://codepen.io/anon/pen/eBpdjx here I just changed it so ImageItem renderes image element rather than background image on a div and it works as expected. Can anyone explain what is the difference?
EDIT 3:
Apparently this is happening not only on react apps but on jquery app aswell, have a look here:
http://codepen.io/anon/pen/VmvyPZ
Again when I try to load the image as background-image property of the css, the browser doesn't cache the image and load it twice.
I faced the exact same issue. The image gets loaded again because the browser is not holding a reference to the image that you have loaded.
All I did was create a global array and push all the images to the array.
Now, this array is global and the browser has to maintain the array until the whole app gets destroyed.
var allImages = [];
function loadImages(imageUrls) {
imageUrls.forEach((q) => {
const img = new Image();
img.src = q;
allImages.push(img);
});}
After this, I was able to load the images on other pages, even when offline.
Chrome shows 2 image requests in devtool for one image. Try to uncheck disable cache option in the network tab.

How can you dynamically change the source in a require statement that requires an image file?

The image I'm using in React Native uses a require statement for the source of the image. I want to change the source of the image so it is kind of of like switching out frames in an animation.
var module1 = './hello';
var module2 = './goodbye';
state = {
module: module1 // will later be changed to module2
}
require(this.state.module);
Require both and then use the correct one where you need it:
var hello = require('./hello');
var goodbye = require('./goodbye');
hello.myFunction();
// later:
goodbye.anotherFunction()
I dont think it is a good programming style but it is possible.
For example the modules look like this
exports.name = () => {
console.log('modul1')
}
And the main file like this, it will work like expected
const modul1 = './modul1'
const modul2 = './modul2'
var modul = require(modul1)
modul.name() // -> modul1
modul = require(modul2)
modul.name() // -> modul2
I ended up just creating an object like this:
var frames = {
'1': require('./assets/phase1.png'),
'2': require('./assets/phase2.png'),
'3': require('./assets/phase3.png'),
'4': require('./assets/phase4.png'),
}
and in my Image tag, I set the source attribute to this.state.frame and setState with a new key from frames like frames[imageIndex]. Luckily I didn't have too many images, but this isn't the most ideal solution.
EDIT:
Another solution (which is more elegant and less verbose) is to create a drawable folder in android>app>src>main>res and drop all the images in the that folder. On iOS, you can drop all your images in ios>Appname>Images.xcassets.
From there, you can set the source of your images to {uri: this.state.imageFile} where this.state.imageFile is a string without the file extension and you can change them dynamically without having to require() each file.

Categories

Resources