Repository: moeru-ai/airi
File: apps/stage-web/src/pages/devtools/gesture-circle.vue (Vue)

Code before:
  const anyWindow = window as any
  anyWindow.testCanvasRef = canvasRef
})

const pointThrottled = refThrottled(pointComputed, 50)
const pointDebounced = refDebounced(pointComputed, 50)

const lastPoint = ref<Point>(pointDebounced.value)
const distance = ref(0)
const count = ref(0)
const show = ref(false)

const lastPoints = ref<Point[]>([])
const isCircle = ref(false)

watch([x, y], () => {
  if (!canvasContext.value)
    return

  canvasContext.value.beginPath()
  canvasContext.value.fillStyle = 'red'
  canvasContext.value.arc(x.value, y.value, 4, 0, 2 * Math.PI)
  canvasContext.value.closePath()
  canvasContext.value.fill()
})

watch(pointDebounced, () => {
  if (canvasContext.value) {
    canvasContext.value.reset()
  }

  // Use least squares method to determine if points form a circle
  if (lastPoints.value.length >= 6) {
    // Calculate mean center point
    const meanX = lastPoints.value.reduce((sum, p) => sum + p.x, 0) / lastPoints.value.length
    const meanY = lastPoints.value.reduce((sum, p) => sum + p.y, 0) / lastPoints.value.length

    // Calculate average radius and deviation
    const radii = lastPoints.value.map(p =>
      Math.sqrt((p.x - meanX) ** 2 + (p.y - meanY) ** 2),
    )
    const avgRadius = radii.reduce((sum, r) => sum + r, 0) / radii.length

    // Calculate standard deviation of radii
    const variance = radii.reduce((sum, r) => sum + (r - avgRadius) ** 2, 0) / radii.length
    const stdDev = Math.sqrt(variance)

    // If points roughly form a circle (low standard deviation)
    if (stdDev < 20) {
      count.value++
      isCircle.value = true

Review comment (suggestion):
```suggestion
watch(pointDebounced, () => {
  isCircle.value = false
```

Code after:
  canvasContainerRef.value?.appendChild(canvas)
})

const pointThrottled = refThrottled(pointComputed, 50)
const pointDebounced = refDebounced(pointComputed, 50)

const lastPoint = ref<Point>(pointDebounced.value)
const distance = ref(0)
const count = ref(0)
const show = ref(false)

const lastPoints = ref<Point[]>([])
const isCircle = ref(false)

watch([x, y], () => {
  if (!canvasContext.value)
    return

  canvasContext.value.beginPath()
  canvasContext.value.fillStyle = 'red'
  canvasContext.value.arc(x.value, y.value, 4, 0, 2 * Math.PI)
  canvasContext.value.closePath()
  canvasContext.value.fill()
})

watch(pointDebounced, () => {
  isCircle.value = false
  if (canvasContext.value) {
    canvasContext.value.reset()
  }

  // Use standard deviation of radii to check for circularity to determine if points form a circle
  if (lastPoints.value.length >= minimumDataPoints) {
    // Calculate mean center point
    const meanX = lastPoints.value.reduce((sum, p) => sum + p.x, 0) / lastPoints.value.length
    const meanY = lastPoints.value.reduce((sum, p) => sum + p.y, 0) / lastPoints.value.length

    // Calculate average radius and deviation
    const radii = lastPoints.value.map(p =>
      Math.sqrt((p.x - meanX) ** 2 + (p.y - meanY) ** 2),
    )
    const avgRadius = radii.reduce((sum, r) => sum + r, 0) / radii.length

    // Calculate standard deviation of radii
    const variance = radii.reduce((sum, r) => sum + (r - avgRadius) ** 2, 0) / radii.length
    const stdDev = Math.sqrt(variance)

    // If points roughly form a circle (low standard deviation)
    if (stdDev < 20) {
      count.value++
      isCircle.value = true