LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

Siriみたいなボタン

Posted at

作ってみた

まぁ実物は3Dでもっときれいなんだけど、2Dで頑張ってみた
クリックでギュイーンなります

See the Pen Siriみたいなボタン by serna37 (@serna37) on CodePen.

ソース紹介

htmlとcssはほぼ何もやってないので、jsだけ紹介します
長いので、部分ごとに分けて紹介

描画のための設定

  • 非同期でスリープ処理
スリープ.js
function sleep(ms) {
    return new Promise(r => setTimeout(r, ms))
}
  • アニメーション描画用関数(setIntervalより軽い)
アニメーション描画.js
function setAnimationFrame(func, interval) {
    let elapsed = 0,
        time = Date.now(),
        quit = false,
        stop = false

    const update = () => {
        let delta = Date.now() - time
        time = Date.now()
        elapsed += delta
        if (elapsed >= interval) {
            elapsed -= ~~(elapsed)
            if (!stop) func()
        }
        if (!quit) requestAnimationFrame(update)
    }

    //処理中にエラーが発生した場合、強制終了
    try {
        update()
    } catch (e) {
        quit = true
        console.error(e)
        console.trace()
    }

    return {
        // 終了
        quit: () => quit = true,
        // 一時停止
        stop: () => stop = true,
        // 再スタート
        restart: () => stop = false
    }
}

各図形のプロパティを設定

  • 下地、原点、色
下地、原点、色.js
const siri = document.createElement('canvas')
siri.width = $('html').width()
siri.height = $('html').height()
$('body').append(siri)

const origin = { x: siri.width / 2, y: siri.height / 1.1 }

// RGBグラデーション変化
function gradRGB(cR, cG, cB, cRMin, cGMin, cBMin, dcR, dcG, dcB) {
    // 変化中
    if (!(cRMin === cR && cGMin === cG && cBMin === cB)) return { dcR: dcR, dcG: dcG, dcB: dcB }
    // 赤終了→緑開始
    if (dcG === 0 && dcB === 0) return { dcR: 0, dcG: dcR, dcB: dcB }
    // 緑終了→青開始
    if (dcR === 0 && dcB === 0) return { dcR: dcR, dcG: 0, dcB: dcG }
    // 青終了→赤開始
    if (dcR === 0 && dcG === 0) return { dcR: dcB, dcG: dcG, dcB: 0 }
}
円.js
const pCircle1 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    r: 120, dr: 0.4, rMax: 150, rMin: 120,
    updR: () => {
        let me = pCircle1
        if ((me.rMax <= me.r && me.dr > 0) || (me.rMin >= me.r && me.dr < 0)) me.dr *= -1
        me.r += me.dr
    },
    // 色
    cR: 200, dcR: 3, cRMax: 200, cRMin: 100,
    cG: 100, dcG: 0, cGMax: 200, cGMin: 100,
    cB: 100, dcB: 0, cBMax: 200, cBMin: 100,
    updC: () => {
        let me = pCircle1
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pCircle1
        let asis = me.rMax
        me.rMax *= ratio
        me.dr *= speed
        if (me.dr < 0) me.dr *= -1
    }
}
  • 楕円
楕円.js
const pEllipse1 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    rx: 40, ry: 90,
    drx: 0.1, dry: 0.2,
    rxMax: 65, rxMin: 35,
    ryMax: 110, ryMin: 80,
    updR: () => {
        let me = pEllipse1
        if ((me.rxMax <= me.rx && me.drx > 0) || (me.rxMin >= me.rx && me.drx < 0)) me.drx *= -1
        if ((me.ryMax <= me.ry && me.dry > 0) || (me.ryMin >= me.ry && me.dry < 0)) me.dry *= -1
        me.rx += me.drx
        me.ry += me.dry
    },
    // 回転角
    rad: -Math.PI / 36, drad: -Math.PI / 36,
    updRad: () => {
        let me = pEllipse1
        me.rad += me.drad
    },
    // 色
    cR: 200, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 50, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 50, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pEllipse1
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pEllipse1
        me.rxMax *= ratio
        me.ryMax *= ratio
        me.drx *= speed
        me.dry *= speed
        me.drad *= speed
        if (me.drx < 0) me.drx *= -1
        if (me.dry < 0) me.dry *= -1
    }
}

