Spaces:
Sleeping
Sleeping
| import PropTypes from 'prop-types'; | |
| import React from 'react'; | |
| import bindAll from 'lodash.bindall'; | |
| import Box from '../box/box.jsx'; | |
| import styles from './loupe.css'; | |
| const zoomScale = 3; | |
| class LoupeComponent extends React.Component { | |
| constructor (props) { | |
| super(props); | |
| bindAll(this, [ | |
| 'setCanvas' | |
| ]); | |
| } | |
| componentDidUpdate () { | |
| this.draw(); | |
| } | |
| draw () { | |
| const boxSize = 6 / zoomScale; | |
| const boxLineWidth = 1 / zoomScale; | |
| const colorRingWidth = 15 / zoomScale; | |
| const ctx = this.canvas.getContext('2d'); | |
| const {color, data, width, height} = this.props.colorInfo; | |
| this.canvas.width = zoomScale * width; | |
| this.canvas.height = zoomScale * height; | |
| // In order to scale the image data, must draw to a tmp canvas first | |
| const tmpCanvas = document.createElement('canvas'); | |
| tmpCanvas.width = width; | |
| tmpCanvas.height = height; | |
| const tmpCtx = tmpCanvas.getContext('2d'); | |
| const imageData = tmpCtx.createImageData(width, height); | |
| imageData.data.set(data); | |
| tmpCtx.putImageData(imageData, 0, 0); | |
| // Scale the loupe canvas and draw the zoomed image | |
| ctx.save(); | |
| ctx.scale(zoomScale, zoomScale); | |
| ctx.drawImage(tmpCanvas, 0, 0, width, height); | |
| // Draw an outlined square at the cursor position (cursor is hidden) | |
| ctx.lineWidth = boxLineWidth; | |
| ctx.strokeStyle = 'black'; | |
| ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`; | |
| ctx.beginPath(); | |
| ctx.rect((width / 2) - (boxSize / 2), (height / 2) - (boxSize / 2), boxSize, boxSize); | |
| ctx.fill(); | |
| ctx.stroke(); | |
| // Draw a thick ring around the loupe showing the current color | |
| ctx.strokeStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`; | |
| ctx.lineWidth = colorRingWidth; | |
| ctx.beginPath(); | |
| ctx.moveTo(width, height / 2); | |
| ctx.arc(width / 2, height / 2, width / 2, 0, 2 * Math.PI); | |
| ctx.stroke(); | |
| ctx.restore(); | |
| } | |
| setCanvas (element) { | |
| this.canvas = element; | |
| } | |
| render () { | |
| const { | |
| colorInfo, | |
| ...boxProps | |
| } = this.props; | |
| const x = colorInfo.x - ((zoomScale * colorInfo.width) / 2); | |
| const y = colorInfo.y - ((zoomScale * colorInfo.height) / 2); | |
| return ( | |
| <Box | |
| {...boxProps} | |
| className={styles.colorPicker} | |
| componentRef={this.setCanvas} | |
| element="canvas" | |
| height={colorInfo.height} | |
| style={{ | |
| transform: `translate(${x}px, ${y}px)`, | |
| width: colorInfo.width * zoomScale, | |
| height: colorInfo.height * zoomScale | |
| }} | |
| width={colorInfo.width} | |
| /> | |
| ); | |
| } | |
| } | |
| LoupeComponent.propTypes = { | |
| colorInfo: PropTypes.shape({ | |
| color: PropTypes.shape({ | |
| r: PropTypes.number, | |
| g: PropTypes.number, | |
| b: PropTypes.number, | |
| a: PropTypes.number | |
| }), | |
| data: PropTypes.instanceOf(Uint8Array), | |
| width: PropTypes.number, | |
| height: PropTypes.number, | |
| x: PropTypes.number, | |
| y: PropTypes.number | |
| }) | |
| }; | |
| export default LoupeComponent; | |