snake replaced with canvas

This commit is contained in:
Daniel Shleifman
2021-06-19 02:35:09 +03:00
parent 8d555db847
commit a6f966718c
7 changed files with 121 additions and 101 deletions

View File

@@ -1,55 +1,113 @@
import Measure from 'react-measure'
import { useState, memo } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useState, memo, useRef, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import isEqual from 'lodash/isEqual'
import { useCreateCacheMap } from '../customHooks'
import { gapBetweenPieces, miniCacheMaxHeight, pieceSizeForMiniMap, defaultPieceSize } from './snakeSettings'
import getShortCacheMap from './getShortCacheMap'
import { SnakeWrapper, PercentagePiece, ScrollNotification } from './style'
import { SnakeWrapper, ScrollNotification } from './style'
import {
defaultBorderWidth,
miniCacheMaxHeight,
pieceSizeForMiniMap,
defaultPieceSize,
defaultBackgroundColor,
defaultBorderColor,
completeColor,
activeColor,
rangeColor,
defaultGapBetweenPieces,
miniBackgroundColor,
miniBorderWidth,
miniGapBetweenPieces,
createGradient,
} from './snakeSettings'
const TorrentCache = ({ cache, isMini }) => {
const { t } = useTranslation()
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const { width } = dimensions
const canvasRef = useRef(null)
const ctxRef = useRef(null)
const cacheMap = useCreateCacheMap(cache)
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
const canvasWidth = isMini ? width * 0.93 : width
const pieceSize = isMini ? pieceSizeForMiniMap : defaultPieceSize
const gapBetweenPieces = isMini ? miniGapBetweenPieces : defaultGapBetweenPieces
const pieceSizeWithGap = pieceSize + gapBetweenPieces
const piecesInOneRow = Math.floor(canvasWidth / pieceSizeWithGap)
let piecesInOneRow
let shotCacheMap
if (isMini) {
const pieceSizeWithGap = pieceSize + gapBetweenPieces
piecesInOneRow = Math.floor((dimensions.width * 0.95) / pieceSizeWithGap)
shotCacheMap = isMini && getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
shotCacheMap = getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
}
const source = isMini ? shotCacheMap : cacheMap
const startingXPoint = Math.ceil((canvasWidth - pieceSizeWithGap * piecesInOneRow) / 2) // needed to center grid
const height = Math.ceil(source.length / piecesInOneRow) * pieceSizeWithGap
return isMini ? (
useEffect(() => {
if (!canvasWidth || !height) return
const canvas = canvasRef.current
canvas.width = canvasWidth
canvas.height = height
ctxRef.current = canvas.getContext('2d')
}, [canvasRef, height, canvasWidth])
useEffect(() => {
const ctx = ctxRef.current
if (!ctx) return
ctx.clearRect(0, 0, canvasWidth, height)
source.forEach(({ percentage, isReader, isReaderRange }, i) => {
const inProgress = percentage > 0 && percentage < 100
const isCompleted = percentage === 100
const currentRow = i % piecesInOneRow
const currentColumn = Math.floor(i / piecesInOneRow)
const borderWidth = isMini ? miniBorderWidth : defaultBorderWidth
const fixBlurStroke = borderWidth % 2 === 0 ? 0 : 0.5
const requiredFix = Math.ceil(borderWidth / 2) + 1 + fixBlurStroke
const x = currentRow * pieceSize + currentRow * gapBetweenPieces + startingXPoint + requiredFix
const y = currentColumn * pieceSize + currentColumn * gapBetweenPieces + requiredFix
ctx.lineWidth = borderWidth
ctx.fillStyle = inProgress
? createGradient(ctx, percentage)
: isCompleted
? completeColor
: isMini
? miniBackgroundColor
: defaultBackgroundColor
ctx.strokeStyle = isReader
? activeColor
: inProgress || isCompleted
? completeColor
: isReaderRange
? rangeColor
: defaultBorderColor
ctx.translate(x, y)
ctx.fillRect(0, 0, pieceSize, pieceSize)
ctx.strokeRect(0, 0, pieceSize, pieceSize)
ctx.setTransform(1, 0, 0, 1, 0, 0)
})
}, [cacheMap, height, canvasWidth, piecesInOneRow, isMini, startingXPoint, pieceSize, gapBetweenPieces, source])
return (
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
{({ measureRef }) => (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<SnakeWrapper ref={measureRef} pieceSize={pieceSize} piecesInOneRow={piecesInOneRow}>
{shotCacheMap.map(({ className, id, percentage }) => (
<span key={id || uuidv4()} className={className}>
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
</span>
))}
<div style={{ display: 'flex', flexDirection: 'column' }} ref={measureRef}>
<SnakeWrapper isMini={isMini}>
<canvas ref={canvasRef} />
</SnakeWrapper>
{dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
{isMini && height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
</div>
)}
</Measure>
) : (
<SnakeWrapper pieceSize={pieceSize}>
{cacheMap.map(({ className, id, percentage }) => (
<span key={id || uuidv4()} className={className}>
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
</span>
))}
</SnakeWrapper>
)
}