Created
August 1, 2019 23:46
-
-
Save davo/4cedb46b171a5545f90c6a1e67a8fa77 to your computer and use it in GitHub Desktop.
ScratchCard for Framer X
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WIP Refactored from https://github.com/aleksik/react-scratchcard/ | |
import * as React from 'react' | |
import { Frame, addPropertyControls, ControlType } from 'framer' | |
export function ScratchCard({ width, height, children, image: source, finishPercent }) { | |
const [loaded, setLoaded] = React.useState(false) | |
const [context, setContext] = React.useState(false) | |
const [isDrawing, setIsDrawing] = React.useState(false) | |
const [lastPoint, updateLastPoint] = React.useState(null) | |
const canvasRef = React.useRef(null) | |
React.useLayoutEffect(() => { | |
const ctx = canvasRef.current.getContext('2d') | |
const image = new Image() | |
image.crossOrigin = 'Anonymous' | |
image.onload = () => { | |
ctx.drawImage(image, 0, 0) | |
setLoaded(true) | |
} | |
image.src = 'https://source.unsplash.com/random' | |
console.log(ctx) | |
// const image = new Image() | |
// image.crossOrigin = "Anonymous" | |
// image.onload = () => { | |
// // @ts-ignore | |
// this.ctx.drawImage(image, 0, 0) | |
// this.setState({ loaded: true }) | |
// } | |
// // @ts-ignore | |
// image.src = this.props.image | |
}, []) | |
function getFilledInPixels(stride) { | |
if (!stride || stride < 1) { | |
stride = 1 | |
} | |
const ctx = canvasRef.current.getContext('2d') | |
const pixels = ctx.getImageData(0, 0, canvasRef.current.width, canvasRef.current.height) | |
const total = pixels.data.length / stride | |
let count = 0 | |
for (let i = 0; i < pixels.data.length; i += stride) { | |
if (parseInt(pixels.data[i], 10) === 0) { | |
count++ | |
} | |
} | |
return Math.round((count / total) * 100) | |
} | |
function getMouse(e, canvas) { | |
const { top, left } = canvas.getBoundingClientRect() | |
const scrollTop = window.pageYOffset || document.documentElement.scrollTop | |
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft | |
return { | |
x: (e.pageX || e.touches[0].clientX) - left - scrollLeft, | |
y: (e.pageY || e.touches[0].clientY) - top - scrollTop, | |
} | |
} | |
function distanceBetween(point1, point2) { | |
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)) | |
} | |
function angleBetween(point1, point2) { | |
return Math.atan2(point2.x - point1.x, point2.y - point1.y) | |
} | |
function handlePercentage(filledInPixels = 0) { | |
// @ts-ignore | |
// if (filledInPixels > finishPercent) { | |
// // @ts-ignore | |
// this.canvas.parentNode.removeChild(this.canvas) | |
// this.setState({ finished: true }) | |
// // @ts-ignore | |
// if (this.props.onComplete) { | |
// // @ts-ignore | |
// this.props.onComplete() | |
// } | |
} | |
function handleMouseDown(e) { | |
// @ts-ignore | |
setIsDrawing(true) | |
// @ts-ignore | |
// this.lastPoint = this.getMouse(e, this.canvas) | |
} | |
const canvasProps = { | |
width: width, | |
height: height, | |
// @ts-ignore | |
// ref: ref => (this.canvas = ref), | |
// className: 'ScratchCard__Canvas', | |
// style: canvasStyle, | |
// // @ts-ignore | |
// width: this.props.width, | |
// // @ts-ignore | |
// height: this.props.height, | |
// onMouseDown: this.handleMouseDown.bind(this), | |
// onTouchStart: this.handleMouseDown.bind(this), | |
// onMouseMove: this.handleMouseMove.bind(this), | |
// onTouchMove: this.handleMouseMove.bind(this), | |
// onMouseUp: this.handleMouseUp.bind(this), | |
// onTouchEnd: this.handleMouseUp.bind(this), | |
} | |
return ( | |
<> | |
<div style={{ ...containerStyle, width: width, height: height }}> | |
{/* <Frame image='https://source.unsplash.com/random' width={width} height={height} /> */} | |
<canvas ref={canvasRef} style={canvasStyle} {...canvasProps} /> | |
<div | |
style={{ | |
display: 'flex', | |
alignItems: 'center', | |
justifyContent: 'center', | |
position: 'absolute', | |
width: '100%', | |
height: '100%', | |
color: '#fff', | |
background: '#000', | |
visibility: loaded ? 'visible' : 'hidden', | |
}}> | |
{children} | |
</div> | |
</div> | |
</> | |
) | |
} | |
ScratchCard.defaultProps = { | |
width: 640, | |
height: 480, | |
image: '', | |
finishPercent: 0, | |
onComplete: () => null, | |
} | |
addPropertyControls(ScratchCard, { | |
image: { | |
type: ControlType.Image, | |
title: 'Image', | |
}, | |
}) | |
const containerStyle: React.CSSProperties = { | |
position: 'relative', | |
WebkitUserSelect: 'none', | |
MozUserSelect: 'none', | |
msUserSelect: 'none', | |
userSelect: 'none', | |
} | |
const canvasStyle: React.CSSProperties = { | |
position: 'absolute', | |
top: 0, | |
zIndex: 1, | |
} | |
// const resultStyle: React.CSSProperties = { | |
// visibility: this.state.loaded ? 'visible' : 'hidden', | |
// } | |
// export class ScratchCardClass extends React.Component { | |
// constructor(props) { | |
// super(props) | |
// this.state = { loaded: false } | |
// } | |
// componentDidMount() { | |
// // @ts-ignore | |
// this.isDrawing = false | |
// // @ts-ignore | |
// this.lastPoint = null | |
// // @ts-ignore | |
// this.ctx = this.canvas.getContext("2d") | |
// const image = new Image() | |
// image.crossOrigin = "Anonymous" | |
// image.onload = () => { | |
// // @ts-ignore | |
// this.ctx.drawImage(image, 0, 0) | |
// this.setState({ loaded: true }) | |
// } | |
// // @ts-ignore | |
// image.src = this.props.image | |
// } | |
// getFilledInPixels(stride) { | |
// if (!stride || stride < 1) { | |
// stride = 1 | |
// } | |
// // @ts-ignore | |
// const pixels = this.ctx.getImageData( | |
// 0, | |
// 0, | |
// // @ts-ignore | |
// this.canvas.width, | |
// // @ts-ignore | |
// this.canvas.height | |
// ) | |
// const total = pixels.data.length / stride | |
// let count = 0 | |
// for (let i = 0; i < pixels.data.length; i += stride) { | |
// if (parseInt(pixels.data[i], 10) === 0) { | |
// count++ | |
// } | |
// } | |
// return Math.round((count / total) * 100) | |
// } | |
// getMouse(e, canvas) { | |
// const { top, left } = canvas.getBoundingClientRect() | |
// const scrollTop = | |
// window.pageYOffset || document.documentElement.scrollTop | |
// const scrollLeft = | |
// window.pageXOffset || document.documentElement.scrollLeft | |
// return { | |
// x: (e.pageX || e.touches[0].clientX) - left - scrollLeft, | |
// y: (e.pageY || e.touches[0].clientY) - top - scrollTop, | |
// } | |
// } | |
// distanceBetween(point1, point2) { | |
// return Math.sqrt( | |
// Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2) | |
// ) | |
// } | |
// angleBetween(point1, point2) { | |
// return Math.atan2(point2.x - point1.x, point2.y - point1.y) | |
// } | |
// handlePercentage(filledInPixels = 0) { | |
// // @ts-ignore | |
// if (filledInPixels > this.props.finishPercent) { | |
// // @ts-ignore | |
// this.canvas.parentNode.removeChild(this.canvas) | |
// this.setState({ finished: true }) | |
// // @ts-ignore | |
// if (this.props.onComplete) { | |
// // @ts-ignore | |
// this.props.onComplete() | |
// } | |
// } | |
// } | |
// handleMouseDown(e) { | |
// // @ts-ignore | |
// this.isDrawing = true | |
// // @ts-ignore | |
// this.lastPoint = this.getMouse(e, this.canvas) | |
// } | |
// handleMouseMove(e) { | |
// // @ts-ignore | |
// if (!this.isDrawing) { | |
// return | |
// } | |
// e.preventDefault() | |
// // @ts-ignore | |
// const currentPoint = this.getMouse(e, this.canvas) | |
// // @ts-ignore | |
// const distance = this.distanceBetween(this.lastPoint, currentPoint) | |
// // @ts-ignore | |
// const angle = this.angleBetween(this.lastPoint, currentPoint) | |
// let x, y | |
// for (let i = 0; i < distance; i++) { | |
// // @ts-ignore | |
// x = this.lastPoint.x + Math.sin(angle) * i | |
// // @ts-ignore | |
// y = this.lastPoint.y + Math.cos(angle) * i | |
// // @ts-ignore | |
// this.ctx.globalCompositeOperation = "destination-out" | |
// // @ts-ignore | |
// this.ctx.beginPath() | |
// // @ts-ignore | |
// this.ctx.arc(x, y, 25, 0, 2 * Math.PI, false) | |
// // @ts-ignore | |
// this.ctx.fill() | |
// } | |
// // @ts-ignore | |
// this.lastPoint = currentPoint | |
// this.handlePercentage(this.getFilledInPixels(32)) | |
// } | |
// handleMouseUp() { | |
// // @ts-ignore | |
// this.isDrawing = false | |
// } | |
// render() { | |
// const containerStyle = { | |
// // @ts-ignore | |
// width: this.props.width + "px", | |
// // @ts-ignore | |
// height: this.props.height + "px", | |
// position: "relative", | |
// WebkitUserSelect: "none", | |
// MozUserSelect: "none", | |
// msUserSelect: "none", | |
// userSelect: "none", | |
// } | |
// const canvasStyle = { | |
// position: "absolute", | |
// top: 0, | |
// zIndex: 1, | |
// } | |
// const resultStyle = { | |
// // @ts-ignore | |
// visibility: this.state.loaded ? "visible" : "hidden", | |
// } | |
// const canvasProps = { | |
// // @ts-ignore | |
// ref: ref => (this.canvas = ref), | |
// className: "ScratchCard__Canvas", | |
// style: canvasStyle, | |
// // @ts-ignore | |
// width: this.props.width, | |
// // @ts-ignore | |
// height: this.props.height, | |
// onMouseDown: this.handleMouseDown.bind(this), | |
// onTouchStart: this.handleMouseDown.bind(this), | |
// onMouseMove: this.handleMouseMove.bind(this), | |
// onTouchMove: this.handleMouseMove.bind(this), | |
// onMouseUp: this.handleMouseUp.bind(this), | |
// onTouchEnd: this.handleMouseUp.bind(this), | |
// } | |
// return ( | |
// // @ts-ignore | |
// <div className="ScratchCard__Container" style={containerStyle}> | |
// { | |
// // @ts-ignore | |
// <canvas {...canvasProps}></canvas> | |
// } | |
// { | |
// // @ts-ignore | |
// <div className="ScratchCard__Result" style={resultStyle}> | |
// {this.props.children} | |
// </div> | |
// } | |
// </div> | |
// ) | |
// } | |
// } | |
// // ScratchCard.propTypes = { | |
// // image: React.PropTypes.string.isRequired, | |
// // width: React.PropTypes.number.isRequired, | |
// // height: React.PropTypes.number.isRequired, | |
// // finishPercent: React.PropTypes.number.isRequired, | |
// // onComplete: React.PropTypes.func | |
// // } | |
// // export default ScratchCard; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment