import React, { Component } from 'react' import { Link } from 'react-router-dom' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import toBlob from 'data-uri-to-blob' import { clamp } from '../../../util' import { Loader } from '../../../common' const defaultState = { dragging: false, draggingBox: false, bounds: null, mouseX: 0, mouseY: 0, box: { x: 0, y: 0, w: 0, h: 0, } } class ImageSelection extends Component { state = { ...defaultState } constructor() { super() // bind these events in the constructor, so we can remove event listeners later this.handleMouseDown = this.handleMouseDown.bind(this) this.handleMouseDownOnBox = this.handleMouseDownOnBox.bind(this) this.handleMouseMove = this.handleMouseMove.bind(this) this.handleMouseUp = this.handleMouseUp.bind(this) this.handleWindowResize = this.handleWindowResize.bind(this) } componentDidMount() { document.body.addEventListener('mousemove', this.handleMouseMove) document.body.addEventListener('mouseup', this.handleMouseUp) window.addEventListener('resize', this.handleWindowResize) } componentDidUpdate(prevProps) { if (this.state.bounds && this.props.url !== prevProps.url) { this.setState({ ...defaultState, bounds: this.getBoundingClientRect(), box: this.props.crop || defaultState.box, }) } } componentWillUnmount() { document.body.removeEventListener('mousemove', this.handleMouseMove) document.body.removeEventListener('mouseup', this.handleMouseUp) window.removeEventListener('resize', this.handleWindowResize) } getBoundingClientRect() { if (!this.imgRef) return null const rect = this.imgRef.getBoundingClientRect() const scrollTop = document.body.scrollTop || document.body.parentNode.scrollTop const scrollLeft = document.body.scrollLeft || document.body.parentNode.scrollLeft const bounds = { top: rect.top + scrollTop, left: rect.left + scrollLeft, width: rect.width, height: rect.height, } return bounds } handleLoad() { const bounds = this.getBoundingClientRect() const box = this.props.crop || defaultState.box this.setState({ bounds, box }) } handleWindowResize() { if (!this.imgRef) return const bounds = this.getBoundingClientRect() this.setState({ bounds }) } handleMouseDown(e) { e.preventDefault() const bounds = this.getBoundingClientRect() const mouseX = e.pageX const mouseY = e.pageY const x = (mouseX - bounds.left) / bounds.width const y = (mouseY - bounds.top) / bounds.height const w = 1 / bounds.width const h = 1 / bounds.height this.setState({ dragging: true, bounds, mouseX, mouseY, box: { x, y, w, h, } }) } handleMouseDownOnBox(e) { const bounds = this.getBoundingClientRect() const mouseX = e.pageX const mouseY = e.pageY this.setState({ draggingBox: true, bounds, mouseX, mouseY, initialBox: { ...this.state.box }, box: { ...this.state.box } }) } handleMouseMove(e) { const { dragging, draggingBox, bounds, mouseX, mouseY, initialBox, box } = this.state if (dragging) { e.preventDefault() let { x, y } = box let dx = (e.pageX - mouseX) / bounds.width let dy = (e.pageY - mouseY) / bounds.height let w = clamp(dx, 0.0, 1.0 - x) let h = clamp(dy, 0.0, 1.0 - y) this.setState({ box: { x, y, w, h, } }) } else if (draggingBox) { e.preventDefault() let { x, y, w, h } = initialBox let dx = (e.pageX - mouseX) / bounds.width let dy = (e.pageY - mouseY) / bounds.height this.setState({ box: { x: clamp(x + dx, 0, 1.0 - w), y: clamp(y + dy, 0, 1.0 - h), w, h, } }) } } handleMouseUp(e) { const { onCrop } = this.props const { dragging, draggingBox, bounds, box } = this.state if (!dragging && !draggingBox) return e.preventDefault() const { x, y, w, h } = box let url = window.location.pathname this.setState({ dragging: false, draggingBox: false, }) if (w < 10 / bounds.width || h < 10 / bounds.height) { this.setState({ box: { ...defaultState.box }}) onCrop({}) } else { // pass the box dimensions up - do the search again onCrop(box) } } render() { const { url } = this.props const { bounds, box } = this.state const { x, y, w, h } = box return (
this.imgRef = ref} onMouseDown={this.handleMouseDown} onLoad={this.handleLoad.bind(this)} crossOrigin='anonymous' /> {!!w &&
}
) } } const boxToFixed = ({ x, y, w, h }) => ({ x: x.toFixed(3), y: y.toFixed(3), w: w.toFixed(3), h: h.toFixed(3), })