<template>
<div>
<div class="canvas-container">
<canvas ref="canvas" id="canvas"></canvas>
<ul class="step-wrap">
<li :ref="`step${index}`" v-for="(item,index) in stepBarData" :key="index" :style="cssVars" :class="{'active': index == status}">
<span v-if="status < index" class="number">{{ index + 1 }}</span>
<img v-else src="@/assets/images/step.png" class="image" alt />
<p>{{ item.label }}</p>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: '',
props: {
status: {
type: Number,
default: 5,
},
},
components: {},
data() {
return {
stepBarData: [
{
label: '商户下单',
},
{
label: '客户预约',
},
{
label: '人员调配',
},
{
label: '客户确认',
},
{
label: '上门服务',
},
{
label: '结单确认',
},
{
label: '服务完成',
},
],
}
},
computed: {
cssVars() {
return {
'--normal-color': '#afb0b2',
'--active-color': '#0000ff',
}
},
},
watch: {},
methods: {
drawCanvas(status) {
const canvas = document.getElementById('canvas')
const container = document.getElementsByClassName('canvas-container')[0]
canvas.width = container.clientWidth
const ctx = canvas.getContext('2d')
const fontWidth = 3 * 16
const color = status == 5 || status == 6 ? '#0000ff' : '#afb0b2'
ctx.strokeStyle = color
ctx.lineWidth = 1
const canvasWindowLeft = this.$refs[`canvas`].getBoundingClientRect().left
const canvasWindowTop = this.$refs[`canvas`].getBoundingClientRect().top
const startX = this.$refs[`step${5}`][0].getBoundingClientRect().left - canvasWindowLeft + 10
const startY = this.$refs[`step${5}`][0].getBoundingClientRect().top - canvasWindowTop - 10
const middleX = this.$refs[`step${3}`][0].getBoundingClientRect().left - canvasWindowLeft
const middleY = this.$refs[`step${3}`][0].getBoundingClientRect().top - canvasWindowTop
const endX = this.$refs[`step${1}`][0].getBoundingClientRect().left - canvasWindowLeft + 10
const endY = this.$refs[`step${1}`][0].getBoundingClientRect().top - canvasWindowTop - 10
ctx.beginPath()
ctx.moveTo(startX, startY)
const movingUpStartY = startY - 30
const movingUpEndY = endY - 30
ctx.lineTo(startX, movingUpStartY)
ctx.lineTo(middleX + fontWidth, movingUpStartY)
ctx.moveTo(middleX - 32, movingUpStartY)
ctx.lineTo(endX, movingUpEndY)
ctx.lineTo(endX, endY)
ctx.stroke()
ctx.closePath()
ctx.beginPath()
let arrowX, arrowY
const headlen = 12
const theta = 25
const angle = (Math.atan2(endY - movingUpEndY, endX - endX) * 180) / Math.PI
const angleTop = ((angle + theta) * Math.PI) / 180
const angleBot = ((angle - theta) * Math.PI) / 180
const topX = headlen * Math.cos(angleTop)
const topY = headlen * Math.sin(angleTop)
const botX = headlen * Math.cos(angleBot)
const botY = headlen * Math.sin(angleBot)
arrowX = endX - topX
arrowY = endY - topY
ctx.moveTo(arrowX, arrowY)
const endArrowX = endX - botX
const endArrowY = endY - botY
ctx.quadraticCurveTo(endX, endY - headlen / 2, endArrowX, endArrowY)
ctx.lineTo(endX, endY)
ctx.lineTo(arrowX, arrowY)
ctx.fillStyle = color
ctx.fill()
ctx.strokeStyle = color
ctx.font = '16px Arial'
ctx.fillText('未结单', middleX - 14, movingUpStartY + 6)
ctx.lineJoin = 'round'
ctx.stroke()
ctx.closePath()
},
addResizeListener() {
console.log('sss')
window.addEventListener('resize', this.drawCanvas(this.status))
},
removeResizeListener() {
window.removeEventListener('resize', this.drawCanvas)
},
},
created() {},
mounted() {
this.drawCanvas(this.status)
window.addEventListener('resize', this.addResizeListener)
},
beforeCreate() {},
beforeDestroy() {},
destroyed() {
this.removeResizeListener()
},
activated() {},
}
</script>
<style scoped lang='scss'>
.canvas-container {
position: relative;
height: 158px;
width: 100%;
#canvas {
position: absolute;
width: 100%;
height: 158px;
}
}
.step-wrap {
display: flex;
justify-content: space-between;
align-items: center;
height: 158px;
width: 100%;
li {
position: relative;
flex: auto;
display: inline-flex;
align-items: center;
color: var(--active-color);
p {
position: absolute;
top: 30px;
left: -22px;
}
.number {
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
border: 2px solid;
}
img {
width: 24px;
height: 24px;
}
}
li:first-child {
margin-left: 24px;
}
li:last-child {
flex: none;
padding-right: 24px;
}
li:not(:first-child)::before {
content: '➤';
position: absolute;
top: 0px;
left: -20px;
display: block;
height: 2px;
}
li:not(:last-child)::after {
content: '';
border-bottom: 1px solid var(--active-color);
position: absolute;
top: 9.5px;
left: 30px;
display: block;
width: calc(100% - 41px);
height: 2px;
}
}
.step-wrap .active {
color: var(--active-color);
}
/* 高亮的尾箭头 */
.step-wrap .active::after {
border-color: var(--normal-color) !important;
}
/* 未完成 箭头和字体样式置灰 */
.step-wrap > .active ~ li,
.step-wrap > .active ~ li::before {
color: var(--normal-color) !important;
}
/* 未完成 引导线样式置灰 */
.step-wrap > .active ~ li::after {
border-color: var(--normal-color) !important;
}
</style>
canvas实现带箭头拐弯步骤条
于 2024-05-14 10:59:09 首次发布