描画を実行する

  • 実行
描く.js
const ctx = siri.getContext('2d')
const circles = Array.of(pCircle1, pCircle2)
const ellipses = Array.of(pEllipse1, pEllipse2, pEllipse3, pEllipse4)
const figures = Array.of(pCircle1, pCircle2, pEllipse1, pEllipse2, pEllipse3, pEllipse4)

// グラデーション
function gradient(ctx, x0, y0, r, cr, cg, cb) {
    ctx.globalCompositeOperation = 'lighter'
    let g = ctx.createRadialGradient(x0, y0, 0, x0, y0, r)
    g.addColorStop(0.0, `rgb(${cr}, ${cg}, ${cb}, 1)`)
    g.addColorStop(0.5, `rgb(${cr}, ${cg}, ${cb}, 0.6)`)
    g.addColorStop(1.0, `rgb(${cr}, ${cg}, ${cb}, 0.2)`)
    ctx.fillStyle = g
}

// 円描画
function dCircle(prof) {
    ctx.beginPath()
    ctx.arc(prof.x0, prof.y0, prof.r, 0, 2 * Math.PI)
    gradient(ctx, prof.x0, prof.y0, prof.r, prof.cR, prof.cG, prof.cB)
    ctx.fill()
    ctx.closePath()
    prof.updR()
    prof.updC()
}

// 楕円描画
function dEllipse(prof) {
    ctx.beginPath()
    ctx.ellipse(prof.x0, prof.y0, prof.rx, prof.ry, prof.rad, 0, 2 * Math.PI)
    gradient(ctx, prof.x0, prof.y0, prof.rx, prof.cR, prof.cG, prof.cB)
    ctx.fill()
    ctx.closePath()
    prof.updR()
    prof.updRad()
    prof.updC()
}

// フレーム単位描画
function drawFrame() {
    ctx.clearRect(0, 0, siri.width, siri.height)
    circles.forEach(dCircle)
    ellipses.forEach(dEllipse)
}

// 実際の描画
const { quit, stop, restart } = setAnimationFrame(drawFrame, 10)

当たり判定

  • クリック
タッチイベントを設定.js
// クリック↔原点のユークリッド距離と半径で、当たり判定
function isHit(e) {
    let rect = e.target.getBoundingClientRect(),
        x = e.clientX - rect.left,
        y = e.clientY - rect.top,
        distance = Math.sqrt(Math.pow(origin.x - x, 2) + Math.pow(origin.y - y, 2))
    return distance < pCircle1.r
}

// 拡大
function expand(ratio, speed) {
    figures.forEach(v => v.exp(ratio, speed))
    return () => figures.forEach(v => v.exp(1 / ratio, 1 / speed))
}

// ボタン押下時
siri.onclick = async e => {
    if (!isHit(e)) return
    let undo = expand(1.3, 4)
    reveal()
    await sleep(1000)
    undo()
}

js全量

.js
function sleep(ms) {
    return new Promise(r => setTimeout(r, ms))
}

function setAnimationFrame(func, interval) {
    let elapsed = 0,
        time = Date.now(),
        quit = false,
        stop = false

    const update = () => {
        let delta = Date.now() - time
        time = Date.now()
        elapsed += delta
        if (elapsed >= interval) {
            elapsed -= ~~(elapsed)
            if (!stop) func()
        }
        if (!quit) requestAnimationFrame(update)
    }

    //処理中にエラーが発生した場合、強制終了
    try {
        update()
    } catch (e) {
        quit = true
        console.error(e)
        console.trace()
    }

    return {
        // 終了
        quit: () => quit = true,
        // 一時停止
        stop: () => stop = true,
        // 再スタート
        restart: () => stop = false
    }
}

