how do you preload background img with react? - javascript

I have an APi where i pull data from, whereas the images come in the form of url,
i have made it so that when the fetch is done the app renders the feed.
The issue is that the images load after the fetch. How do i persist the loader until the images are done loading?

You didn't show us any code so we could help you much such as what libs you are using to fetch stuff from an api.
But here is one more generic way of doing it:
function loadEverything() {
// get the api response
const res = await fetch(url)
const json = await res.json()
// start loading all images
let images = json.images.map(image => new Promise((rs, rj) => {
const img = new Image()
img.onload = () => rs(img)
img.onerror = () => rj()
}))
// wait for everything to load
images = await Promise.all(images)
// now append everything to the DOM and remove the loader
}
means you have to append dom element and not simply bind some src attribute to a url
ofc, there is other ways to solve it too. like using a service worker + a custom cache storage. or hiding the DOM until everything is complete

Related

How to get another html file as if getting it by document without using jquery

How to get another html file as if getting it by document
Basically, the same 'document' instance type used for document.getElementsByClassName(), but instead of getting the document the javascript code is in, it gets another .html file in the same domain. For example, "blog.html".
Here's what I want it to hypothetically look like
var blogdocument = getDocument("blog.html");
var blogposts = blogdocument.getElementsByClassName("blogpost");
If it's on the same domain, you can make a network request to get the text of the response back, then send it through DOMParser to construct a document from the text:
fetch('./blog.html')
.then(res => res.text())
.then((result) => {
const doc = new DOMParser().parseFromString(result, 'text/html');
const posts = doc.querySelectorAll('.blogpost');
// ...
})
// .catch(handleErrors);
Just wanted to add some suggestions to the answer
const doc = new DOMParser();
You may not want to use const
Because you should use
doc = null;
to actively release memory after you done with it
DOMParser is very expensive
I have encountered serious performance issues because I didn't do it
DOM Parser Chrome extension memory leak
An alternative to a fetch or AJAX request is to load an iframe with the source set to the URL, then read from its contentWindow, and then remove it from the DOM.
var desiredPage = "www.google.com";
var ifrm = document.createElement("iframe");
ifrm.setAttribute("src", desiredPage);
document.body.appendChild(ifrm);
setTimeout(function() {
console.log(ifrm.contentWindow.document.getElementsByTagName("somestuff"));
ifrm.remove();
}, 100);

Capture HTML canvas of third-party site as image, from command line

I know one can use tools such as wget or curl to perform HTTP requests from the command line, or use HTTP client requests from various programming languages. These tools also support fetching images or other files that are referenced in the HTML code.
What I'm searching for is a mechanism that also executes the JavaScript of that web page that renders an image into an HTML canvas. I then want to extract that rendered image as an image file. The goal to achieve is to grab a time series of those images, e.g. weather maps or other diagrams that plot time-variant data into a constant DOM object, via a cron job.
I'd prefer a solution that works from a script. How could this be done?
You can use puppeteer to load the page inside a headless chrome instance
Open the page and wait for it to load
Using page.evaluate return the dataUrl of the canvas
Convert the dataUrl to a buffer and write the result to a file
const puppeteer = require('puppeteer');
const fs = require('fs');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://games.novatoz.com/jigsaw-puzzle');
const dataUrl = await page.evaluate(async () => {
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
await sleep(5000);
return document.getElementById('canvas').toDataURL();
});
const data = Buffer.from(dataUrl.split(',').pop(), 'base64');
fs.writeFileSync('image.png', data);
await browser.close();
})();

Is there a good way to ensure an object gets created before moving through code that uses it?

