【问题标题】:react-konva How to change image after uploading?react-konva 上传后如何更改图像?
【发布时间】:2018-09-19 01:27:10
【问题描述】:

我正在做一个小项目,允许用户上传图片,然后图片将显示在画布上。

我为此使用react-konva

我有一个名为 DesignPage 的容器组件,它管理状态将事件处理程序传递给它的子级。

在这个 DesignPage 组件中,我还有 2 个其他组件:Tools - Canvas

当我使用 Tools 组件上传图片时,图片应显示在 Canvas 组件上。

我在 Tools 组件中使用react-dropzone 来处理文件上传

在这个Canvas组件内部,有一个名为DesignImage的子组件,它只是用来展示图片的。

但问题是,我上传时它不会改变画布上的图像。

我该如何解决这个问题?

这是我的代码:

DesignPage组件:

import React, {Component} from 'react';
import {
    Row,
    Col
} from 'reactstrap';

import Tools from "../components/DesignPage/Tools";
import Canvas from "../components/DesignPage/Canvas";
import Styles from "../components/DesignPage/Styles";

class DesignPage extends Component {

    state = {
        text: '',
        image: '',
        files: []
    };

    static propTypes = {};

    handleTextChange = e => {
        this.setState({text: e.target.value});
    };

    handleFileDrop = files => {
        this.setState({
            files,
            image: files[0].preview
        });
    };

    render() {
        return <Row>
            <Col xs={12} md={4}>
                <Tools
                    files={this.state.files}
                    onTextChange={this.handleTextChange}
                    onFileDrop={this.handleFileDrop}/>
            </Col>
            <Col xs={12} md={5}>
                <Canvas
                    text={this.state.text}
                    image={this.state.image}/>
            </Col>
            <Col xs={12} md={3}>
                <Styles/>
            </Col>
        </Row>;
    }
}

export default DesignPage;

工具组件:

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
    TabContent,
    TabPane,
    Nav,
    NavItem,
    NavLink,
    Row,
    Col,
    FormGroup,
    Label
} from 'reactstrap';
import classnames from 'classnames';
import Dropzone from 'react-dropzone';

class Tools extends Component {
    state = {
        activeTab: '1'
    };

    toggle = (tab) => {
        if (this.state.activeTab !== tab) {
            this.setState({
                activeTab: tab
            });
        }
    };

    render() {
        return <Row>
            <Col xs={12}>
                <div>
                    <Nav tabs justified>
                        <NavItem>
                            <NavLink
                                className={classnames({active: this.state.activeTab === '1'})}
                                onClick={() => {
                                    this.toggle('1');
                                }}
                            >
                                Text
                            </NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink
                                className={classnames({active: this.state.activeTab === '2'})}
                                onClick={() => {
                                    this.toggle('2');
                                }}
                            >
                                Art
                            </NavLink>
                        </NavItem>
                    </Nav>
                    <TabContent activeTab={this.state.activeTab}>
                        <TabPane tabId="1">
                            <Row>
                                <Col sm="12">
                                    <FormGroup>
                                        <Label for={"custom-text"}>Enter text below</Label>
                                        <textarea
                                            className={"form-control"}
                                            id={"custom-text"}
                                            onChange={this.props.onTextChange}/>
                                    </FormGroup>
                                    <FormGroup>
                                        <Label for={"font-select"}>Choose a font</Label>

                                    </FormGroup>
                                </Col>
                            </Row>
                        </TabPane>
                        <TabPane tabId="2">
                            <Row>
                                <Col sm="12">
                                    <FormGroup>
                                        <div className="dropzone-container">
                                            <Dropzone onDrop={this.props.onFileDrop}>
                                                <p>Drop a design here, or click to select design to upload.</p>
                                            </Dropzone>
                                        </div>
                                    </FormGroup>
                                </Col>
                            </Row>
                        </TabPane>
                    </TabContent>
                </div>
            </Col>
        </Row>;
    }
}

Tools.propTypes = {
    files: PropTypes.array.isRequired,
    onTextChange: PropTypes.func.isRequired,
    onFileDrop: PropTypes.func.isRequired
};

export default Tools;

画布组件:

import React from 'react';
import PropTypes from 'prop-types';
import {
    Row,
    Col
} from 'reactstrap';
import {Stage, Layer} from 'react-konva';

import UserText from "./Canvas/UserText";
import DesignImage from "./Canvas/DesignImage";

const Canvas = props => {
    return <Row>
        <Col xs={12} className={"canvas-container"}>
            <div className={"object-container"}>
                <img className={"object-img"} src={"images/iPhone5A.png"} alt={"iPhone5A"}/>
                <div className="drawing-area">
                    <Stage width={window.innerWidth} height={window.innerHeight}>
                        <Layer>
                            <UserText text={props.text}/>
                            <DesignImage image={props.image}/>
                        </Layer>
                    </Stage>
                </div>
            </div>
        </Col>
    </Row>;
};

Canvas.propTypes = {
    text: PropTypes.string.isRequired,
    image: PropTypes.string.isRequired
};

export default Canvas;

DesignImage组件:

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Image} from 'react-konva';

class DesignImage extends Component {
    state = {
        image: null
    };

    static propTypes = {
        image: PropTypes.string.isRequired
    };

    componentDidMount() {
        const image = new window.Image();
        image.src = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRYTULZCGUVEQJEXt9iB8PU4Kb2FMS9Z6ufR1FnQTdrEl5uBOl52Q';
        image.onload = () => {
            // setState will redraw layer
            // because "image" property is changed
            this.setState({
                image: image
            });
        };
    }

    render() {
        return <Image image={this.props.image} draggable={true}/>;
    }
}

export default DesignImage;

【问题讨论】:

  • 我不明白你的代码。您确实应该发布该问题的最小示例。但是,我在任何地方都没有看到对 stage.draw() 的调用。会这样吗?
  • 嗨@VanquiishedWombat,谢谢。 react-konva的作者已经在下面回答了。

标签: reactjs html5-canvas konvajs


【解决方案1】:

当组件有来自 props 的新图像时,您需要编写代码来更新图像。

class DesignImage extends Component {
  state = {
    image: null
  };

  static propTypes = {
    image: PropTypes.string.isRequired
  };

  componentDidMount() {
    this.updateImage();
  }

  componentDidUpdate() {
    this.updateImage();
  }



  updateImage() {
    const image = new window.Image();
    image.src = this.props.image;
    image.onload = () => {
        this.setState({
            image: image
        });
    };
  }

  render() {
    return <Image image={this.state.image} draggable={true}/>;
  }
}

更新:

您可以使用use-image 挂钩来简化图像加载:

import useImage from 'use-image';

const DesignImage = ({ image }) => {
   const imgElement = useImage(image);
   return <Image image={imgElement} draggable={true}/>;
}

【讨论】:

  • 谢谢@lavrton。这里重要的是componentDidUpdate(y)
  • 你能帮我做一件事吗?如何设置图像适合其容器? prntscr.com/j34u62 容器是 "drawing-area"
  • @lavtron,我如何在 react-knova 中将 blob 设置为图像,就像我在画布中有一个对图像的引用,单击它们时,图像应该根据我从服务器,我的服务器将图像作为 blob 发送到 react 应用程序,所以我正在寻找一种方法将其设置为 this.imageNode.image(blob),这可能吗?
  • @sajanthomas01 var objectURL = URL.createObjectURL(myBlob); 然后使用该 URL 创建图像。
猜你喜欢
  • 1970-01-01
  • 2019-11-08
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
相关资源
最近更新 更多