import React from 'react' import ReactCrop, { makeAspectCrop } from 'react-image-crop' import RandomImage from './RandomImage' import PhotoCredit from './PhotoCredit' import Input from './Input' import { Link } from './Meta' import { fileToDataURL } from '../lib/util' import ApiContext from './ApiContext' const getCroppedImg = (imageDataURL, pixelCrop) => { const canvas = document.createElement('canvas') canvas.width = pixelCrop.width canvas.height = pixelCrop.height const ctx = canvas.getContext('2d') return new Promise(resolve => { const image = new Image() image.src = imageDataURL image.onload = () => { ctx.drawImage( image, pixelCrop.x, pixelCrop.y, pixelCrop.width, pixelCrop.height, 0, 0, pixelCrop.width, pixelCrop.height ) resolve(canvas.toDataURL('image/jpeg')) } }) } const INITIAL_STATE = { mode: 'file', crop: null, imageAspectRatio: null, pixelCrop: null, photographer: null, dataURL: null } export default class ImagePicker extends React.Component { static contextType = ApiContext constructor(props) { super(props) this.state = INITIAL_STATE this.selectMode = this.selectMode.bind(this) this.handleURLInput = this.handleURLInput.bind(this) this.uploadImage = this.uploadImage.bind(this) this.selectImage = this.selectImage.bind(this) this.removeImage = this.removeImage.bind(this) this.onImageLoaded = this.onImageLoaded.bind(this) this.onCropChange = this.onCropChange.bind(this) this.onDragEnd = this.onDragEnd.bind(this) } static getDerivedStateFromProps(nextProps, state) { if (state.crop) { // update crop for editor container aspect-ratio change return { crop: makeAspectCrop( { ...state.crop, aspect: nextProps.aspectRatio }, state.imageAspectRatio ) } } return null } selectMode(mode) { this.setState({ mode }) } async onDragEnd() { if (this.state.pixelCrop) { const croppedImg = await getCroppedImg(this.state.dataURL, this.state.pixelCrop) this.props.onChange({ backgroundImageSelection: croppedImg }) } } onCropChange(crop, pixelCrop) { this.setState({ crop: { ...crop, aspect: this.props.aspectRatio }, pixelCrop }) } onImageLoaded(image) { const imageAspectRatio = image.width / image.height const initialCrop = { x: 0, y: 0, width: 100, aspect: this.props.aspectRatio } this.setState({ imageAspectRatio, crop: makeAspectCrop(initialCrop, imageAspectRatio) }) } handleImageChange = (url, dataURL, photographer) => { this.setState({ dataURL, photographer }, () => { this.props.onChange({ backgroundImage: url, backgroundImageSelection: null, photographer }) }) } handleURLInput(e) { e.preventDefault() const url = e.target[0].value return this.context .downloadThumbnailImage({ url }) .then(res => res.dataURL) .then(dataURL => this.handleImageChange(url, dataURL)) .catch(err => { if (err.message.indexOf('Network Error') > -1) { this.setState({ error: 'Fetching the image failed. This is probably a CORS-related issue. You can either enable CORS in your browser, or use another image.' }) } }) } async uploadImage(e) { const dataURL = await fileToDataURL(e.target.files[0]) return this.handleImageChange(dataURL, dataURL) } async selectImage(url, { photographer } = {}) { // TODO use React suspense for loading this asset const { dataURL } = await this.context.downloadThumbnailImage({ url }) return this.handleImageChange(url, dataURL, photographer) } removeImage() { this.setState(INITIAL_STATE, () => { this.props.onChange({ backgroundImage: null, backgroundImageSelection: null }) }) } render() { let content = (
Upload a background image: {this.state.mode === 'file' ? ( ) : (
)} {this.state.error && {this.state.error}}

Or use a random Unsplash image:
) if (this.state.dataURL) { content = (
Background image
{this.state.photographer && }
) } return (
{content}
) } }