I have a bit of code that uses fetch() to grab and convert .tiff images to an html5 canvas to be displayed in a browser using tiff.js (https://github.com/seikichi/tiff.js/tree/master). It almost works great, however, I am noticing that sometimes the images don't make it to the browser.
Some images will appear, but occasionally others will not, with the following error message in the browser:
ReferenceError: Tiff is not defined
I need to find out if there is a good way to ensure that these objects get created successfully, and would appreciate any insight I could get into what causes this behavior.
class tiffImage {
constructor() {
this.tiffURL = 'url-to-image';
this.height;
this.width;
this.canvas;
}
async loadImage() {
fetch(this.tiffURL)
// retrieve tiff and convert it to an html5 canvas
let response = await fetch(this.tiffURL);
let buffer = await response.arrayBuffer();
let tiff = new Tiff({buffer: buffer}); // error points to this line
this.canvas = tiff.toCanvas();
/* Parse some data from image and do DOM stuff */
}
}
// retrieve and display boards
let someTiff1 = new tiffImage();
let someTiff2 = new tiffImage();
let someTiff3 = new tiffImage();
let someTiff4 = new tiffImage();
let someTiff5 = new tiffImage();
someTiff1.loadImage();
someTiff2.loadImage();
someTiff3.loadImage();
someTiff4.loadImage();
someTiff5.loadImage();
Sometimes all of the images are loaded probably, and sometimes not. If the page is refreshed enough times it is guaranteed to see some images fail to load. Note that in my actual project I am instantiating and calling loadImage() on 13 objects.
Read up on Promises. A promise will allow you to wait for asynchronous actions to complete before progressing.
loadImage() {
return fetch(this.tiffURL)
.then(response=>{
// retrieve tiff and convert it to an html5 canvas
let buffer = response.arrayBuffer();
let tiff = new Tiff({buffer: buffer}); // error points to this line
this.canvas = tiff.toCanvas();
return this;
/* Parse some data from image and do DOM stuff */
}
}
Promise.all([someTiff1.loadImage(),someTiff2.loadImage()])
.then(results=>{
console.log("My results", results)
})
Don't use async and await in your code. If you're using these, you're using Promises wrong.

D3.js pulling and embedding DataURI images with Promises

I'm building a data visualization which relies on a lot of small raster images, delivered as AWS URLs via JSON API.
This works fairly well, until I try to implement my next step, which is rendering the data visualization as a PNG to download. In the PNG, the raster images are broken.
I've understood that to solve this, I need to embed images as Data URLs.
Here's what I've got so far:
const companies_base64 = companies.map(c => {
var o = Object.assign({}, c)
o.base64 = imageToBase64(c.mimetype, c.logo)
return o
})
Where companies is an array of objects. Here's imageToBase64, the Heroku app being a clone of CORS anywhere:
function imageToBase64(mimetype, logo) {
var url = 'https://example.herokuapp.com/' + logo
return d3.blob(url)
.then(blob => blobToBase64(blob))
.then(base64 => mimetype + base64)
.catch(error => console.error(error))
}
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = () => {
let dataUrl = reader.result
let base64 = dataUrl.split(',')[1]
resolve(base64)
}
reader.onerror = () => {
reject("Error")
}
reader.readAsDataURL(blob)
})
}
Which results in a Promise being returned when calling base64 on any of the objects in companies_base64, the [[PromiseValue]] being of course what I'm after. How am I supposed to make sure it is what gets returned so I can, ultimately, place it inside the xlink:href attributes of the <image>s in my <svg>?
I think that once it works and I can call imageToBase64 wherever, it's something I want to do only when the user presses Download. I imagine I can do this using D3, iterating over the <image>s and swapping out their xlink:href. Or should I go about it another way?
I have also tried getting the images as objects and then converting them to base64 in my RoR backend so they come packaged with the JSON, via an Image#to_base64 method. This does work, but it A) feels very wrong and B) is obviously very slow on initial load.
Thank you for your time and please bear with me as I am a beginner.
Your imageToBase64 function returns a promise, not the resolved data URL. That means you have to wait before you can attach them to the companies_base64 members. It is your choice if you do that as soon as the individual base64 string is ready, or if you wait for them all:
Promise.all(companies.map(c => {
return imageToBase64(c.mimetype, c.logo)
.then(u => Object.assign({ base64: u }, c))
.then(/* change the image reference here one by one... */)
}))
.then(companies_base64 => /* ...or here, in a loop over the array */)
.catch(error => console.error(error))

How to load an HTML5 Canvas with an image from an image-service?

My web app calls a Web API service, which returns an image. The service returns nothing but an image. Calling the service is little different because there is a function in the routing code that adds the required auth-code and such. Anyway, my point is, I don't have the full URL and even if I did, I wouldn't want to pass it into code in plain-text. So what I have is a response, and that response is an image.
getThumb(filename: string) {
return this.http.get('/Picture/' + filename).subscribe(response => {
return response;
});
}
What I need to do is draw that image on to a canvas. From what I've seen on the internet so far, it looks like I want to create an image element, then assign that element src a URL, then I can add it to the canvas. It's the src part that's perplexing me. All the samples I see are either loading the image from a local filesystem or predefined URL, or from a base64 string, etc. I can't figure out how to just load an image I have as a response from a service. I'm sure I'm overthinking it.
Does anyone have some sample code to illustrate this?
e.g Something like this:
var img = new Image(); // Create new img element
img.src = ... ; // Set source to image
You could convert the image to Base64. In my example, you request the image and convert it to a blob using response.blob(). Once it's a blob, use fileReader.readAsDataURL to get the Base64.
const fileReader = new FileReader();
fetch("image-resource").then((response) => {
if(response.ok) {
return response.blob();
}
}).then((blob) => {
fileReader.readAsDataURL(blob);
fileReader.onloadend = () => {
console.log(fileReader.result);
}
});
References:
readAsDataURL
Blob

Categories