whiteboard图片元素增加自定义圆角效果

This commit is contained in:
jingrow 2026-05-04 18:04:49 +08:00
parent 620beea0f5
commit ccda5d038a
4 changed files with 42 additions and 20 deletions

View File

@ -143,7 +143,7 @@ const hasFillControl = computed(() => {
const hasStrokeControl = computed(() => {
if (!selectedElement.value) return false
const t = selectedElement.value.type
return t !== 'text' && t !== 'sticky-note' && t !== 'image'
return t !== 'text' && t !== 'sticky-note'
})
//
@ -153,8 +153,12 @@ const hasStrokeWidthControl = computed(() => {
return t !== 'text' && t !== 'sticky-note' && t !== 'freehand'
})
//
const hasBorderRadiusControl = computed(() => selectedElement.value?.type === 'rectangle')
// /
const hasBorderRadiusControl = computed(() => {
if (!selectedElement.value) return false
const t = selectedElement.value.type
return t === 'rectangle' || t === 'image'
})
//
const elementTypeLabel = computed(() => {

View File

@ -323,8 +323,7 @@ export class BoardModel {
rotation: options.rotation ?? 0,
style: {
...DEFAULT_STYLE_VAL,
fill: colors.fill,
stroke: colors.stroke,
...colors,
...(options.style || {}),
},
zIndex: options.zIndex ?? this._zIndexCounter++,

View File

@ -414,5 +414,5 @@ export const ELEMENT_COLORS = {
arrow: { fill: 'transparent', stroke: '#64748b' },
line: { fill: 'transparent', stroke: '#64748b' },
freehand: { fill: 'transparent', stroke: '#1e293b' },
image: { fill: '#f1f5f9', stroke: '#94a3b8' },
image: { fill: '#f1f5f9', stroke: '#94a3b8', strokeWidth: 1 },
} as const

View File

@ -554,18 +554,35 @@ export class BoardRenderer {
this.imageCache.set(el.id, img)
}
const radius = Math.max(0, el.style.borderRadius ?? 0)
if (img.complete && img.naturalWidth > 0) {
// 边框
// 圆角裁剪图片
if (radius > 0) {
this.ctx.save()
this.roundRect(el.x, el.y, el.width, el.height, radius)
this.ctx.clip()
this.ctx.drawImage(img, el.x, el.y, el.width, el.height)
this.ctx.restore()
} else {
this.ctx.drawImage(img, el.x, el.y, el.width, el.height)
}
// 圆角边框
if (el.style.stroke && el.style.stroke !== 'transparent') {
this.ctx.strokeStyle = el.style.stroke
this.ctx.lineWidth = el.style.strokeWidth ?? 1
this.ctx.strokeRect(el.x, el.y, el.width, el.height)
this.ctx.lineWidth = el.style.strokeWidth ?? 2
this.roundRect(el.x, el.y, el.width, el.height, radius)
this.ctx.stroke()
}
this.ctx.drawImage(img, el.x, el.y, el.width, el.height)
} else {
// 占位符
this.ctx.fillStyle = el.style.fill || '#f1f5f9'
this.ctx.fillRect(el.x, el.y, el.width, el.height)
if (radius > 0) {
this.roundRect(el.x, el.y, el.width, el.height, radius)
this.ctx.fill()
} else {
this.ctx.fillRect(el.x, el.y, el.width, el.height)
}
this.ctx.fillStyle = '#94a3b8'
this.ctx.font = '12px sans-serif'
this.ctx.textAlign = 'center'
@ -1161,16 +1178,18 @@ export class BoardRenderer {
/** 圆角矩形 */
private roundRect(x: number, y: number, w: number, h: number, r: number): void {
// Fully rounded sentinel (9999) and clamp to available space
const radius = Math.min(r, w / 2, h / 2)
this.ctx.beginPath()
this.ctx.moveTo(x + r, y)
this.ctx.lineTo(x + w - r, y)
this.ctx.arcTo(x + w, y, x + w, y + r, r)
this.ctx.lineTo(x + w, y + h - r)
this.ctx.arcTo(x + w, y + h, x + w - r, y + h, r)
this.ctx.lineTo(x + r, y + h)
this.ctx.arcTo(x, y + h, x, y + h - r, r)
this.ctx.lineTo(x, y + r)
this.ctx.arcTo(x, y, x + r, y, r)
this.ctx.moveTo(x + radius, y)
this.ctx.lineTo(x + w - radius, y)
this.ctx.arcTo(x + w, y, x + w, y + radius, radius)
this.ctx.lineTo(x + w, y + h - radius)
this.ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius)
this.ctx.lineTo(x + radius, y + h)
this.ctx.arcTo(x, y + h, x, y + h - radius, radius)
this.ctx.lineTo(x, y + radius)
this.ctx.arcTo(x, y, x + radius, y, radius)
this.ctx.closePath()
}