|
|
- <template>
- <uv-popup
- ref="popup"
- :overlayOpacity="0.6"
- mode="center"
- bgColor="none"
- :zIndex="1000000"
- @change="onPopupChange"
- >
- <view class="popup__view">
- <view class="canvas" style="width: 566rpx; height: 1060rpx; overflow: hidden;">
- <canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas>
- </view>
-
- <button class="btn" @click="saveImg">
- <view class="content">保存到相册</view>
- </button>
- </view>
- </uv-popup>
- </template>
-
-
- <script>
- export default {
- data() {
- return {
- wxCodeImage: '',
- baseUrl: 'https://image.hhlm1688.com/',
- canvas: {},
- retry: 10,
- }
- },
- async onLoad() {
- },
- methods: {
- open() {
- this.retry = 10
- this.$refs.popup.open();
- },
- close() {
- this.$refs.popup.close();
- },
- async fetchQrCode(path) {
- // todo: delete
- this.wxCodeImage = 'https://uploadfile.bizhizu.cn/up/e3/64/e0/e364e0f7f6af11f11abdafc22d17b15c.jpg'
- return
- try {
- this.wxCodeImage = (await this.$fetch('getInviteCode', { path }))?.url
-
- } catch (err) {
-
- }
- },
- // 生成有圆角的矩形
- drawBg(ctx, x, y, width, height, radius) {
- ctx.beginPath();
- ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
- ctx.lineTo(width - radius + x, y);
- ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
- ctx.lineTo(width + x, height + y - radius);
- ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
- ctx.lineTo(radius + x, height + y);
- ctx.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
- ctx.closePath();
- ctx.fillStyle = '#fff'
- ctx.fill()
- },
- drawCoverImg(canvas, ctx, x, y, width, height, radius, lineWidth) {
- return new Promise(resolve => {
- // 海报图片
- const paperImage = canvas.createImage()
- console.log('paperImage', paperImage)
- // todo: fetch
- paperImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
- paperImage.onload = () => {
- console.log('paperImage onload')
-
- ctx.beginPath();
- ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
- ctx.lineTo(width - radius + x, y);
- ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
- ctx.lineTo(width + x, height + y);
- ctx.lineTo(x, height + y);
- ctx.closePath();
- ctx.lineWidth = lineWidth;
- ctx.strokeStyle = '#F8F8F8';
- ctx.stroke();
-
- ctx.clip();
-
- ctx.drawImage(paperImage, x, y, width, height)
-
- resolve()
- }
- })
- },
- drawContentBg(ctx, x, y, width, height, radius) {
-
- ctx.beginPath();
- // ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
- ctx.moveTo(x, y);
- ctx.lineTo(width + x, y);
- ctx.lineTo(width + x, height + y - radius);
- ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
- ctx.lineTo(radius + x, height + y);
- ctx.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
- ctx.closePath();
-
- let gradient = ctx.createLinearGradient(x, y, x, y + height);
- gradient.addColorStop('0', '#DAF3FF');
- gradient.addColorStop('0.2', '#FBFEFF');
- gradient.addColorStop('1.0', '#FBFEFF');
- ctx.fillStyle = gradient
- ctx.fill()
- },
- drawAvatar(canvas, ctx, x, y, r) {
- console.log('drawAvatar', 'x', x, 'y', y, 'r', r)
-
- return new Promise(resolve => {
- // 头像图片
- const avatarImage = canvas.createImage()
- // todo: fetch
- avatarImage.src = 'https://i1.hdslb.com/bfs/archive/c0101b4ce06e6bdda803728408e79c8f8b8d0725.jpg'
- avatarImage.onload = () => {
- console.log('avatarImage onload')
-
- ctx.beginPath();
- console.log('arc', 'x', x + r, 'y', y + r, 'r', r)
- ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
- ctx.clip();
-
- const size = r*2
- console.log('size', size)
- ctx.drawImage(avatarImage, x, y, size, size)
-
- resolve()
- }
- })
- },
- drawMultilineText(ctx, text, x, y, maxWidth, lineHeight) {
- console.log('drawMultilineText', 'x', x, 'y', y)
- let line = '';
-
- for (let n = 0; n < text.length; n++) {
- const testLine = line + text[n];
- const metrics = ctx.measureText(testLine);
- const testWidth = metrics.width;
- if (testWidth > maxWidth && n > 0) {
- ctx.fillText(line, x, y);
- console.log(n, 'line', line, 'x', x, 'y', y)
- line = text[n];
- y += lineHeight;
- } else {
- line = testLine;
- }
- }
- console.log('line', line, 'x', x, 'y', y)
- ctx.fillText(line, x, y);
- },
- drawQrCodeImg(canvas, ctx, x, y, size) {
- return new Promise(resolve => {
- //二维码图片
- const coderImage = canvas.createImage()
- coderImage.src = this.wxCodeImage
- coderImage.onload = () => {
- console.log('coderImage onload')
- ctx.drawImage(coderImage, x, y, size, size)
-
- resolve()
- }
- })
- },
- draw() {
-
- wx.createSelectorQuery().in(this)
- .select('#myCanvas') // 绘制的canvas的id
- .fields({
- node: true,
- size: true
- })
- .exec(async (res) => {
- console.log('res', res)
- if (!res?.[0]?.node) {
- if (!this.retry) {
- console.log('retry fail')
- return
- }
- console.log('retry')
- this.retry -= 1
- setTimeout(() => {
- this.draw()
- }, 200)
- return
- }
- const canvas = res[0].node
- // 渲染上下文
- const ctx = canvas.getContext('2d')
- // Canvas 画布的实际绘制宽高
- const width = res[0].width
- const height = res[0].height
- // 初始化画布大小
- const dpr = wx.getWindowInfo().pixelRatio
-
- //根据dpr调整
- // dpr 2 4
- // 3 6
- console.log("--dpr", dpr)
- canvas.width = width * dpr
- canvas.height = height * dpr
-
- let Ratio = canvas.width / 566
-
- this.canvas = canvas
- ctx.scale(dpr, dpr)
- ctx.clearRect(0, 0, width, height)
-
- ctx.fillStyle = 'transparent'
- ctx.fillRect(0, 0, canvas.width, canvas.height)
-
- ctx.save()
-
- let radius = 48 * Ratio / dpr
- let w = 566 * Ratio / dpr
- let h = 1060 * Ratio / dpr
- this.drawBg(ctx, 0, 0, w, h, radius)
-
- ctx.restore();
- ctx.save()
-
- let lineWidth = 2 * Ratio / dpr
- let x = lineWidth
- let y = lineWidth
- w = 566 * Ratio / dpr - lineWidth * 2
- h = 400 * Ratio / dpr - lineWidth * 2
- await this.drawCoverImg(canvas, ctx, x, y, w, h, radius, lineWidth)
-
- ctx.restore();
- ctx.save()
-
- x = lineWidth
- y = 400 * Ratio / dpr + lineWidth
- h = 660 * Ratio / dpr - lineWidth * 2
- this.drawContentBg(ctx, x, y, w, h, radius, lineWidth)
-
- ctx.restore();
- ctx.save()
-
- radius = Math.floor(27 * Ratio / dpr)
- x = Math.floor(40 * Ratio / dpr)
- y = Math.floor(440 * Ratio / dpr)
- await this.drawAvatar(canvas, ctx, x, y, radius)
-
- ctx.restore();
- ctx.save()
-
- let text = '战斗世界'
- let maxWidth = 220 * Ratio / dpr
- let lineHeight = 17 * Ratio / dpr
- x = 100 * Ratio / dpr
- y = 474 * Ratio / dpr
- ctx.font = "normal normal normal 11px normal";
- ctx.fillStyle = "#7D7D7D";
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
-
- ctx.restore();
- ctx.save()
-
- maxWidth = 560 * Ratio / dpr
- lineHeight = 60 * Ratio / dpr
- ctx.font = "normal normal 600 16px normal";
- ctx.fillStyle = "#181818";
- text = '邀请您'
- x = 40 * Ratio / dpr
- y = 564 * Ratio / dpr
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
- y += lineHeight
- text = '探索新世界,开启研学之旅!'
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
-
- ctx.restore();
- ctx.save()
-
- text = '是否渴望一场充满知识与乐趣的冒险?现在,我们诚挚邀请你加入我们的研学小程序,开启一场别开生面的学习之旅!'
- maxWidth = 486 * Ratio / dpr
- lineHeight = 30 * Ratio / dpr
- ctx.font = "normal normal normal 10px normal";
- ctx.fillStyle = "#7D7D7D";
- x = 40 * Ratio / dpr
- y = 690 * Ratio / dpr
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
-
- ctx.restore();
- ctx.save()
-
- // 设置虚线样式
- ctx.setLineDash([4, 4]); // 第一个参数是实线长度, 第二个参数是间隔长度
- ctx.lineDashOffset = 2; // 设置虚线的起始偏移量
- ctx.lineWidth = lineWidth;
- ctx.strokeStyle = '#DADADA';
- // 开始绘制
- ctx.beginPath();
- x = 40 * Ratio / dpr
- y = 778 * Ratio / dpr
- ctx.moveTo(x, y);
- x += 486 * Ratio / dpr
- ctx.lineTo(x, y);
- ctx.stroke();
-
- ctx.restore();
- ctx.save()
-
- maxWidth = 250 * Ratio / dpr
- lineHeight = 44 * Ratio / dpr
- ctx.font = "normal normal 600 13px normal";
- ctx.fillStyle = "#181818";
- text = '立即加入我们,'
- x = 40 * Ratio / dpr
- y = 879 * Ratio / dpr
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
- text = '开启你的研学之旅!'
- y += lineHeight
- this.drawMultilineText(ctx, text, x, y, maxWidth, lineHeight)
-
- ctx.restore();
- ctx.save()
-
- x = 316 * Ratio / dpr
- y = 810 * Ratio / dpr
- let size = 210 * Ratio / dpr
- await this.drawQrCodeImg(canvas, ctx, x, y, size)
-
- uni.hideLoading()
-
- })
-
- },
- async init() {
- uni.showLoading({
- title: '加载中...'
- });
-
- await this.fetchQrCode()
- uni.hideLoading();
-
- uni.showLoading({
- title: "拼命绘画中..."
- })
- this.draw()
- },
- saveImg() {
- this.$authorize('scope.writePhotosAlbum').then((res) => {
- this.imgApi()
- })
- },
- imgApi() {
- uni.showLoading({
- title: '保存中...'
- });
- wx.canvasToTempFilePath({
- x: 0,
- y: 0,
- width: this.canvas.width,
- height: this.canvas.height,
- canvas: this.canvas,
- success: (res) => {
- let tempFilePath = res.tempFilePath;
- this.saveImgToPhone(tempFilePath)
- },
- fail: (err) => {
- console.log('--canvasToTempFilePath--fail', err)
- uni.hideLoading();
- }
- }, this);
-
- },
- saveImgToPhone(image) {
- /* 获取图片的信息 */
- uni.getImageInfo({
- src: image,
- success: function(image) {
- /* 保存图片到手机相册 */
- uni.saveImageToPhotosAlbum({
- filePath: image.path,
- success: function() {
- uni.showModal({
- title: '保存成功',
- content: '图片已成功保存到相册',
- showCancel: false
- });
- },
- complete(res) {
- console.log(res);
- uni.hideLoading();
- }
- });
- }
- });
- },
- onPopupChange(e) {
- if (!e.show) {
- return
- }
-
- this.init()
- },
- },
- }
- </script>
-
- <style scoped lang="scss">
- .canvas {
- border-radius: 48rpx;
- }
-
- .btn {
- margin-top: 32rpx;
- width: 100%;
- padding: 22rpx 0;
- box-sizing: border-box;
- font-family: PingFang SC;
- font-weight: 500;
- font-size: 36rpx;
- line-height: 1.4;
- color: #FFFFFF;
- background: linear-gradient(to right, #21FEEC, #019AF9);
- border: 2rpx solid #00A9FF;
- border-radius: 41rpx;
- }
- </style>
|