skyderby/skyderby

View on GitHub
app/javascript/components/Events/PerformanceCompetition/Show/Replay/RoundReplay/Player/CompetitorCards/utils.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import { differenceInMilliseconds, differenceInSeconds } from 'date-fns'
import colors from 'utils/colors'
import { ProfileRecord } from 'api/profiles'
import { PlayerPoint } from '../types'

const boxHeight = 250
const boxWidth = 759

function drawSpeedometer(
  ctx: CanvasRenderingContext2D,
  textX: number,
  textY: number,
  point: { vSpeed: number }
) {
  const speedometerX = textX + 600
  const speedometerY = textY + 60
  const textMargin = 10

  ctx.save()

  ctx.beginPath()
  ctx.strokeStyle = '#ddd'
  ctx.lineWidth = 30
  ctx.lineCap = 'butt'
  ctx.arc(speedometerX, speedometerY, 50, Math.PI / 2, Math.PI * 2)
  ctx.stroke()
  ctx.closePath()

  const angle = Math.max(0, ((Math.PI * 1.5) / 200) * Math.min(200, point.vSpeed))

  const gradient = ctx.createLinearGradient(
    speedometerX - 50,
    speedometerY + 50,
    speedometerX + 50,
    speedometerY - 50
  )
  gradient.addColorStop(0, '#0f0')
  gradient.addColorStop(0.4, '#ff0')
  gradient.addColorStop(0.6, '#ff0')
  gradient.addColorStop(0.8, '#f00')
  gradient.addColorStop(1.0, '#f00')

  ctx.beginPath()
  ctx.strokeStyle = gradient
  ctx.arc(speedometerX, speedometerY, 50, Math.PI / 2, Math.PI / 2 + angle)
  ctx.stroke()
  ctx.closePath()

  ctx.strokeStyle

  ctx.textBaseline = 'top'
  ctx.font = '50px Arial'
  ctx.fillText(String(point.vSpeed), speedometerX + textMargin, speedometerY + textMargin)

  ctx.restore()
}

export const updateCardNumbers = (ctx: CanvasRenderingContext2D, point: PlayerPoint) => {
  const value = point.taskResult
  const textX = 40
  const textY = 100

  ctx.save()
  ctx.fillStyle = 'white'
  ctx.fillRect(textX - 20, textY - 10, 750, 160)

  ctx.fillStyle = '#555'

  drawSpeedometer(ctx, textX, textY, point)

  ctx.font = '140px Arial'
  ctx.textBaseline = 'top'
  ctx.fillText(String(value || ''), textX, textY)

  if (differenceInMilliseconds(point.gpsTime, point.endTime) > 200) {
    const timeDiff = differenceInSeconds(point.gpsTime, point.endTime)
    const blur = Math.max(0, 5 - timeDiff * 10)
    if (blur > 0) {
      ctx.shadowBlur = blur
      ctx.shadowColor = '#59C3C3'
      ctx.shadowOffsetX = 0
      ctx.shadowOffsetY = 1
      ctx.fillStyle = '#59C3C3'
      ctx.fillText(String(value || ''), textX, textY)
    }
  }

  ctx.restore()
}

export const drawCard = (
  ctx: CanvasRenderingContext2D,
  el: { profile: ProfileRecord },
  idx = 0
) => {
  const boxX = 0
  const boxY = 0
  const photoRadius = 30
  const photoPadding = 20
  const colorMarkWidth = 20
  const photoX = boxX + photoPadding + colorMarkWidth
  const photoY = boxY + photoPadding
  const arcX = photoX + photoRadius
  const arcY = photoY + photoRadius

  ctx.save()
  ctx.shadowColor = 'rgba(0, 0, 0, 0.14)'
  ctx.shadowBlur = 6
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 3
  ctx.fillStyle = 'white'
  ctx.fillRect(boxX, boxY, boxWidth, boxHeight)
  ctx.restore()

  ctx.save()
  ctx.fillStyle = colors[idx]
  ctx.fillRect(boxX, boxY, colorMarkWidth, boxHeight)
  ctx.restore()

  ctx.save()
  ctx.textBaseline = 'top'
  ctx.font = '40px Arial'
  ctx.fillStyle = '#555'
  ctx.fillText(
    el.profile.name,
    photoX + photoRadius * 2 + photoPadding,
    photoY + photoRadius / 3
  )
  ctx.restore()

  const img = new Image()
  img.src = '/images/thumb/missing.png'
  img.onload = () => {
    ctx.save()
    ctx.beginPath()
    ctx.arc(arcX, arcY, photoRadius, 0, Math.PI * 2, true)
    ctx.clip()
    ctx.drawImage(img, photoX, photoY, photoRadius * 2, photoRadius * 2)
    ctx.closePath()
    ctx.restore()
  }
}