-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Image Upload with the react engine won't work #130
Comments
|
Hi @kunaumadein ! Sorry for the delay answering. The image input it's a tricky one right now. The value it returns to the design function isn't something that can be used that directly, it's actually a File Object as that's the type of object that an HTML file input returns. There are ways of using that object though. In your case, for a React based function, you would need something like this: export const handler = ({ inputs, mechanic }) => {
const {
myImage,
} = inputs;
const [href, setHref] = useState("");
useEffect(() => {
if (myImage) {
const reader = new FileReader();
reader.onload = function () {
setHref(reader.result);
};
reader.readAsDataURL(myImage);
}
}, []);
return <image href={href} />; This is not the best, and we are aware of it, hopefully we refactor how this input works in the future. Although it's already possible to define your own input components, so maybe someone does it before! I hope this helps! |
Thank you for the answer @fdoflorenzano
Thank you in advance! |
EDIT: I needed to import useState here:
Now it is working! |
Amazing! 🎉 |
Hello it is me again! |
@kunaumadein sure, using the technique described by @fdoflorenzano you can add as many images as you'd like. import React, { useEffect, useState } from "react";
export const handler = ({ inputs, mechanic }) => {
const { topLogo, bottomLogo } = inputs;
const [topHref, setTopHref] = useState("");
const [bottomHref, setBottomHref] = useState("");
const loadImageFromFileObject = (fileObject, stateSetter) => {
const reader = new FileReader();
reader.onload = () => {
stateSetter(reader.result);
};
reader.readAsDataURL(fileObject);
};
useEffect(() => {
if (topLogo) loadImageFromFileObject(topLogo, setTopHref);
if (bottomLogo) loadImageFromFileObject(bottomLogo, setBottomHref);
mechanic.done();
}, []);
return (
<svg width={400} height={400}>
<image href={topHref} />
<image href={bottomHref} />
</svg>
);
};
export const inputs = {
topLogo: {
type: "image",
multiple: false,
},
bottomLogo: {
type: "image",
multiple: false,
},
};
export const settings = {
engine: require("@mechanic-design/engine-react"),
}; |
ahh that's great @lnolte @fdoflorenzano to rename the "hrefs" I also tried earlier but your variant is much better! Currently I have also built in a multiple export option so that I can output it as SVG or as PNG but it happens in the export that my 2 images that I retrieve through the filereader then do not appear in the PNG export. Only the background that I have currently imported and linked locally is displayed in the PNG export. Do I have to save the images in the browser storage from the retrieved filereader in between or something? my current background which I imported from my machine:
i return everything via:
And i defined my inputs like the code you mentioned above. EDIT: I changed the current position of
|
Interesting. So the way you've currently set it up Normally state (where you store the hrefs) should be persisted between renders. So if it's working in the preview it should in theory also yield a working download. But exporting PNGs from SVG functions is a relatively new feature and I'm not fully aware of how it's implemented. I'll have a look at it later and get back to you :-) |
My solution with The method above where i put the But thank you @lnolte for having a look :) EDIT: just in case my current code from the index.js file
|
@kunaumadein sorry it took a bit to get to this. I think there is some work for us to do, to make working with image uploads more straightforward. Thanks again so much for pointing this out 😊 For now you should be able to get things working as expected by wrapping import React, { useEffect, useState } from "react";
export const handler = ({ inputs, mechanic }) => {
const { topLogo, bottomLogo } = inputs;
const [topHref, setTopHref] = useState("");
const [bottomHref, setBottomHref] = useState("");
const loadImageFromFileObject = (fileObject, stateSetter) => {
const reader = new FileReader();
reader.onload = () => {
stateSetter(reader.result);
};
reader.readAsDataURL(fileObject);
};
useEffect(() => {
if (topLogo) loadImageFromFileObject(topLogo, setTopHref);
if (bottomLogo) loadImageFromFileObject(bottomLogo, setBottomHref);
}, []);
useEffect(() => {
if (topHref && bottomHref) mechanic.done();
}, [topHref, bottomHref]);
return (
<svg width={400} height={400}>
<rect x={0} y={0} width={400} height={400} fill="black" />
<image href={topHref} />
<image href={bottomHref} />
</svg>
);
};
export const inputs = {
topLogo: {
type: "image",
multiple: false,
},
bottomLogo: {
type: "image",
multiple: false,
},
};
export const settings = {
engine: require("@mechanic-design/engine-react"),
showMultipleExports: true,
optimize: false,
}; This will evaluate the second |
Hello @lnolte My last question would be if the engine was updated somehow because i wanted to Thank you! |
@kunaumadein That error could be from a update we did in a recent release. Please report that last error in another issue, since it looks like another error not related to the original one reported in this issue. Make sure to check and report which version of mechanic you are using. |
@fdoflorenzano I see ok I will report it in another issue. |
Hello @lnolte, I tried to make something work with logical operators but everytime the mechanic.done(); function will be recalled several times and i will sometimes download 2 or 3 PNG files. |
@kunaumadein do you mind sharing the section of code that tries this? useEffect(() => {
if (topHref || bottomHref) mechanic.done();
}, [topHref, bottomHref]); ? |
@fdoflorenzano oh yeah sorry My Code:
The method with |
Gotcha, I was missing the rest of it. You get that because the readers change the state of the React component in different moments, so you get two calls to In a way, you need an extra validation to check that if there's an image waiting to be loaded, the function waits for it to load and to call useEffect(() => {
if ((topHref || bottomHref) && (!topLogo || topHref) && (!bottomLogo || bottomHref)) mechanic.done();
}, [topLogo, topHref, bottomLogo, bottomHref]); Also @kunaumadein, at this point these questions are becoming more about React rendering more than about Mechanic. Please consider researching about React state and rendering, that could probably help you with some of these questions. |
I just tried your code and everything works! And also realized that my questions are going more and more in the direction of react but my problem with the images you have solved wonderfully and therefore you could close the ticket at this point :) |
Describe the bug
To get a feel for the framework I had the Business Card Generator compiled as an example. I wanted to test something basic and add text and 2-3 images. But when I add an upload image input and reference it in react via the image is displayed as broken.
Expected behavior
the uploaded Image should work as a background on the whole canvas.
Desktop (please complete the following information):
The text was updated successfully, but these errors were encountered: