diff --git a/src/game_pages/sharePoster/index.tsx b/src/game_pages/sharePoster/index.tsx
index 3f32c63..2c6211c 100644
--- a/src/game_pages/sharePoster/index.tsx
+++ b/src/game_pages/sharePoster/index.tsx
@@ -4,6 +4,7 @@ import { View, Image, Text, Button } from "@tarojs/components";
import Taro, { useRouter } from "@tarojs/taro";
import classnames from "classnames";
import dayjs from "dayjs";
+import "dayjs/locale/zh-cn";
import { generatePosterImage, base64ToTempFilePath, delay } from "@/utils";
import { withAuth } from "@/components";
import GeneralNavbar from "@/components/GeneralNavbar";
@@ -17,6 +18,8 @@ import { genNTRPRequirementText } from "@/utils/helper";
import { waitForAuthInit } from "@/utils/authInit";
import styles from "./index.module.scss";
+dayjs.locale("zh-cn");
+
function SharePoster(props) {
const [url, setUrl] = useState("");
const { fetchUserInfo } = useUserActions();
@@ -63,8 +66,9 @@ function SharePoster(props) {
playType: play_type,
ntrp: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`,
mainCoursal:
- image_list[0] ||
- "https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png",
+ image_list[0] && image_list[0].startsWith("http")
+ ? image_list[0]
+ : "https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png",
nickname,
avatarUrl: avatar_url,
title,
@@ -84,10 +88,7 @@ function SharePoster(props) {
return (
<>
-
+
{url && (
diff --git a/src/utils/genPoster.ts b/src/utils/genPoster.ts
index c7b5fb7..a690046 100644
--- a/src/utils/genPoster.ts
+++ b/src/utils/genPoster.ts
@@ -3,6 +3,8 @@ import Taro from "@tarojs/taro";
// const qrCodeUrl =
// "https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/5e013195-fc79-4082-bf06-9aa79aea65ae.png";
+const bgUrl = "https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/5e2c85ab-fb0c-4026-974d-1e0725181542.png";
+
const ringUrl =
"https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/b635164f-ecec-434a-a00b-69614a918f2f.png";
@@ -64,6 +66,8 @@ function loadImage(canvas: any, src: string): Promise {
});
}
+const deg2rad = d => d * Math.PI / 180;
+
/** 圆角矩形渐变 */
function roundRectGradient(
ctx: any,
@@ -131,6 +135,57 @@ async function drawCoverImage(
ctx.restore();
}
+/** 绘制 cover 图片(支持圆角 + 旋转) */
+async function drawRotateCoverImage(
+ ctx: any,
+ canvas: any,
+ src: string,
+ img: any,
+ x: number,
+ y: number,
+ w: number,
+ h: number,
+ r = 0,
+ rotate = 0 // 旋转角度(弧度)
+) {
+ const { width, height } = await getImageWh(src);
+ const scale = Math.max(w / width, h / height);
+ const newW = width * scale;
+ const newH = height * scale;
+ const offsetX = x + (w - newW) / 2;
+ const offsetY = y + (h - newH) / 2;
+
+ ctx.save();
+
+ // 以 cover 区域中心为旋转点
+ const cx = x + w / 2;
+ const cy = y + h / 2;
+ ctx.translate(cx, cy);
+ ctx.rotate(rotate);
+ ctx.translate(-cx, -cy);
+
+ // ------- clipping(注意要在旋转变换之后做 path)-------
+ if (r > 0) {
+ ctx.beginPath();
+ ctx.moveTo(x + r, y);
+ ctx.lineTo(x + w - r, y);
+ ctx.arcTo(x + w, y, x + w, y + r, r);
+ ctx.lineTo(x + w, y + h - r);
+ ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
+ ctx.lineTo(x + r, y + h);
+ ctx.arcTo(x, y + h, x, y + h - r, r);
+ ctx.lineTo(x, y + r);
+ ctx.arcTo(x, y, x + r, y, r);
+ ctx.closePath();
+ ctx.clip();
+ }
+
+ // 绘制 cover
+ ctx.drawImage(img, offsetX, offsetY, newW, newH);
+
+ ctx.restore();
+}
+
/** 圆角矩形 */
function roundRect(
ctx: any,
@@ -156,9 +211,47 @@ function roundRect(
ctx.fill();
}
+/** 圆角矩形(支持旋转) */
+function roundRotateRect(
+ ctx: any,
+ x: number,
+ y: number,
+ w: number,
+ h: number,
+ r: number,
+ fillStyle: string,
+ rotate: number = 0 // 弧度
+) {
+ ctx.save();
+
+ // 以圆角矩形中心作为旋转点
+ const cx = x + w / 2;
+ const cy = y + h / 2;
+
+ ctx.translate(cx, cy);
+ ctx.rotate(rotate);
+ ctx.translate(-cx, -cy);
+
+ ctx.beginPath();
+ ctx.moveTo(x + r, y);
+ ctx.lineTo(x + w - r, y);
+ ctx.arcTo(x + w, y, x + w, y + r, r);
+ ctx.lineTo(x + w, y + h - r);
+ ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
+ ctx.lineTo(x + r, y + h);
+ ctx.arcTo(x, y + h, x, y + h - r, r);
+ ctx.lineTo(x, y + r);
+ ctx.arcTo(x, y, x + r, y, r);
+ ctx.closePath();
+
+ ctx.fillStyle = fillStyle;
+ ctx.fill();
+ ctx.restore();
+}
+
/** 绘制标签 */
function drawTag(ctx: any, text: string, x: number, y: number) {
- ctx.font = "22px sans-serif";
+ ctx.font = "600 22px sans-serif";
const padding = 12;
const textWidth = ctx.measureText(text).width;
roundRect(ctx, x, y, textWidth + padding * 2, 40, 20, "#fff");
@@ -212,26 +305,42 @@ export async function generatePosterImage(data: any): Promise {
// 背景渐变
roundRectGradient(ctx, 0, 0, width, height, 24, "#BFFFEF", "#F2FFFC");
+ const bgImg = await loadImage(canvas, bgUrl);
+ ctx.drawImage(bgImg, 0, 0, width, height);
+
+ roundRotateRect(ctx, 70, 100, width - 140, width - 140, 20, '#fff', deg2rad(-6));
// 顶部图片
const mainImg = await loadImage(canvas, data.mainCoursal);
- await drawCoverImage(
+ await drawRotateCoverImage(
ctx,
canvas,
data.mainCoursal,
mainImg,
- 10,
- 10,
- width - 20,
- width - 20,
- 20
+ 75,
+ 105,
+ width - 150,
+ width - 150,
+ 20,
+ deg2rad(-6),
);
+ // await drawCoverImage(
+ // ctx,
+ // canvas,
+ // data.mainCoursal,
+ // mainImg,
+ // 10,
+ // 10,
+ // width - 20,
+ // width - 20,
+ // 20
+ // );
// 标签
- let left = drawTag(ctx, data.playType, 18, 18);
- drawTag(ctx, data.ntrp, left + 4, 18);
+ let left = drawTag(ctx, data.playType, 20, 20);
+ drawTag(ctx, data.ntrp, left + 8, 20);
let top = width - 10 + 16;
- left = 16;
+ left = 20;
// 用户头像
const avatarImg = await loadImage(canvas, data.avatarUrl);
@@ -246,7 +355,7 @@ export async function generatePosterImage(data: any): Promise {
top += 40;
// 用户名 + 邀请
- ctx.fillStyle = "#333";
+ ctx.fillStyle = "#000";
ctx.font = "bold 28px sans-serif";
const nickNameText = `${data.nickname} 邀你加入`;
ctx.fillText(nickNameText, left, top);
@@ -258,16 +367,16 @@ export async function generatePosterImage(data: any): Promise {
const ringImg = await loadImage(canvas, ringUrl);
ctx.drawImage(ringImg, left - 10, top - 30, 80, 36);
- left = 16;
+ left = 20;
top += 60;
// 活动标题
- ctx.fillStyle = "#333";
+ ctx.fillStyle = "#000";
ctx.font = "bold 34px sans-serif";
let r = drawTextWrap(ctx, data.title, left, top, width - 32, 40);
- top = r.top + 40;
- left = 16;
+ top = r.top + 30;
+ left = 20;
const dateImg = await loadImage(canvas, dateIcon);
await drawCoverImage(
@@ -279,34 +388,34 @@ export async function generatePosterImage(data: any): Promise {
top,
40,
40,
- 8
+ 12
);
- left += 40 + 8;
+ left += 40 + 16;
top += 30;
- ctx.font = "26px sans-serif";
+ ctx.font = "500 26px sans-serif";
ctx.fillStyle = "#00B578";
ctx.fillText(data.date, left, top);
textW = ctx.measureText(data.date).width;
left += 8 + textW;
- ctx.fillStyle = "#333";
+ ctx.fillStyle = "#000";
ctx.fillText(data.time, left, top);
- left = 16;
+ left = 20;
top += 24;
const mapImg = await loadImage(canvas, mapIcon);
- await drawCoverImage(ctx, canvas, mapIcon, mapImg, left, top, 40, 40, 8);
+ await drawCoverImage(ctx, canvas, mapIcon, mapImg, left, top, 40, 40, 12);
- left += 40 + 8;
+ left += 40 + 16;
top += 30;
- ctx.fillStyle = "#666";
- ctx.font = "26px sans-serif";
+ ctx.fillStyle = "#000";
+ ctx.font = "500 26px sans-serif";
r = drawTextWrap(ctx, data.locationName, left, top, width - 32 - left, 34);
- left = 16;
+ left = 20;
top = r.top + 60;
const logoWh = await getImageWh(logoText);
@@ -314,22 +423,23 @@ export async function generatePosterImage(data: any): Promise {
ctx.drawImage(
logoTextImg,
left,
- top,
+ // top,
+ height - logoWh.height - 30 - 30,
400,
400 / (logoWh.width / logoWh.height)
);
const qrImg = await loadImage(canvas, data.qrCodeUrl);
- roundRectGradient(ctx, width - 12 - 150, top - 50, 140, 140, 20, "#fff", "#fff")
- ctx.drawImage(qrImg, width - 12 - 145, top - 45, 130, 130);
+ // roundRectGradient(ctx, width - 12 - 150, height - 22 - 140, 140, 140, 20, "#fff", "#fff")
+ ctx.drawImage(qrImg, width - 22 - 100, height - 22 - 100 - 2, 100, 100);
- left = 16;
- top += 400 / (logoWh.width / logoWh.height) + 30;
+ left = 20;
+ // top += 400 / (logoWh.width / logoWh.height) + 30;
- ctx.fillStyle = "#333";
- ctx.font = "20px sans-serif";
- ctx.fillText("长按识别二维码,快来加入,有你就有场!", left, top);
+ ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
+ ctx.font = "400 20px sans-serif";
+ ctx.fillText("长按识别二维码,快来加入,有你就有场!", left, height - 30/* top */);
// 导出图片
const { tempFilePath } = await Taro.canvasToTempFilePath({