// ========================================
// 図形の設定
// ========================================
const siri = document.createElement('canvas')
siri.width = $('body').width()
siri.height = $('body').height()
$('body').append(siri)

const origin = { x: siri.width / 2, y: siri.height / 2 }

// RGBグラデーション変化
function gradRGB(cR, cG, cB, cRMin, cGMin, cBMin, dcR, dcG, dcB) {
    // 変化中
    if (!(cRMin === cR && cGMin === cG && cBMin === cB)) return { dcR: dcR, dcG: dcG, dcB: dcB }
    // 赤終了→緑開始
    if (dcG === 0 && dcB === 0) return { dcR: 0, dcG: dcR, dcB: dcB }
    // 緑終了→青開始
    if (dcR === 0 && dcB === 0) return { dcR: dcR, dcG: 0, dcB: dcG }
    // 青終了→赤開始
    if (dcR === 0 && dcG === 0) return { dcR: dcB, dcG: dcG, dcB: 0 }
}

// 円1
const pCircle1 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    r: 120, dr: 0.4, rMax: 150, rMin: 120,
    updR: () => {
        let me = pCircle1
        if ((me.rMax <= me.r && me.dr > 0) || (me.rMin >= me.r && me.dr < 0)) me.dr *= -1
        me.r += me.dr
    },
    // 色
    cR: 200, dcR: 3, cRMax: 200, cRMin: 100,
    cG: 100, dcG: 0, cGMax: 200, cGMin: 100,
    cB: 100, dcB: 0, cBMax: 200, cBMin: 100,
    updC: () => {
        let me = pCircle1
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pCircle1
        let asis = me.rMax
        me.rMax *= ratio
        me.dr *= speed
        if (me.dr < 0) me.dr *= -1
    }
}

// 円2
const pCircle2 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    r: 100, dr: 0.4, rMax: 130, rMin: 100,
    updR: () => {
        let me = pCircle2
        if ((me.rMax <= me.r && me.dr > 0) || (me.rMin >= me.r && me.dr < 0)) me.dr *= -1
        me.r += me.dr
    },
    // 色
    cR: 200, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 50, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 50, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pCircle2
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pCircle2
        let asis = me.rMax
        me.rMax *= ratio
        me.dr *= speed
        if (me.dr < 0) me.dr *= -1
    }
}

// 楕円1
const pEllipse1 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    rx: 40, ry: 90,
    drx: 0.1, dry: 0.2,
    rxMax: 65, rxMin: 35,
    ryMax: 110, ryMin: 80,
    updR: () => {
        let me = pEllipse1
        if ((me.rxMax <= me.rx && me.drx > 0) || (me.rxMin >= me.rx && me.drx < 0)) me.drx *= -1
        if ((me.ryMax <= me.ry && me.dry > 0) || (me.ryMin >= me.ry && me.dry < 0)) me.dry *= -1
        me.rx += me.drx
        me.ry += me.dry
    },
    // 回転角
    rad: -Math.PI / 36, drad: -Math.PI / 36,
    updRad: () => {
        let me = pEllipse1
        me.rad += me.drad
    },
    // 色
    cR: 200, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 50, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 50, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pEllipse1
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pEllipse1
        me.rxMax *= ratio
        me.ryMax *= ratio
        me.drx *= speed
        me.dry *= speed
        me.drad *= speed
        if (me.drx < 0) me.drx *= -1
        if (me.dry < 0) me.dry *= -1
    }
}

