如何解决图像滑块反应模因生成器
我有一个关于 React 中的 ImageSlider 的问题,从 Imgflip API 获取图片以用于 Meme 生成器。 附上你找到的app.js。 ImageSlider 应该发生在“Meme Editor”部分(从第 175 行开始),它在我也附上的 index.js 中编码。 我尝试在 App.js 和 index.js 中实现按钮并通过数组状态工作,但图片没有相应改变。
我知道制作一个Imageslider应该很容易,但是由于我们远程处理代码并且结构在某个时候变得非常不清楚,我有点迷茫。 非常感谢您的帮助。
import React,{ useState,useEffect } from "react";
import { Meme } from "./components/Meme";
import Topbar from "./components/Topbar";
import TemplatePicker from "./components/TemplatePicker";
import Editor from "./components/Editor";
//MaterialUI
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import { TextField } from "@material-ui/core";
import Box from "@material-ui/core/Box";
import MemeHistory from "./components/MemeHistory";
import TemplateOverview from "./components/TemplateOverview";
const useStyles = makeStyles((theme) => ({
grid: {
width: "100%",height: "100%",margin: "0px",},root: {
flexGrow: 1,paper: {
padding: theme.spacing(2),textAlign: "center",color: theme.palette.text.secondary,scroll: {
overflow: "scroll",height: "700px",scroll2: {
overflow: "scroll",height: "500px",search: {
overflow: "scroll",height: "430px",margin: {
margin: theme.spacing(1),}));
function App() {
const [templates,setTemplates] = useState([]);
const [template,setTemplate] = useState(null);
const [newMemeCreated,setNewMemeCreated] = useState(false);
const [newTemplateCreated,setNewTemplateCreated] = useState(false);
const [index,setIndex] = useState(0); // create state to keep track of images index,set the default index to 0
const slideRight = () => {
setIndex((index + 1) % templates.length); // increases index by 1
console.log(index);
console.log(templates.length);
setTemplate(index)
};
// let [editedMemeUrl,setEditedMemeUrl] = useState("");
const classes = useStyles(); // const classes is created,which refers to useStyles
// here,we get the images from the Imgflip API through a backend request,it can be found in the routes folder
useEffect(() => {
fetch("http://localhost:3001/memes")
.then((x) => x.json())
.then((response) => setTemplates(response.data.memes));
},[]);
// Text update function => !!! Redundant,put can potentially be re-used for image sharing functionalities
// const updateText = async (e) => {
// if (!template.isUserUploaded) {
// // if template is not user uploaded,then use the updateText function. This needs to be changed into an editor that can both handle text inputs for Imgflip API templates and customones.
// console.log("button update text");
// e.preventDefault(); // This makes sure that the Form is not refreshed every time it is submitted
// // add the logic to create meme from the imgflip api
// const params = {
// //these are the properties of caption_image of the imgflip api
// template_id: template.id,// text0: topText,// text1: bottomText,// username: "isakl",// password: "omm2020",// };
// const response = await fetch(
// `https://api.imgflip.com/caption_image${objectToQueryParam(params)}`
// );
// const imgFlipResponse = await response.json();
// editedMemeUrl = imgFlipResponse.data.url;
// setEditedMemeUrl(imgFlipResponse.data.url);
// console.log(editedMemeUrl);
// function pictureChange() {
// document.getElementById("memeStateDiv").innerHTML =
// "<img id='memeState' src='' alt='memeState' width='250'>";
// document.getElementById("memeState").src = editedMemeUrl;
// }
// pictureChange();
// //setMeme(editedMemeUrl); // After editing the Meme,the Imgflip API creates a new URL with the edited Meme which is even accessible over the Imgflip site.
// }
// };
// we are displaying a list of memes until a meme is selected
return (
<div style={{ textAlign: "center" }}>
<div className={classes.root}>
<Grid container spacing={2} direction="row" alignItems="stretch">
<Grid item xs={12}>
<Paper className={classes.paper} elevation={3}>
<Topbar></Topbar>
</Paper>
</Grid>
</Grid>
{/* Search function */}
<Grid item xs={3}>
<TextField
className={classes.margin}
id="input-with-icon-textfield"
label="Search for Meme"
></TextField>
</Grid>
<Grid container spacing={2} direction="row">
<Grid item xs={3}>
<Paper className={classes.paper} elevation={3} position="fixed">
<div elevation={3} className={classes.scroll}>
{/* {" "} */}
{/* Get MEMES for the sidebar */}
<Grid container spacing={3}>
<Grid item sm={3} elevation={3}>
<Box>
{templates.map((template) => {
return (
<Meme // the image logic is extracted into the Meme.js component so it does not have to be rewritten
template={template}
onClick={() => {
// The image that is clicked on,will be selected as the template and the useState is being updated
setTemplate(template);
}}
/>
);
})}
</Box>
</Grid>
</Grid>
</div>
</Paper>
</Grid>
<Grid item xs={6} className={classes.grid}>
<Grid container spacing={1} direction="row">
<Grid item xs={12}>
<Paper
className={classes.paper}
elevation={3}
position="center"
>
{/* Meme Editor */}
<Typography variant="h5" color="primary">
EDITOR
</Typography>
<Box>
<button onClick={slideRight}>{">"}</button>
<Editor
memeToEdit={template}
handleReloadMemes={(bool) => setNewMemeCreated(bool)}
>
</Editor>
</Box>
</Paper>
</Grid>
</Grid>
</Grid>
<Grid item xs={3}>
<Paper className={classes.paper} elevation={3}>
{/* Settings */}
<Typography variant="h5" color="primary">
SETTINGS
</Typography>
<TemplatePicker
setShouldReloadSavedTemplates={(bool) =>
setNewTemplateCreated(bool)
}
// passing our uploaded image up to the App.js,to pass it down to the Meme component
setTemplateInEditor={(img) => setTemplate(img)}
></TemplatePicker>
</Paper>
</Grid>
</Grid>
<Grid container spacing={2} direction="row" alignItems="stretch">
<Grid item xs={12}>
<Paper className={classes.paper} elevation={3} position="fixed">
{/* Your Memes */}
<Typography variant="h5" color="primary">
YOUR MEMES
</Typography>
<div elevation={3} className={classes.scroll2}>
<MemeHistory
setShouldReloadSavedMemes={(bool) => setNewMemeCreated(bool)}
shouldReloadSavedMemes={newMemeCreated}
/>
</div>
</Paper>
</Grid>
</Grid>
<Grid container spacing={2} direction="row" alignItems="stretch">
<Grid item xs={12}>
<Paper className={classes.paper} elevation={3}>
{/* Your Templates */}
<Typography variant="h5" color="primary">
YOUR CUSTOM TEMPLATES
</Typography>
<div elevation={3} className={classes.scroll2}>
<TemplateOverview
setShouldReloadSavedTemplates={(bool) =>
setNewTemplateCreated(bool)
}
shouldReloadSavedTemplates={newTemplateCreated}
setTemplateInEditor={(img) => {
setTemplate(img);
}}
/>
</div>
</Paper>
</Grid>
</Grid>
</div>
</div>
);
}
export default App;
// This is the Component for the Editor Box in the Middle of the webapp in which Meme Templates are selected into in order to be edited.
import React,useEffect,useRef } from "react";
import { Button } from "@material-ui/core";
import { TextField } from "@material-ui/core";
import IconButton from "@material-ui/core/IconButton";
import ArrowBackIcon from "@material-ui/icons/ArrowBack";
import ArrowForwardIcon from "@material-ui/icons/ArrowForward";
import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward";
import ArrowUpwardIcon from "@material-ui/icons/ArrowUpward";
//Share Buttons
import {
EmailShareButton,FacebookShareButton,TwitterShareButton,EmailIcon,FacebookIcon,TwitterIcon,} from "react-share";
// we pre-define the canvas width and height
const CANVAS_WIDTH = 300; // Wie können wir die variabel machen => Abängig von der Größe des Originalbildes??
const CANVAS_HEIGHT = 300;
const Editor = (props) => {
const { memeToEdit,handleReloadMemes } = props;
console.log("memeToEdit",memeToEdit);
const [image,setImage] = useState(null);
const [imageWidth,setImageWidth] = useState(0);
const [imageHeight,setImageHeight] = useState(0);
const [templates,setTemplate] = useState(null);
const [index,set the default index to 0
const canvas = useRef(null);
const [fontColor,setFontColor] = useState("white");
const [fontStyle,setFontStyle] = useState("30px Impact");
const [topText,setTopText] = useState("");
const [topTextPosX,setTopTextPosX] = useState(CANVAS_WIDTH / 2);
const [topTextPosY,setTopTextPosY] = useState(CANVAS_HEIGHT * 0.1);
const [bottomTextPosX,setBottomTextPosX] = useState(CANVAS_WIDTH / 2);
const [bottomTextPosY,setBottomTextPosY] = useState(CANVAS_HEIGHT * 0.9);
const [bottomText,setBottomText] = useState("");
const [additionalTextA,setAdditionalTextA] = useState("");
const [additionalTextAPosX,setAdditionalTextAPosX] = useState(
CANVAS_WIDTH / 2
);
const [additionalTextAPosY,setAdditionalTextAPosY] = useState(
CANVAS_HEIGHT * 0.5
);
useEffect(() => {
fetch("http://localhost:3001/memes")
.then((x) => x.json())
.then((response) => setTemplates(response.data.memes));
},[]);
// Define functions with which the font colors and styles are changed OnClick => See Buttons at the bottom
const changeFontColorBlack = () => {
setFontColor("black");
};
const changeFontColorWhite = () => {
setFontColor("white");
};
const changeFontBold = () => {
setFontStyle("30px Impact");
};
const changeFontItalic = () => {
setFontStyle("Italic 30px Impact");
};
const changeFontStyle = () => {
setFontStyle("50px Impact");
};
//ImageSlider
const slideRight = () => {
setIndex((index + 1) % templates.length); // increases index by 1
console.log(index);
console.log(image);
console.log(templates.length);
};
const slideLeft = () => {
const nextIndex = index - 1;
if (nextIndex < 0) {
setIndex(templates.length - 1); // returns last index of images array if index is less than 0
} else {
setIndex(nextIndex);
}
console.log(index);
};
// Function to save Meme to DB (takes the exported Canvas)
const saveMemeFromEditorToDB = () => {
const bodyToSend = JSON.stringify({
url: memeToEdit.url,exportedImage: exportCanvasAsImage(),});
// the upcoming fetch function sends the generated Meme (accessible throught the new URL above) to the Express Backend Server. In the Express App,there is a route "saveMeme" in the Meme.js file that sends the URL with the generated Meme to the Server.
fetch("http://localhost:3001/memes/saveMeme",{
method: "POST",headers: {
"Content-Type": "application/json",body: bodyToSend,})
.then((x) => x.json())
.then((response) => handleReloadMemes(true));
};
// Here,we export the current state of the canvas to an image,so it can be dowloaded at a later stage.
const exportCanvasAsImage = () => {
const ctx = document.getElementById("meme-canvas");
return ctx.toDataURL("image/png");
};
// Download Meme
const downloadMeme = () => {
var link = document.createElement("a");
link.download = "meme.png";
link.href = exportCanvasAsImage();
link.click();
};
// Here,we set the "Image" which is the template to be edited for our Meme
useEffect(() => {
try {
if (!memeToEdit) return; // if there is no Template to edit,do nothing
const { url } = memeToEdit;
console.log("url",url);
const meme = new Image();
meme.src = url;
console.log("meme",meme);
meme.onload = () => {
setImage(meme);
const { height,width } = meme;
setImageHeight(height);
setImageWidth(width);
};
meme.setAttribute("crossorigin","anonymous"); // Added this,so the url of the meme can be worked with.
} catch (error) {
console.log("error",error);
}
},[memeToEdit]);
useEffect(
() => {
if (image && canvas) {
const ctx = canvas.current.getContext("2d");
ctx.fillStyle = "black"; // the canvas is filled with black background color
ctx.fillRect(0,CANVAS_WIDTH,CANVAS_HEIGHT); // the canvas rectangle is filled according to the set width and height (which is fixed at the moment)
console.log("imageHeight,imageWidth",imageHeight,imageWidth);
const contentOffset = 10;
const factorWidth = CANVAS_WIDTH / imageWidth;
const factorHeight = CANVAS_HEIGHT / imageHeight;
// drawImage is responsible for taking the image that you selected and putting it on the Canvas (ctx). Source: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
ctx.drawImage(
image,contentOffset,imageWidth * factorWidth - contentOffset * 2,imageHeight * factorHeight - contentOffset * 2
);
// set the font with which the text is entered
ctx.font = fontStyle;
ctx.fillStyle = fontColor;
ctx.textAlign = "center";
// text edit options
ctx.fillText(topText,topTextPosX,topTextPosY);
ctx.fillText(bottomText,bottomTextPosX,bottomTextPosY);
ctx.fillText(additionalTextA,additionalTextAPosX,additionalTextAPosY);
}
},//Remember to add each const here at the end if you define it
[
image,canvas,topText,bottomText,additionalTextA,topTextPosY,bottomTextPosY,additionalTextAPosY,imageWidth,fontColor,fontStyle,]
);
return (
<div>
<div>
<h2>Meme Title : XY </h2>
</div>
<div>
<button onClick={slideLeft}>{"<"}</button>
{image ? (
<canvas
id={"meme-canvas"}
ref={canvas}
width={CANVAS_WIDTH}
height={CANVAS_HEIGHT}
/>
) : (
// if no image is selected,show the following message
<p>Select a meme,please</p>
)}
<button onClick={slideRight}>{">"}</button>
</div>
<br></br>
<div>
<TextField
style={{ width: 200 }}
size="small"
type="text"
label="Upper text"
variant="outlined"
value={topText}
onChange={(e) => setTopText(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setTopTextPosX(topTextPosX - 10)}
>
<ArrowBackIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position X"
value={topTextPosX}
onChange={(e) => setTopTextPosX(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setTopTextPosX(topTextPosX + 10)}
>
<ArrowForwardIcon />
</IconButton>
<IconButton
size="large"
variant="contained"
onClick={(e) => setTopTextPosY(topTextPosY - 10)}
>
<ArrowUpwardIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position Y"
value={topTextPosY}
onChange={(e) => setTopTextPosY(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setTopTextPosY(topTextPosY + 10)}
>
<ArrowDownwardIcon />
</IconButton>
<br />
<br></br>
<TextField
style={{ width: 200 }}
size="small"
type="text"
label="Bottom text"
variant="outlined"
value={bottomText}
onChange={(e) => setBottomText(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setBottomTextPosX(bottomTextPosX - 10)}
>
<ArrowBackIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position X"
value={bottomTextPosX}
onChange={(e) => setBottomTextPosX(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setBottomTextPosX(bottomTextPosX + 10)}
>
<ArrowForwardIcon />
</IconButton>
<IconButton
size="large"
variant="contained"
onClick={(e) => setBottomTextPosY(bottomTextPosY - 10)}
>
<ArrowUpwardIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position Y"
value={bottomTextPosY}
onChange={(e) => setBottomTextPosY(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setBottomTextPosY(bottomTextPosY + 10)}
>
<ArrowDownwardIcon />
</IconButton>
<br />
<br></br>
<TextField
style={{ width: 200 }}
size="small"
type="text"
label="Additional Text A"
variant="outlined"
value={additionalTextA}
onChange={(e) => setAdditionalTextA(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setAdditionalTextAPosX(additionalTextAPosX - 10)}
>
<ArrowBackIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position X"
value={additionalTextAPosX}
onChange={(e) => setAdditionalTextAPosX(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setAdditionalTextAPosX(additionalTextAPosX + 10)}
>
<ArrowForwardIcon />
</IconButton>
<IconButton
size="large"
variant="contained"
onClick={(e) => setAdditionalTextAPosY(additionalTextAPosY - 10)}
>
<ArrowUpwardIcon />
</IconButton>
<TextField
style={{ width: 80 }}
size="small"
type="text"
variant="outlined"
label="Position Y"
value={additionalTextAPosY}
onChange={(e) => setAdditionalTextAPosY(e.target.value)}
/>
<IconButton
size="large"
variant="contained"
onClick={(e) => setAdditionalTextAPosY(additionalTextAPosY + 10)}
>
<ArrowDownwardIcon />
</IconButton>
</div>
<br></br>
<div>
<Button
size="small"
variant="outlined"
color="black"
onClick={changeFontColorBlack}
>
Font: Black
</Button>
<Button size="small" variant="outlined" onClick={changeFontColorWhite}>
Font: White
</Button>
<Button size="small" variant="outlined" onClick={changeFontItalic}>
Font: Italic
</Button>
<Button size="small" variant="outlined" onClick={changeFontBold}>
Font: Bold
</Button>
<Button size="small" variant="outlined" onClick={changeFontStyle}>
Bigger Font
</Button>
</div>
<br></br>
<div>
<Button
variant="contained"
color="primary"
onClick={saveMemeFromEditorToDB}
disabled={!image && true}
>
SAVE MEME
</Button>
<Button
variant="contained"
color="primary"
onClick={downloadMeme}
disabled={!image && true}
>
DOWNLOAD
</Button>
</div>
<div>
<FacebookShareButton url={memeToEdit}>
<FacebookIcon size={32} round />
</FacebookShareButton>
<TwitterShareButton url={memeToEdit}>
<TwitterIcon size={32} round />
</TwitterShareButton>
<EmailShareButton url={memeToEdit}>
<EmailIcon size={32} round />
</EmailShareButton>
</div>
</div>
);
};
export default Editor;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。