149 lines
5.5 KiB
Vue
149 lines
5.5 KiB
Vue
|
|
<template>
|
||
|
|
<div class="canvas-wrap">
|
||
|
|
<canvas id="lineCanvas" width="400" height="500"></canvas>
|
||
|
|
<canvas id="carCanvas" width="400" height="500"></canvas>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import Easing from '@config/Easing.js'
|
||
|
|
export default {
|
||
|
|
data () {
|
||
|
|
return {
|
||
|
|
keyPoints: [{x: 160, y: 200}, {x: 60, y: 200}, {x: 60, y: 400}, {x: 160, y: 400}]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
mounted () {
|
||
|
|
setTimeout(() => {
|
||
|
|
this.handleCanvasLine()
|
||
|
|
}, 5000)
|
||
|
|
setTimeout(() => {
|
||
|
|
this.handleCanvasCar()
|
||
|
|
}, 5900)
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
handleCanvasLine () {
|
||
|
|
const canvas = document.querySelector('#lineCanvas')
|
||
|
|
const ctx = canvas.getContext('2d')
|
||
|
|
let img = new Image()
|
||
|
|
img.src = require('../images/che.png')
|
||
|
|
// 设置线条样式
|
||
|
|
ctx.lineWidth = 1
|
||
|
|
ctx.lineJoin = 'round'
|
||
|
|
ctx.lineCap = 'round'
|
||
|
|
let prevX = this.keyPoints[0].x
|
||
|
|
let prevY = this.keyPoints[0].y
|
||
|
|
let nextX
|
||
|
|
let nextY
|
||
|
|
// 第一帧执行的时间
|
||
|
|
let startTime
|
||
|
|
// 期望动画持续的时间
|
||
|
|
const duration = 900
|
||
|
|
// 动画被切分成若干段,每一段所占总进度的比例
|
||
|
|
const partProportion = 1 / (this.keyPoints.length - 1)
|
||
|
|
// 缓存绘制第n段线段的n值,为了在进行下一段绘制前把这一段线段的末尾补齐
|
||
|
|
let lineIndexCache = 1
|
||
|
|
// 动画帧绘制方法currentTime是requestAnimation执行回调方法step时会传入的一个执行时的时间(由performance.now()获得).
|
||
|
|
const step = (currentTime) => {
|
||
|
|
// 第一帧绘制时记录下开始的时间
|
||
|
|
!startTime && (startTime = currentTime)
|
||
|
|
// 已经过去的时间(ms)
|
||
|
|
const timeElapsed = currentTime - startTime
|
||
|
|
// 动画执行的进度 {0,1}
|
||
|
|
let progress = Math.min(timeElapsed / duration, 1)
|
||
|
|
// 加入二次方缓动函数
|
||
|
|
progress = Easing.Quadratic.In(progress)
|
||
|
|
// 描述当前所绘制的是第几段线段
|
||
|
|
const lineIndex = Math.min(Math.floor(progress / partProportion) + 1, this.keyPoints.length - 1)
|
||
|
|
// 当前线段的进度 {0,1}
|
||
|
|
const partProgress = (progress - (lineIndex - 1) * partProportion) / partProportion
|
||
|
|
// 绘制方法
|
||
|
|
const draw = () => {
|
||
|
|
ctx.strokeStyle = `rgba(${81 + 175 * Math.abs(1 - progress * 2)}, ${160 - 160 * Math.abs(progress * 2 - 1)}, ${255},${1})`
|
||
|
|
ctx.beginPath()
|
||
|
|
ctx.moveTo(prevX, prevY)
|
||
|
|
// 当绘制下一段线段前,把上一段末尾缺失的部分补齐
|
||
|
|
if (lineIndex !== lineIndexCache) {
|
||
|
|
ctx.lineTo(this.keyPoints[lineIndex - 1].x, this.keyPoints[lineIndex - 1].y)
|
||
|
|
lineIndexCache = lineIndex
|
||
|
|
}
|
||
|
|
prevX = nextX = ~~(this.keyPoints[lineIndex - 1].x + ((this.keyPoints[lineIndex]).x - this.keyPoints[lineIndex - 1].x) * partProgress)
|
||
|
|
prevY = nextY = ~~(this.keyPoints[lineIndex - 1].y + ((this.keyPoints[lineIndex]).y - this.keyPoints[lineIndex - 1].y) * partProgress)
|
||
|
|
ctx.lineTo(nextX, nextY)
|
||
|
|
ctx.stroke()
|
||
|
|
}
|
||
|
|
draw()
|
||
|
|
if (progress < 1) {
|
||
|
|
requestAnimationFrame(step)
|
||
|
|
} else {
|
||
|
|
console.log('动画执行完毕')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
requestAnimationFrame(step)
|
||
|
|
},
|
||
|
|
handleCanvasCar () {
|
||
|
|
const canvas = document.querySelector('#carCanvas')
|
||
|
|
const ctx = canvas.getContext('2d')
|
||
|
|
let img = new Image()
|
||
|
|
img.src = require('../images/che.png')
|
||
|
|
let nextX
|
||
|
|
let nextY
|
||
|
|
// 第一帧执行的时间
|
||
|
|
let startTime
|
||
|
|
// 期望动画持续的时间
|
||
|
|
const duration = 2000
|
||
|
|
// 动画被切分成若干段,每一段所占总进度的比例
|
||
|
|
const partProportion = 1 / (this.keyPoints.length - 1)
|
||
|
|
// 缓存绘制第n段线段的n值,为了在进行下一段绘制前把这一段线段的末尾补齐
|
||
|
|
// 动画帧绘制方法currentTime是requestAnimation执行回调方法step时会传入的一个执行时的时间(由performance.now()获得).
|
||
|
|
const step = (currentTime) => {
|
||
|
|
// 第一帧绘制时记录下开始的时间
|
||
|
|
!startTime && (startTime = currentTime)
|
||
|
|
// 已经过去的时间(ms)
|
||
|
|
const timeElapsed = currentTime - startTime
|
||
|
|
// 动画执行的进度 {0,1}
|
||
|
|
let progress = Math.min(timeElapsed / duration, 1)
|
||
|
|
// 加入二次方缓动函数
|
||
|
|
progress = Easing.Quadratic.In(progress)
|
||
|
|
// 描述当前所绘制的是第几段线段
|
||
|
|
const lineIndex = Math.min(Math.floor(progress / partProportion) + 1, this.keyPoints.length - 1)
|
||
|
|
// 当前线段的进度 {0,1}
|
||
|
|
const partProgress = (progress - (lineIndex - 1) * partProportion) / partProportion
|
||
|
|
// 绘制方法
|
||
|
|
const draw = () => {
|
||
|
|
ctx.beginPath()
|
||
|
|
ctx.clearRect(0, 0, 400, 500)
|
||
|
|
nextX = ~~(this.keyPoints[lineIndex - 1].x + ((this.keyPoints[lineIndex]).x - this.keyPoints[lineIndex - 1].x) * partProgress)
|
||
|
|
nextY = ~~(this.keyPoints[lineIndex - 1].y + ((this.keyPoints[lineIndex]).y - this.keyPoints[lineIndex - 1].y) * partProgress)
|
||
|
|
ctx.drawImage(img, nextX - 15, nextY - 50, 30, 50)
|
||
|
|
}
|
||
|
|
draw()
|
||
|
|
if (progress < 1) {
|
||
|
|
requestAnimationFrame(step)
|
||
|
|
} else {
|
||
|
|
console.log('动画执行完毕')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
requestAnimationFrame(step)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="stylus" scoped>
|
||
|
|
.canvas-wrap
|
||
|
|
position relative
|
||
|
|
width 100%
|
||
|
|
height 100%
|
||
|
|
#lineCanvas
|
||
|
|
position absolute
|
||
|
|
left 0
|
||
|
|
top 0
|
||
|
|
z-index 10
|
||
|
|
#carCanvas
|
||
|
|
position absolute
|
||
|
|
left 0
|
||
|
|
top 0
|
||
|
|
z-index 11
|
||
|
|
</style>
|