Selected image is not shown on canvas

2019-07-21 13:54发布

问题:

I am developing an app where user will get to choose image from the list of images that are provided. When user clicks on the image from the list, the selected image should be shown on canvas as a background. I am developing this using reactjs, redux and fabricjs.

i dont get selected image when i do this.props.getSelectedImage.image.image so i can update in setCanvasBackground.

image-list.js

class Images extends React.Component {
  renderImages() {
    const { images, selectImage } = this.props;
    return _.map(images, (image, key) =>
      <li key={key}>
        <img
          src={image.image}
          alt={image.id}
          className="responsive-img default-images"
          width="400px"
          onClick={() => selectImage(image)}
        />
      </li>
    );
  }
  render() {
    return (
      <ul className="image-list">
        {this.renderImages()}
      </ul>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    images: state.images
  }
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ selectImage: selectImage }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Images);

actions.js

export function selectImage(image) {
  return {
    type: 'SELECT_IMAGE',
    payload: image
  }
}

reducers.js

const initialState = {
  selectedImage: require('./img/image1.jpg')
};

export function getSelectedImage(state = initialState, action) {
  switch (action.type) {
    case 'SELECT_IMAGE':
      return Object.assign({}, state, { selectedImage: action.payload.image })
    default:
      return state;
  }
}

image-board.js

class ImageBoard extends React.Component {
  constructor() {
    super();
    this.state = {
      canvas: undefined,
      selected: undefined
    };
  }

  componentDidMount() {
    const canvas = new fabric.Canvas('canvas');
    this.setCanvasBackground(this.props.getSelectedImage.selectedImage, canvas);
  }

  setCanvasBackground(image, canvas) {
    canvas.setBackgroundImage(image, function(e) {
    let iw = canvas.backgroundImage.width,
          ih = canvas.backgroundImage.height,
          cw = canvas.getWidth(),
          ch = canvas.getHeight();

    let iar = iw/ih,
      car = cw/ch;

    let nw = cw,
      nh = ch;

    if (iar > car){
      nh = ch;
      nw = nh * iar;
    }
    else if (iar < car){
      nw = cw;
      nh = cw/iar;
    }
    canvas.backgroundImage.width = nw;
    canvas.backgroundImage.height = nh;
    canvas.renderAll();
    }.bind(this));
  }

  render() {
    return(
      <div className="image-board">
         <canvas
           id="canvas"
           className="z-depth-1"
           width={600}
           height={400}
         />
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  console.log('state', state);
  return {
    images: state.images,
    getSelectedImage: state.getSelectedImage
  }
};

export default connect(mapStateToProps)(ImageBoard);

Right now i could show the default image but could not change the background image in canvas when image from list is clicked.However when i put console.log('image selected', this.props.getSelectedImage.image.image);inside render function i get the selected image but could not set this on setBackgroundImage so i can show the selected image on canvas.

How can i do so?

react v15.4.2 has been used

UPDATE

componentDidUpdate() {
    console.log('componentDidUpdate');
    const canvas = new fabric.Canvas('canvas');
    this.setCanvasBackground(this.props.getSelectedImage.selectedImage, canvas);
  }

if i use componentDidUpdate lifecycle method, it works but i get the following result. So many canvas are re-created and i know its because i have created an object of canvas in componentDidUpdate to update the canvas. How can i do this in clear way?

回答1:

I see two potential solutions to this:

  • Delete the old canvas from the DOM (so you will only have the new one):

How to destroy / reload the canvas in html 5?

componentDidUpdate() {
    console.log('componentDidUpdate');
    // Get the old canvas and remove it
    var oldCanvas = document.getElementById('canvas');
    oldCanvas = null;

    // Add your completely new canvas
    const canvas = new fabric.Canvas('canvas');
    this.setCanvasBackground(this.props.getSelectedImage.selectedImage,      canvas);
}
  • Clear the old canvas before redrawing the new one:

Redrawing Canvas in HTML5 using Javascript

To clear the canvas you need to do what was mentioned in the above link. If you are using this approach make sure not to add a new canvas to the page in componentDidUpdate().

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, 500, 500);

The link for the second solution specifically mentions that if you don't clear your canvas the drawn elements will stack.