// 楕円2
const pEllipse2 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    rx: 40, ry: 80,
    drx: 0.2, dry: 0.3,
    rxMax: 60, rxMin: 30,
    ryMax: 100, ryMin: 70,
    updR: () => {
        let me = pEllipse2
        if ((me.rxMax <= me.rx && me.drx > 0) || (me.rxMin >= me.rx && me.drx < 0)) me.drx *= -1
        if ((me.ryMax <= me.ry && me.dry > 0) || (me.ryMin >= me.ry && me.dry < 0)) me.dry *= -1
        me.rx += me.drx
        me.ry += me.dry
    },
    // 回転角
    rad: Math.PI / 72, drad: Math.PI / 72,
    updRad: () => {
        let me = pEllipse2
        me.rad += me.drad
    },
    // 色
    cR: 50, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 200, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 50, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pEllipse2
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pEllipse2
        me.rxMax *= ratio
        me.ryMax *= ratio
        me.drx *= speed
        me.dry *= speed
        me.drad *= speed
        if (me.drx < 0) me.drx *= -1
        if (me.dry < 0) me.dry *= -1
    }
}

// 楕円3
const pEllipse3 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    rx: 60, ry: 80,
    drx: 0.2, dry: 0.3,
    rxMax: 70, rxMin: 40,
    ryMax: 110, ryMin: 70,
    updR: () => {
        let me = pEllipse3
        if ((me.rxMax <= me.rx && me.drx > 0) || (me.rxMin >= me.rx && me.drx < 0)) me.drx *= -1
        if ((me.ryMax <= me.ry && me.dry > 0) || (me.ryMin >= me.ry && me.dry < 0)) me.dry *= -1
        me.rx += me.drx
        me.ry += me.dry
    },
    // 回転角
    rad: -Math.PI / 72, drad: -Math.PI / 72,
    updRad: () => {
        let me = pEllipse3
        me.rad += me.drad
    },
    // 色
    cR: 50, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 50, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 200, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pEllipse3
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pEllipse3
        me.rxMax *= ratio
        me.ryMax *= ratio
        me.drx *= speed
        me.dry *= speed
        me.drad *= speed
        if (me.drx < 0) me.drx *= -1
        if (me.dry < 0) me.dry *= -1
    }
}

// 楕円4
const pEllipse4 = {
    // 原点
    x0: origin.x, y0: origin.y,
    // 半径
    rx: 50, ry: 100,
    drx: 0.1, dry: 0.2,
    rxMax: 70, rxMin: 30,
    ryMax: 120, ryMin: 90,
    updR: () => {
        let me = pEllipse4
        if ((me.rxMax <= me.rx && me.drx > 0) || (me.rxMin >= me.rx && me.drx < 0)) me.drx *= -1
        if ((me.ryMax <= me.ry && me.dry > 0) || (me.ryMin >= me.ry && me.dry < 0)) me.dry *= -1
        me.rx += me.drx
        me.ry += me.dry
    },
    // 回転角
    rad: Math.PI / 144, drad: Math.PI / 144,
    updRad: () => {
        let me = pEllipse4
        me.rad += me.drad
    },
    // 色
    cR: 50, dcR: 3, cRMax: 200, cRMin: 50,
    cG: 50, dcG: 0, cGMax: 200, cGMin: 50,
    cB: 200, dcB: 0, cBMax: 200, cBMin: 50,
    updC: () => {
        let me = pEllipse4
        if (me.cRMax <= me.cR || me.cRMin >= me.cR) me.dcR *= -1
        if (me.cGMax <= me.cG || me.cGMin >= me.cG) me.dcG *= -1
        if (me.cBMax <= me.cB || me.cBMin >= me.cB) me.dcB *= -1
        let { dcR, dcG, dcB } = gradRGB(me.cR, me.cB, me.cG,
            me.cRMin, me.cGMin, me.cBMin, me.dcR, me.dcG, me.dcB)
        me.dcR = dcR
        me.dcG = dcG
        me.dcB = dcB
        me.cR += me.dcR
        me.cG += me.dcG
        me.cB += me.dcB
    },
    exp: (ratio, speed) => {
        let me = pEllipse4
        me.rxMax *= ratio
        me.ryMax *= ratio
        me.drx *= speed
        me.dry *= speed
        me.drad *= speed
        if (me.drx < 0) me.drx *= -1
        if (me.dry < 0) me.dry *= -1
    }
}

