7 changed files with 630 additions and 1231 deletions
File diff suppressed because it is too large
@ -1,200 +0,0 @@ |
|||||
<template> |
|
||||
<div class="canvas-bg" :style="bgStyle"> |
|
||||
<div :style="canvasStyle" class="canvas-panel-wrap"> |
|
||||
{{ canvasStyle }} <slot></slot> |
|
||||
</div> |
|
||||
|
|
||||
<canvas ref="topRulerRef" class="canvas-ruler top" :style="topStyle"></canvas> |
|
||||
<canvas ref="leftRulerRef" class="canvas-ruler left" :style="leftStyle"></canvas> |
|
||||
<i class="canvas-ruler-cross"></i> |
|
||||
|
|
||||
<div |
|
||||
class="canvas-move" |
|
||||
v-show="isMoveCanvas" |
|
||||
@mousedown="onMoveCanvasDown" |
|
||||
@mouseup="onMoveCanvasUp" |
|
||||
></div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts"> |
|
||||
import { |
|
||||
defineComponent, |
|
||||
ref, |
|
||||
onMounted, |
|
||||
computed, |
|
||||
watch, |
|
||||
nextTick, |
|
||||
onBeforeUnmount, |
|
||||
} from "vue"; |
|
||||
import { drawRuler } from "./drawRuler.ts"; |
|
||||
import { useUserRulerStore } from "@/store/ruler/index"; |
|
||||
import { keyCode } from "./data/keyCode"; |
|
||||
|
|
||||
export default defineComponent({ |
|
||||
name: "CanvasBg", |
|
||||
|
|
||||
setup() { |
|
||||
const editorStore = useUserRulerStore(); |
|
||||
const topRulerRef = ref(); |
|
||||
const leftRulerRef = ref(); |
|
||||
const isMoveCanvas = computed(() => editorStore.isMoveCanvas); |
|
||||
watch( |
|
||||
() => editorStore.screenWidth, |
|
||||
() => { |
|
||||
refreshRuler(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.screenHeight, |
|
||||
() => { |
|
||||
refreshRuler(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.scale, |
|
||||
() => { |
|
||||
refreshRuler(); |
|
||||
} |
|
||||
); |
|
||||
|
|
||||
let isRuler = false; |
|
||||
const refreshRuler = () => { |
|
||||
if (!isRuler) { |
|
||||
isRuler = true; |
|
||||
nextTick(() => { |
|
||||
drawRuler( |
|
||||
"top", |
|
||||
topRulerRef.value, |
|
||||
editorStore.scale, |
|
||||
editorStore.showWidth, |
|
||||
24, |
|
||||
60 |
|
||||
); |
|
||||
drawRuler( |
|
||||
"left", |
|
||||
leftRulerRef.value, |
|
||||
editorStore.scale, |
|
||||
editorStore.showWidth, |
|
||||
24, |
|
||||
60 |
|
||||
); |
|
||||
isRuler = false; |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
||||
const scrollLeft = computed(() => { |
|
||||
return editorStore.scrollLeft - 24; |
|
||||
}); |
|
||||
const scrollTop = computed(() => { |
|
||||
return editorStore.scrollTop - 24; |
|
||||
}); |
|
||||
const onKeyAction = (e: KeyboardEvent) => { |
|
||||
if (e.keyCode == keyCode.space) { |
|
||||
editorStore.setMoveCanvas(!editorStore.isMoveCanvas); |
|
||||
} |
|
||||
}; |
|
||||
const onWheelAction = (e: WheelEvent) => { |
|
||||
if (isMoveCanvas.value) { |
|
||||
if (e.wheelDelta > 0) { |
|
||||
editorStore.setScale(editorStore.scale + 1); |
|
||||
} else { |
|
||||
editorStore.setScale(editorStore.scale - 1); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
onMounted(() => { |
|
||||
window.addEventListener("keydown", onKeyAction); |
|
||||
window.addEventListener("wheel", onWheelAction); |
|
||||
refreshRuler(); |
|
||||
}); |
|
||||
onBeforeUnmount(() => { |
|
||||
window.removeEventListener("keydown", onKeyAction); |
|
||||
window.removeEventListener("wheel", onWheelAction); |
|
||||
}); |
|
||||
let moveInfo = { |
|
||||
startX: 0, |
|
||||
startY: 0, |
|
||||
}; |
|
||||
return { |
|
||||
topRulerRef, |
|
||||
leftRulerRef, |
|
||||
topStyle: computed(() => ({ |
|
||||
left: -scrollLeft.value + "px", |
|
||||
})), |
|
||||
leftStyle: computed(() => ({ top: -scrollTop.value + "px" })), |
|
||||
isMoveCanvas, |
|
||||
bgStyle: computed(() => ({ |
|
||||
width: editorStore.showWidth + "px", |
|
||||
height: editorStore.showHeight + "px", |
|
||||
})), |
|
||||
canvasStyle: computed(() => ({ |
|
||||
left: -scrollLeft.value + "px", |
|
||||
top: -scrollTop.value + "px", |
|
||||
width: editorStore.screenWidth + "px", |
|
||||
height: editorStore.screenHeight + "px", |
|
||||
transform: `scale(${editorStore.scale * 0.01})`, |
|
||||
})), |
|
||||
scrollLeft, |
|
||||
scrollTop, |
|
||||
onMoveCanvasDown: (e: MouseEvent) => { |
|
||||
e.stopPropagation(); |
|
||||
|
|
||||
moveInfo = { |
|
||||
startX: e.clientX, |
|
||||
startY: e.clientY, |
|
||||
}; |
|
||||
}, |
|
||||
onMoveCanvasUp: (e: MouseEvent) => { |
|
||||
e.stopPropagation(); |
|
||||
let left = scrollLeft.value - (e.clientX - moveInfo.startX); |
|
||||
let top = scrollTop.value - (e.clientY - moveInfo.startY); |
|
||||
// console.log('move', left, top); |
|
||||
editorStore.setScroll({ left, top }); |
|
||||
}, |
|
||||
}; |
|
||||
}, |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.canvas-ruler-cross { |
|
||||
display: inline-block; |
|
||||
width: 24px; |
|
||||
height: 24px; |
|
||||
position: absolute; |
|
||||
|
|
||||
background-color: var(--ruler-bg); |
|
||||
} |
|
||||
.canvas-panel-wrap { |
|
||||
position: absolute; |
|
||||
box-shadow: var(--canvas-shadow) 0 0 30px 0; |
|
||||
transform-origin: left top; |
|
||||
margin-left: 60px; |
|
||||
margin-top: 60px; |
|
||||
} |
|
||||
.canvas-move { |
|
||||
position: absolute; |
|
||||
height: 100%; |
|
||||
width: 100%; |
|
||||
background-color: var(--move-bg); |
|
||||
cursor: move; |
|
||||
} |
|
||||
|
|
||||
.canvas-ruler { |
|
||||
position: absolute; |
|
||||
transform-origin: left top; |
|
||||
// cursor: ew-resize; |
|
||||
background-color: var(--ruler-bg); |
|
||||
|
|
||||
&.left { |
|
||||
top: 24px; |
|
||||
left: 0px; |
|
||||
} |
|
||||
|
|
||||
&.top { |
|
||||
top: 0px; |
|
||||
left: 24px; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,148 +0,0 @@ |
|||||
<template> |
|
||||
<div class="canvas-slider"> |
|
||||
<el-tooltip placement="top" effect="light"> |
|
||||
<template #content> |
|
||||
<div class="operation-tip-item"> |
|
||||
<div>按下空格键,可移动画布</div> |
|
||||
<div>按下空格键,滚动鼠标滑轮可放缩画布</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
<i class="el-icon-thumb" /> |
|
||||
</el-tooltip> |
|
||||
<el-input-number v-model="scalePercent" :min="20" :max="200" size="small"></el-input-number> |
|
||||
<el-slider |
|
||||
size="small" |
|
||||
v-model="scalePercent" |
|
||||
:min="20" |
|
||||
:max="200" |
|
||||
:step="5" |
|
||||
style="width: 100px; margin: 0 12px" |
|
||||
></el-slider> |
|
||||
|
|
||||
<el-tooltip placement="top"> |
|
||||
<template #content> 实际大小 </template> |
|
||||
<i class="el-icon-full-screen" @click="onRealCanvas" /> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip placement="top"> |
|
||||
<template #content> 适应屏幕大小 </template> |
|
||||
<i class="el-icon-aim" @click="onFitCanvas" /> |
|
||||
</el-tooltip> |
|
||||
<i |
|
||||
class="el-icon-monitor" |
|
||||
:style="{ color: showThumbnail ? 'dodgerblue' : 'rgba(0,0,0,0.5)' }" |
|
||||
@click="onMagic" |
|
||||
></i> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts"> |
|
||||
import { useEditorStore } from '@/stores/editor'; |
|
||||
|
|
||||
import { defineComponent, ref, computed, onMounted, onBeforeUnmount } from 'vue'; |
|
||||
|
|
||||
//下方状态栏 |
|
||||
export default defineComponent({ |
|
||||
name: 'CanvasSlider', |
|
||||
setup() { |
|
||||
const store = useEditorStore(); |
|
||||
|
|
||||
const scalePercent = computed({ |
|
||||
get: () => store.scale, |
|
||||
set: (value) => { |
|
||||
store.setScale(value); |
|
||||
} |
|
||||
}); |
|
||||
const showThumbnail = computed({ |
|
||||
get: () => store.$state.isThumbnail, |
|
||||
set: (value) => { |
|
||||
store.setThumbnail(value); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const onFitCanvas = () => { |
|
||||
store.setScale( |
|
||||
parseInt( |
|
||||
//@ts-ignore |
|
||||
((document.getElementById('dashboard').offsetHeight - 84) / store.screenHeight) * 100 |
|
||||
) |
|
||||
); |
|
||||
}; |
|
||||
const onRealCanvas = () => { |
|
||||
store.setScale(100); |
|
||||
}; |
|
||||
const onMagic = () => { |
|
||||
showThumbnail.value = !showThumbnail.value; |
|
||||
}; |
|
||||
|
|
||||
return { |
|
||||
showThumbnail, |
|
||||
|
|
||||
scalePercent, |
|
||||
|
|
||||
//method |
|
||||
onMagic, |
|
||||
onFitCanvas, |
|
||||
onRealCanvas |
|
||||
}; |
|
||||
} |
|
||||
}); |
|
||||
</script> |
|
||||
<style lang="scss" scoped> |
|
||||
.operation-tip-item > div { |
|
||||
color: var(--el-color-primary); |
|
||||
background: rgba(26, 103, 255, 0.1); |
|
||||
padding: 5px 10px; |
|
||||
} |
|
||||
|
|
||||
.operation-tip-item > div:not(:last-child) { |
|
||||
margin-bottom: 8px; |
|
||||
} |
|
||||
|
|
||||
i { |
|
||||
font-size: 16px; |
|
||||
color: var(--slider-icon); |
|
||||
cursor: pointer; |
|
||||
|
|
||||
&:not(:last-child) { |
|
||||
margin-right: 10px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
:deep(.el-input-number__decrease) { |
|
||||
border: none; |
|
||||
background: none; |
|
||||
} |
|
||||
|
|
||||
:deep(.el-input-number__increase) { |
|
||||
border: none; |
|
||||
background: none; |
|
||||
} |
|
||||
|
|
||||
:deep(.el-input__wrapper) { |
|
||||
border: none; |
|
||||
border-radius: 0; |
|
||||
background: none; |
|
||||
box-shadow: none; |
|
||||
} |
|
||||
|
|
||||
.el-input-number--small { |
|
||||
width: 84px; |
|
||||
} |
|
||||
|
|
||||
$line: solid 1px var(--canvas-slider-border); |
|
||||
|
|
||||
.canvas-slider { |
|
||||
display: flex; |
|
||||
position: fixed; |
|
||||
bottom: 10px; |
|
||||
right: 310px; |
|
||||
background-color: var(--slider-bg); |
|
||||
height: 32px; |
|
||||
justify-content: flex-end; |
|
||||
align-items: center; |
|
||||
border: $line; |
|
||||
z-index: 9; |
|
||||
border-radius: 2px; |
|
||||
padding: 0 16px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,193 +0,0 @@ |
|||||
<template> |
|
||||
<canvas |
|
||||
class="canvas-thumbnail" |
|
||||
:width="canvasConfig.thumbnailWrapWidth" |
|
||||
:height="canvasConfig.thumbnailWrapHeight" |
|
||||
ref="thumbnailRef" |
|
||||
v-show="showThumbnail" |
|
||||
@mousedown="onMoveStart" |
|
||||
@mousemove="onMove" |
|
||||
@mouseup="onMoveEnd" |
|
||||
@mouseleave="onMoveEnd" |
|
||||
> |
|
||||
</canvas> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts"> |
|
||||
import { useEditorStore } from '@/stores/editor'; |
|
||||
import { |
|
||||
defineComponent, |
|
||||
ref, |
|
||||
computed, |
|
||||
reactive, |
|
||||
watch, |
|
||||
onMounted, |
|
||||
nextTick, |
|
||||
onBeforeUnmount |
|
||||
} from 'vue'; |
|
||||
export default defineComponent({ |
|
||||
name: 'CanvasThumbnail', |
|
||||
setup(props, context) { |
|
||||
const editorStore = useEditorStore(); |
|
||||
const thumbnailRef = ref(); |
|
||||
const canvasConfig = computed(() => editorStore.canvasConfig); |
|
||||
let isLock = false; |
|
||||
const viewBox = computed({ |
|
||||
get: () => ({ viewWidth: editorStore.viewWidth, viewHeight: editorStore.viewHeight }), |
|
||||
set: (v) => { |
|
||||
editorStore.setViewBox(v); |
|
||||
} |
|
||||
}); |
|
||||
const unscale = computed(() => { |
|
||||
if (editorStore.scale > 100) { |
|
||||
return 1 / editorStore.thumbnailSize; |
|
||||
} else { |
|
||||
return 10; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const getViewBox = () => { |
|
||||
nextTick(() => { |
|
||||
let dashboardDom = document.getElementById('dashboard'); |
|
||||
if (!dashboardDom) { |
|
||||
return; |
|
||||
} |
|
||||
viewBox.value.viewWidth = dashboardDom.offsetWidth; |
|
||||
viewBox.value.viewHeight = dashboardDom.offsetHeight; |
|
||||
drawThumbnail(); |
|
||||
}); |
|
||||
}; |
|
||||
const drawThumbnail = () => { |
|
||||
if (!isLock) { |
|
||||
isLock = true; |
|
||||
nextTick(() => { |
|
||||
let startLen = 6; |
|
||||
|
|
||||
const ctx = thumbnailRef.value.getContext('2d'); |
|
||||
ctx.clearRect( |
|
||||
0, |
|
||||
0, |
|
||||
canvasConfig.value.thumbnailWrapWidth, |
|
||||
canvasConfig.value.thumbnailWrapHeight |
|
||||
); |
|
||||
ctx.beginPath(); |
|
||||
ctx.fillStyle = 'rgba(26, 103, 255, 0.5)'; |
|
||||
ctx.rect( |
|
||||
startLen, |
|
||||
startLen, |
|
||||
canvasConfig.value.thumbnailWidth, |
|
||||
canvasConfig.value.thumbnailHeight |
|
||||
); |
|
||||
ctx.fill(); |
|
||||
ctx.beginPath(); |
|
||||
ctx.strokeStyle = '#1a67ff'; |
|
||||
ctx.rect( |
|
||||
Math.round(editorStore.scrollLeft * editorStore.thumbnailSize), |
|
||||
Math.round(editorStore.scrollTop * editorStore.thumbnailSize), |
|
||||
viewBox.value.viewWidth * editorStore.thumbnailSize, |
|
||||
viewBox.value.viewHeight * editorStore.thumbnailSize |
|
||||
); |
|
||||
ctx.stroke(); |
|
||||
|
|
||||
isLock = false; |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
||||
watch( |
|
||||
() => editorStore.scale, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.screenWidth, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.screenHeight, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.scrollLeft, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.scrollTop, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
|
|
||||
watch( |
|
||||
() => editorStore.screenHeight, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.viewHeight, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
watch( |
|
||||
() => editorStore.viewWidth, |
|
||||
() => { |
|
||||
drawThumbnail(); |
|
||||
} |
|
||||
); |
|
||||
|
|
||||
onMounted(() => { |
|
||||
window.addEventListener('resize', getViewBox); |
|
||||
getViewBox(); |
|
||||
}); |
|
||||
onBeforeUnmount(() => { |
|
||||
window.removeEventListener('resize', getViewBox); |
|
||||
}); |
|
||||
let moveInfo = { |
|
||||
startX: 0, |
|
||||
startY: 0, |
|
||||
isMove: false |
|
||||
}; |
|
||||
return { |
|
||||
canvasConfig, |
|
||||
thumbnailRef, |
|
||||
showThumbnail: computed(() => editorStore.isThumbnail), |
|
||||
onMoveStart: (e: MouseEvent) => { |
|
||||
moveInfo.isMove = true; |
|
||||
moveInfo.startX = e.clientX; |
|
||||
moveInfo.startY = e.clientY; |
|
||||
}, |
|
||||
onMove: (e: MouseEvent) => { |
|
||||
if (moveInfo.isMove) { |
|
||||
let left = editorStore.scrollLeft + (e.clientX - moveInfo.startX) * unscale.value; |
|
||||
let top = editorStore.scrollTop + (e.clientY - moveInfo.startY) * unscale.value; |
|
||||
// console.log('thumbnail', left, top); |
|
||||
editorStore.setScroll({ left, top }); |
|
||||
moveInfo.startX = e.clientX; |
|
||||
moveInfo.startY = e.clientY; |
|
||||
} |
|
||||
}, |
|
||||
onMoveEnd: () => { |
|
||||
moveInfo.isMove = false; |
|
||||
} |
|
||||
}; |
|
||||
} |
|
||||
}); |
|
||||
</script> |
|
||||
<style lang="scss" scoped> |
|
||||
.canvas-thumbnail { |
|
||||
background-color: var(--thumbnail-wrap-bg); |
|
||||
position: fixed; |
|
||||
right: 310px; |
|
||||
bottom: 48px; |
|
||||
z-index: 9; |
|
||||
cursor: move; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,41 +0,0 @@ |
|||||
export const keyCode = { |
|
||||
space: 32, |
|
||||
backspace: 8, |
|
||||
shift: 16, |
|
||||
ctr: 17, |
|
||||
option: 18, |
|
||||
command: 91, |
|
||||
alt: 18, |
|
||||
ctrl: 17, |
|
||||
equal: 187, |
|
||||
minus: 189, |
|
||||
q: 81, |
|
||||
w: 87, |
|
||||
c: 67, |
|
||||
d: 68, |
|
||||
z: 90, |
|
||||
y: 89, |
|
||||
g: 71, |
|
||||
l: 76, |
|
||||
h: 72, |
|
||||
u: 85, |
|
||||
o: 79, |
|
||||
r: 82, |
|
||||
t: 84, |
|
||||
b: 66, |
|
||||
s: 83, |
|
||||
p: 80, |
|
||||
left: 37, |
|
||||
top: 38, |
|
||||
right: 39, |
|
||||
bottom: 40 |
|
||||
}; |
|
||||
|
|
||||
// export function getCodeKey(code) {
|
|
||||
// for (let k in keyCode) {
|
|
||||
// if (keyCode[k] == code) {
|
|
||||
// return k;
|
|
||||
// }
|
|
||||
// }
|
|
||||
// return '';
|
|
||||
// }
|
|
||||
@ -1,98 +0,0 @@ |
|||||
/** |
|
||||
* 画标尺刻度Canvas |
|
||||
* @param direction 方向 |
|
||||
* @param canvas canvas DOM |
|
||||
* @param scale 缩放比例[20-200] |
|
||||
* @param width 长度 |
|
||||
* @param height 高度 |
|
||||
* @param startLen 开始距离 |
|
||||
*/ |
|
||||
export function drawRuler( |
|
||||
direction: string, |
|
||||
canvas: HTMLCanvasElement, |
|
||||
scale: number = 100, |
|
||||
width: number, |
|
||||
height: number = 24, |
|
||||
startLen: number = 60 |
|
||||
) { |
|
||||
const padding = 2; |
|
||||
const ctx: CanvasRenderingContext2D = canvas.getContext('2d'); |
|
||||
const percent = scale * 0.01; |
|
||||
let unit = Math.ceil(10 / percent); |
|
||||
if (unit < 8) { |
|
||||
unit = 8; |
|
||||
} |
|
||||
//计算出要绘制多少个刻度
|
|
||||
const scaleCount = Math.ceil(width + startLen / unit); |
|
||||
if (direction == 'top') { |
|
||||
canvas.width = width + startLen; |
|
||||
canvas.height = height; |
|
||||
ctx.clearRect(0, 0, width, height); |
|
||||
ctx.beginPath(); |
|
||||
//绘制起点
|
|
||||
ctx.strokeStyle = 'rgb(161, 174, 179)'; |
|
||||
ctx.font = '10px Arial'; |
|
||||
ctx.lineWidth = 0.5; |
|
||||
ctx.moveTo(startLen, 0); |
|
||||
ctx.lineTo(startLen, height); |
|
||||
ctx.fillText('0', startLen + padding, 13); |
|
||||
|
|
||||
for (let i = 1; i <= scaleCount; i++) { |
|
||||
//计算每个刻度的位置
|
|
||||
const step = startLen + Math.round(i * unit * percent); |
|
||||
//10的倍数刻度大长度
|
|
||||
if (i % 10 === 0) { |
|
||||
ctx.moveTo(step, 0); |
|
||||
ctx.lineTo(step, height); |
|
||||
//标注刻度值
|
|
||||
const scaleText = i * unit + ''; |
|
||||
ctx.fillText(scaleText, step + padding, 13); |
|
||||
} else if (i % 5 === 0) {//5的倍数刻度中长度
|
|
||||
ctx.moveTo(step, 15); |
|
||||
ctx.lineTo(step, height); |
|
||||
//标注刻度值
|
|
||||
const scaleText = i * unit + ''; |
|
||||
ctx.fillText(scaleText, step + padding, 13); |
|
||||
} else {//其他刻度小长度
|
|
||||
ctx.moveTo(step, height - 2); |
|
||||
ctx.lineTo(step, height); |
|
||||
} |
|
||||
} |
|
||||
ctx.stroke(); |
|
||||
} else { |
|
||||
canvas.width = height; |
|
||||
canvas.height = width + startLen; |
|
||||
ctx.clearRect(0, 0, height, width + startLen); |
|
||||
|
|
||||
ctx.beginPath(); |
|
||||
//绘制起点
|
|
||||
ctx.strokeStyle = 'rgb(161, 174, 179)'; |
|
||||
ctx.font = '10px Arial'; |
|
||||
ctx.lineWidth = 0.5; |
|
||||
ctx.moveTo(0, startLen); |
|
||||
ctx.lineTo(height, startLen); |
|
||||
ctx.fillText('0', padding, startLen - padding); |
|
||||
//计算出要绘制多少个刻度
|
|
||||
|
|
||||
for (let i = 1; i <= scaleCount; i++) { |
|
||||
const step = startLen + Math.round(i * unit * percent); |
|
||||
if (i % 10 === 0) { |
|
||||
ctx.moveTo(0, step); |
|
||||
ctx.lineTo(height, step); |
|
||||
//标注刻度值
|
|
||||
const scaleText = unit * i + ''; |
|
||||
ctx.fillText(scaleText, padding, step - padding); |
|
||||
} else if (i % 5 === 0) { |
|
||||
ctx.moveTo(15, step); |
|
||||
ctx.lineTo(height, step); |
|
||||
//标注刻度值
|
|
||||
const scaleText = unit * i + ''; |
|
||||
ctx.fillText(scaleText, padding, step - padding); |
|
||||
} else { |
|
||||
ctx.moveTo(height - 2, step); |
|
||||
ctx.lineTo(height, step); |
|
||||
} |
|
||||
} |
|
||||
ctx.stroke(); |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue