This commit is contained in:
张成
2026-04-22 11:10:28 +08:00
parent 3212503a64
commit 10dab7ee84
3 changed files with 93 additions and 103 deletions

View File

@@ -45,10 +45,9 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
// 获取屏幕宽度如果没有传入width则使用屏幕宽度 // 获取屏幕宽度如果没有传入width则使用屏幕宽度
const windowWidth = Taro.getSystemInfoSync().windowWidth const windowWidth = Taro.getSystemInfoSync().windowWidth
// 获取 DPR - 使用系统像素比确保高清显示 // 获取 DPR:统一与 share.ts 策略,限制上限避免内存过高
// const systemDpr = Taro.getSystemInfoSync().pixelRatio const systemDpr = (Taro as any).getSystemInfoSync?.().pixelRatio || 1
const dpr = 1 const dpr = Math.min(Math.max(systemDpr, 1), 2)
// Math.min(systemDpr, 3) // 限制最大dpr为3避免过度放大
// 2. 计算缩放比例(设备宽度 / 设计稿宽度) // 2. 计算缩放比例(设备宽度 / 设计稿宽度)
const scale = windowWidth / designWidth const scale = windowWidth / designWidth
@@ -105,7 +104,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
// 绘制边框 // 绘制边框
ctx.strokeStyle = borderColor ctx.strokeStyle = borderColor
ctx.lineWidth = 1 * dpr ctx.lineWidth = 1
ctx.stroke() ctx.stroke()
// 绘制文字 // 绘制文字
@@ -145,14 +144,14 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
const drawSVGPathToCanvas = (ctx: any) => { const drawSVGPathToCanvas = (ctx: any) => {
// 设置绘制样式 // 设置绘制样式
ctx.strokeStyle = '#00E5AD'; ctx.strokeStyle = '#00E5AD';
ctx.lineWidth = scale * 3 * dpr; ctx.lineWidth = scale * 3;
ctx.lineCap = 'round'; ctx.lineCap = 'round';
ctx.lineJoin = 'round'; ctx.lineJoin = 'round';
ctx.save(); ctx.save();
// 移动到指定位置并缩放 // 移动到指定位置并缩放
ctx.translate(scale * 200 * dpr, scale * 90 * dpr); ctx.translate(scale * 200, scale * 90);
const scaleValue = 0.8 const scaleValue = 0.8
ctx.scale(scaleValue, scaleValue); ctx.scale(scaleValue, scaleValue);
@@ -382,43 +381,39 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
setIsDrawing(true) setIsDrawing(true)
try { try {
// 设置Canvas的实际尺寸使用dpr确保高清显示 // 统一坐标系:先用物理像素清空,再缩放到逻辑坐标绘制
const canvasWidthPx = canvasWidth * dpr const canvasWidthPx = canvasWidth * dpr
const canvasHeightPx = canvasHeight * dpr const canvasHeightPx = canvasHeight * dpr
if (typeof ctx.setTransform === 'function') {
// 清空画布 ctx.setTransform(1, 0, 0, 1, 0, 0)
}
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx) ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
ctx.save()
ctx.scale(dpr, dpr)
console.log('画布已清空') console.log('画布已清空')
// 如果dpr大于2进行缩放处理以避免内容过大
if (dpr > 2) {
const scale = 2 / dpr
ctx.scale(scale, scale)
console.log('应用缩放:', scale)
}
// 绘制背景 - 渐变色 已完成 // 绘制背景 - 渐变色 已完成
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeightPx) const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight)
gradient.addColorStop(0, '#BFFFEF') gradient.addColorStop(0, '#BFFFEF')
gradient.addColorStop(1, '#F2FFFC') gradient.addColorStop(1, '#F2FFFC')
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, 0, canvasWidthPx, canvasHeightPx) ctx.fillRect(0, 0, canvasWidth, canvasHeight)
console.log('背景绘制完成') console.log('背景绘制完成')
// 绘制背景条纹 已完成 // 绘制背景条纹 已完成
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)' ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
ctx.lineWidth = 2 ctx.lineWidth = 2
for (let i = 0; i < canvasWidthPx; i += 4) { for (let i = 0; i < canvasWidth; i += 4) {
ctx.beginPath() ctx.beginPath()
ctx.moveTo(i, 0) ctx.moveTo(i, 0)
ctx.lineTo(i, canvasHeightPx) ctx.lineTo(i, canvasHeight)
ctx.stroke() ctx.stroke()
} }
// 绘制用户头像(左上角) 已完成 // 绘制用户头像(左上角) 已完成
const avatarSize = scale * 32 * dpr // 32px * dpr const avatarSize = scale * 32
const avatarX = scale * 35 * dpr // 距离左侧35px const avatarX = scale * 35
const avatarY = scale * 35 * dpr // 距离顶部35px const avatarY = scale * 35
try { try {
const avatarPath = await loadImage(data.userAvatar, canvasNode) const avatarPath = await loadImage(data.userAvatar, canvasNode)
@@ -438,23 +433,23 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
} }
// 绘制用户昵称 已完成 // 绘制用户昵称 已完成
const nicknameX = avatarX + avatarSize + 8 * dpr // 距离头像8px const nicknameX = avatarX + avatarSize + scale * 8
const nicknameY = avatarY + (avatarSize - 18 * dpr) / 2 // 与头像水平居中对齐 const nicknameY = avatarY + (avatarSize - scale * 18) / 2
const nicknameFontSize = scale * 18 * dpr const nicknameFontSize = scale * 18
// drawText(ctx, data.userNickname, nicknameX, nicknameY, 200 * dpr, nicknameFontSize, '#000000', true, 'Noto Sans SC') // drawText(ctx, data.userNickname, nicknameX, nicknameY, 200 * dpr, nicknameFontSize, '#000000', true, 'Noto Sans SC')
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900') drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
// 绘制"邀你加入球局"文案 // 绘制"邀你加入球局"文案
const inviteX = scale * 35 * dpr // 距离画布左侧35px const inviteX = scale * 35
const inviteY = scale * 100 * dpr // 距离画布顶部79px const inviteY = scale * 100
const inviteFontSize = scale * 44 * dpr const inviteFontSize = scale * 44
// 绘制"邀你加入" // 绘制"邀你加入"
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900') drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
// 绘制"球局"特殊样式 // 绘制"球局"特殊样式
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + 4 * dpr const qiuJuX = inviteX + ctx.measureText('邀你加入').width + scale * 4
const qiuJuFontSize = scale * 44 * dpr const qiuJuFontSize = scale * 44
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900') drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
// 测试绘制网络图片 // 测试绘制网络图片
@@ -462,12 +457,12 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
// 绘制球员图片(右上角)已完成 // 绘制球员图片(右上角)已完成
let venueBaseConfig = { let venueBaseConfig = {
venueImgX: scale * 340 * dpr, venueImgX: scale * 340,
venueImgY: scale * 35 * dpr, venueImgY: scale * 35,
rotation: scale * -8, // 旋转-8度 rotation: scale * -8, // 旋转-8度
venueImgSize: scale * 124 * dpr, venueImgSize: scale * 124,
borderRadius: scale * 24 * dpr, borderRadius: scale * 24,
padding: scale * 4 * dpr, padding: scale * 4,
venueImage: data.venueImages?.[0] venueImage: data.venueImages?.[0]
} }
@@ -476,8 +471,8 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
const venueBackConfig = { const venueBackConfig = {
...venueBaseConfig, ...venueBaseConfig,
venueImage: data.venueImages?.[1], venueImage: data.venueImages?.[1],
venueImgX: scale * 400 * dpr, venueImgX: scale * 400,
venueImgY: scale * 35 * dpr, venueImgY: scale * 35,
rotation: scale * -10, // 旋转-10度 rotation: scale * -10, // 旋转-10度
} }
await drawVenueImages(ctx, venueBackConfig, canvasNode) await drawVenueImages(ctx, venueBackConfig, canvasNode)
@@ -512,11 +507,11 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
// 绘制"单打"标签 // 绘制"单打"标签
const danDaX = scale * 100 const danDaX = scale * 100
const danDaY = scale * 196 const danDaY = scale * 196
const danDaHeight = scale * 40 * dpr const danDaHeight = scale * 40
const danDaRadius = scale * 20 * dpr const danDaRadius = scale * 20
const danDaFontSize = scale * 22 * dpr const danDaFontSize = scale * 22
// 根据内容动态计算标签宽度(左右内边距) // 根据内容动态计算标签宽度(左右内边距)
const danDaPaddingX = scale * 16 * dpr const danDaPaddingX = scale * 16
setFont2D(ctx, danDaFontSize) setFont2D(ctx, danDaFontSize)
const danDaTextWidth = ctx.measureText(data.gameType).width const danDaTextWidth = ctx.measureText(data.gameType).width
const danDaWidth = danDaTextWidth + danDaPaddingX * 2 const danDaWidth = danDaTextWidth + danDaPaddingX * 2
@@ -527,11 +522,11 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr保持视觉间距 const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr保持视觉间距
const skillX = danDaX + danDaWidth + labelGap const skillX = danDaX + danDaWidth + labelGap
const skillY = scale * 196 const skillY = scale * 196
const skillHeight = scale * 40 * dpr const skillHeight = scale * 40
const skillRadius = scale * 20 * dpr const skillRadius = scale * 20
const skillFontSize = scale * 22 * dpr const skillFontSize = scale * 22
// 根据内容动态计算技能标签宽度 // 根据内容动态计算技能标签宽度
const skillPaddingX = scale * 20 * dpr const skillPaddingX = scale * 20
setFont2D(ctx, skillFontSize) setFont2D(ctx, skillFontSize)
const skillTextWidth = ctx.measureText(data.skillLevel).width const skillTextWidth = ctx.measureText(data.skillLevel).width
const skillWidth = skillTextWidth + skillPaddingX * 2 const skillWidth = skillTextWidth + skillPaddingX * 2
@@ -541,7 +536,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
// 绘制日期时间 // 绘制日期时间
const dateX = danDaX const dateX = danDaX
const timeInfoY = infoStartY + infoSpacing const timeInfoY = infoStartY + infoSpacing
const timeInfoFontSize = scale * 24 * dpr const timeInfoFontSize = scale * 24
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`, canvasNode) const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`, canvasNode)
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize) ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
@@ -549,17 +544,18 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD') drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
// 绘制时间(黑色) // 绘制时间(黑色)
const timeX = textX + ctx.measureText(data.gameDate).width + 10 * dpr const timeX = textX + ctx.measureText(data.gameDate).width + scale * 10
// drawText(ctx, data.gameTime, timeX, timeInfoY + 8, 300, timeInfoFontSize, '#000000') // drawText(ctx, data.gameTime, timeX, timeInfoY + 8, 300, timeInfoFontSize, '#000000')
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000') drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
// 绘制地点 // 绘制地点
const locationInfoY = infoStartY + infoSpacing * 2 const locationInfoY = infoStartY + infoSpacing * 2
const locationFontSize = scale * 22 * dpr const locationFontSize = scale * 22
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`, canvasNode) const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`, canvasNode)
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize) ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000') drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
ctx.restore()
// 绘制完成调用draw方法 // 绘制完成调用draw方法
console.log('开始调用ctx.draw()') console.log('开始调用ctx.draw()')
const doExport = () => { const doExport = () => {
@@ -649,12 +645,9 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
if (data && data.node) { if (data && data.node) {
const canvas = data.node const canvas = data.node
const context = canvas.getContext('2d') const context = canvas.getContext('2d')
// DPR 缩放,提升清晰度(当前 dpr = 1 也可正常显示) // 仅设置物理像素尺寸,绘制阶段统一在 drawShareCard 中做 ctx.scale(dpr, dpr)
const sys = (Taro as any).getSystemInfoSync?.() || {} canvas.width = canvasWidth * dpr
const ratio = sys.pixelRatio || 1 canvas.height = canvasHeight * dpr
canvas.width = canvasWidth * ratio
canvas.height = canvasHeight * ratio
context.scale(ratio, ratio)
setCanvasNode(canvas) setCanvasNode(canvas)
setCtx2d(context) setCtx2d(context)
setIs2dCtx(true) setIs2dCtx(true)

View File

@@ -743,9 +743,12 @@ function Result() {
rid && !Number.isNaN(Number(rid)) rid && !Number.isNaN(Number(rid))
? `/other_pages/ntrp-evaluate/index?stage=${StageType.RESULT}&id=${rid}&from_share=1` ? `/other_pages/ntrp-evaluate/index?stage=${StageType.RESULT}&id=${rid}&from_share=1`
: `/other_pages/ntrp-evaluate/index?stage=${StageType.INTRO}`; : `/other_pages/ntrp-evaluate/index?stage=${StageType.INTRO}`;
const shareNickname = fromShare
? result?.sharer_nickname || "好友"
: (userInfo as any)?.nickname || "好友";
return { return {
title: result?.ntrp_level title: result?.ntrp_level
? `来看看 NTRP ${formatNtrpDisplay(result.ntrp_level)} 的测评结果` ? `来看看 ${shareNickname} 的测评结果`
: "来测一测你的NTRP等级吧", : "来测一测你的NTRP等级吧",
imageUrl: result?.level_img || undefined, imageUrl: result?.level_img || undefined,
path: sharePath, path: sharePath,

View File

@@ -87,7 +87,7 @@ const drawLabel = (ctx: any, x: number, y: number, width: number, height: number
// 绘制边框 // 绘制边框
ctx.strokeStyle = borderColor ctx.strokeStyle = borderColor
ctx.lineWidth = 1 * dpr ctx.lineWidth = 1
ctx.stroke() ctx.stroke()
// 绘制文字 // 绘制文字
@@ -142,14 +142,14 @@ const loadImage = (src: string): Promise<any> => {
const drawSVGPathToCanvas = (ctx: any) => { const drawSVGPathToCanvas = (ctx: any) => {
// 设置绘制样式 // 设置绘制样式
ctx.strokeStyle = '#00E5AD'; ctx.strokeStyle = '#00E5AD';
ctx.lineWidth = scale * 3 * dpr; ctx.lineWidth = scale * 3;
ctx.lineCap = 'round'; ctx.lineCap = 'round';
ctx.lineJoin = 'round'; ctx.lineJoin = 'round';
ctx.save(); ctx.save();
// 移动到指定位置并缩放 // 移动到指定位置并缩放
ctx.translate(scale * 200 * dpr, scale * 90 * dpr); ctx.translate(scale * 200, scale * 90);
const scaleValue = 0.8 const scaleValue = 0.8
ctx.scale(scaleValue, scaleValue); ctx.scale(scaleValue, scaleValue);
@@ -372,43 +372,36 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
console.log('开始绘制分享卡片...') console.log('开始绘制分享卡片...')
try { try {
// 设置Canvas的实际尺寸使用dpr确保高清显示 // 统一逻辑坐标:先按 dpr 缩放,再使用设计坐标绘制
const canvasWidthPx = canvasWidth * dpr const canvasWidthPx = canvasWidth * dpr
const canvasHeightPx = canvasHeight * dpr const canvasHeightPx = canvasHeight * dpr
// 清空画布
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx) ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
ctx.save()
ctx.scale(dpr, dpr)
console.log('画布已清空') console.log('画布已清空')
// 如果dpr大于2进行缩放处理以避免内容过大
if (dpr > 2) {
const scale = 2 / dpr
ctx.scale(scale, scale)
console.log('应用缩放:', scale)
}
// 绘制背景 - 渐变色 已完成 // 绘制背景 - 渐变色 已完成
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeightPx) const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight)
gradient.addColorStop(0, '#BFFFEF') gradient.addColorStop(0, '#BFFFEF')
gradient.addColorStop(1, '#F2FFFC') gradient.addColorStop(1, '#F2FFFC')
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, 0, canvasWidthPx, canvasHeightPx) ctx.fillRect(0, 0, canvasWidth, canvasHeight)
console.log('背景绘制完成') console.log('背景绘制完成')
// 绘制背景条纹 已完成 // 绘制背景条纹 已完成
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)' ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
ctx.lineWidth = 2 ctx.lineWidth = 2
for (let i = 0; i < canvasWidthPx; i += 4) { for (let i = 0; i < canvasWidth; i += 4) {
ctx.beginPath() ctx.beginPath()
ctx.moveTo(i, 0) ctx.moveTo(i, 0)
ctx.lineTo(i, canvasHeightPx) ctx.lineTo(i, canvasHeight)
ctx.stroke() ctx.stroke()
} }
// 绘制用户头像(左上角) 已完成 // 绘制用户头像(左上角) 已完成
const avatarSize = scale * 32 * dpr // 32px * dpr const avatarSize = scale * 32
const avatarX = scale * 35 * dpr // 距离左侧35px const avatarX = scale * 35
const avatarY = scale * 35 * dpr // 距离顶部35px const avatarY = scale * 35
try { try {
const avatarPath = await loadImage(data.userAvatar) const avatarPath = await loadImage(data.userAvatar)
@@ -428,22 +421,22 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
} }
// 绘制用户昵称 已完成 // 绘制用户昵称 已完成
const nicknameX = avatarX + avatarSize + 8 * dpr // 距离头像8px const nicknameX = avatarX + avatarSize + scale * 8
const nicknameY = avatarY + (avatarSize - 18 * dpr) / 2 // 与头像水平居中对齐 const nicknameY = avatarY + (avatarSize - scale * 18) / 2
const nicknameFontSize = scale * 18 * dpr const nicknameFontSize = scale * 18
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900') drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
// 绘制"邀你加入球局"文案 // 绘制"邀你加入球局"文案
const inviteX = scale * 35 * dpr // 距离画布左侧35px const inviteX = scale * 35
const inviteY = scale * 100 * dpr // 距离画布顶部79px const inviteY = scale * 100
const inviteFontSize = scale * 44 * dpr const inviteFontSize = scale * 44
// 绘制"邀你加入" // 绘制"邀你加入"
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900') drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
// 绘制"球局"特殊样式 // 绘制"球局"特殊样式
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + 4 * dpr const qiuJuX = inviteX + ctx.measureText('邀你加入').width + scale * 4
const qiuJuFontSize = scale * 44 * dpr const qiuJuFontSize = scale * 44
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900') drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
// 测试绘制网络图片 // 测试绘制网络图片
@@ -451,12 +444,12 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
// 绘制球员图片(右上角)已完成 // 绘制球员图片(右上角)已完成
let venueBaseConfig = { let venueBaseConfig = {
venueImgX: scale * 340 * dpr, venueImgX: scale * 340,
venueImgY: scale * 35 * dpr, venueImgY: scale * 35,
rotation: scale * -8, // 旋转-8度 rotation: scale * -8, // 旋转-8度
venueImgSize: scale * 124 * dpr, venueImgSize: scale * 124,
borderRadius: scale * 24 * dpr, borderRadius: scale * 24,
padding: scale * 4 * dpr, padding: scale * 4,
venueImage: data.venueImages?.[0] venueImage: data.venueImages?.[0]
} }
@@ -465,8 +458,8 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
const venueBackConfig = { const venueBackConfig = {
...venueBaseConfig, ...venueBaseConfig,
venueImage: data.venueImages?.[1], venueImage: data.venueImages?.[1],
venueImgX: scale * 400 * dpr, venueImgX: scale * 400,
venueImgY: scale * 35 * dpr, venueImgY: scale * 35,
rotation: scale * -10, // 旋转-10度 rotation: scale * -10, // 旋转-10度
} }
await drawVenueImages(ctx, venueBackConfig) await drawVenueImages(ctx, venueBackConfig)
@@ -501,11 +494,11 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
// 绘制"单打"标签 // 绘制"单打"标签
const danDaX = scale * 100 const danDaX = scale * 100
const danDaY = scale * 196 const danDaY = scale * 196
const danDaHeight = scale * 40 * dpr const danDaHeight = scale * 40
const danDaRadius = scale * 20 * dpr const danDaRadius = scale * 20
const danDaFontSize = scale * 22 * dpr const danDaFontSize = scale * 22
// 根据内容动态计算标签宽度(左右内边距) // 根据内容动态计算标签宽度(左右内边距)
const danDaPaddingX = scale * 16 * dpr const danDaPaddingX = scale * 16
setFont2D(ctx, danDaFontSize) setFont2D(ctx, danDaFontSize)
const danDaTextWidth = ctx.measureText(data.gameType).width const danDaTextWidth = ctx.measureText(data.gameType).width
const danDaWidth = danDaTextWidth + danDaPaddingX * 2 const danDaWidth = danDaTextWidth + danDaPaddingX * 2
@@ -516,11 +509,11 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr保持视觉间距 const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr保持视觉间距
const skillX = danDaX + danDaWidth + labelGap const skillX = danDaX + danDaWidth + labelGap
const skillY = scale * 196 const skillY = scale * 196
const skillHeight = scale * 40 * dpr const skillHeight = scale * 40
const skillRadius = scale * 20 * dpr const skillRadius = scale * 20
const skillFontSize = scale * 22 * dpr const skillFontSize = scale * 22
// 根据内容动态计算技能标签宽度 // 根据内容动态计算技能标签宽度
const skillPaddingX = scale * 20 * dpr const skillPaddingX = scale * 20
setFont2D(ctx, skillFontSize) setFont2D(ctx, skillFontSize)
const skillTextWidth = ctx.measureText(data.skillLevel).width const skillTextWidth = ctx.measureText(data.skillLevel).width
const skillWidth = skillTextWidth + skillPaddingX * 2 const skillWidth = skillTextWidth + skillPaddingX * 2
@@ -530,7 +523,7 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
// 绘制日期时间 // 绘制日期时间
const dateX = danDaX const dateX = danDaX
const timeInfoY = infoStartY + infoSpacing const timeInfoY = infoStartY + infoSpacing
const timeInfoFontSize = scale * 24 * dpr const timeInfoFontSize = scale * 24
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`) const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`)
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize) ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
@@ -538,15 +531,16 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD') drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
// 绘制时间(黑色) // 绘制时间(黑色)
const timeX = textX + ctx.measureText(data.gameDate).width + 10 * dpr const timeX = textX + ctx.measureText(data.gameDate).width + scale * 10
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000') drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
// 绘制地点 // 绘制地点
const locationInfoY = infoStartY + infoSpacing * 2 const locationInfoY = infoStartY + infoSpacing * 2
const locationFontSize = scale * 22 * dpr const locationFontSize = scale * 22
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`) const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`)
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize) ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000') drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
ctx.restore()
try { try {
const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null
if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') { if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') {