// ====================
// siri設定
// ====================

// def
const ctx = siri.getContext('2d')
const circles = Array.of(pCircle1, pCircle2)
const ellipses = Array.of(pEllipse1, pEllipse2, pEllipse3, pEllipse4)
const figures = Array.of(pCircle1, pCircle2, pEllipse1, pEllipse2, pEllipse3, pEllipse4)

// グラデーション
function gradient(ctx, x0, y0, r, cr, cg, cb) {
    ctx.globalCompositeOperation = 'lighter'
    let g = ctx.createRadialGradient(x0, y0, 0, x0, y0, r)
    g.addColorStop(0.0, `rgb(${cr}, ${cg}, ${cb}, 1)`)
    g.addColorStop(0.5, `rgb(${cr}, ${cg}, ${cb}, 0.6)`)
    g.addColorStop(1.0, `rgb(${cr}, ${cg}, ${cb}, 0.2)`)
    ctx.fillStyle = g
}

// 円描画
function dCircle(prof) {
    ctx.beginPath()
    ctx.arc(prof.x0, prof.y0, prof.r, 0, 2 * Math.PI)
    gradient(ctx, prof.x0, prof.y0, prof.r, prof.cR, prof.cG, prof.cB)
    ctx.fill()
    ctx.closePath()
    prof.updR()
    prof.updC()
}

// 楕円描画
function dEllipse(prof) {
    ctx.beginPath()
    ctx.ellipse(prof.x0, prof.y0, prof.rx, prof.ry, prof.rad, 0, 2 * Math.PI)
    gradient(ctx, prof.x0, prof.y0, prof.rx, prof.cR, prof.cG, prof.cB)
    ctx.fill()
    ctx.closePath()
    prof.updR()
    prof.updRad()
    prof.updC()
}

// フレーム単位描画
function drawFrame() {
    ctx.clearRect(0, 0, siri.width, siri.height)
    circles.forEach(dCircle)
    ellipses.forEach(dEllipse)
}

// ====================
// siri押下イベント
// ====================

// クリック↔原点のユークリッド距離と半径で、当たり判定
function isHit(e) {
    let rect = e.target.getBoundingClientRect(),
        x = e.clientX - rect.left,
        y = e.clientY - rect.top,
        distance = Math.sqrt(Math.pow(origin.x - x, 2) + Math.pow(origin.y - y, 2))
    return distance < pCircle1.r
}

// 拡大
function expand(ratio, speed) {
    figures.forEach(v => v.exp(ratio, speed))
    return () => figures.forEach(v => v.exp(1 / ratio, 1 / speed))
}

// ボタン押下時
siri.onclick = async e => {
    if (!isHit(e)) return
    let undo = expand(1.3, 4)
    console.log('open')
    await sleep(1000)
    undo()
}

// ====================
// 初期表示
// ====================

async function initiate() {
    let inicr1 = circles[0].r, inicr2 = circles[1].r
    circles.forEach(v => v.r = 0)
    ellipses.forEach(v => {
        v.rx = 0
        v.ry = 0
    })
    let undo = expand(1, 12)
    await sleep(200)
    undo()
    undo = expand(1, 10)
    await sleep(200)
    undo()
    undo = expand(1, 7)
    await sleep(100)
    undo()
    undo = expand(1, 4)
    await sleep(100)
    undo()
    undo = expand(1, 2)
    await sleep(100)
    undo()
    circles[0].r = inicr1
    circles[1].r = inicr2
}

// 連続描画
const { quit, stop, restart } = setAnimationFrame(drawFrame, 10)
initiate()

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up