Skip to content

Instantly share code, notes, and snippets.

@davo
Created August 1, 2019 23:46
Show Gist options
  • Save davo/4cedb46b171a5545f90c6a1e67a8fa77 to your computer and use it in GitHub Desktop.
Save davo/4cedb46b171a5545f90c6a1e67a8fa77 to your computer and use it in GitHub Desktop.

Revisions

  1. davo created this gist Aug 1, 2019.
    348 changes: 348 additions & 0 deletions ScratchCard.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,348 @@
    // 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;