├── .editorconfig ├── .gitignore ├── README.md ├── assets └── image2d-tracking │ ├── home │ ├── bg.jpg │ ├── button.png │ ├── image.png │ ├── shadow.png │ └── text.png │ ├── loading.png │ ├── loading_bg.png │ ├── photo │ ├── poster-frame.png │ ├── retake.png │ └── save.png │ ├── progress.png │ ├── scan │ ├── bg.png │ ├── focus-frame.png │ └── id-picture.png │ ├── share.jpg │ └── take-photo.png ├── image2d-tracking ├── .eslintrc.js ├── app.js ├── app.json ├── app.wxss ├── components │ ├── loading │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── private-modal │ │ ├── private-modal.js │ │ ├── private-modal.json │ │ ├── private-modal.wxml │ │ └── private-modal.wxss │ ├── progress-bar │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── scanning │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── marker.png ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── photo │ │ ├── photo.js │ │ ├── photo.json │ │ ├── photo.wxml │ │ └── photo.wxss │ └── scene │ │ ├── scene.js │ │ ├── scene.json │ │ ├── scene.wxml │ │ └── scene.wxss ├── project.config.json ├── sitemap.json └── utils │ └── util.js ├── solar-divine-bird-mp ├── .gitignore ├── Kivicube │ └── pages │ │ ├── offline │ │ ├── offline.js │ │ ├── offline.json │ │ ├── offline.wxml │ │ └── offline.wxss │ │ └── online │ │ ├── online.js │ │ ├── online.json │ │ ├── online.wxml │ │ └── online.wxss ├── app.js ├── app.json ├── app.wxss ├── asset │ ├── back.png │ ├── bg.jpg │ ├── button.png │ ├── changecamera.png │ ├── close.png │ ├── location-icon.png │ ├── qrcode.jpg │ ├── qrcode.png │ ├── share.jpg │ ├── takephoto.png │ ├── watermark.png │ └── work.png ├── components │ ├── back-button │ │ ├── back-button.js │ │ ├── back-button.json │ │ ├── back-button.wxml │ │ ├── back-button.wxss │ │ └── images │ │ │ └── back.png │ ├── copyright │ │ ├── copyright.js │ │ ├── copyright.json │ │ ├── copyright.wxml │ │ ├── copyright.wxss │ │ └── images │ │ │ └── copyright.png │ ├── loading │ │ ├── images │ │ │ ├── loading-bird.png │ │ │ └── sun.png │ │ ├── loading.js │ │ ├── loading.json │ │ ├── loading.wxml │ │ └── loading.wxss │ ├── poster │ │ ├── poster.js │ │ ├── poster.json │ │ ├── poster.wxml │ │ └── poster.wxss │ ├── private-modal │ │ ├── private-modal.js │ │ ├── private-modal.json │ │ ├── private-modal.wxml │ │ └── private-modal.wxss │ ├── scan-tips │ │ ├── images │ │ │ ├── corner.png │ │ │ ├── phone.png │ │ │ └── work.png │ │ ├── scan-tips.js │ │ ├── scan-tips.json │ │ ├── scan-tips.wxml │ │ └── scan-tips.wxss │ ├── warning │ │ ├── images │ │ │ └── warning.png │ │ ├── warning.js │ │ ├── warning.json │ │ ├── warning.wxml │ │ └── warning.wxss │ └── work-detail │ │ ├── images │ │ └── close.png │ │ ├── work-detail.js │ │ ├── work-detail.json │ │ ├── work-detail.wxml │ │ └── work-detail.wxss ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── webview │ │ ├── webview.js │ │ ├── webview.json │ │ ├── webview.wxml │ │ └── webview.wxss ├── project.config.json ├── sitemap.json └── 识别图.jpg ├── tiger-year-red-envelopes-高级api ├── Kivicube │ └── pages │ │ └── exprience │ │ ├── exprience.js │ │ ├── exprience.json │ │ ├── exprience.wxml │ │ └── exprience.wxss ├── app.js ├── app.json ├── app.wxss ├── asset │ ├── 2022.png │ ├── button.png │ ├── custom-photo.png │ ├── fish.png │ ├── home-bg-short.jpg │ ├── home-bg.jpg │ ├── logo.png │ ├── poster-bg.png │ ├── qrcode.png │ ├── red-envelopes.png │ ├── share-red-envelopes-button.png │ ├── share.png │ ├── switch-camera.png │ └── tiger.png ├── components │ ├── back-button │ │ ├── back-button.js │ │ ├── back-button.json │ │ ├── back-button.wxml │ │ ├── back-button.wxss │ │ └── images │ │ │ └── back.png │ ├── loading │ │ ├── loading.js │ │ ├── loading.json │ │ ├── loading.wxml │ │ └── loading.wxss │ ├── poster │ │ ├── poster.js │ │ ├── poster.json │ │ ├── poster.wxml │ │ └── poster.wxss │ └── private-modal │ │ ├── private-modal.js │ │ ├── private-modal.json │ │ ├── private-modal.wxml │ │ └── private-modal.wxss ├── pages │ └── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── project.config.json └── sitemap.json └── tiger-year-red-envelopes ├── Kivicube └── pages │ └── exprience │ ├── exprience.js │ ├── exprience.json │ ├── exprience.wxml │ └── exprience.wxss ├── app.js ├── app.json ├── app.wxss ├── asset ├── 2022.png ├── button.png ├── fish.png ├── home-bg-short.jpg ├── home-bg.jpg ├── logo.png ├── poster-bg.png ├── qrcode.png ├── red-envelopes.png ├── share-red-envelopes-button.png ├── share.png └── tiger.png ├── components ├── back-button │ ├── back-button.js │ ├── back-button.json │ ├── back-button.wxml │ ├── back-button.wxss │ └── images │ │ └── back.png └── private-modal │ ├── private-modal.js │ ├── private-modal.json │ ├── private-modal.wxml │ └── private-modal.wxss ├── pages └── index │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── project.config.json └── sitemap.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | miniprogram_npm 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | project.private.config.json 25 | assets/package.json 26 | assets/package-lock.json 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/README.md -------------------------------------------------------------------------------- /assets/image2d-tracking/home/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/home/bg.jpg -------------------------------------------------------------------------------- /assets/image2d-tracking/home/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/home/button.png -------------------------------------------------------------------------------- /assets/image2d-tracking/home/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/home/image.png -------------------------------------------------------------------------------- /assets/image2d-tracking/home/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/home/shadow.png -------------------------------------------------------------------------------- /assets/image2d-tracking/home/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/home/text.png -------------------------------------------------------------------------------- /assets/image2d-tracking/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/loading.png -------------------------------------------------------------------------------- /assets/image2d-tracking/loading_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/loading_bg.png -------------------------------------------------------------------------------- /assets/image2d-tracking/photo/poster-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/photo/poster-frame.png -------------------------------------------------------------------------------- /assets/image2d-tracking/photo/retake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/photo/retake.png -------------------------------------------------------------------------------- /assets/image2d-tracking/photo/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/photo/save.png -------------------------------------------------------------------------------- /assets/image2d-tracking/progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/progress.png -------------------------------------------------------------------------------- /assets/image2d-tracking/scan/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/scan/bg.png -------------------------------------------------------------------------------- /assets/image2d-tracking/scan/focus-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/scan/focus-frame.png -------------------------------------------------------------------------------- /assets/image2d-tracking/scan/id-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/scan/id-picture.png -------------------------------------------------------------------------------- /assets/image2d-tracking/share.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/share.jpg -------------------------------------------------------------------------------- /assets/image2d-tracking/take-photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/assets/image2d-tracking/take-photo.png -------------------------------------------------------------------------------- /image2d-tracking/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Eslint config file 3 | * Documentation: https://eslint.org/docs/user-guide/configuring/ 4 | * Install the Eslint extension before using this feature. 5 | */ 6 | module.exports = { 7 | env: { 8 | es6: true, 9 | browser: true, 10 | node: true, 11 | }, 12 | ecmaFeatures: { 13 | modules: true, 14 | }, 15 | parserOptions: { 16 | ecmaVersion: 2018, 17 | sourceType: "module", 18 | }, 19 | globals: { 20 | wx: true, 21 | App: true, 22 | Page: true, 23 | getCurrentPages: true, 24 | getApp: true, 25 | Component: true, 26 | requirePlugin: true, 27 | requireMiniProgram: true, 28 | }, 29 | // extends: 'eslint:recommended', 30 | rules: {}, 31 | }; 32 | -------------------------------------------------------------------------------- /image2d-tracking/app.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | App({ 3 | onLaunch() {}, 4 | 5 | globalData: { 6 | userInfo: null, 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /image2d-tracking/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": ["pages/index/index", "pages/scene/scene", "pages/photo/photo"], 3 | "window": { 4 | "backgroundTextStyle": "light", 5 | "navigationBarBackgroundColor": "#fff", 6 | "navigationBarTitleText": "Weixin", 7 | "navigationBarTextStyle": "black", 8 | "navigationStyle": "custom" 9 | }, 10 | "plugins": { 11 | "kivicube": { 12 | "version": "2.16.8", 13 | "provider": "wx3bbab3920eabccb2" 14 | } 15 | }, 16 | "__usePrivacyCheck__": true, 17 | "style": "v2", 18 | "sitemapLocation": "sitemap.json" 19 | } 20 | -------------------------------------------------------------------------------- /image2d-tracking/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | page { 3 | height: 100%; 4 | } 5 | .container { 6 | height: 100%; 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | justify-content: center; 11 | box-sizing: border-box; 12 | } 13 | -------------------------------------------------------------------------------- /image2d-tracking/components/loading/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | styleIsolation: "isolated", 4 | }, 5 | properties: { 6 | progress: { 7 | type: Number, 8 | value: 0, 9 | }, 10 | }, 11 | data: { 12 | percent: 0, 13 | posX: 0, 14 | posY: 0, 15 | }, 16 | observers: { 17 | progress() { 18 | const imageWidth = 58.67; 19 | const r = imageWidth / 2; 20 | const percent = parseInt(this.properties.progress); 21 | const posX = Math.sin((percent / 50) * Math.PI) * r; 22 | const posY = (1 - Math.cos((percent / 50) * Math.PI)) * r; 23 | this.setData({ 24 | posX, 25 | posY, 26 | percent, 27 | }); 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /image2d-tracking/components/loading/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": { 4 | "progress-bar": "../progress-bar/index" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /image2d-tracking/components/loading/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{percent}}% 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /image2d-tracking/components/loading/index.wxss: -------------------------------------------------------------------------------- 1 | .loading { 2 | height: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | background-color: rgba(239, 237, 255, 1); 8 | } 9 | 10 | .box { 11 | position: relative; 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | height: 92.27vw; 16 | width: 92.27vw; 17 | } 18 | 19 | .box-image { 20 | position: absolute; 21 | height: 100%; 22 | width: 100%; 23 | } 24 | 25 | .loading-image { 26 | position: absolute; 27 | width: 58.67vw; 28 | height: 58.67vw; 29 | z-index: 10; 30 | } 31 | 32 | .text { 33 | position: absolute; 34 | bottom: 2.93vw; 35 | font-size: 3.73vw; 36 | color: rgba(179, 145, 253, 1); 37 | } 38 | 39 | .progress-bar { 40 | position: absolute; 41 | display: flex; 42 | justify-content: center; 43 | align-items: center; 44 | width: calc(58.67vw + 5px); 45 | height: calc(58.67vw + 5px); 46 | z-index: 9; 47 | } 48 | 49 | .progress { 50 | position: absolute; 51 | top: calc(14.93vw * -0.5); 52 | left: calc(100% / 2 - (14.93vw * 0.5)); 53 | display: flex; 54 | justify-content: center; 55 | align-items: center; 56 | width: 14.93vw; 57 | height: 14.93vw; 58 | z-index: 1000; 59 | } 60 | 61 | .progress-text { 62 | position: absolute; 63 | font-size: 3.2vw; 64 | color: #ffffff; 65 | } 66 | -------------------------------------------------------------------------------- /image2d-tracking/components/private-modal/private-modal.js: -------------------------------------------------------------------------------- 1 | let privacyHandler; 2 | let privacyResolves = new Set(); 3 | let closeOtherPagePopUpHooks = new Set(); 4 | 5 | if (wx.onNeedPrivacyAuthorization) { 6 | wx.onNeedPrivacyAuthorization((resolve) => { 7 | console.log( 8 | "触发 onNeedPrivacyAuthorization", 9 | typeof privacyHandler === "function" 10 | ); 11 | if (typeof privacyHandler === "function") { 12 | privacyHandler(resolve); 13 | } 14 | }); 15 | } 16 | 17 | const closeOtherPagePopUp = (closePopUp) => { 18 | closeOtherPagePopUpHooks.forEach((hook) => { 19 | if (closePopUp !== hook) { 20 | hook(); 21 | } 22 | }); 23 | }; 24 | 25 | Component({ 26 | properties: { 27 | currentBtnText: { 28 | type: String, 29 | value: "同意", 30 | }, 31 | }, 32 | data: { 33 | innerShow: false, 34 | privacyContractName: "AR图像跟踪小程序隐私保护指引", 35 | }, 36 | lifetimes: { 37 | attached() { 38 | const closePopUp = () => { 39 | this.disPopUp(); 40 | }; 41 | privacyHandler = (resolve) => { 42 | privacyResolves.add(resolve); 43 | this.popUp(); 44 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 45 | closeOtherPagePopUp(closePopUp); 46 | }; 47 | 48 | this.closePopUp = closePopUp; 49 | closeOtherPagePopUpHooks.add(this.closePopUp); 50 | }, 51 | detached() { 52 | closeOtherPagePopUpHooks.delete(this.closePopUp); 53 | }, 54 | }, 55 | pageLifetimes: { 56 | show() { 57 | if (this.closePopUp) { 58 | privacyHandler = (resolve) => { 59 | privacyResolves.add(resolve); 60 | this.popUp(); 61 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 62 | closeOtherPagePopUp(this.closePopUp); 63 | }; 64 | } 65 | }, 66 | }, 67 | methods: { 68 | handleAgree() { 69 | this.disPopUp(); 70 | // 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行 (看page/index/index中的 wx.getClipboardData 和 wx.startCompass) 71 | privacyResolves.forEach((resolve) => { 72 | resolve({ 73 | event: "agree", 74 | buttonId: "agree-btn", 75 | }); 76 | }); 77 | privacyResolves.clear(); 78 | }, 79 | handleDisagree() { 80 | this.disPopUp(); 81 | privacyResolves.forEach((resolve) => { 82 | resolve({ 83 | event: "disagree", 84 | }); 85 | }); 86 | privacyResolves.clear(); 87 | }, 88 | popUp() { 89 | if (this.data.innerShow === false) { 90 | this.setData({ 91 | innerShow: true, 92 | }); 93 | } 94 | }, 95 | disPopUp() { 96 | if (this.data.innerShow === true) { 97 | this.setData({ 98 | innerShow: false, 99 | }); 100 | } 101 | }, 102 | openPrivacyContract() { 103 | wx.openPrivacyContract({ 104 | success: () => { 105 | console.log("openPrivacyContract success"); 106 | }, 107 | fail: (res) => { 108 | console.error("openPrivacyContract fail", res); 109 | }, 110 | }); 111 | }, 112 | getPrivateInfo() { 113 | if (wx.getPrivacySetting) { 114 | wx.getPrivacySetting({ 115 | success: (res) => { 116 | console.log( 117 | "是否需要授权:", 118 | res.needAuthorization, 119 | "隐私协议的名称为:", 120 | res.privacyContractName 121 | ); 122 | }, 123 | fail: () => {}, 124 | complete: () => {}, 125 | }); 126 | } else { 127 | console.log("不需要隐私授权"); 128 | } 129 | }, 130 | }, 131 | }); 132 | -------------------------------------------------------------------------------- /image2d-tracking/components/private-modal/private-modal.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /image2d-tracking/components/private-modal/private-modal.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 隐私保护指引 4 | 5 | 在使用当前小程序服务之前,请仔细阅读《{{privacyContractName}}》。如你同意《{{privacyContractName}}》,请点击“同意”开始使用。 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /image2d-tracking/components/private-modal/private-modal.wxss: -------------------------------------------------------------------------------- 1 | .privacy { 2 | position: fixed; 3 | z-index: 9999999; 4 | top: 0; 5 | right: 0; 6 | bottom: 0; 7 | left: 0; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | background: rgba(0, 0, 0, .5); 12 | } 13 | 14 | .content { 15 | width: 632rpx; 16 | box-sizing: border-box; 17 | padding: 48rpx; 18 | background: #fff; 19 | border-radius: 16rpx; 20 | } 21 | 22 | .content .title { 23 | color: #333; 24 | font-size: 32rpx; 25 | font-weight: bold; 26 | text-align: center; 27 | } 28 | 29 | .content .des { 30 | margin-top: 40rpx; 31 | color: #666; 32 | font-size: 26rpx; 33 | line-height: 1.6; 34 | text-align: justify; 35 | } 36 | 37 | .content .des .link { 38 | color: #07c160; 39 | text-decoration: underline; 40 | } 41 | 42 | .btns { 43 | display: flex; 44 | margin-top: 48rpx; 45 | } 46 | 47 | .btns .item { 48 | display: flex; 49 | width: 244rpx; 50 | height: 80rpx; 51 | box-sizing: border-box; 52 | align-items: center; 53 | justify-content: space-between; 54 | justify-content: center; 55 | padding-right: 1px; 56 | padding-left: 1px; 57 | border: none; 58 | border-radius: 16rpx; 59 | } 60 | 61 | .btns .reject { 62 | background: #f4f4f5; 63 | color: #909399; 64 | } 65 | 66 | .btns .agree { 67 | background: #07c160; 68 | color: #fff; 69 | } 70 | -------------------------------------------------------------------------------- /image2d-tracking/components/progress-bar/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | styleIsolation: "isolated", 4 | }, 5 | properties: { 6 | progress: { 7 | type: Number, 8 | value: 0, 9 | }, 10 | }, 11 | data: { 12 | rotateRight: "", 13 | rotateLeft: "", 14 | }, 15 | observers: { 16 | progress() { 17 | const progress = parseInt(this.properties.progress); 18 | const rotateRight = `transform: rotate(${ 19 | progress > 50 ? 180 : (progress / 50) * 180 20 | }deg)`; 21 | const rotateLeft = `transform: rotate(${ 22 | progress < 50 ? 0 : ((progress - 50) / 50) * 180 23 | }deg)`; 24 | this.setData({ 25 | rotateRight, 26 | rotateLeft, 27 | }); 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /image2d-tracking/components/progress-bar/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /image2d-tracking/components/progress-bar/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /image2d-tracking/components/progress-bar/index.wxss: -------------------------------------------------------------------------------- 1 | .circle { 2 | position: absolute; 3 | border-radius: 50%; 4 | background-color: #ffffff; 5 | width: 100%; 6 | height: 100%; 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | } 11 | 12 | .sm { 13 | width: calc(100% - 5px); 14 | height: calc(100% - 5px); 15 | } 16 | 17 | .left, 18 | .right { 19 | width: 50%; 20 | height: 100%; 21 | overflow: hidden; 22 | position: relative; 23 | float: left; 24 | background-color: #ffffff; 25 | } 26 | .left { 27 | border-radius: 10000px 0 0 10000px; 28 | } 29 | .right { 30 | border-radius: 0 10000px 10000px 0; 31 | } 32 | .ring { 33 | content: ""; 34 | position: absolute; 35 | display: block; 36 | width: 100%; 37 | height: 100%; 38 | background-color: #000000; 39 | } 40 | .right .ring { 41 | transform-origin: left center; 42 | } 43 | .left .ring { 44 | transform-origin: right center; 45 | } 46 | -------------------------------------------------------------------------------- /image2d-tracking/components/scanning/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | styleIsolation: "isolated", 4 | }, 5 | }); 6 | -------------------------------------------------------------------------------- /image2d-tracking/components/scanning/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /image2d-tracking/components/scanning/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 请对准海报识别 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /image2d-tracking/components/scanning/index.wxss: -------------------------------------------------------------------------------- 1 | .scanning { 2 | position: absolute; 3 | top: 0; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | height: 100%; 8 | width: 100%; 9 | } 10 | .focus-frame { 11 | position: relative; 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | font-size: 3.73vw; 16 | color: rgba(255, 255, 255, 1); 17 | width: 75.47vw; 18 | height: 109.6vw; 19 | } 20 | 21 | .text { 22 | position: absolute; 23 | top: 0; 24 | } 25 | 26 | .focus-frame-image1 { 27 | position: absolute; 28 | z-index: -1; 29 | width: 100%; 30 | height: 100%; 31 | } 32 | 33 | .focus-frame-image2 { 34 | position: absolute; 35 | z-index: -1; 36 | width: 44vw; 37 | height: 78.13vw; 38 | } 39 | 40 | .shadow { 41 | position: absolute; 42 | width: 100%; 43 | z-index: -2; 44 | } 45 | -------------------------------------------------------------------------------- /image2d-tracking/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/image2d-tracking/marker.png -------------------------------------------------------------------------------- /image2d-tracking/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | setAuth, 3 | getPrivate 4 | } from "../../utils/util"; 5 | 6 | // 获取应用实例 7 | const app = getApp(); 8 | 9 | Page({ 10 | data: {}, 11 | shareInfo: { 12 | path: "/pages/index/index", 13 | title: "AR元宇宙开启 伊弥戟王者出击", 14 | imageUrl: "https://meta.kivisense.com/wechat-kivicube-plugin-cases/image2d-tracking/share.jpg", 15 | }, 16 | async start() { 17 | try { 18 | await getPrivate(); 19 | const userAuthorize = await setAuth( 20 | "scope.camera", 21 | "摄像头权限被拒绝", 22 | "AR体验需要您授予摄像头权限,摄像头权限仅用作AR体验时的本地实景画面预览" 23 | ); 24 | if (!userAuthorize) return; 25 | wx.navigateTo({ 26 | url: "../scene/scene", 27 | }); 28 | } catch (error) { 29 | console.log(error); 30 | } 31 | }, 32 | onShareAppMessage() { 33 | return this.shareInfo; 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /image2d-tracking/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "disableScroll": true, 3 | "usingComponents": { 4 | "private-modal": "../../components/private-modal/private-modal" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /image2d-tracking/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 点击体验AR 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /image2d-tracking/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: flex-end; 5 | } 6 | .bg, 7 | .mask { 8 | position: absolute; 9 | width: 100%; 10 | height: 100%; 11 | z-index: -10; 12 | } 13 | .mask { 14 | background-color: rgba(36, 36, 36, 0.64); 15 | } 16 | 17 | .text-box { 18 | display: inline-flex; 19 | flex-direction: column; 20 | width: 66.4vw; 21 | margin-bottom: 8.53vw; 22 | } 23 | 24 | .image { 25 | width: 13vw; 26 | height: 3.2vw; 27 | margin-bottom: 4.8vw; 28 | } 29 | 30 | .text { 31 | width: 48vw; 32 | height: 20vw; 33 | } 34 | 35 | .button { 36 | position: relative; 37 | display: inline-flex; 38 | justify-content: center; 39 | align-items: center; 40 | width: 75vw; 41 | height: 24vw; 42 | font-size: 4vw; 43 | font-family: PingFangSC-Semibold, PingFang SC; 44 | color: #ffffff; 45 | line-height: 5.6vw; 46 | letter-spacing: 1px; 47 | margin-bottom: 1.87vw; 48 | } 49 | 50 | .button image { 51 | position: absolute; 52 | width: 100%; 53 | height: 100%; 54 | z-index: -1; 55 | } 56 | 57 | .link { 58 | font-size: 4vw; 59 | font-family: PingFangSC-Medium, PingFang SC; 60 | color: #ffffff; 61 | line-height: 5.6vw; 62 | margin-bottom: 20.27vw; 63 | border-bottom: 1px solid #ffffff; 64 | } 65 | 66 | .shadow { 67 | position: fixed; 68 | bottom: 0; 69 | width: 100%; 70 | z-index: -2; 71 | } 72 | -------------------------------------------------------------------------------- /image2d-tracking/pages/photo/photo.js: -------------------------------------------------------------------------------- 1 | const { setAuth } = require("../../utils/util"); 2 | 3 | Page({ 4 | data: { 5 | photo: "", 6 | marginTop: 0, 7 | }, 8 | shareInfo: { 9 | path: "/pages/index/index", 10 | title: "AR元宇宙开启 伊弥戟王者出击", 11 | imageUrl: "https://meta.kivisense.com/wechat-kivicube-plugin-cases/image2d-tracking/share.jpg", 12 | }, 13 | async onLoad({ photo: photoUrl }) { 14 | const menu = wx.getMenuButtonBoundingClientRect(); 15 | this.setData({ 16 | marginTop: menu.bottom + 19, 17 | }); 18 | wx.showLoading({ title: "加载中...", mask: true }); 19 | await this.drawPhoto(photoUrl); 20 | wx.hideLoading(); 21 | }, 22 | 23 | async drawPhoto(photoUrl) { 24 | const res = await new Promise((resolve) => { 25 | wx.createSelectorQuery() 26 | .select("#canvas") 27 | .fields({ 28 | node: true, 29 | size: true, 30 | }) 31 | .exec((els) => resolve(els[0])); 32 | }); 33 | const canvas = res.node; 34 | const ctx = canvas.getContext("2d"); 35 | const { width, height } = res; 36 | canvas.width = width; 37 | canvas.height = height; 38 | 39 | // 海报相框image 40 | const frameImg = canvas.createImage(); 41 | await new Promise((resolve) => { 42 | frameImg.onload = resolve; 43 | frameImg.src = "https://meta.kivisense.com/wechat-kivicube-plugin-cases/image2d-tracking/photo/poster-frame.png"; 44 | }); 45 | 46 | // 照片image 47 | const photoImg = canvas.createImage(); 48 | await new Promise((resolve) => { 49 | photoImg.onload = resolve; 50 | photoImg.src = decodeURIComponent(photoUrl); 51 | }); 52 | // 照片展示的高度 53 | let photoHeight = photoImg.height; 54 | // 照片展示的宽度 55 | let photoWidth = photoImg.width; 56 | // 画布的宽高比 57 | const ratio = width / height; 58 | if (photoImg.height * ratio < width) { 59 | // 比frame窄, 截取高度 60 | photoHeight = photoHeight - (photoHeight - photoWidth * (height / width)); 61 | } else { 62 | // 比frame宽,截取宽度 63 | photoWidth = photoWidth - (photoWidth - photoHeight * (width / height)); 64 | } 65 | // 将照片裁切后画入canvas 66 | ctx.drawImage( 67 | photoImg, 68 | (photoImg.width - photoWidth) / 2, 69 | (photoImg.height - photoHeight) / 2, 70 | photoWidth, 71 | photoHeight, 72 | 0, 73 | 0, 74 | width, 75 | height 76 | ); 77 | // 将相框画入canvas 78 | ctx.drawImage( 79 | frameImg, 80 | 0, 81 | 0, 82 | frameImg.width, 83 | frameImg.height, 84 | 0, 85 | 0, 86 | width, 87 | height 88 | ); 89 | 90 | await new Promise((resolve) => { 91 | setTimeout(resolve, 500); 92 | }); 93 | 94 | const pic = await new Promise((resolve) => { 95 | wx.canvasToTempFilePath({ 96 | fileType: "jpg", 97 | canvas, 98 | success: (res) => { 99 | resolve(res.tempFilePath); 100 | }, 101 | fail: (e) => { 102 | console.warn("生成图像失败", e); 103 | }, 104 | }); 105 | }); 106 | this.setData({ 107 | photo: pic, 108 | }); 109 | }, 110 | 111 | async save() { 112 | const userAuth = await setAuth( 113 | "scope.writePhotosAlbum", 114 | "相册权限被拒绝", 115 | "保存照片需要您授予相册权限" 116 | ); 117 | if (!userAuth) { 118 | return wx.showToast({ title: "保存照片失败, 需要相机权限", icon: none }); 119 | } 120 | wx.saveImageToPhotosAlbum({ 121 | filePath: this.data.photo, 122 | success() { 123 | wx.showToast({ title: "保存照片成功" }); 124 | }, 125 | fail(e) { 126 | console.error("保存照片失败", e); 127 | wx.showToast({ title: "保存照片失败", icon: none }); 128 | }, 129 | }); 130 | }, 131 | 132 | retake() { 133 | wx.navigateBack(); 134 | }, 135 | 136 | onShareAppMessage() { 137 | return this.shareInfo; 138 | }, 139 | }); 140 | -------------------------------------------------------------------------------- /image2d-tracking/pages/photo/photo.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } 4 | -------------------------------------------------------------------------------- /image2d-tracking/pages/photo/photo.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 重拍 10 | 11 | 12 | 13 | 保存 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /image2d-tracking/pages/photo/photo.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | overflow: hidden; 3 | } 4 | .photo { 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | height: 100%; 9 | background: linear-gradient(134deg, #0e345f 0%, #411a46 100%); 10 | box-sizing: border-box; 11 | margin-bottom: 1000px; 12 | } 13 | .container { 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | } 18 | .picture { 19 | position: relative; 20 | width: 86.93vw; 21 | height: 147.2vw; 22 | max-height: calc(100% - 36vw); 23 | overflow: hidden; 24 | } 25 | 26 | .picture image { 27 | display: block; 28 | width: 100%; 29 | height: 100%; 30 | } 31 | 32 | .btns { 33 | display: flex; 34 | align-items: center; 35 | flex: 1; 36 | gap: 15.2vw; 37 | transform: translateY(-6vw); 38 | } 39 | 40 | .btn { 41 | position: relative; 42 | display: inline-flex; 43 | justify-content: center; 44 | align-items: center; 45 | width: 26.67vw; 46 | height: 12.8vw; 47 | color: #ffffff; 48 | font-size: 4vw; 49 | } 50 | 51 | .btn image { 52 | width: 100%; 53 | height: 100%; 54 | } 55 | .btn text { 56 | position: absolute; 57 | } 58 | 59 | #canvas { 60 | width: 652px; 61 | height: 1104px; 62 | } 63 | -------------------------------------------------------------------------------- /image2d-tracking/pages/scene/scene.js: -------------------------------------------------------------------------------- 1 | import { setAuth } from "../../utils/util"; 2 | Page({ 3 | playing: false, 4 | data: { 5 | scanning: false, 6 | loading: false, 7 | photoing: false, 8 | showScene: false, 9 | progress: 0, 10 | }, 11 | shareInfo: { 12 | path: "/pages/scene/scene", 13 | title: "AR元宇宙开启 伊弥戟王者出击", 14 | imageUrl: "https://meta.kivisense.com/wechat-kivicube-plugin-cases/image2d-tracking/share.jpg", 15 | }, 16 | 17 | onLoad: async function () { 18 | wx.setKeepScreenOn({ 19 | keepScreenOn: true, 20 | }); 21 | wx.showLoading({ 22 | title: "加载中...", 23 | }); 24 | const userAuthorize = await setAuth( 25 | "scope.camera", 26 | "摄像头权限被拒绝", 27 | "AR体验需要您授予摄像头权限,摄像头权限仅用作AR体验时的本地实景画面预览" 28 | ); 29 | if (!userAuthorize) { 30 | wx.navigateTo({ 31 | url: "../index/index", 32 | }); 33 | return; 34 | } 35 | this.setData({ 36 | showScene: true, 37 | }); 38 | }, 39 | 40 | onUnload: function () { 41 | this.stopAllAnim(); 42 | wx.setKeepScreenOn({ 43 | keepScreenOn: false, 44 | }); 45 | }, 46 | 47 | ready({ detail: view }) { 48 | this.view = view; 49 | wx.hideLoading(); 50 | this.setData({ 51 | loading: true, 52 | }); 53 | }, 54 | 55 | sceneStart() { 56 | this.stopAllAnim(); 57 | this.setData({ 58 | scanning: true, 59 | loading: false, 60 | }); 61 | if (typeof this.view.getObject === "function") { 62 | this.model = this.view.getObject("image"); 63 | this.mask = this.view.getObject("image-mask"); 64 | this.model.addEventListener("animationEnded", ({ animationName }) => { 65 | if (animationName !== "start") return; 66 | this.play(this.model, "loop", true); 67 | }); 68 | } 69 | 70 | this.mask && this.mask.setEnableMask(); 71 | }, 72 | 73 | downloadAssetProgress({ detail }) { 74 | this.setData({ 75 | progress: detail.progress * 100, 76 | }); 77 | }, 78 | 79 | tracked() { 80 | this.startAnim(); 81 | }, 82 | 83 | lostTrack() { 84 | this.stopAllAnim(); 85 | }, 86 | 87 | startAnim() { 88 | if (!this.playing) { 89 | this.playing = true; 90 | const { model, mask } = this; 91 | this.play(model, "start", false); 92 | this.play(mask, "start", false); 93 | this.setData({ 94 | scanning: false, 95 | photoing: true, 96 | }); 97 | } 98 | }, 99 | 100 | stopAllAnim() { 101 | this.playing = false; 102 | this.stop(this.model); 103 | this.stop(this.mask); 104 | this.setData({ 105 | scanning: true, 106 | photoing: false, 107 | }); 108 | }, 109 | 110 | play(model, name, loop) { 111 | if (!model) return false; 112 | this.stop(model); 113 | const names = model.getAnimationNames(); 114 | if (!Array.isArray(names)) return; 115 | if (!names.includes(name)) return false; 116 | model.playAnimation({ 117 | name, // 动画名称 118 | loop, // 是否循环播放 119 | clampWhenFinished: true, // 播放完毕后是否停留在动画最后一帧 120 | }); 121 | }, 122 | 123 | stop(model) { 124 | if (!model) return; 125 | const names = model.getAnimationNames(); 126 | if (!Array.isArray(names)) return; 127 | names.forEach((name) => { 128 | model.stopAnimation(name); 129 | }); 130 | }, 131 | 132 | takePhoto: async function () { 133 | wx.showLoading({ title: "拍照中...", mask: true }); 134 | const photoPath = await this.view.takePhoto(); 135 | wx.navigateTo({ 136 | url: `/pages/photo/photo?photo=${encodeURIComponent(photoPath)}`, 137 | }); 138 | }, 139 | 140 | onShareAppMessage() { 141 | return this.shareInfo; 142 | }, 143 | }); 144 | -------------------------------------------------------------------------------- /image2d-tracking/pages/scene/scene.json: -------------------------------------------------------------------------------- 1 | { 2 | "disableScroll": true, 3 | "usingComponents": { 4 | "kivicube-scene": "plugin://kivicube/kivicube-scene", 5 | "loading": "/components/loading/index", 6 | "scanning": "/components/scanning/index" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /image2d-tracking/pages/scene/scene.wxml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /image2d-tracking/pages/scene/scene.wxss: -------------------------------------------------------------------------------- 1 | .kivicube { 2 | position: absolute; 3 | display: block; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | .loading { 9 | position: absolute; 10 | height: 100%; 11 | width: 100%; 12 | z-index: 1000; 13 | } 14 | .scan { 15 | position: absolute; 16 | height: 100%; 17 | width: 100%; 18 | z-index: 10; 19 | } 20 | 21 | .photo { 22 | position: absolute; 23 | bottom: 14.4vw; 24 | left: 50%; 25 | transform: translateX(-50%); 26 | width: 21.87vw; 27 | height: 21.87vw; 28 | z-index: 10; 29 | } 30 | -------------------------------------------------------------------------------- /image2d-tracking/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [ 5 | { 6 | "value": ".eslintrc.js", 7 | "type": "file" 8 | }, 9 | { 10 | "value": "marker.png", 11 | "type": "file" 12 | } 13 | ], 14 | "include": [] 15 | }, 16 | "setting": { 17 | "urlCheck": true, 18 | "es6": true, 19 | "enhance": true, 20 | "postcss": true, 21 | "preloadBackgroundData": false, 22 | "minified": true, 23 | "newFeature": false, 24 | "coverView": true, 25 | "nodeModules": false, 26 | "autoAudits": false, 27 | "showShadowRootInWxmlPanel": true, 28 | "scopeDataCheck": false, 29 | "uglifyFileName": false, 30 | "checkInvalidKey": true, 31 | "checkSiteMap": true, 32 | "uploadWithSourceMap": true, 33 | "compileHotReLoad": false, 34 | "lazyloadPlaceholderEnable": false, 35 | "useMultiFrameRuntime": true, 36 | "useApiHook": true, 37 | "useApiHostProcess": true, 38 | "babelSetting": { 39 | "ignore": [], 40 | "disablePlugins": [], 41 | "outputPath": "" 42 | }, 43 | "enableEngineNative": false, 44 | "useIsolateContext": true, 45 | "userConfirmedBundleSwitch": false, 46 | "packNpmManually": false, 47 | "packNpmRelationList": [], 48 | "minifyWXSS": true, 49 | "disableUseStrict": false, 50 | "minifyWXML": true, 51 | "showES6CompileOption": false, 52 | "useCompilerPlugins": false, 53 | "condition": false, 54 | "compileWorklet": false, 55 | "localPlugins": false, 56 | "swc": false, 57 | "disableSWC": true 58 | }, 59 | "compileType": "miniprogram", 60 | "libVersion": "3.7.9", 61 | "appid": "wx03800a762308862c", 62 | "projectname": "image2d-tracking", 63 | "condition": {}, 64 | "editorSetting": { 65 | "tabIndent": "insertSpaces", 66 | "tabSize": 2 67 | }, 68 | "simulatorPluginLibVersion": {} 69 | } -------------------------------------------------------------------------------- /image2d-tracking/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /image2d-tracking/utils/util.js: -------------------------------------------------------------------------------- 1 | // 获取用户设备权限 2 | async function setAuth(scope, title, content) { 3 | const { authSetting } = await wx.getSetting(); 4 | if (authSetting[scope]) return true; 5 | try { 6 | await wx.authorize({ 7 | scope, 8 | }); 9 | return true; 10 | } catch (error) { 11 | const res = await new Promise((resolve) => { 12 | wx.showModal({ 13 | title, 14 | content, 15 | cancelText: "不授权", 16 | cancelColor: "#999999", 17 | confirmText: "去授权", 18 | confirmColor: "#f94218", 19 | success: resolve, 20 | }); 21 | }); 22 | if (res.confirm) { 23 | const { authSetting } = await wx.openSetting(); 24 | if (authSetting[scope]) return true; 25 | return false; 26 | } else { 27 | return false; 28 | } 29 | } 30 | } 31 | 32 | function getPrivate() { 33 | if (wx.requirePrivacyAuthorize) { 34 | return new Promise((resolve, reject) => { 35 | wx.requirePrivacyAuthorize({ 36 | success: (res) => { 37 | console.log("用户同意了隐私协议"); 38 | resolve(res); 39 | }, 40 | fail: (res) => { 41 | reject(res); 42 | console.log("用户拒绝了隐私协议"); 43 | }, 44 | }); 45 | }); 46 | } else { 47 | return Promise.resolve(); 48 | } 49 | } 50 | 51 | module.exports = { 52 | setAuth, 53 | getPrivate, 54 | }; -------------------------------------------------------------------------------- /solar-divine-bird-mp/.gitignore: -------------------------------------------------------------------------------- 1 | # Windows 2 | [Dd]esktop.ini 3 | Thumbs.db 4 | $RECYCLE.BIN/ 5 | 6 | # macOS 7 | .DS_Store 8 | .fseventsd 9 | .Spotlight-V100 10 | .TemporaryItems 11 | .Trashes 12 | 13 | # Node.js 14 | node_modules/ 15 | miniprogram_npm/ 16 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/offline/offline.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | showLoading: true, 4 | showAR: false, 5 | progress: 0, 6 | showInfo: false, 7 | showWarning: false, 8 | showScanTips: false, 9 | showPoster: false, 10 | tempUrl: "", 11 | }, 12 | async onLoad() { 13 | //获取用户授权信息 14 | const { authSetting } = await wx.getSetting(); 15 | 16 | if (!authSetting["scope.camera"]) { 17 | try { 18 | await wx.authorize({ 19 | scope: "scope.camera", 20 | }); 21 | this.setData({ 22 | showAR: true, 23 | }); 24 | } catch (error) { 25 | wx.showModal({ 26 | title: "摄像头权限被拒绝", 27 | content: 28 | "AR体验需要您授予摄像头权限,摄像头权限仅用作AR体验时的本地实景画面预览", 29 | cancelText: "不授权", 30 | cancelColor: "#999", 31 | confirmText: "授权", 32 | confirmColor: "#f94218", 33 | success: async (res) => { 34 | if (res.confirm) { 35 | const { authSetting } = await wx.openSetting(); 36 | if (authSetting["scope.camera"]) { 37 | this.setData({ 38 | showAR: true, 39 | }); 40 | } else { 41 | wx.navigateBack(); 42 | } 43 | } else if (res.cancel) { 44 | wx.navigateBack(); 45 | } 46 | }, 47 | }); 48 | } 49 | } else { 50 | this.setData({ 51 | showAR: true, 52 | }); 53 | } 54 | }, 55 | 56 | onShow() { 57 | wx.setKeepScreenOn({ 58 | keepScreenOn: true, 59 | }); 60 | }, 61 | 62 | ready({ detail: view }) { 63 | this.view = view; 64 | }, 65 | 66 | downloadProgress({ detail }) { 67 | this.setData({ 68 | progress: parseInt(detail.progress * 100), 69 | }); 70 | }, 71 | 72 | loadEnd() { 73 | const alphaVideos = this.view.sceneInfo.objects; 74 | const { name: startName } = alphaVideos[0]; 75 | const { name: loopName } = alphaVideos[1]; 76 | this.startVideo = this.view.getObject(startName); 77 | this.loopVideo = this.view.getObject(loopName); 78 | 79 | this.startVideo.addEventListener("ended", () => { 80 | this.startVideoEnded = true; 81 | this.startVideo.visible = false; 82 | this.loopVideo.visible = true; 83 | this.loopVideo.loop = true; // 是否循环播放 84 | this.loopVideo.videoContext.play(); 85 | }); 86 | 87 | this.startVideo.visible = false; 88 | this.loopVideo.visible = false; 89 | this.setData({ 90 | showLoading: false, 91 | showWarning: true, 92 | }); 93 | }, 94 | 95 | tracked() { 96 | //此标志位为true时(已经track到图像时),点击“知道了”可以直接播放startVideo 97 | this.imgTracked = true; 98 | if (!this.data.showWarning) { 99 | //startVideo未播放完,再次track时,继续播放startVideo。 100 | //startVideo播放完后,再次track时,循环播放loopVideo 101 | if (this.startVideoEnded) { 102 | this.loopVideo.loop = true; 103 | this.loopVideo.videoContext.play(); 104 | } else { 105 | this.startVideo.visible = true; 106 | this.startVideo.loop = false; // 是否循环播放 107 | this.startVideo.videoContext.play(); 108 | } 109 | this.setData({ 110 | showInfo: true, 111 | showScanTips: false, 112 | }); 113 | } 114 | }, 115 | 116 | lostTrack() { 117 | this.imgTracked = false; 118 | if (!this.data.showWarning) { 119 | this.startVideo.videoContext.pause(); 120 | this.loopVideo.videoContext.pause(); 121 | this.setData({ 122 | showInfo: false, 123 | showScanTips: true, 124 | }); 125 | } 126 | }, 127 | error(e) { 128 | const { detail } = e; 129 | // 判定是否camera权限问题,是则向用户申请权限。 130 | if (detail && detail.isCameraAuthDenied) { 131 | const page = this; 132 | wx.showModal({ 133 | title: "提示", 134 | content: "请给予“摄像头”权限", 135 | success() { 136 | wx.openSetting({ 137 | success({ authSetting: { "scope.camera": isGrantedCamera } }) { 138 | if (isGrantedCamera) { 139 | wx.redirectTo({ url: "/" + page.__route__ }); 140 | } else { 141 | wx.showToast({ title: "获取“摄像头”权限失败!", icon: "none" }); 142 | } 143 | }, 144 | }); 145 | }, 146 | }); 147 | } 148 | console.error(detail); 149 | }, 150 | 151 | //自定义拍照按钮需要2步操作:1,在kivicube-scene上设置hideTakePhoto;2给自定义的点击按钮绑定方法 152 | takePhoto() { 153 | wx.showLoading({ 154 | title: "拍照中", 155 | }); 156 | this.view 157 | .takePhoto() 158 | .then((photoPath) => { 159 | this.setData({ 160 | tempUrl: photoPath, 161 | showPoster: true, 162 | }); 163 | }) 164 | .catch((e) => { 165 | wx.showToast({ 166 | icon: "none", 167 | title: "照片生成失败,请稍后再试", 168 | duration: 1000, 169 | }); 170 | console.error(e); 171 | }); 172 | }, 173 | rePhoto() { 174 | this.setData({ 175 | showPoster: false, 176 | tempUrl: "", 177 | }); 178 | }, 179 | closeWarning() { 180 | if (this.imgTracked) { 181 | this.startVideo.visible = true; 182 | this.startVideo.loop = false; 183 | this.startVideo.videoContext.play(); 184 | this.setData({ 185 | showInfo: true, 186 | }); 187 | } else { 188 | this.setData({ 189 | showScanTips: true, 190 | }); 191 | } 192 | this.setData({ 193 | showWarning: false, 194 | }); 195 | }, 196 | //分享小程序到微信聊天界面 197 | onShareAppMessage() { 198 | return { 199 | title: "扫描线下“The Sun”壁画查看AR效果", 200 | path: "/pages/index/index", 201 | imageUrl: "/asset/share.jpg", 202 | }; 203 | }, 204 | //分享小程序到朋友圈 205 | onShareTimeline() { 206 | return { 207 | title: "扫描线下“The Sun”壁画查看AR效果", 208 | path: "/pages/index/index", 209 | imageUrl: "/asset/share.jpg", 210 | }; 211 | }, 212 | }); 213 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/offline/offline.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "kivicube-scene": "plugin://kivicube/kivicube-scene", 6 | "back-button": "/components/back-button/back-button", 7 | "loading": "/components/loading/loading", 8 | "warning": "/components/warning/warning", 9 | "copyright": "/components/copyright/copyright", 10 | "work-detail": "/components/work-detail/work-detail", 11 | "scan-tips": "/components/scan-tips/scan-tips", 12 | "poster": "/components/poster/poster" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/offline/offline.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/offline/offline.wxss: -------------------------------------------------------------------------------- 1 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 2 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 3 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/online/online.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | showLoading: true, 4 | progress: 0, 5 | showAR: false, 6 | cameraPos: "front", 7 | }, 8 | async onLoad() { 9 | const { authSetting } = await wx.getSetting(); 10 | if (!authSetting["scope.camera"]) { 11 | try { 12 | await wx.authorize({ 13 | scope: "scope.camera", 14 | }); 15 | this.setData({ 16 | showAR: true, 17 | }); 18 | } catch (error) { 19 | wx.showModal({ 20 | title: "摄像头权限被拒绝", 21 | content: 22 | "AR体验需要您授予摄像头权限,摄像头权限仅用作AR体验时的本地实景画面预览", 23 | cancelText: "取消", 24 | cancelColor: "#999", 25 | confirmText: "去授权", 26 | confirmColor: "#f94218", 27 | success: async (res) => { 28 | if (res.confirm) { 29 | const { authSetting } = await wx.openSetting(); 30 | if (authSetting["scope.camera"]) { 31 | this.setData({ 32 | showAR: true, 33 | }); 34 | } else { 35 | wx.navigateBack(); 36 | } 37 | } else if (res.cancel) { 38 | wx.navigateBack(); 39 | } 40 | }, 41 | }); 42 | } 43 | } else { 44 | this.setData({ 45 | showAR: true, 46 | }); 47 | } 48 | }, 49 | 50 | onShow() { 51 | wx.setKeepScreenOn({ 52 | keepScreenOn: true, 53 | }); 54 | }, 55 | ready({ detail: view }) { 56 | this.view = view; 57 | }, 58 | downloadProgress({ detail: progress }) { 59 | this.setData({ 60 | progress: parseInt(progress * 100), 61 | }); 62 | }, 63 | loadEnd() { 64 | this.setData({ 65 | showLoading: false, 66 | }); 67 | }, 68 | 69 | error(e) { 70 | const { detail } = e; 71 | // 判定是否camera权限问题,是则向用户申请权限。 72 | if (detail && detail.isCameraAuthDenied) { 73 | const page = this; 74 | wx.showModal({ 75 | title: "提示", 76 | content: "请给予“摄像头”权限", 77 | success() { 78 | wx.openSetting({ 79 | success({ authSetting: { "scope.camera": isGrantedCamera } }) { 80 | if (isGrantedCamera) { 81 | wx.redirectTo({ url: "/" + page.__route__ }); 82 | } else { 83 | wx.showToast({ title: "获取“摄像头”权限失败!", icon: "none" }); 84 | } 85 | }, 86 | }); 87 | }, 88 | }); 89 | } 90 | console.error(detail); 91 | }, 92 | //自定义拍照按钮需要2步操作:1,在kivicube-scene上设置hideTakePhoto;2给自定义的点击按钮绑定方法 93 | takePhoto() { 94 | wx.showLoading({ 95 | title: "拍照中", 96 | mask: true, 97 | }); 98 | this.view 99 | .takePhoto() 100 | .then((photoPath) => { 101 | this.setData({ 102 | tempUrl: photoPath, 103 | showPoster: true, 104 | }); 105 | }) 106 | .catch((e) => { 107 | wx.showToast({ 108 | icon: "none", 109 | title: "照片生成失败,请稍后再试", 110 | duration: 1000, 111 | }); 112 | console.error(e); 113 | }); 114 | }, 115 | 116 | rePhoto() { 117 | this.setData({ 118 | showPoster: false, 119 | tempUrl: "", 120 | }); 121 | }, 122 | 123 | //切换前后置摄像头的逻辑 124 | changeCamera() { 125 | const position = this.data.cameraPos === "front" ? "back" : "front"; 126 | this.view.switchCamera(position); 127 | this.setData({ 128 | cameraPos: position, 129 | }); 130 | }, 131 | //分享小程序到微信聊天界面 132 | onShareAppMessage() { 133 | return { 134 | title: "扫描线下“The Sun”壁画查看AR效果", 135 | path: "/pages/index/index", 136 | imageUrl: "/asset/share.jpg", 137 | }; 138 | }, 139 | //分享小程序到朋友圈 140 | onShareTimeline() { 141 | return { 142 | title: "扫描线下“The Sun”壁画查看AR效果", 143 | path: "/pages/index/index", 144 | imageUrl: "/asset/share.jpg", 145 | }; 146 | }, 147 | }); 148 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/online/online.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "kivicube-scene": "plugin://kivicube/kivicube-scene", 6 | "back-button": "/components/back-button/back-button", 7 | "loading": "/components/loading/loading", 8 | "work-detail": "/components/work-detail/work-detail", 9 | "poster": "/components/poster/poster", 10 | "copyright": "/components/copyright/copyright" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/online/online.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/Kivicube/pages/online/online.wxss: -------------------------------------------------------------------------------- 1 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 2 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 3 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/app.js: -------------------------------------------------------------------------------- 1 | App({}); 2 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": ["pages/index/index", "pages/webview/webview"], 3 | "subpackages": [ 4 | { 5 | "root": "Kivicube", 6 | "pages": ["pages/offline/offline", "pages/online/online"], 7 | "plugins": { 8 | "kivicube": { 9 | "version": "2.16.8", 10 | "provider": "wx3bbab3920eabccb2" 11 | } 12 | } 13 | } 14 | ], 15 | "preloadRule": { 16 | "pages/index/index": { 17 | "network": "wifi", 18 | "packages": ["Kivicube"] 19 | } 20 | }, 21 | "__usePrivacyCheck__": true, 22 | "style": "v2", 23 | "sitemapLocation": "sitemap.json", 24 | "lazyCodeLoading": "requiredComponents" 25 | } 26 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/app.wxss: -------------------------------------------------------------------------------- 1 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 2 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 3 | 4 | .subpkg-scene { 5 | display: block; 6 | width: 100vw; 7 | height: 100vh; 8 | } 9 | 10 | .subpkg-takephoto { 11 | position: absolute; 12 | z-index: 3; 13 | bottom: 60px; 14 | left: 50%; 15 | transform: translateX(-50%); 16 | width: 21.87vw; 17 | height: 21.87vw; 18 | } 19 | 20 | .subpkg-changeamera { 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | position: absolute; 25 | bottom: 19.73vw; 26 | right: 14.13vw; 27 | width: 11.2vw; 28 | height: 11.2vw; 29 | background: rgba(255, 238, 228, 0.41); 30 | box-shadow: 0vw 0.53vw 1.87vw 0vw rgba(58, 40, 40, 0.25); 31 | backdrop-filter: blur(15px); 32 | border-radius: 50%; 33 | z-index: 2; 34 | } 35 | 36 | .subpkg-changeamera image { 37 | width: 5.33vw; 38 | height: 5.33vw; 39 | } 40 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/back.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/bg.jpg -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/button.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/changecamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/changecamera.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/close.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/location-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/location-icon.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/qrcode.jpg -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/qrcode.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/share.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/share.jpg -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/takephoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/takephoto.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/watermark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/watermark.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/asset/work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/asset/work.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/back-button/back-button.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: { 3 | // 胶囊按钮高度 4 | menuButtonHeight: "32px", 5 | // 左边返回按钮距屏幕顶部的距离 6 | capsuleTop: "48px", 7 | }, 8 | lifetimes: { 9 | attached() { 10 | const { top, height } = wx.getMenuButtonBoundingClientRect(); 11 | this.setData({ 12 | // 胶囊按钮高度 13 | menuButtonHeight: height + "px", 14 | //返回按钮的位置 15 | capsuleTop: top + "px", 16 | }); 17 | }, 18 | }, 19 | methods: { 20 | async goBack() { 21 | try { 22 | await wx.navigateBack(); 23 | } catch (error) { 24 | wx.navigateTo({ 25 | url: "/pages/index/index", 26 | }); 27 | } 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/back-button/back-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/back-button/back-button.wxml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/back-button/back-button.wxss: -------------------------------------------------------------------------------- 1 | .back { 2 | position: absolute; 3 | left: 2.67vw; 4 | z-index: 10; 5 | } 6 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/back-button/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/back-button/images/back.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/copyright/copyright.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | onPageLeft: { 4 | type: Boolean, 5 | value: true, 6 | }, 7 | }, 8 | 9 | data: { 10 | animationData: {}, 11 | }, 12 | 13 | lifetimes: { 14 | attached() { 15 | let animation = wx.createAnimation({ 16 | duration: 500, 17 | timingFunction: "ease-out", 18 | transformOrigin: this.properties.onPageLeft ? "0 0" : "100% 0", 19 | }); 20 | this.animation = animation; 21 | this.copyrightDetailShowing = false; 22 | }, 23 | }, 24 | 25 | methods: { 26 | onIconClicked() { 27 | if (this.copyrightDetailShowing) { 28 | this.animation.scale(0, 0).step(); 29 | this.setData({ 30 | animationData: this.animation.export(), 31 | }); 32 | this.copyrightDetailShowing = false; 33 | } else { 34 | this.animation.scale(1, 1).step(); 35 | this.setData({ 36 | animationData: this.animation.export(), 37 | }); 38 | this.copyrightDetailShowing = true; 39 | } 40 | }, 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/copyright/copyright.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/copyright/copyright.wxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 版权声明 8 | 该作品“太阳”(The Sun),其版权属于原创作者Key Detail所有。 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/copyright/copyright.wxss: -------------------------------------------------------------------------------- 1 | .copyright-container { 2 | position: absolute; 3 | top: 30.13vw; 4 | width: 8.53vw; 5 | height: 8.53vw; 6 | z-index: 2; 7 | } 8 | 9 | .copyright-icon-container { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | width: 8.53vw; 14 | height: 8.53vw; 15 | border-radius: 50%; 16 | background-color: rgba(255, 238, 228, 0.41); 17 | color: #ffffff; 18 | font-size: 3.73vw; 19 | text-align: center; 20 | line-height: 8.53vw; 21 | z-index: 3; 22 | backdrop-filter: blur(15px); 23 | box-shadow: 0vw 0.53vw 1.87vw 0vw rgba(58, 40, 40, 0.25); 24 | } 25 | 26 | .copyright-icon-container .copyright-image { 27 | height: auto; 28 | width: 4.27vw; 29 | } 30 | 31 | .copyright-detail { 32 | position: absolute; 33 | top: 4.265vw; 34 | width: 35.47vw; 35 | height: 32vw; 36 | background-color: rgba(255, 255, 255, 0.53); 37 | text-align: center; 38 | border-radius: 4.8vw; 39 | box-shadow: 0vw 0.53vw 1.87vw 0vw rgba(58, 40, 40, 0.25); 40 | backdrop-filter: blur(27px); 41 | z-index: 0; 42 | transform: scale(0); 43 | } 44 | 45 | .copyright-title { 46 | margin-top: 2.93vw; 47 | color: rgba(70, 70, 70, 1); 48 | font-size: 3.73vw; 49 | font-weight: bold; 50 | line-height: 5.33vw; 51 | } 52 | 53 | .copyright-content { 54 | margin-top: 1.33vw; 55 | margin-left: 1.7vw; 56 | color: rgba(80, 80, 80, 1); 57 | font-size: 3.47vw; 58 | line-height: 4.8vw; 59 | text-align: left; 60 | } 61 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/copyright/images/copyright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/copyright/images/copyright.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/images/loading-bird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/loading/images/loading-bird.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/images/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/loading/images/sun.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/loading.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | progress: { 4 | type: Number, 5 | value: 0, 6 | }, 7 | isOnlineLoading: { 8 | type: Boolean, 9 | value: false, 10 | }, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/loading.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/loading.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 14 | 15 | 加载中{{progress}}% 16 | 17 | 18 | 在天气晴朗的白天进行体验 19 | 20 | 21 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/loading/loading.wxss: -------------------------------------------------------------------------------- 1 | .loading-warper { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | position: absolute; 6 | width: 100vw; 7 | height: 100%; 8 | z-index: 5; 9 | overflow: hidden; 10 | } 11 | 12 | .bg { 13 | position: absolute; 14 | top: 0; 15 | left: 0; 16 | vertical-align: middle; 17 | width: 100%; 18 | height: 100%; 19 | } 20 | 21 | .mask { 22 | position: absolute; 23 | top: 0; 24 | left: 0; 25 | width: 100%; 26 | height: 100%; 27 | background: linear-gradient( 28 | 180deg, 29 | rgba(90, 136, 157, 0) 0%, 30 | rgba(45, 73, 86, 0.54) 42%, 31 | #e57850 100% 32 | ); 33 | backdrop-filter: blur(27px); 34 | } 35 | 36 | .loading-bird { 37 | position: absolute; 38 | top: 64.8vw; 39 | left: 17.33vw; 40 | width: 60.27vw; 41 | height: 56vw; 42 | } 43 | 44 | .loading-warper .progress { 45 | margin-top: 3.2vw; 46 | width: 17.87vw; 47 | height: 4.53vw; 48 | font-size: 3.2vw; 49 | font-weight: normal; 50 | color: #ffffff; 51 | line-height: 4.53vw; 52 | z-index: 10; 53 | } 54 | 55 | @media screen and (min-aspect-ratio: 375/668) { 56 | .loading-warper text { 57 | top: 117.33vw; 58 | } 59 | } 60 | 61 | .loading-warper .notice { 62 | display: flex; 63 | align-items: center; 64 | margin-top: 9.33vw; 65 | width: 54vw; 66 | height: 5.33vw; 67 | font-size: 3.73vw; 68 | font-weight: normal; 69 | color: #ffffff; 70 | line-height: 5.33vw; 71 | z-index: 10; 72 | } 73 | 74 | .loading-warper .notice .sun-image { 75 | width: 6.93vw; 76 | height: 6.93vw; 77 | } 78 | 79 | .loading-warper .notice text { 80 | margin-left: 1.87vw; 81 | } 82 | 83 | .loadingcircle-left { 84 | border: 1vw solid #b7b7b7; 85 | border-radius: 50%; 86 | clip: rect(0, 27.5vw, 55vw, 0); 87 | } 88 | 89 | .loadingcircle-right { 90 | border: 1vw solid #b7b7b7; 91 | border-radius: 50%; 92 | clip: rect(0, 55vw, 55vw, 27.5vw); 93 | } 94 | 95 | .loadingcircle-box { 96 | position: relative; 97 | margin-top: 62.67vw; 98 | width: 55vw; 99 | height: 55vw; 100 | border-radius: 50%; 101 | box-shadow: inset 0 0 0 1vw rgb(255, 138, 70); 102 | } 103 | 104 | .loadingcircle-box view { 105 | position: absolute; 106 | left: 0; 107 | right: 0; 108 | top: 0; 109 | bottom: 0; 110 | margin: auto; 111 | } 112 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/poster/poster.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | tempUrl: { 4 | type: String, 5 | value: "", 6 | }, 7 | }, 8 | data: { 9 | posterUrl: "", 10 | showPoster: false, 11 | }, 12 | lifetimes: { 13 | async attached() { 14 | //因为图像追踪造成部分机型运算压力过大,如果用RenderingContext来进行canvas渲染,会造成渲染还未完成就调用了wx.canvasToTempFilePath,这会生成空图片或不完整的图片, 15 | //所以改用wx.createCanvasContext创建上下文,并使用ctx.draw(),保证生成canvas后再调用wx.canvasToTempFilePath 16 | const ctx = wx.createCanvasContext("poster-canvas", this); 17 | 18 | const { pixelRatio: dpr, windowWidth } = wx.getSystemInfoSync(); 19 | 20 | const vwToPx = (vw) => (windowWidth / 100) * vw; 21 | 22 | const handleImageGeneratingError = () => { 23 | wx.hideLoading(); 24 | wx.showToast({ 25 | icon: "none", 26 | title: "照片生成失败,请稍后再试", 27 | duration: 1000, 28 | }); 29 | }; 30 | 31 | //生成海报背景色 32 | ctx.setFillStyle("white"); 33 | ctx.fillRect(0, 0, vwToPx(100), vwToPx(173.28)); 34 | 35 | try { 36 | //获取照片的长宽信息(像素值) 37 | const { width: picWidth, height: picHeight } = await wx.getImageInfo({ 38 | src: this.properties.tempUrl, 39 | }); 40 | //生成海报内容图 41 | let imgTotalHeight = (picWidth / 100) * 141.98; 42 | let imgStartY = (picHeight - imgTotalHeight) / 2; 43 | 44 | ctx.drawImage( 45 | this.properties.tempUrl, 46 | 0, 47 | imgStartY, 48 | picWidth, 49 | imgTotalHeight, 50 | 0, 51 | 0, 52 | windowWidth, 53 | vwToPx(141.98) 54 | ); 55 | } catch (error) { 56 | handleImageGeneratingError(); 57 | } 58 | 59 | //生成渐变 60 | let lingrad = ctx.createLinearGradient( 61 | 0, 62 | vwToPx(93.89), 63 | 0, 64 | vwToPx(141.98) 65 | ); 66 | lingrad.addColorStop(0, "rgba(90, 136, 157, 0)"); 67 | lingrad.addColorStop(1, "#66483B"); 68 | ctx.setFillStyle(lingrad); 69 | ctx.fillRect(0, vwToPx(93.89), vwToPx(100), vwToPx(48.09)); 70 | 71 | //水印 72 | ctx.drawImage( 73 | "/asset/watermark.png", 74 | vwToPx(70.23), 75 | vwToPx(130.15), 76 | vwToPx(26.72), 77 | vwToPx(8.78) 78 | ); 79 | 80 | //生成二维码 81 | ctx.drawImage( 82 | "/asset/qrcode.jpg", 83 | vwToPx(74), 84 | vwToPx(146.95), 85 | vwToPx(21.76), 86 | vwToPx(21.76) 87 | ); 88 | 89 | //生成文本 90 | ctx.setFillStyle("#51585C"); 91 | ctx.setFontSize(vwToPx(5.4)); 92 | ctx.fillText("扫描“太阳”", vwToPx(6.49), vwToPx(150 + 5.4)); 93 | ctx.fillText( 94 | "即刻体验AR实境动态壁画。", 95 | vwToPx(6.49), 96 | vwToPx(157.63 + 5.4) 97 | ); 98 | 99 | ctx.draw(true, () => { 100 | wx.canvasToTempFilePath( 101 | { 102 | x: 0, 103 | y: 0, 104 | width: windowWidth, 105 | height: windowWidth * 1.7328, 106 | destWidth: windowWidth * dpr, 107 | destHeight: windowWidth * 1.7328 * dpr, 108 | canvasId: "poster-canvas", 109 | success: (res) => { 110 | this.setData({ 111 | posterUrl: res.tempFilePath, 112 | showPoster: true, 113 | }); 114 | wx.hideLoading(); 115 | }, 116 | fail(e) { 117 | wx.showToast({ 118 | title: "海报生成失败,请稍后重试", 119 | icon: "none", 120 | duration: 1000, 121 | }); 122 | console.error(e); 123 | }, 124 | }, 125 | this 126 | ); 127 | }); 128 | }, 129 | }, 130 | methods: { 131 | //获取保存图片权限后,保存图片 132 | async savePhoto() { 133 | //保存图片到本地 134 | const savePhotoToAlbum = () => { 135 | wx.saveImageToPhotosAlbum({ 136 | filePath: this.data.posterUrl, 137 | success() { 138 | wx.showToast({ 139 | icon: "none", 140 | title: "照片已保存到相册", 141 | duration: 1000, 142 | }); 143 | }, 144 | fail(e) { 145 | wx.showToast({ 146 | icon: "none", 147 | title: "照片保存失败,请稍后再试", 148 | duration: 1000, 149 | }); 150 | console.error(e); 151 | }, 152 | }); 153 | }; 154 | 155 | const { authSetting } = await wx.getSetting(); 156 | if (!authSetting["scope.writePhotosAlbum"]) { 157 | try { 158 | await wx.authorize({ 159 | scope: "scope.writePhotosAlbum", 160 | }); 161 | savePhotoToAlbum(); 162 | } catch (error) { 163 | wx.showModal({ 164 | title: "相册权限被拒绝", 165 | content: "保存照片需要您授予相册权限", 166 | cancelText: "取消", 167 | cancelColor: "#999", 168 | confirmText: "去授权", 169 | confirmColor: "#f94218", 170 | success: async (res) => { 171 | if (res.confirm) { 172 | const { authSetting } = await wx.openSetting(); 173 | if (authSetting["scope.writePhotosAlbum"]) { 174 | savePhotoToAlbum(); 175 | } else { 176 | return; 177 | } 178 | } else if (res.cancel) { 179 | return; 180 | } 181 | }, 182 | }); 183 | } 184 | } else { 185 | // 有权限则直接存 186 | savePhotoToAlbum(); 187 | } 188 | }, 189 | 190 | rePhoto() { 191 | this.triggerEvent("rephoto"); 192 | }, 193 | }, 194 | }); 195 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/poster/poster.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/poster/poster.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 重 拍 7 | 保 存 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/poster/poster.wxss: -------------------------------------------------------------------------------- 1 | .photo-container { 2 | overflow: hidden; 3 | } 4 | 5 | .poster-canvas { 6 | position: absolute; 7 | top: -50vw; 8 | left: 1000vw; 9 | width: 100vw; 10 | height: 173.28vw; 11 | z-index: 100; 12 | } 13 | 14 | .poster-warper { 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: center; 18 | align-items: center; 19 | position: absolute; 20 | left: 0; 21 | right: 0; 22 | bottom: 0; 23 | top: 0; 24 | z-index: 5; 25 | } 26 | 27 | @supports ((-webkit-backdrop-filter: none) or (backdrop-filter: none)) { 28 | .poster-warper { 29 | -webkit-backdrop-filter: blur(50px); 30 | backdrop-filter: blur(50px); 31 | } 32 | } 33 | 34 | .poster-img { 35 | width: 69.87vw; 36 | height: 121.07vw; 37 | z-index: 10; 38 | border-radius: 3.48vw; 39 | } 40 | 41 | .btn-warper { 42 | margin-top: 8vw; 43 | width: 68vw; 44 | display: flex; 45 | justify-content: space-between; 46 | } 47 | 48 | .btn { 49 | display: flex; 50 | justify-content: center; 51 | align-items: center; 52 | width: 26.13vw; 53 | height: 12.27vw; 54 | border-radius: 6.27vw; 55 | border: 0.27vw solid #ffffff; 56 | font-size: 4.27vw; 57 | font-weight: bold; 58 | color: #ffffff; 59 | line-height: 12.27vw; 60 | } 61 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/private-modal/private-modal.js: -------------------------------------------------------------------------------- 1 | let privacyHandler; 2 | let privacyResolves = new Set(); 3 | let closeOtherPagePopUpHooks = new Set(); 4 | 5 | if (wx.onNeedPrivacyAuthorization) { 6 | wx.onNeedPrivacyAuthorization((resolve) => { 7 | console.log( 8 | "触发 onNeedPrivacyAuthorization", 9 | typeof privacyHandler === "function" 10 | ); 11 | if (typeof privacyHandler === "function") { 12 | privacyHandler(resolve); 13 | } 14 | }); 15 | } 16 | 17 | const closeOtherPagePopUp = (closePopUp) => { 18 | closeOtherPagePopUpHooks.forEach((hook) => { 19 | if (closePopUp !== hook) { 20 | hook(); 21 | } 22 | }); 23 | }; 24 | 25 | Component({ 26 | properties: { 27 | currentBtnText: { 28 | type: String, 29 | value: "同意", 30 | }, 31 | }, 32 | data: { 33 | innerShow: false, 34 | privacyContractName: "AR动态壁画小程序隐私保护指引", 35 | }, 36 | lifetimes: { 37 | attached() { 38 | const closePopUp = () => { 39 | this.disPopUp(); 40 | }; 41 | privacyHandler = (resolve) => { 42 | privacyResolves.add(resolve); 43 | this.popUp(); 44 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 45 | closeOtherPagePopUp(closePopUp); 46 | }; 47 | 48 | this.closePopUp = closePopUp; 49 | closeOtherPagePopUpHooks.add(this.closePopUp); 50 | }, 51 | detached() { 52 | closeOtherPagePopUpHooks.delete(this.closePopUp); 53 | }, 54 | }, 55 | pageLifetimes: { 56 | show() { 57 | if (this.closePopUp) { 58 | privacyHandler = (resolve) => { 59 | privacyResolves.add(resolve); 60 | this.popUp(); 61 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 62 | closeOtherPagePopUp(this.closePopUp); 63 | }; 64 | } 65 | }, 66 | }, 67 | methods: { 68 | handleAgree() { 69 | this.disPopUp(); 70 | // 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行 (看page/index/index中的 wx.getClipboardData 和 wx.startCompass) 71 | privacyResolves.forEach((resolve) => { 72 | resolve({ 73 | event: "agree", 74 | buttonId: "agree-btn", 75 | }); 76 | }); 77 | privacyResolves.clear(); 78 | }, 79 | handleDisagree() { 80 | this.disPopUp(); 81 | privacyResolves.forEach((resolve) => { 82 | resolve({ 83 | event: "disagree", 84 | }); 85 | }); 86 | privacyResolves.clear(); 87 | }, 88 | popUp() { 89 | if (this.data.innerShow === false) { 90 | this.setData({ 91 | innerShow: true, 92 | }); 93 | } 94 | }, 95 | disPopUp() { 96 | if (this.data.innerShow === true) { 97 | this.setData({ 98 | innerShow: false, 99 | }); 100 | } 101 | }, 102 | openPrivacyContract() { 103 | wx.openPrivacyContract({ 104 | success: () => { 105 | console.log("openPrivacyContract success"); 106 | }, 107 | fail: (res) => { 108 | console.error("openPrivacyContract fail", res); 109 | }, 110 | }); 111 | }, 112 | getPrivateInfo() { 113 | if (wx.getPrivacySetting) { 114 | wx.getPrivacySetting({ 115 | success: (res) => { 116 | console.log( 117 | "是否需要授权:", 118 | res.needAuthorization, 119 | "隐私协议的名称为:", 120 | res.privacyContractName 121 | ); 122 | }, 123 | fail: () => {}, 124 | complete: () => {}, 125 | }); 126 | } else { 127 | console.log("不需要隐私授权"); 128 | } 129 | }, 130 | }, 131 | }); 132 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/private-modal/private-modal.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/private-modal/private-modal.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 隐私保护指引 4 | 5 | 在使用当前小程序服务之前,请仔细阅读《{{privacyContractName}}》。如你同意《{{privacyContractName}}》,请点击“同意”开始使用。 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/private-modal/private-modal.wxss: -------------------------------------------------------------------------------- 1 | .privacy { 2 | position: fixed; 3 | z-index: 9999999; 4 | top: 0; 5 | right: 0; 6 | bottom: 0; 7 | left: 0; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | background: rgba(0, 0, 0, .5); 12 | } 13 | 14 | .content { 15 | width: 632rpx; 16 | box-sizing: border-box; 17 | padding: 48rpx; 18 | background: #fff; 19 | border-radius: 16rpx; 20 | } 21 | 22 | .content .title { 23 | color: #333; 24 | font-size: 32rpx; 25 | font-weight: bold; 26 | text-align: center; 27 | } 28 | 29 | .content .des { 30 | margin-top: 40rpx; 31 | color: #666; 32 | font-size: 26rpx; 33 | line-height: 1.6; 34 | text-align: justify; 35 | } 36 | 37 | .content .des .link { 38 | color: #07c160; 39 | text-decoration: underline; 40 | } 41 | 42 | .btns { 43 | display: flex; 44 | margin-top: 48rpx; 45 | } 46 | 47 | .btns .item { 48 | display: flex; 49 | width: 244rpx; 50 | height: 80rpx; 51 | box-sizing: border-box; 52 | align-items: center; 53 | justify-content: space-between; 54 | justify-content: center; 55 | padding-right: 1px; 56 | padding-left: 1px; 57 | border: none; 58 | border-radius: 16rpx; 59 | } 60 | 61 | .btns .reject { 62 | background: #f4f4f5; 63 | color: #909399; 64 | } 65 | 66 | .btns .agree { 67 | background: #07c160; 68 | color: #fff; 69 | } 70 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/images/corner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/scan-tips/images/corner.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/images/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/scan-tips/images/phone.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/images/work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/scan-tips/images/work.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/scan-tips.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: { 3 | animationData: {}, 4 | }, 5 | lifetimes: { 6 | attached() { 7 | setTimeout(() => { 8 | let animation = wx.createAnimation({ 9 | duration: 500, 10 | timingFunction: "ease-out", 11 | }); 12 | animation.bottom(0).step(); 13 | 14 | this.setData({ 15 | animationData: animation.export(), 16 | }); 17 | }, 3000); 18 | }, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/scan-tips.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/scan-tips.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 正对与壁画重合并扫描 9 | 10 | 11 | 12 | 请保持手机静止,正对壁画扫描。 13 | 14 | 15 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/scan-tips/scan-tips.wxss: -------------------------------------------------------------------------------- 1 | .scan-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | position: fixed; 6 | top: 0; 7 | left: 0; 8 | width: 100vw; 9 | height: 100%; 10 | background: rgba(36, 36, 36, 0.8); 11 | text-align: center; 12 | z-index: 4; 13 | } 14 | 15 | .scan-warper { 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; 19 | position: relative; 20 | width: 58.94vw; 21 | height: 107.73vw; 22 | } 23 | 24 | .scan-warper image { 25 | width: 9.87vw; 26 | height: 10.93vw; 27 | } 28 | 29 | .scan-warper .work { 30 | margin-top: 3.73vw; 31 | width: 50.13vw; 32 | height: 92.8vw; 33 | } 34 | 35 | .top-left { 36 | position: absolute; 37 | top: 0; 38 | left: 0; 39 | } 40 | 41 | .top-right { 42 | position: absolute; 43 | top: 0; 44 | right: 0; 45 | transform: scaleX(-1); 46 | } 47 | 48 | .bottom-left { 49 | position: absolute; 50 | bottom: 0; 51 | left: 0; 52 | transform: scaleY(-1); 53 | } 54 | 55 | .bottom-right { 56 | position: absolute; 57 | bottom: 0; 58 | right: 0; 59 | transform: scaleX(-1) scaleY(-1); 60 | } 61 | 62 | .tips { 63 | position: absolute; 64 | left: 50%; 65 | transform: translateX(-50%); 66 | bottom: 4.8vw; 67 | width: 65.07vw; 68 | height: 13.87vw; 69 | width: 37.33vw; 70 | height: 5.33vw; 71 | font-size: 3.73vw; 72 | font-weight: normal; 73 | color: #ffffff; 74 | line-height: 5.33vw; 75 | } 76 | .tips-container { 77 | display: flex; 78 | flex-direction: row; 79 | align-items: center; 80 | position: fixed; 81 | bottom: -22.93vw; 82 | width: 100vw; 83 | height: 22.93vw; 84 | background: rgba(36, 36, 36, 0.8); 85 | z-index: 6; 86 | } 87 | 88 | .tips-container image { 89 | margin-left: 12.27vw; 90 | width: 6.93vw; 91 | height: 11.2vw; 92 | } 93 | 94 | .tips-container view { 95 | margin-left: 6.93vw; 96 | font-size: 3.73vw; 97 | font-weight: normal; 98 | color: #ffffff; 99 | line-height: 5.33vw; 100 | } 101 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/warning/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/warning/images/warning.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/warning/warning.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | methods: { 3 | closeWarning() { 4 | this.triggerEvent("closeWarning"); 5 | }, 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/warning/warning.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/warning/warning.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 警告 6 | 7 | 您需要一个安全无阻的空间来感受此增强现实体验。请站在道路两旁的人行道上体验,时刻注意道路上往来的行人以及障碍物。 10 | 11 | 12 | 13 | 知道了 14 | 15 | 16 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/warning/warning.wxss: -------------------------------------------------------------------------------- 1 | .warning-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | width: 100vw; 9 | height: 100%; 10 | background: rgba(36, 36, 36, 0.8); 11 | z-index: 5; 12 | } 13 | 14 | .warning-warper { 15 | margin-top: 96.53vw; 16 | padding: 0 10vw; 17 | } 18 | 19 | .warning-title-warper { 20 | text-align: left; 21 | } 22 | 23 | .warning-title-warper image { 24 | vertical-align: middle; 25 | width: 6.4vw; 26 | height: 5.6vw; 27 | } 28 | 29 | .warning-title-warper text { 30 | margin-left: 2.4vw; 31 | width: 9.07vw; 32 | height: 6.4vw; 33 | font-size: 4.53vw; 34 | font-weight: normal; 35 | color: #ffffff; 36 | line-height: 6.4vw; 37 | } 38 | 39 | .warning-warper .warning-content { 40 | margin-top: 10.13vw; 41 | width: 78.4vw; 42 | height: 24.53vw; 43 | font-size: 3.73vw; 44 | font-weight: normal; 45 | color: #ffffff; 46 | line-height: 6.13vw; 47 | letter-spacing: 1px; 48 | text-align: left; 49 | } 50 | 51 | .close { 52 | position: absolute; 53 | bottom: 8.8vw; 54 | width: 65.07vw; 55 | height: 13.87vw; 56 | } 57 | 58 | .close image { 59 | width: 100%; 60 | height: 100%; 61 | } 62 | 63 | .close view { 64 | position: absolute; 65 | top: 50%; 66 | left: 50%; 67 | transform: translate(-50%, -50%); 68 | color: rgba(255, 255, 255, 1); 69 | } 70 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/work-detail/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/components/work-detail/images/close.png -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/work-detail/work-detail.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: { 3 | showDetail: false, 4 | showMoreDetail: false, 5 | animationData: {}, 6 | }, 7 | lifetimes: { 8 | attached() { 9 | let animation = wx.createAnimation({ 10 | duration: 500, 11 | timingFunction: "ease-out", 12 | }); 13 | this.animation = animation; 14 | }, 15 | }, 16 | methods: { 17 | onClickDetail() { 18 | this.setData({ 19 | showDetail: true, 20 | }); 21 | }, 22 | onClickClose() { 23 | this.setData({ 24 | showDetail: false, 25 | showMoreDetail: false, 26 | }); 27 | }, 28 | showMoreDetail() { 29 | this.setData({ 30 | showMoreDetail: true, 31 | }); 32 | this.animation.height("124.8vw").step(); 33 | this.setData({ 34 | animationData: this.animation.export(), 35 | }); 36 | }, 37 | hideMoreDetail() { 38 | this.setData({ 39 | showMoreDetail: false, 40 | }); 41 | this.animation.height("54.67vw").step(); 42 | this.setData({ 43 | animationData: this.animation.export(), 44 | }); 45 | }, 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/work-detail/work-detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/work-detail/work-detail.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 作品 4 | 详情 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 太 阳 13 | 14 | 15 | “太阳”的作者是一对白俄罗斯夫妇,Key 17 | Detail和他的妻子Yu-BABA。该项目是立邦漆“为爱上色”公益活动。这幅壁画究竟有何含义? 在Key 18 | Detail提供的作品介绍中提到,他将女孩设计为太阳的模样,女孩身着传统川剧服饰,鲜艳饱和的色彩,代表成都人民热情好客的性格特点。女孩身边围绕的凤凰,代表动物与人的和平相处。同时,他也想把凤凰在中国文化中吉祥的美好寓意传递给成都人民。 19 | 此外,凤凰在西方文化中被称为“Phoenix”,除了被翻译为凤凰之外,还有一个名字叫做长生鸟,这样就能把长寿的祝愿带给这里的居民。 20 | 21 | 22 | “太阳”的作者是一对白俄罗斯夫妇,Key 23 | Detail和他的妻子Yu-BABA。该项目是立邦漆“为爱上色”公益活动。这幅壁画究竟有何含义? 24 | 查看全文 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/components/work-detail/work-detail.wxss: -------------------------------------------------------------------------------- 1 | .detail-btn { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | position: absolute; 7 | top: 30.13vw; 8 | left: 6.67vw; 9 | width: 10.13vw; 10 | height: 10.13vw; 11 | background: rgba(255, 238, 228, 0.41); 12 | box-shadow: 0vw 0.53vw 1.87vw 0vw rgba(58, 40, 40, 0.25); 13 | border-radius: 2.13vw; 14 | backdrop-filter: blur(15px); 15 | z-index: 2; 16 | font-size: 2.93vw; 17 | text-shadow: 0px 1px 2px rgba(58, 40, 40, 0.25); 18 | line-height: 3.2vw; 19 | box-sizing: border-box; 20 | color: #ffffff; 21 | } 22 | 23 | .detail-warper { 24 | position: absolute; 25 | width: 100%; 26 | height: 100%; 27 | background: rgba(36, 36, 36, 0.78); 28 | backdrop-filter: blur(50px); 29 | z-index: 10; 30 | } 31 | 32 | .close-btn { 33 | display: flex; 34 | justify-content: center; 35 | align-items: center; 36 | position: absolute; 37 | top: 30.13vw; 38 | right: 6.67vw; 39 | width: 8.53vw; 40 | height: 8.53vw; 41 | background-color: rgba(255, 238, 228, 0.41); 42 | border-radius: 50%; 43 | line-height: 8.53vw; 44 | z-index: 2; 45 | } 46 | 47 | .close-btn .close-image { 48 | width: 4.27vw; 49 | } 50 | 51 | .detail-warper .work { 52 | position: absolute; 53 | width: 78.13vw; 54 | top: 34.4vw; 55 | left: 50%; 56 | transform: translateX(-50%); 57 | } 58 | 59 | .introduction { 60 | display: flex; 61 | flex-direction: column; 62 | align-items: center; 63 | position: absolute; 64 | bottom: 0px; 65 | width: 100vw; 66 | height: 54.67vw; 67 | background: rgba(255, 255, 255, 0.72); 68 | box-shadow: 0vw 0.53vw 9.87vw 0vw #2e5064; 69 | border-radius: 6.67vw 6.67vw 0vw 0vw; 70 | backdrop-filter: blur(27px); 71 | } 72 | 73 | .title { 74 | margin-top: 5.6vw; 75 | height: 9.6vw; 76 | font-size: 6.67vw; 77 | font-weight: bold; 78 | color: #313435; 79 | line-height: 9.6vw; 80 | } 81 | 82 | .breakline { 83 | margin-top: 3vw; 84 | width: 80vw; 85 | height: 1px; 86 | background-color: #c0c0c0; 87 | } 88 | 89 | .introduction-detail { 90 | margin-top: 4.8vw; 91 | width: 80vw; 92 | height: 25.33vw; 93 | font-weight: normal; 94 | color: #464b50; 95 | line-height: 6vw; 96 | font-size: 4vw; 97 | color: #464b50; 98 | text-align: left; 99 | } 100 | 101 | .more-detail { 102 | width: 16vw; 103 | height: 4.53vw; 104 | font-size: 3.2vw; 105 | font-weight: normal; 106 | color: #912c07; 107 | line-height: 4.53vw; 108 | } 109 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/index/index.js: -------------------------------------------------------------------------------- 1 | function getPrivate() { 2 | if (wx.requirePrivacyAuthorize) { 3 | return new Promise((resolve, reject) => { 4 | wx.requirePrivacyAuthorize({ 5 | success: (res) => { 6 | console.log("用户同意了隐私协议"); 7 | resolve(res); 8 | }, 9 | fail: (res) => { 10 | reject(res); 11 | console.log("用户拒绝了隐私协议"); 12 | }, 13 | }); 14 | }); 15 | } else { 16 | return Promise.resolve(); 17 | } 18 | } 19 | 20 | Page({ 21 | data: { 22 | showVideo: false, 23 | showChooseBtn: false, 24 | // 胶囊按钮高度 25 | menuButtonHeight: "32px", 26 | // 胶囊按钮位置 27 | capsuleTop: "48px", 28 | }, 29 | 30 | onLoad() { 31 | wx.loadFontFace({ 32 | family: "PangMenZhengDao", 33 | source: 34 | 'url("https://kivicube-resource.kivisense.com/projects/solar-divine-bird-mp/fonts/PangMenZhengDaoBiaoTiTi.ttf")', 35 | fail(e) { 36 | wx.showToast({ 37 | title: "字体文件加载失败", 38 | icon: "none", 39 | duration: 1000, 40 | }); 41 | console.error(e); 42 | }, 43 | }); 44 | //设置左上角按钮的位置和高度 45 | const { top: capsuleTop, height: capsuleHeight } = 46 | wx.getMenuButtonBoundingClientRect(); 47 | 48 | this.setData({ 49 | menuButtonHeight: capsuleHeight + "px", 50 | capsuleTop: capsuleTop + "px", 51 | }); 52 | }, 53 | 54 | videoPlay() { 55 | this.setData({ 56 | showVideo: true, 57 | }); 58 | }, 59 | 60 | async showChooseBtn() { 61 | try { 62 | await getPrivate(); 63 | this.setData({ 64 | showChooseBtn: true, 65 | }); 66 | } catch (error) { 67 | console.log(error); 68 | } 69 | }, 70 | hideChooseBtn() { 71 | this.setData({ 72 | showChooseBtn: false, 73 | }); 74 | }, 75 | 76 | //分享小程序到微信聊天界面 77 | onShareAppMessage() { 78 | return { 79 | title: "扫描线下“The Sun”壁画查看AR效果", 80 | path: "/pages/index/index", 81 | imageUrl: "/asset/share.jpg", 82 | }; 83 | }, 84 | //分享小程序到朋友圈 85 | onShareTimeline() { 86 | return { 87 | title: "扫描线下“The Sun”壁画查看AR效果", 88 | path: "/pages/index/index", 89 | imageUrl: "/asset/share.jpg", 90 | }; 91 | }, 92 | }); 93 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "disableScroll": true, 3 | "navigationStyle": "custom", 4 | "usingComponents": { 5 | "private-modal": "../../components/private-modal/private-modal", 6 | "copyright": "/components/copyright/copyright" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 26 | AR实境动态壁画 27 | 28 | 29 | 成都市武侯区得胜社区 30 | 31 | 32 | 33 | 即刻体验 34 | 35 | 36 | 37 | 38 | 我在线上 39 | 40 | 41 | 42 | 我在线下 43 | 44 | 45 | 46 | 免费制作同款AR 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | position: absolute; 6 | width: 100%; 7 | height: 100%; 8 | overflow: hidden; 9 | } 10 | 11 | .bg { 12 | position: absolute; 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | .bg-video { 18 | position: absolute; 19 | top: 0; 20 | left: 0; 21 | width: 100vw; 22 | height: 100%; 23 | } 24 | 25 | .mask { 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | width: 100%; 30 | height: 100%; 31 | background: linear-gradient(183deg, rgba(7, 6, 6, 0) 0%, #292323 100%); 32 | opacity: 0.84; 33 | } 34 | 35 | .hide-choose-btn { 36 | position: absolute; 37 | left: 16px; 38 | } 39 | 40 | .title { 41 | margin-top: 101.6vw; 42 | width: 36vw; 43 | height: 17.07vw; 44 | font-size: 8.53vw; 45 | font-family: PangMenZhengDao; 46 | color: #ffffff; 47 | line-height: 9.87vw; 48 | text-shadow: 0px 1px 5px rgba(32, 35, 44, 0.63); 49 | z-index: 2; 50 | text-align: center; 51 | } 52 | 53 | .position { 54 | display: flex; 55 | align-items: center; 56 | margin-top: 7.47vw; 57 | z-index: 2; 58 | } 59 | 60 | .position image { 61 | width: 4.8vw; 62 | height: 5.87vw; 63 | } 64 | 65 | .position-content { 66 | margin-left: 1.86vw; 67 | width: 45vw; 68 | color: rgba(255, 255, 255, 1); 69 | font-weight: normal; 70 | } 71 | 72 | .btn { 73 | display: flex; 74 | justify-content: center; 75 | align-items: center; 76 | width: 66.13vw; 77 | } 78 | 79 | .btn image { 80 | position: absolute; 81 | width: 100%; 82 | height: auto; 83 | } 84 | 85 | .btn view { 86 | color: rgba(255, 255, 255, 1); 87 | font-weight: bold; 88 | z-index: 2; 89 | } 90 | 91 | .exprience { 92 | position: absolute; 93 | bottom: 25vw; 94 | width: 66.13vw; 95 | height: 15.47vw; 96 | } 97 | 98 | .btn-warper { 99 | position: absolute; 100 | bottom: 10vw; 101 | z-index: 2; 102 | } 103 | 104 | .online { 105 | position: relative; 106 | width: 52.27vw; 107 | height: 12.53vw; 108 | } 109 | 110 | .offline { 111 | position: relative; 112 | margin-top: 5.07vw; 113 | width: 52.27vw; 114 | height: 12.53vw; 115 | } 116 | 117 | .produce { 118 | position: absolute; 119 | bottom: 15vw; 120 | height: 4.53vw; 121 | font-size: 3.2vw; 122 | font-weight: bold; 123 | color: #ffffff; 124 | line-height: 4.53vw; 125 | z-index: 2; 126 | } 127 | 128 | .produce view { 129 | height: 4.53vw; 130 | font-size: 3.2vw; 131 | font-weight: bold; 132 | color: #ffffff; 133 | line-height: 4.53vw; 134 | } 135 | 136 | .produce .underline { 137 | width: 100%; 138 | height: 1px; 139 | background-color: #ffffff; 140 | } 141 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/webview/webview.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | //分享小程序到微信聊天界面 3 | onShareAppMessage() { 4 | return { 5 | title: "扫描线下“The Sun”壁画查看AR效果", 6 | path: "/pages/index/index", 7 | imageUrl: "/asset/share.jpg", 8 | }; 9 | }, 10 | //分享小程序到朋友圈 11 | onShareTimeline() { 12 | return { 13 | title: "扫描线下“The Sun”壁画查看AR效果", 14 | path: "/pages/index/index", 15 | imageUrl: "/asset/share.jpg", 16 | }; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/webview/webview.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/webview/webview.wxml: -------------------------------------------------------------------------------- 1 | 4 | 点击打开 5 | 6 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/pages/webview/webview.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/pages/webview/webview.wxss -------------------------------------------------------------------------------- /solar-divine-bird-mp/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [], 5 | "include": [] 6 | }, 7 | "setting": { 8 | "urlCheck": true, 9 | "es6": true, 10 | "enhance": true, 11 | "postcss": true, 12 | "preloadBackgroundData": false, 13 | "minified": true, 14 | "newFeature": false, 15 | "coverView": true, 16 | "nodeModules": true, 17 | "autoAudits": false, 18 | "showShadowRootInWxmlPanel": true, 19 | "scopeDataCheck": false, 20 | "uglifyFileName": false, 21 | "checkInvalidKey": true, 22 | "checkSiteMap": true, 23 | "uploadWithSourceMap": true, 24 | "compileHotReLoad": false, 25 | "lazyloadPlaceholderEnable": false, 26 | "useMultiFrameRuntime": true, 27 | "useApiHook": true, 28 | "useApiHostProcess": true, 29 | "babelSetting": { 30 | "ignore": [], 31 | "disablePlugins": [], 32 | "outputPath": "" 33 | }, 34 | "enableEngineNative": false, 35 | "useIsolateContext": false, 36 | "userConfirmedBundleSwitch": false, 37 | "packNpmManually": false, 38 | "packNpmRelationList": [], 39 | "minifyWXSS": true, 40 | "disableUseStrict": false, 41 | "minifyWXML": true, 42 | "showES6CompileOption": false, 43 | "useCompilerPlugins": false, 44 | "condition": false, 45 | "compileWorklet": false, 46 | "localPlugins": false, 47 | "swc": false, 48 | "disableSWC": true 49 | }, 50 | "compileType": "miniprogram", 51 | "libVersion": "2.21.3", 52 | "appid": "wx03800a762308862c", 53 | "projectname": "solar-divine-bird-mp", 54 | "condition": {}, 55 | "editorSetting": { 56 | "tabIndent": "insertSpaces", 57 | "tabSize": 2 58 | }, 59 | "simulatorPluginLibVersion": {} 60 | } -------------------------------------------------------------------------------- /solar-divine-bird-mp/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [ 4 | { 5 | "action": "allow", 6 | "page": "*" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /solar-divine-bird-mp/识别图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/solar-divine-bird-mp/识别图.jpg -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/Kivicube/pages/exprience/exprience.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | //是否显示loading页面,在进入页面时显示,在kivicube-scene场景加载完成后(loadSceneEnd)关闭 4 | showCustomDownload: true, 5 | //判断是否加载kivicube-scene,因为kivicube-scene需要摄像机权限,所以获取摄像机权限后再加载整个kivicube-scene组件 6 | showKiviScene: false, 7 | //是否显示领取红包封面 8 | showRedEnvelopes: false, 9 | //设定kivicube-scene初始化使用的摄像头 10 | cameraPos: "front", 11 | //海报标签的显示 12 | hidePoster: true, 13 | //需要展示的海报的地址,方便保存,base64字符串,生成速度比canvasToTempFilePath快很多 14 | posterUrl: "", 15 | }, 16 | async onLoad() { 17 | //获取摄像头权限后,渲染kivicube-scene 18 | const { authSetting } = await wx.getSetting(); 19 | if (!authSetting["scope.camera"]) { 20 | try { 21 | await wx.authorize({ 22 | scope: "scope.camera", 23 | }); 24 | this.setData({ 25 | showKiviScene: true, 26 | }); 27 | } catch (error) { 28 | wx.showModal({ 29 | title: "摄像头权限被拒绝", 30 | content: "AR体验需要您授予摄像头权限", 31 | cancelText: "不授权", 32 | cancelColor: "#999", 33 | confirmText: "去授权", 34 | confirmColor: "#f94218", 35 | success: async (res) => { 36 | if (res.confirm) { 37 | const { authSetting } = await wx.openSetting(); 38 | if (authSetting["scope.camera"]) { 39 | this.setData({ 40 | showKiviScene: true, 41 | }); 42 | } else { 43 | wx.navigateBack(); 44 | } 45 | } else if (res.cancel) { 46 | wx.navigateBack(); 47 | } 48 | }, 49 | }); 50 | } 51 | } else { 52 | // 有权限则直接获取 53 | this.setData({ 54 | showKiviScene: true, 55 | }); 56 | } 57 | }, 58 | 59 | onShow() { 60 | //页面常亮 61 | wx.setKeepScreenOn({ 62 | keepScreenOn: true, 63 | }); 64 | }, 65 | 66 | //kivicube-scene组件的bindready事件绑定的函数,通过这个函数获取并保存场景的信息 67 | ready({ detail: view }) { 68 | this.view = view; 69 | }, 70 | 71 | //场景加载完成后才关闭loading页面 72 | loadSceneEnd() { 73 | //跳过云识别 74 | this.view.skipCloudar(); 75 | this.setData({ 76 | showCustomDownload: false, 77 | }); 78 | }, 79 | 80 | //如果跳过云识别,直接进入这个函数;如果没跳过云识别,在扫描到识别图时进入这个函数 81 | sceneStart() { 82 | //5s后展示领取红包封面的弹窗 83 | setTimeout(() => { 84 | if (!wx.getStorageSync("redEnvelopesShowed")) { 85 | wx.setStorageSync("redEnvelopesShowed", true); 86 | this.setData({ 87 | showRedEnvelopes: true, 88 | }); 89 | } 90 | }, 5000); 91 | }, 92 | 93 | //自定义拍照按钮需要2步操作:1,在kivicube-scene上设置hideTakePhoto;2给自定义的点击按钮绑定方法 94 | generatePhoto() { 95 | wx.showLoading({ 96 | title: "拍照中", 97 | mask: true, 98 | }); 99 | //自定义拍照 100 | this.view 101 | .takePhoto() 102 | .then(async (photo) => { 103 | //在canvas上生成海报 104 | //获取canvas实例 105 | const canvasInstance = await new Promise((resolve) => { 106 | wx.createSelectorQuery() 107 | .select("#photoCanvas") 108 | .fields({ 109 | node: true, 110 | size: true, 111 | }) 112 | .exec((res) => { 113 | resolve(res[0]); 114 | }); 115 | }); 116 | 117 | //因为后面要设置canvas画布的实际大小,所以获取物理像素比 118 | let dpr = wx.getSystemInfoSync().pixelRatio; 119 | //canvas的宽度和高度,在生成海报时大量使用(逻辑像素) 120 | const canvasWidth = canvasInstance.width; 121 | const canvasHeight = canvasInstance.height; 122 | 123 | //获取并存储canvas实例,在生成海报阶段的wx.canvasToTempFilePath使用 124 | const canvas = canvasInstance.node; 125 | 126 | //获取canvas上下文,在生成海报中绘制各种元素时使用 127 | const ctx = canvas.getContext("2d"); 128 | 129 | //设置canvas画布的大小(物理像素) 130 | canvas.width = canvasWidth * dpr; 131 | canvas.height = canvasHeight * dpr; 132 | 133 | const vwToPx = (vw) => (canvas.width / 100) * vw; 134 | 135 | const loadImg = (canvas, imgPath) => { 136 | return new Promise((resolve, reject) => { 137 | let img = canvas.createImage(); 138 | img.src = imgPath; 139 | img.onload = () => { 140 | resolve(img); 141 | }; 142 | img.onerror = () => { 143 | //onerror函数没有参数 144 | reject(new Error("图片加载错误")); 145 | }; 146 | }); 147 | }; 148 | 149 | //canvas绘制过程中出现的数字均为设计图上的内容 150 | //生成海报背景图片 151 | try { 152 | const bgImg = await loadImg(canvas, "/asset/poster-bg.png"); 153 | ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height); 154 | } catch (error) { 155 | throw new Error(error); 156 | } 157 | 158 | //在海报上生成kivicube-scene拍摄出的照片 159 | try { 160 | //kivicube-scene生成照片的宽和高信息,在生成海报时裁切照片时用到 161 | const { width: picWidth, height: picHeight } = await wx.getImageInfo({ 162 | src: photo, 163 | }); 164 | let img = await loadImg(canvas, photo); 165 | //最终生成在海报上照片的宽高比 166 | let genePhotoRatio = 59.07 / 92.77; 167 | //获取最终生成海报时所需kivi-scene拍摄出照片的总高度和纵向起始位置 168 | let imgTotalHeight = picWidth / genePhotoRatio; 169 | let imgStartY = (picHeight - imgTotalHeight) / 2; 170 | ctx.drawImage( 171 | img, 172 | 0, 173 | imgStartY, 174 | picWidth, 175 | imgTotalHeight, 176 | vwToPx(5.65), 177 | vwToPx(16.77), 178 | vwToPx(88.6), 179 | vwToPx(139.14) 180 | ); 181 | } catch (error) { 182 | throw new Error(error); 183 | } 184 | 185 | //生成二维码 186 | try { 187 | let qrcode = await loadImg(canvas, "/asset/qrcode.png"); 188 | ctx.drawImage( 189 | qrcode, 190 | vwToPx(68.9), 191 | vwToPx(159.45), 192 | vwToPx(21.04), 193 | vwToPx(21.34) 194 | ); 195 | } catch (error) { 196 | throw new Error(error); 197 | } 198 | 199 | //生成kivisense的logo 200 | try { 201 | let logo = await loadImg(canvas, "/asset/logo.png"); 202 | ctx.drawImage( 203 | logo, 204 | vwToPx(26.22), 205 | vwToPx(7.32), 206 | vwToPx(46.04), 207 | vwToPx(4.57) 208 | ); 209 | } catch (error) { 210 | throw new Error(error); 211 | } 212 | 213 | //生成文本 214 | ctx.fillStyle = "#feeca3"; 215 | ctx.font = `normal 700 ${vwToPx(6.1)}px PingFangSC-Semibold`; 216 | ctx.fillText("AR虎娃贺新春", vwToPx(8.23), vwToPx(161.59 + 6.1)); 217 | ctx.font = `normal 400 ${vwToPx(4.57)}px PingFangSC`; 218 | ctx.fillText( 219 | "即刻体验,领取红包封面", 220 | vwToPx(8.23), 221 | vwToPx(161.59 + 6.1 + 8.54) 222 | ); 223 | 224 | //cnavas转换成能展示的图片 225 | try { 226 | const { tempFilePath } = await wx.canvasToTempFilePath({ 227 | x: 0, 228 | y: 0, 229 | width: canvasWidth, 230 | height: canvasHeight, 231 | destWidth: canvas.width, 232 | destHeight: canvas.height, 233 | canvas, 234 | }); 235 | //显示海报,隐藏拍照按钮 236 | this.setData({ 237 | posterUrl: tempFilePath, 238 | hidePoster: false, 239 | }); 240 | } catch (error) { 241 | throw new Error(error); 242 | } 243 | 244 | wx.hideLoading(); 245 | }) 246 | .catch((e) => { 247 | wx.hideLoading(); 248 | wx.showToast({ 249 | icon: "none", 250 | title: "照片生成失败,请稍后再试", 251 | duration: 1000, 252 | }); 253 | console.error(e); 254 | }); 255 | }, 256 | 257 | //kivicube-scene的binderror事件绑定的函数,用于判定错误信息, 258 | error(e) { 259 | const { detail } = e; 260 | // 判定是否camera权限问题,是则向用户申请权限。 261 | if (detail && detail.isCameraAuthDenied) { 262 | const page = this; 263 | wx.showModal({ 264 | title: "提示", 265 | content: "请给予“摄像头”权限", 266 | success() { 267 | wx.openSetting({ 268 | success({ authSetting: { "scope.camera": isGrantedCamera } }) { 269 | if (isGrantedCamera) { 270 | wx.redirectTo({ 271 | url: "/" + page.__route__, 272 | }); 273 | } else { 274 | wx.showToast({ 275 | title: "获取“摄像头”权限失败!", 276 | icon: "none", 277 | }); 278 | } 279 | }, 280 | }); 281 | }, 282 | }); 283 | } 284 | console.error(detail); 285 | }, 286 | 287 | //切换前后置摄像头的逻辑 288 | switchCamera() { 289 | const position = this.data.cameraPos === "front" ? "back" : "front"; 290 | this.view.switchCamera(position); 291 | this.setData({ 292 | cameraPos: position, 293 | }); 294 | }, 295 | 296 | //重新拍摄海报的逻辑 297 | rePhoto() { 298 | this.setData({ 299 | hidePoster: true, 300 | posterUrl: "", 301 | }); 302 | }, 303 | 304 | //分享小程序到微信聊天界面 305 | onShareAppMessage() { 306 | return { 307 | title: "AR虎娃贺新春", 308 | path: "/pages/index/index", 309 | imageUrl: "/asset/share.jpg", 310 | }; 311 | }, 312 | //分享小程序到朋友圈 313 | onShareTimeline() { 314 | return { 315 | title: "AR虎娃贺新春", 316 | path: "/pages/index/index", 317 | imageUrl: "/asset/share.jpg", 318 | }; 319 | }, 320 | 321 | //领取红包封面 322 | showRedPackage() { 323 | wx.showRedPackage({ 324 | url: "https://support.weixin.qq.com/cgi-bin/mmsupport-bin/showredpacket?receiveuri=abcJqTpylEG&check_type=2#wechat_redirect", 325 | success: () => { 326 | this.setData({ 327 | showRedEnvelopes: false, 328 | }); 329 | }, 330 | }); 331 | }, 332 | }); 333 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/Kivicube/pages/exprience/exprience.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "kivicube-scene": "plugin://kivicube/kivicube-scene", 6 | "back-button": "/components/back-button/back-button", 7 | "loading": "/components/loading/loading", 8 | "poster": "/components/poster/poster" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/Kivicube/pages/exprience/exprience.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 领取红包封面 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/Kivicube/pages/exprience/exprience.wxss: -------------------------------------------------------------------------------- 1 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 2 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 3 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/app.js: -------------------------------------------------------------------------------- 1 | App({}); 2 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": ["pages/index/index"], 3 | "window": { 4 | "backgroundTextStyle": "light", 5 | "navigationBarBackgroundColor": "#fff", 6 | "navigationBarTitleText": "Weixin", 7 | "navigationBarTextStyle": "black", 8 | "initialRenderingCache": "static" 9 | }, 10 | "subpackages": [ 11 | { 12 | "root": "Kivicube", 13 | "pages": ["pages/exprience/exprience"], 14 | "plugins": { 15 | "kivicube": { 16 | "version": "2.16.8", 17 | "provider": "wx3bbab3920eabccb2" 18 | } 19 | } 20 | } 21 | ], 22 | "preloadRule": { 23 | "pages/index/index": { 24 | "network": "wifi", 25 | "packages": ["Kivicube"] 26 | } 27 | }, 28 | "__usePrivacyCheck__": true, 29 | "style": "v2", 30 | "sitemapLocation": "sitemap.json" 31 | } 32 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/app.wxss: -------------------------------------------------------------------------------- 1 | .gold-text { 2 | color: #feeca3; 3 | } 4 | 5 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 6 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 7 | .subpkg-kivi-scene { 8 | display: block; 9 | position: absolute; 10 | width: 100vw; 11 | height: 100%; 12 | } 13 | 14 | .subpkg-custom-photo { 15 | position: absolute; 16 | left: 50%; 17 | bottom: 6.49vw; 18 | transform: translateX(-50%); 19 | width: 45.96vw; 20 | height: 45.96vw; 21 | z-index: 5; 22 | } 23 | 24 | .subpkg-switch-camera { 25 | position: absolute; 26 | right: 8.71vw; 27 | bottom: 23.11vw; 28 | transform: translateX(-50%); 29 | width: 12.71vw; 30 | height: 12.71vw; 31 | z-index: 5; 32 | } 33 | 34 | .subpkg-poster-canvas { 35 | position: absolute; 36 | top: 20vw; 37 | left: -1000vw; 38 | width: 100vw; 39 | height: 188.1vw; 40 | } 41 | 42 | .subpkg-red-envelopes-container { 43 | position: absolute; 44 | width: 100vw; 45 | height: 100%; 46 | background-color: rgba(255, 255, 255, 0.9); 47 | z-index: 6; 48 | } 49 | 50 | @supports ((-webkit-backdrop-filter: none) or (backdrop-filter: none)) { 51 | .subpkg-red-envelopes-container { 52 | background-color: rgba(255, 255, 255, 0.5); 53 | -webkit-backdrop-filter: blur(10px); 54 | backdrop-filter: blur(10px); 55 | } 56 | } 57 | 58 | .subpkg-red-envelopes-warper { 59 | position: absolute; 60 | top: 50%; 61 | left: 50%; 62 | transform: translate(-50%, -50%); 63 | width: 60.53vw; 64 | height: 85.33vw; 65 | animation: zoom 0.2s ease-in 0s 1; 66 | } 67 | 68 | @keyframes zoom { 69 | 0% { 70 | opacity: 0; 71 | transform: translate(-50%, -50%) scale(0); 72 | } 73 | 74 | 50% { 75 | opacity: 1; 76 | } 77 | 78 | 100% { 79 | transform: translate(-50%, -50%) scale(1); 80 | } 81 | } 82 | 83 | .subpkg-red-envelopes-warper .subpkg-red-envelopes-bg { 84 | width: 100%; 85 | height: 100%; 86 | } 87 | 88 | .subpkg-red-envelopes-button { 89 | position: absolute; 90 | bottom: 6.13vw; 91 | left: 50%; 92 | transform: translateX(-50%); 93 | width: 46.67vw; 94 | height: 12.27vw; 95 | } 96 | 97 | .subpkg-red-envelopes-button image { 98 | width: 100%; 99 | height: 100%; 100 | } 101 | 102 | .subpkg-red-envelopes-button text { 103 | position: absolute; 104 | top: 50%; 105 | left: 50%; 106 | height: 4.53vw; 107 | line-height: 4.53vw; 108 | transform: translate(-50%, -50%); 109 | z-index: 100; 110 | font-size: 3.73vw; 111 | } 112 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/2022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/2022.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/button.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/custom-photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/custom-photo.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/fish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/fish.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/home-bg-short.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/home-bg-short.jpg -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/home-bg.jpg -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/logo.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/poster-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/poster-bg.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/qrcode.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/red-envelopes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/red-envelopes.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/share-red-envelopes-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/share-red-envelopes-button.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/share.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/switch-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/switch-camera.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/asset/tiger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/asset/tiger.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/back-button/back-button.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: { 3 | // // 胶囊按钮高度 4 | menuButtonHeight: "32px", 5 | // // 左边返回按钮距屏幕顶部的距离 6 | capsuleTop: "48px", 7 | }, 8 | 9 | lifetimes: { 10 | attached() { 11 | //在自定义navigationStyle的情况下自定义返回键的位置需要获取如下信息 12 | const { top, height } = wx.getMenuButtonBoundingClientRect(); 13 | 14 | this.setData({ 15 | menuButtonHeight: height + "px", 16 | capsuleTop: top + "px", 17 | }); 18 | }, 19 | }, 20 | 21 | methods: { 22 | async goBack() { 23 | try { 24 | await wx.navigateBack(); 25 | } catch (error) { 26 | wx.navigateTo({ 27 | url: "/pages/index/index", 28 | }); 29 | } 30 | }, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/back-button/back-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/back-button/back-button.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/back-button/back-button.wxss: -------------------------------------------------------------------------------- 1 | .back { 2 | position: absolute; 3 | left: 2.67vw; 4 | z-index: 100; 5 | } 6 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/back-button/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes-高级api/components/back-button/images/back.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/loading/loading.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | styleIsolation: "apply-shared", 4 | }, 5 | }); 6 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/loading/loading.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/loading/loading.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 加载中... 5 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/loading/loading.wxss: -------------------------------------------------------------------------------- 1 | .loading-warper { 2 | position: absolute; 3 | width: 100vw; 4 | height: 100%; 5 | text-align: center; 6 | background: linear-gradient( 7 | 8deg, 8 | #ff3737 0%, 9 | #ee6853 63%, 10 | #dd3c2d 100%, 11 | #dd3c2d 100% 12 | ); 13 | z-index: 5; 14 | } 15 | 16 | .loading-tiger { 17 | position: absolute; 18 | top: 50%; 19 | left: 50%; 20 | transform: translate(-50%, -50%); 21 | width: 37.6vw; 22 | height: 37.6vw; 23 | } 24 | 25 | .loading-fish { 26 | position: absolute; 27 | top: 50%; 28 | left: 50%; 29 | width: 60.53vw; 30 | height: 60.8vw; 31 | animation: spin 4s linear 0s infinite; 32 | } 33 | 34 | @keyframes spin { 35 | 0% { 36 | transform: translate(-50%, -50%) rotateZ(0deg); 37 | } 38 | 39 | 100% { 40 | transform: translate(-50%, -50%) rotateZ(360deg); 41 | } 42 | } 43 | 44 | .loading-warper text { 45 | position: absolute; 46 | top: 142.47vw; 47 | transform: translateX(-50%); 48 | width: 18.35vw; 49 | height: 5.96vw; 50 | font-size: 14px; 51 | line-height: 4.53vw; 52 | font-weight: normal; 53 | } 54 | 55 | @media screen and (min-aspect-ratio: 375/668) { 56 | .loading-warper text { 57 | top: 117.33vw; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/poster/poster.js: -------------------------------------------------------------------------------- 1 | // components/poster/poster.js 2 | Component({ 3 | options: { 4 | styleIsolation: "apply-shared", 5 | }, 6 | properties: { 7 | posterUrl: String, 8 | //自定义组件手动支持hidden 9 | hidden: Boolean, 10 | }, 11 | 12 | methods: { 13 | rePhoto() { 14 | this.triggerEvent("rephoto"); 15 | }, 16 | //将海报保存到本地相册 17 | async savePhoto() { 18 | const { authSetting } = await wx.getSetting(); 19 | //保存图片到本地 20 | const savePhotoToAlbum = () => { 21 | wx.saveImageToPhotosAlbum({ 22 | filePath: this.data.posterUrl, 23 | success() { 24 | wx.showToast({ 25 | icon: "none", 26 | title: "照片已保存到相册", 27 | duration: 1000, 28 | }); 29 | }, 30 | fail() { 31 | wx.showToast({ 32 | icon: "none", 33 | title: "照片保存失败,请稍后再试", 34 | duration: 1000, 35 | }); 36 | }, 37 | }); 38 | }; 39 | if (!authSetting["scope.writePhotosAlbum"]) { 40 | try { 41 | await wx.authorize({ 42 | scope: "scope.writePhotosAlbum", 43 | }); 44 | savePhotoToAlbum(); 45 | } catch (error) { 46 | wx.showModal({ 47 | title: "相册权限被拒绝", 48 | content: "保存照片需要您授予相册权限", 49 | cancelText: "取消", 50 | cancelColor: "#999", 51 | confirmText: "去授权", 52 | confirmColor: "#f94218", 53 | success: async (res) => { 54 | if (res.confirm) { 55 | const { authSetting } = await wx.openSetting(); 56 | if (authSetting["scope.writePhotosAlbum"]) { 57 | savePhotoToAlbum(); 58 | } else { 59 | return; 60 | } 61 | } else if (res.cancel) { 62 | return; 63 | } 64 | }, 65 | }); 66 | } 67 | } else { 68 | // 有权限则直接存 69 | savePhotoToAlbum(); 70 | } 71 | }, 72 | }, 73 | }); 74 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/poster/poster.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/poster/poster.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/poster/poster.wxss: -------------------------------------------------------------------------------- 1 | .poster-img { 2 | position: absolute; 3 | top: 27.73vw; 4 | left: 6.27vw; 5 | width: 87.47vw; 6 | height: 164.53vw; 7 | z-index: 10; 8 | } 9 | 10 | .savephoto { 11 | position: absolute; 12 | right: 3.73vw; 13 | top: 195.2vw; 14 | width: 45.33vw; 15 | height: 14.93vw; 16 | } 17 | 18 | .savephoto image { 19 | width: 100%; 20 | height: 100%; 21 | vertical-align: middle; 22 | } 23 | 24 | .savephoto text { 25 | position: absolute; 26 | top: 50%; 27 | left: 50%; 28 | transform: translate(-50%, -50%); 29 | font-size: 3.73vw; 30 | line-height: 5.73vw; 31 | } 32 | 33 | .rephoto { 34 | position: absolute; 35 | left: 4vw; 36 | top: 195.2vw; 37 | width: 45.07vw; 38 | height: 14.93vw; 39 | } 40 | 41 | .rephoto image { 42 | width: 100%; 43 | height: 100%; 44 | vertical-align: middle; 45 | } 46 | 47 | .rephoto text { 48 | position: absolute; 49 | top: 50%; 50 | left: 50%; 51 | transform: translate(-50%, -50%); 52 | font-size: 3.73vw; 53 | line-height: 5.73vw; 54 | } 55 | 56 | @media screen and (min-aspect-ratio: 375/668) { 57 | .poster-img { 58 | top: 21.87vw; 59 | left: 17.33vw; 60 | width: 66.93vw; 61 | height: 125.6vw; 62 | } 63 | 64 | .savephoto { 65 | bottom: 12.8vw; 66 | left: 8.27vw; 67 | width: 41.6vw; 68 | height: 13.6vw; 69 | } 70 | 71 | .rephoto { 72 | bottom: 12.8vw; 73 | right: 6.67vw; 74 | width: 41.6vw; 75 | height: 13.6vw; 76 | } 77 | } 78 | 79 | .poster-warper { 80 | position: absolute; 81 | left: 0; 82 | right: 0; 83 | bottom: 0; 84 | top: 0; 85 | background-color: rgba(255, 255, 255, 0.9); 86 | z-index: 5; 87 | } 88 | 89 | @supports ((-webkit-backdrop-filter: none) or (backdrop-filter: none)) { 90 | .poster-warper { 91 | background-color: rgba(255, 255, 255, 0.5); 92 | -webkit-backdrop-filter: blur(10px); 93 | backdrop-filter: blur(10px); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/private-modal/private-modal.js: -------------------------------------------------------------------------------- 1 | let privacyHandler; 2 | let privacyResolves = new Set(); 3 | let closeOtherPagePopUpHooks = new Set(); 4 | 5 | if (wx.onNeedPrivacyAuthorization) { 6 | wx.onNeedPrivacyAuthorization((resolve) => { 7 | console.log( 8 | "触发 onNeedPrivacyAuthorization", 9 | typeof privacyHandler === "function" 10 | ); 11 | if (typeof privacyHandler === "function") { 12 | privacyHandler(resolve); 13 | } 14 | }); 15 | } 16 | 17 | const closeOtherPagePopUp = (closePopUp) => { 18 | closeOtherPagePopUpHooks.forEach((hook) => { 19 | if (closePopUp !== hook) { 20 | hook(); 21 | } 22 | }); 23 | }; 24 | 25 | Component({ 26 | properties: { 27 | currentBtnText: { 28 | type: String, 29 | value: "同意", 30 | }, 31 | }, 32 | data: { 33 | innerShow: false, 34 | privacyContractName: "AR虎娃贺新春小程序隐私保护指引", 35 | }, 36 | lifetimes: { 37 | attached() { 38 | const closePopUp = () => { 39 | this.disPopUp(); 40 | }; 41 | privacyHandler = (resolve) => { 42 | privacyResolves.add(resolve); 43 | this.popUp(); 44 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 45 | closeOtherPagePopUp(closePopUp); 46 | }; 47 | 48 | this.closePopUp = closePopUp; 49 | closeOtherPagePopUpHooks.add(this.closePopUp); 50 | }, 51 | detached() { 52 | closeOtherPagePopUpHooks.delete(this.closePopUp); 53 | }, 54 | }, 55 | pageLifetimes: { 56 | show() { 57 | if (this.closePopUp) { 58 | privacyHandler = (resolve) => { 59 | privacyResolves.add(resolve); 60 | this.popUp(); 61 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 62 | closeOtherPagePopUp(this.closePopUp); 63 | }; 64 | } 65 | }, 66 | }, 67 | methods: { 68 | handleAgree() { 69 | this.disPopUp(); 70 | // 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行 (看page/index/index中的 wx.getClipboardData 和 wx.startCompass) 71 | privacyResolves.forEach((resolve) => { 72 | resolve({ 73 | event: "agree", 74 | buttonId: "agree-btn", 75 | }); 76 | }); 77 | privacyResolves.clear(); 78 | }, 79 | handleDisagree() { 80 | this.disPopUp(); 81 | privacyResolves.forEach((resolve) => { 82 | resolve({ 83 | event: "disagree", 84 | }); 85 | }); 86 | privacyResolves.clear(); 87 | }, 88 | popUp() { 89 | if (this.data.innerShow === false) { 90 | this.setData({ 91 | innerShow: true, 92 | }); 93 | } 94 | }, 95 | disPopUp() { 96 | if (this.data.innerShow === true) { 97 | this.setData({ 98 | innerShow: false, 99 | }); 100 | } 101 | }, 102 | openPrivacyContract() { 103 | wx.openPrivacyContract({ 104 | success: () => { 105 | console.log("openPrivacyContract success"); 106 | }, 107 | fail: (res) => { 108 | console.error("openPrivacyContract fail", res); 109 | }, 110 | }); 111 | }, 112 | getPrivateInfo() { 113 | if (wx.getPrivacySetting) { 114 | wx.getPrivacySetting({ 115 | success: (res) => { 116 | console.log( 117 | "是否需要授权:", 118 | res.needAuthorization, 119 | "隐私协议的名称为:", 120 | res.privacyContractName 121 | ); 122 | }, 123 | fail: () => {}, 124 | complete: () => {}, 125 | }); 126 | } else { 127 | console.log("不需要隐私授权"); 128 | } 129 | }, 130 | }, 131 | }); 132 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/private-modal/private-modal.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/private-modal/private-modal.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 隐私保护指引 4 | 5 | 在使用当前小程序服务之前,请仔细阅读《{{privacyContractName}}》。如你同意《{{privacyContractName}}》,请点击“同意”开始使用。 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/components/private-modal/private-modal.wxss: -------------------------------------------------------------------------------- 1 | .privacy { 2 | position: fixed; 3 | z-index: 9999999; 4 | top: 0; 5 | right: 0; 6 | bottom: 0; 7 | left: 0; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | background: rgba(0, 0, 0, .5); 12 | } 13 | 14 | .content { 15 | width: 632rpx; 16 | box-sizing: border-box; 17 | padding: 48rpx; 18 | background: #fff; 19 | border-radius: 16rpx; 20 | } 21 | 22 | .content .title { 23 | color: #333; 24 | font-size: 32rpx; 25 | font-weight: bold; 26 | text-align: center; 27 | } 28 | 29 | .content .des { 30 | margin-top: 40rpx; 31 | color: #666; 32 | font-size: 26rpx; 33 | line-height: 1.6; 34 | text-align: justify; 35 | } 36 | 37 | .content .des .link { 38 | color: #07c160; 39 | text-decoration: underline; 40 | } 41 | 42 | .btns { 43 | display: flex; 44 | margin-top: 48rpx; 45 | } 46 | 47 | .btns .item { 48 | display: flex; 49 | width: 244rpx; 50 | height: 80rpx; 51 | box-sizing: border-box; 52 | align-items: center; 53 | justify-content: space-between; 54 | justify-content: center; 55 | padding-right: 1px; 56 | padding-left: 1px; 57 | border: none; 58 | border-radius: 16rpx; 59 | } 60 | 61 | .btns .reject { 62 | background: #f4f4f5; 63 | color: #909399; 64 | } 65 | 66 | .btns .agree { 67 | background: #07c160; 68 | color: #fff; 69 | } 70 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/pages/index/index.js: -------------------------------------------------------------------------------- 1 | const { windowWidth, windowHeight } = wx.getSystemInfoSync(); 2 | 3 | function getPrivate() { 4 | if (wx.requirePrivacyAuthorize) { 5 | return new Promise((resolve, reject) => { 6 | wx.requirePrivacyAuthorize({ 7 | success: (res) => { 8 | console.log("用户同意了隐私协议"); 9 | resolve(res); 10 | }, 11 | fail: (res) => { 12 | reject(res); 13 | console.log("用户拒绝了隐私协议"); 14 | }, 15 | }); 16 | }); 17 | } else { 18 | return Promise.resolve(); 19 | } 20 | } 21 | 22 | Page({ 23 | data: { 24 | isShortScreen: windowWidth / windowHeight > 375 / 668, 25 | }, 26 | async gotoExprience() { 27 | try { 28 | await getPrivate(); 29 | wx.navigateTo({ 30 | url: '/Kivicube/pages/exprience/exprience', 31 | }) 32 | } catch (error) { 33 | console.log(error); 34 | } 35 | }, 36 | onShareAppMessage() { 37 | return { 38 | title: "AR虎娃贺新春", 39 | path: "/pages/index/index", 40 | imageUrl: "/asset/share.png", 41 | }; 42 | }, 43 | onShareTimeline() { 44 | return { 45 | title: "AR虎娃贺新春", 46 | path: "/pages/index/index", 47 | imageUrl: "/asset/share.png", 48 | }; 49 | }, 50 | }); 51 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "private-modal": "../../components/private-modal/private-modal" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 开启虎年AR 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .new-year { 2 | position: absolute; 3 | top: 165.33vw; 4 | left: 12.27vw; 5 | width: 75.47vw; 6 | height: 23.2vw; 7 | } 8 | 9 | .btn-warper { 10 | position: absolute; 11 | top: 193.6vw; 12 | left: 19.2vw; 13 | width: 62.13vw; 14 | height: 20.27vw; 15 | } 16 | 17 | .btn-content { 18 | position: absolute; 19 | top: 50%; 20 | left: 50%; 21 | transform: translate(-50%, -50%); 22 | font-size: 5.6vw; 23 | color: #feeca3; 24 | } 25 | 26 | .bg-container { 27 | position: absolute; 28 | width: 100vw; 29 | height: 100%; 30 | overflow: hidden; 31 | background-size: 100% auto; 32 | } 33 | 34 | .bg-container image { 35 | position: absolute; 36 | width: 100vw; 37 | height: 100%; 38 | } 39 | 40 | @media screen and (min-aspect-ratio: 375/668) { 41 | .new-year { 42 | top: 127.73vw; 43 | left: 16.53vw; 44 | width: 66.93vw; 45 | height: 20vw; 46 | } 47 | 48 | .btn-warper { 49 | top: 149.33vw; 50 | left: 22.67vw; 51 | width: 54.67vw; 52 | height: 17.87vw; 53 | } 54 | 55 | .btn-content { 56 | font-size: 4.94vw; 57 | } 58 | } 59 | 60 | .btn-bg { 61 | width: 100%; 62 | height: 100%; 63 | } 64 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [], 5 | "include": [] 6 | }, 7 | "setting": { 8 | "urlCheck": false, 9 | "es6": true, 10 | "enhance": true, 11 | "postcss": true, 12 | "preloadBackgroundData": false, 13 | "minified": true, 14 | "newFeature": false, 15 | "coverView": true, 16 | "nodeModules": true, 17 | "autoAudits": false, 18 | "showShadowRootInWxmlPanel": true, 19 | "scopeDataCheck": false, 20 | "uglifyFileName": false, 21 | "checkInvalidKey": true, 22 | "checkSiteMap": true, 23 | "uploadWithSourceMap": true, 24 | "compileHotReLoad": false, 25 | "lazyloadPlaceholderEnable": false, 26 | "useMultiFrameRuntime": true, 27 | "useApiHook": true, 28 | "useApiHostProcess": true, 29 | "babelSetting": { 30 | "ignore": [], 31 | "disablePlugins": [], 32 | "outputPath": "" 33 | }, 34 | "enableEngineNative": false, 35 | "useIsolateContext": false, 36 | "userConfirmedBundleSwitch": false, 37 | "packNpmManually": false, 38 | "packNpmRelationList": [], 39 | "minifyWXSS": true, 40 | "disableUseStrict": false, 41 | "minifyWXML": true, 42 | "showES6CompileOption": false, 43 | "useCompilerPlugins": false, 44 | "condition": false 45 | }, 46 | "compileType": "miniprogram", 47 | "libVersion": "2.21.4", 48 | "appid": "wx03800a762308862c", 49 | "projectname": "tiger-year-red-envelopes", 50 | "cloudfunctionTemplateRoot": "", 51 | "condition": { 52 | "miniprogram": { 53 | "list": [ 54 | { 55 | "name": "", 56 | "pathName": "Kivicube/pages/exprience/exprience", 57 | "query": "", 58 | "scene": null 59 | } 60 | ] 61 | } 62 | }, 63 | "editorSetting": { 64 | "tabIndent": "insertSpaces", 65 | "tabSize": 2 66 | } 67 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes-高级api/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/Kivicube/pages/exprience/exprience.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | //是否显示loading页面,在进入页面时显示,在kivicube-scene场景加载完成后(loadSceneEnd)关闭 4 | showLoading: true, 5 | //判断是否加载kivicube-scene,因为kivicube-scene需要摄像机权限,所以获取摄像机权限后再加载整个kivicube-scene组件 6 | showKiviScene: false, 7 | //是否显示领取红包封面 8 | showRedEnvelopes: false, 9 | //是否隐藏拍照按钮 10 | hideTakePhoto: false, 11 | //是否隐藏海报 12 | hidePoster: true, 13 | //需要展示的海报的地址,方便保存 14 | posterUrl: "", 15 | }, 16 | 17 | async onLoad() { 18 | //获取摄像头权限后,渲染kivicube-scene 19 | const { authSetting } = await wx.getSetting(); 20 | if (!authSetting["scope.camera"]) { 21 | try { 22 | await wx.authorize({ 23 | scope: "scope.camera", 24 | }); 25 | this.setData({ 26 | showKiviScene: true, 27 | }); 28 | } catch (error) { 29 | wx.showModal({ 30 | title: "摄像头权限被拒绝", 31 | content: "AR体验需要您授予摄像头权限", 32 | cancelText: "取消", 33 | cancelColor: "#999", 34 | confirmText: "去授权", 35 | confirmColor: "#f94218", 36 | success: async (res) => { 37 | if (res.confirm) { 38 | const { authSetting } = await wx.openSetting(); 39 | if (authSetting["scope.camera"]) { 40 | this.setData({ 41 | showKiviScene: true, 42 | }); 43 | } else { 44 | wx.navigateBack(); 45 | } 46 | } else if (res.cancel) { 47 | wx.navigateBack(); 48 | } 49 | }, 50 | }); 51 | } 52 | } else { 53 | // 有权限则直接获取 54 | this.setData({ 55 | showKiviScene: true, 56 | }); 57 | } 58 | }, 59 | 60 | onShow() { 61 | //在拍摄页面时保持页面常亮 62 | wx.setKeepScreenOn({ 63 | keepScreenOn: true, 64 | }); 65 | }, 66 | 67 | //若在红包封面还没有弹出时退出了页面,则清除展示红包封面的定时器 68 | onUnload() { 69 | clearTimeout(this.showRedEnvelopesTimer); 70 | }, 71 | 72 | //场景加载完成后才关闭loading页面 73 | loadSceneEnd() { 74 | this.setData({ 75 | showLoading: false, 76 | }); 77 | }, 78 | 79 | //如果跳过云识别,直接进入这个函数;如果没跳过云识别,在扫描到识别图时进入这个函数 80 | sceneStart() { 81 | const isRedEnvelopesShowed = wx.getStorageSync("redEnvelopesShowed"); 82 | if (!isRedEnvelopesShowed) { 83 | //5s后展示领取红包封面的弹窗 84 | this.showRedEnvelopesTimer = setTimeout(() => { 85 | this.setData({ 86 | showRedEnvelopes: true, 87 | }); 88 | wx.setStorageSync("redEnvelopesShowed", true); 89 | }, 5000); 90 | } 91 | }, 92 | 93 | //生成海报的方法 94 | //未使用高级api无法自定义拍照按钮 95 | async generatePhoto({ detail: photoPath }) { 96 | wx.showLoading({ 97 | title: "拍照中", 98 | }); 99 | 100 | //在canvas上生成海报 101 | //获取canvas实例 102 | const canvasInstance = await new Promise((resolve) => { 103 | wx.createSelectorQuery() 104 | .select("#photoCanvas") 105 | .fields({ 106 | node: true, 107 | size: true, 108 | }) 109 | .exec((res) => { 110 | resolve(res[0]); 111 | }); 112 | }); 113 | 114 | //因为后面要设置canvas画布的实际大小,所以获取物理像素比 115 | let dpr = wx.getSystemInfoSync().pixelRatio; 116 | //canvas的宽度和高度,在生成海报时大量使用(逻辑像素) 117 | const canvasWidth = canvasInstance.width; 118 | const canvasHeight = canvasInstance.height; 119 | 120 | //获取并存储canvas实例,在生成海报阶段的wx.canvasToTempFilePath使用 121 | const canvas = canvasInstance.node; 122 | 123 | //获取canvas上下文,在生成海报中绘制各种元素时使用 124 | const ctx = canvas.getContext("2d"); 125 | 126 | //设置canvas画布的大小(物理像素) 127 | canvas.width = canvasWidth * dpr; 128 | canvas.height = canvasHeight * dpr; 129 | 130 | const vwToPx = (vw) => (canvas.width / 100) * vw; 131 | 132 | const loadImg = (canvas, imgPath) => { 133 | return new Promise((resolve, reject) => { 134 | let img = canvas.createImage(); 135 | img.src = imgPath; 136 | img.onload = () => { 137 | resolve(img); 138 | }; 139 | img.onerror = () => { 140 | //onerror函数没有参数 141 | reject(new Error("图片加载错误")); 142 | }; 143 | }); 144 | }; 145 | 146 | const handleImageGeneratingError = () => { 147 | wx.hideLoading(); 148 | wx.showToast({ 149 | icon: "none", 150 | title: "照片生成失败,请稍后再试", 151 | duration: 1000, 152 | }); 153 | }; 154 | 155 | //canvas绘制过程中出现的数字均为设计图上的内容 156 | //生成海报背景图片 157 | try { 158 | const bgImg = await loadImg(canvas, "/asset/poster-bg.png"); 159 | ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height); 160 | } catch (error) { 161 | handleImageGeneratingError(); 162 | } 163 | 164 | //在海报上生成kivicube-scene拍摄出的照片 165 | try { 166 | //kivicube-scene生成照片的宽和高信息,在生成海报时裁切照片时用到 167 | const { width: picWidth, height: picHeight } = await wx.getImageInfo({ 168 | src: photoPath, 169 | }); 170 | let img = await loadImg(canvas, photoPath); 171 | //最终生成在海报上照片的宽高比 172 | let genePhotoRatio = 59.07 / 92.77; 173 | //获取最终生成海报时所需kivi-scene拍摄出照片的总高度和纵向起始位置 174 | let imgTotalHeight = picWidth / genePhotoRatio; 175 | let imgStartY = (picHeight - imgTotalHeight) / 2; 176 | ctx.drawImage( 177 | img, 178 | 0, 179 | imgStartY, 180 | picWidth, 181 | imgTotalHeight, 182 | vwToPx(5.65), 183 | vwToPx(16.77), 184 | vwToPx(88.6), 185 | vwToPx(139.14) 186 | ); 187 | } catch (error) { 188 | handleImageGeneratingError(); 189 | } 190 | 191 | //生成二维码 192 | try { 193 | let qrcode = await loadImg(canvas, "/asset/qrcode.png"); 194 | ctx.drawImage( 195 | qrcode, 196 | vwToPx(68.9), 197 | vwToPx(159.45), 198 | vwToPx(21.04), 199 | vwToPx(21.34) 200 | ); 201 | } catch (error) { 202 | handleImageGeneratingError(); 203 | } 204 | 205 | //生成kivisense的logo 206 | try { 207 | let logo = await loadImg(canvas, "/asset/logo.png"); 208 | ctx.drawImage( 209 | logo, 210 | vwToPx(26.22), 211 | vwToPx(7.32), 212 | vwToPx(46.04), 213 | vwToPx(4.57) 214 | ); 215 | } catch (error) { 216 | handleImageGeneratingError(); 217 | } 218 | 219 | //生成文本 220 | ctx.fillStyle = "#feeca3"; 221 | ctx.font = `normal 700 ${vwToPx(6.1)}px PingFangSC-Semibold`; 222 | ctx.fillText("AR虎娃贺新春", vwToPx(8.23), vwToPx(161.59 + 6.1)); 223 | ctx.font = `normal 400 ${vwToPx(4.57)}px PingFangSC`; 224 | ctx.fillText( 225 | "即刻体验,领取红包封面", 226 | vwToPx(8.23), 227 | vwToPx(161.59 + 6.1 + 8.54) 228 | ); 229 | 230 | //cnavas转换成能展示的图片 231 | try { 232 | const { tempFilePath } = await wx.canvasToTempFilePath({ 233 | x: 0, 234 | y: 0, 235 | width: canvasWidth, 236 | height: canvasHeight, 237 | destWidth: canvas.width, 238 | destHeight: canvas.height, 239 | canvas, 240 | }); 241 | 242 | //显示海报,隐藏拍照按钮 243 | this.setData({ 244 | posterUrl: tempFilePath, 245 | hidePoster: false, 246 | hideTakePhoto: true, 247 | }); 248 | } catch (error) { 249 | handleImageGeneratingError(); 250 | } 251 | 252 | wx.hideLoading(); 253 | }, 254 | 255 | rePhoto() { 256 | this.setData({ 257 | hidePoster: true, 258 | hideTakePhoto: false, 259 | }); 260 | }, 261 | 262 | //获取保存图片权限后,保存图片 263 | async savePhoto() { 264 | const { authSetting } = await wx.getSetting(); 265 | //保存图片到本地 266 | const savePhotoToAlbum = () => { 267 | wx.saveImageToPhotosAlbum({ 268 | filePath: this.data.posterUrl, 269 | success() { 270 | wx.showToast({ 271 | icon: "none", 272 | title: "照片已保存到相册", 273 | duration: 1000, 274 | }); 275 | }, 276 | fail() { 277 | wx.showToast({ 278 | icon: "none", 279 | title: "照片保存失败,请稍后再试", 280 | duration: 1000, 281 | }); 282 | }, 283 | }); 284 | }; 285 | if (!authSetting["scope.writePhotosAlbum"]) { 286 | try { 287 | await wx.authorize({ 288 | scope: "scope.writePhotosAlbum", 289 | }); 290 | savePhotoToAlbum(); 291 | } catch (error) { 292 | wx.showModal({ 293 | title: "相册权限被拒绝", 294 | content: "保存照片需要您授予相册权限", 295 | cancelText: "取消", 296 | cancelColor: "#999", 297 | confirmText: "去授权", 298 | confirmColor: "#f94218", 299 | success: async (res) => { 300 | if (res.confirm) { 301 | const { authSetting } = await wx.openSetting(); 302 | if (authSetting["scope.writePhotosAlbum"]) { 303 | savePhotoToAlbum(); 304 | } else { 305 | return; 306 | } 307 | } else if (res.cancel) { 308 | return; 309 | } 310 | }, 311 | }); 312 | } 313 | } else { 314 | // 有权限则直接存 315 | savePhotoToAlbum(); 316 | } 317 | }, 318 | 319 | //kivicube-scene的binderror事件绑定的函数,用于判定错误信息, 320 | error(e) { 321 | const { detail } = e; 322 | // 判定是否camera权限问题,是则向用户申请权限。 323 | if (detail && detail.isCameraAuthDenied) { 324 | const page = this; 325 | wx.showModal({ 326 | title: "提示", 327 | content: "请给予“摄像头”权限", 328 | success() { 329 | wx.openSetting({ 330 | success({ authSetting: { "scope.camera": isGrantedCamera } }) { 331 | if (isGrantedCamera) { 332 | wx.redirectTo({ 333 | url: "/" + page.__route__, 334 | }); 335 | } else { 336 | wx.showToast({ 337 | title: "获取“摄像头”权限失败!", 338 | icon: "none", 339 | }); 340 | } 341 | }, 342 | }); 343 | }, 344 | }); 345 | } 346 | }, 347 | 348 | //分享小程序到微信聊天界面 349 | onShareAppMessage() { 350 | return { 351 | title: "AR虎娃贺新春", 352 | path: "/pages/index/index", 353 | imageUrl: "/asset/share.jpg", 354 | }; 355 | }, 356 | //分享小程序到朋友圈 357 | onShareTimeline() { 358 | return { 359 | title: "AR虎娃贺新春", 360 | path: "/pages/index/index", 361 | imageUrl: "/asset/share.jpg", 362 | }; 363 | }, 364 | 365 | //领取红包封面 366 | showRedPackage() { 367 | wx.showRedPackage({ 368 | url: "https://support.weixin.qq.com/cgi-bin/mmsupport-bin/showredpacket?receiveuri=abcJqTpylEG&check_type=2#wechat_redirect", 369 | success: () => { 370 | this.setData({ 371 | showRedEnvelopes: false, 372 | }); 373 | }, 374 | }); 375 | }, 376 | }); 377 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/Kivicube/pages/exprience/exprience.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "kivicube-scene": "plugin://kivicube/kivicube-scene", 6 | "back-button": "/components/back-button/back-button" 7 | } 8 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/Kivicube/pages/exprience/exprience.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 加载中... 7 | 8 | 9 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 领取红包封面 32 | 33 | 34 | 35 | 36 | 37 | 48 | 49 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/Kivicube/pages/exprience/exprience.wxss: -------------------------------------------------------------------------------- 1 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 2 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 3 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/app.js: -------------------------------------------------------------------------------- 1 | App({}); 2 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": ["pages/index/index"], 3 | "subpackages": [ 4 | { 5 | "root": "Kivicube", 6 | "pages": ["pages/exprience/exprience"], 7 | "plugins": { 8 | "kivicube": { 9 | "version": "2.16.8", 10 | "provider": "wx3bbab3920eabccb2" 11 | } 12 | } 13 | } 14 | ], 15 | "preloadRule": { 16 | "pages/index/index": { 17 | "network": "wifi", 18 | "packages": ["Kivicube"] 19 | } 20 | }, 21 | "__usePrivacyCheck__": true, 22 | "style": "v2", 23 | "sitemapLocation": "sitemap.json", 24 | "lazyCodeLoading": "requiredComponents" 25 | } 26 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/app.wxss: -------------------------------------------------------------------------------- 1 | .gold-text { 2 | color: #feeca3; 3 | } 4 | 5 | /* 写在分包里的css样式无法生效,所以样式写在了app.wxss,分包中使用的样式以subpkg开头 */ 6 | /* 详情见https://developers.weixin.qq.com/community/develop/doc/0004a84f8149b842802c298a650800 */ 7 | 8 | .subpkg-loading-warper { 9 | position: absolute; 10 | width: 100vw; 11 | height: 100%; 12 | text-align: center; 13 | background: linear-gradient( 14 | 8deg, 15 | #ff3737 0%, 16 | #ee6853 63%, 17 | #dd3c2d 100%, 18 | #dd3c2d 100% 19 | ); 20 | z-index: 5; 21 | } 22 | 23 | .subpkg-loading-tiger { 24 | position: absolute; 25 | top: 50%; 26 | left: 50%; 27 | transform: translate(-50%, -50%); 28 | width: 37.6vw; 29 | height: 37.6vw; 30 | } 31 | 32 | .subpkg-loading-fish { 33 | position: absolute; 34 | top: 50%; 35 | left: 50%; 36 | width: 60vw; 37 | height: 60vw; 38 | animation: spin 4s linear 0s infinite; 39 | } 40 | 41 | @keyframes spin { 42 | 0% { 43 | transform: translate(-50%, -50%) rotateZ(0deg); 44 | } 45 | 46 | 100% { 47 | transform: translate(-50%, -50%) rotateZ(360deg); 48 | } 49 | } 50 | 51 | .subpkg-loading-text { 52 | position: absolute; 53 | top: 142.47vw; 54 | transform: translateX(-50%); 55 | width: 18.35vw; 56 | height: 5.96vw; 57 | font-size: 14px; 58 | line-height: 4.53vw; 59 | font-weight: normal; 60 | } 61 | 62 | @media screen and (min-aspect-ratio: 375/668) { 63 | .subpkg-loading-text { 64 | top: 117.33vw; 65 | } 66 | } 67 | 68 | .subpkg-kivi-scene { 69 | display: block; 70 | position: absolute; 71 | width: 100vw; 72 | height: 100%; 73 | } 74 | 75 | .subpkg-red-envelopes-container { 76 | position: absolute; 77 | width: 100vw; 78 | height: 100%; 79 | backdrop-filter: blur(10px); 80 | background-color: rgba(255, 255, 255, 0.5); 81 | z-index: 6; 82 | } 83 | 84 | .subpkg-red-envelopes-warper { 85 | position: absolute; 86 | top: 50%; 87 | left: 50%; 88 | transform: translate(-50%, -50%); 89 | width: 60.53vw; 90 | height: 85.33vw; 91 | animation: zoom 0.2s ease-in 0s 1; 92 | } 93 | 94 | @keyframes zoom { 95 | 0% { 96 | opacity: 0; 97 | transform: translate(-50%, -50%) scale(0); 98 | } 99 | 100 | 50% { 101 | opacity: 1; 102 | } 103 | 104 | 100% { 105 | transform: translate(-50%, -50%) scale(1); 106 | } 107 | } 108 | 109 | .subpkg-red-envelopes-warper .subpkg-red-envelopes-bg { 110 | width: 100%; 111 | height: 100%; 112 | } 113 | 114 | .subpkg-red-envelopes-button { 115 | position: absolute; 116 | bottom: 6.13vw; 117 | left: 50%; 118 | transform: translateX(-50%); 119 | width: 46.67vw; 120 | height: 12.27vw; 121 | text-align: center; 122 | } 123 | 124 | .subpkg-red-envelopes-button image { 125 | width: 100%; 126 | height: 100%; 127 | } 128 | 129 | .subpkg-red-envelopes-button text { 130 | position: absolute; 131 | top: 50%; 132 | left: 50%; 133 | height: 4.53vw; 134 | width: 100%; 135 | line-height: 4.53vw; 136 | transform: translate(-50%, -50%); 137 | z-index: 100; 138 | font-size: 3.73vw; 139 | } 140 | 141 | .subpkg-poster-img { 142 | position: absolute; 143 | top: 27.73vw; 144 | left: 6.27vw; 145 | width: 87.47vw; 146 | height: 164.53vw; 147 | z-index: 10; 148 | } 149 | 150 | .subpkg-savephoto { 151 | position: absolute; 152 | right: 3.73vw; 153 | top: 195.2vw; 154 | width: 45.33vw; 155 | height: 14.93vw; 156 | } 157 | 158 | .subpkg-savephoto image { 159 | width: 100%; 160 | height: 100%; 161 | vertical-align: middle; 162 | } 163 | 164 | .subpkg-savephoto text { 165 | position: absolute; 166 | top: 50%; 167 | left: 50%; 168 | transform: translate(-50%, -50%); 169 | font-size: 3.73vw; 170 | line-height: 5.73vw; 171 | } 172 | 173 | .subpkg-rephoto { 174 | position: absolute; 175 | left: 4vw; 176 | top: 195.2vw; 177 | width: 45.07vw; 178 | height: 14.93vw; 179 | } 180 | 181 | .subpkg-rephoto image { 182 | width: 100%; 183 | height: 100%; 184 | vertical-align: middle; 185 | } 186 | 187 | .subpkg-rephoto text { 188 | position: absolute; 189 | top: 50%; 190 | left: 50%; 191 | transform: translate(-50%, -50%); 192 | font-size: 3.73vw; 193 | line-height: 5.73vw; 194 | } 195 | 196 | @media screen and (min-aspect-ratio: 375/668) { 197 | .subpkg-poster-img { 198 | top: 21.87vw; 199 | left: 17.33vw; 200 | width: 66.93vw; 201 | height: 125.6vw; 202 | } 203 | 204 | .subpkg-savephoto { 205 | bottom: 12.8vw; 206 | left: 8.27vw; 207 | width: 41.6vw; 208 | height: 13.6vw; 209 | } 210 | 211 | .subpkg-rephoto { 212 | bottom: 12.8vw; 213 | right: 6.67vw; 214 | width: 41.6vw; 215 | height: 13.6vw; 216 | } 217 | } 218 | 219 | .subpkg-poster-canvas { 220 | position: absolute; 221 | top: 20vw; 222 | left: -1000vw; 223 | width: 100vw; 224 | height: 188.1vw; 225 | } 226 | 227 | .subpkg-poster-warper { 228 | position: absolute; 229 | backdrop-filter: blur(10px); 230 | left: 0; 231 | right: 0; 232 | bottom: 0; 233 | top: 0; 234 | background-color: rgba(255, 255, 255, 0.5); 235 | z-index: 10000; 236 | } 237 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/2022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/2022.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/button.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/fish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/fish.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/home-bg-short.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/home-bg-short.jpg -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/home-bg.jpg -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/logo.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/poster-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/poster-bg.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/qrcode.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/red-envelopes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/red-envelopes.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/share-red-envelopes-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/share-red-envelopes-button.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/share.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/asset/tiger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/asset/tiger.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/back-button/back-button.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: { 3 | // 胶囊按钮高度 4 | menuButtonHeight: "32px", 5 | // 左边返回按钮距屏幕顶部的距离 6 | capsuleTop: "48px", 7 | }, 8 | lifetimes: { 9 | attached() { 10 | const { top, height } = wx.getMenuButtonBoundingClientRect(); 11 | this.setData({ 12 | // 胶囊按钮高度 13 | menuButtonHeight: height + "px", 14 | //返回按钮的位置 15 | capsuleTop: top + "px", 16 | }); 17 | }, 18 | }, 19 | methods: { 20 | async goBack() { 21 | try { 22 | await wx.navigateBack(); 23 | } catch (error) { 24 | wx.navigateTo({ 25 | url: "/pages/index/index", 26 | }); 27 | } 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/back-button/back-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/back-button/back-button.wxml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/back-button/back-button.wxss: -------------------------------------------------------------------------------- 1 | .back { 2 | position: absolute; 3 | left: 2.67vw; 4 | z-index: 100; 5 | } 6 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/back-button/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivisense/wechat-kivicube-plugin-cases/6b7f11d86a59afb6d2dee23f1f2dc897b77af024/tiger-year-red-envelopes/components/back-button/images/back.png -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/private-modal/private-modal.js: -------------------------------------------------------------------------------- 1 | let privacyHandler; 2 | let privacyResolves = new Set(); 3 | let closeOtherPagePopUpHooks = new Set(); 4 | 5 | if (wx.onNeedPrivacyAuthorization) { 6 | wx.onNeedPrivacyAuthorization((resolve) => { 7 | console.log( 8 | "触发 onNeedPrivacyAuthorization", 9 | typeof privacyHandler === "function" 10 | ); 11 | if (typeof privacyHandler === "function") { 12 | privacyHandler(resolve); 13 | } 14 | }); 15 | } 16 | 17 | const closeOtherPagePopUp = (closePopUp) => { 18 | closeOtherPagePopUpHooks.forEach((hook) => { 19 | if (closePopUp !== hook) { 20 | hook(); 21 | } 22 | }); 23 | }; 24 | 25 | Component({ 26 | properties: { 27 | currentBtnText: { 28 | type: String, 29 | value: "同意", 30 | }, 31 | }, 32 | data: { 33 | innerShow: false, 34 | privacyContractName: "AR虎娃贺新春小程序隐私保护指引", 35 | }, 36 | lifetimes: { 37 | attached() { 38 | const closePopUp = () => { 39 | this.disPopUp(); 40 | }; 41 | privacyHandler = (resolve) => { 42 | privacyResolves.add(resolve); 43 | this.popUp(); 44 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 45 | closeOtherPagePopUp(closePopUp); 46 | }; 47 | 48 | this.closePopUp = closePopUp; 49 | closeOtherPagePopUpHooks.add(this.closePopUp); 50 | }, 51 | detached() { 52 | closeOtherPagePopUpHooks.delete(this.closePopUp); 53 | }, 54 | }, 55 | pageLifetimes: { 56 | show() { 57 | if (this.closePopUp) { 58 | privacyHandler = (resolve) => { 59 | privacyResolves.add(resolve); 60 | this.popUp(); 61 | // 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗 62 | closeOtherPagePopUp(this.closePopUp); 63 | }; 64 | } 65 | }, 66 | }, 67 | methods: { 68 | handleAgree() { 69 | this.disPopUp(); 70 | // 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行 (看page/index/index中的 wx.getClipboardData 和 wx.startCompass) 71 | privacyResolves.forEach((resolve) => { 72 | resolve({ 73 | event: "agree", 74 | buttonId: "agree-btn", 75 | }); 76 | }); 77 | privacyResolves.clear(); 78 | }, 79 | handleDisagree() { 80 | this.disPopUp(); 81 | privacyResolves.forEach((resolve) => { 82 | resolve({ 83 | event: "disagree", 84 | }); 85 | }); 86 | privacyResolves.clear(); 87 | }, 88 | popUp() { 89 | if (this.data.innerShow === false) { 90 | this.setData({ 91 | innerShow: true, 92 | }); 93 | } 94 | }, 95 | disPopUp() { 96 | if (this.data.innerShow === true) { 97 | this.setData({ 98 | innerShow: false, 99 | }); 100 | } 101 | }, 102 | openPrivacyContract() { 103 | wx.openPrivacyContract({ 104 | success: () => { 105 | console.log("openPrivacyContract success"); 106 | }, 107 | fail: (res) => { 108 | console.error("openPrivacyContract fail", res); 109 | }, 110 | }); 111 | }, 112 | getPrivateInfo() { 113 | if (wx.getPrivacySetting) { 114 | wx.getPrivacySetting({ 115 | success: (res) => { 116 | console.log( 117 | "是否需要授权:", 118 | res.needAuthorization, 119 | "隐私协议的名称为:", 120 | res.privacyContractName 121 | ); 122 | }, 123 | fail: () => {}, 124 | complete: () => {}, 125 | }); 126 | } else { 127 | console.log("不需要隐私授权"); 128 | } 129 | }, 130 | }, 131 | }); 132 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/private-modal/private-modal.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/private-modal/private-modal.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 隐私保护指引 4 | 5 | 在使用当前小程序服务之前,请仔细阅读《{{privacyContractName}}》。如你同意《{{privacyContractName}}》,请点击“同意”开始使用。 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/components/private-modal/private-modal.wxss: -------------------------------------------------------------------------------- 1 | .privacy { 2 | position: fixed; 3 | z-index: 9999999; 4 | top: 0; 5 | right: 0; 6 | bottom: 0; 7 | left: 0; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | background: rgba(0, 0, 0, .5); 12 | } 13 | 14 | .content { 15 | width: 632rpx; 16 | box-sizing: border-box; 17 | padding: 48rpx; 18 | background: #fff; 19 | border-radius: 16rpx; 20 | } 21 | 22 | .content .title { 23 | color: #333; 24 | font-size: 32rpx; 25 | font-weight: bold; 26 | text-align: center; 27 | } 28 | 29 | .content .des { 30 | margin-top: 40rpx; 31 | color: #666; 32 | font-size: 26rpx; 33 | line-height: 1.6; 34 | text-align: justify; 35 | } 36 | 37 | .content .des .link { 38 | color: #07c160; 39 | text-decoration: underline; 40 | } 41 | 42 | .btns { 43 | display: flex; 44 | margin-top: 48rpx; 45 | } 46 | 47 | .btns .item { 48 | display: flex; 49 | width: 244rpx; 50 | height: 80rpx; 51 | box-sizing: border-box; 52 | align-items: center; 53 | justify-content: space-between; 54 | justify-content: center; 55 | padding-right: 1px; 56 | padding-left: 1px; 57 | border: none; 58 | border-radius: 16rpx; 59 | } 60 | 61 | .btns .reject { 62 | background: #f4f4f5; 63 | color: #909399; 64 | } 65 | 66 | .btns .agree { 67 | background: #07c160; 68 | color: #fff; 69 | } 70 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/pages/index/index.js: -------------------------------------------------------------------------------- 1 | const { windowWidth, windowHeight } = wx.getSystemInfoSync(); 2 | 3 | function getPrivate() { 4 | if (wx.requirePrivacyAuthorize) { 5 | return new Promise((resolve, reject) => { 6 | wx.requirePrivacyAuthorize({ 7 | success: (res) => { 8 | console.log("用户同意了隐私协议"); 9 | resolve(res); 10 | }, 11 | fail: (res) => { 12 | reject(res); 13 | console.log("用户拒绝了隐私协议"); 14 | }, 15 | }); 16 | }); 17 | } else { 18 | return Promise.resolve(); 19 | } 20 | } 21 | 22 | Page({ 23 | data: { 24 | isShortScreen: windowWidth / windowHeight > 375 / 668, 25 | }, 26 | async gotoExprience() { 27 | try { 28 | await getPrivate(); 29 | wx.navigateTo({ 30 | url: '/Kivicube/pages/exprience/exprience', 31 | }) 32 | } catch (error) { 33 | console.log(error); 34 | } 35 | }, 36 | onShareAppMessage() { 37 | return { 38 | title: "AR虎娃贺新春", 39 | path: "/pages/index/index", 40 | imageUrl: "/asset/share.png", 41 | }; 42 | }, 43 | onShareTimeline() { 44 | return { 45 | title: "AR虎娃贺新春", 46 | path: "/pages/index/index", 47 | imageUrl: "/asset/share.png", 48 | }; 49 | }, 50 | }); 51 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationStyle": "custom", 3 | "disableScroll": true, 4 | "usingComponents": { 5 | "private-modal": "../../components/private-modal/private-modal" 6 | } 7 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 开启虎年AR 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .new-year { 2 | position: absolute; 3 | top: 165.33vw; 4 | left: 12.27vw; 5 | width: 75.47vw; 6 | height: 23.2vw; 7 | } 8 | 9 | .btn-warper { 10 | position: absolute; 11 | top: 193.6vw; 12 | left: 19.2vw; 13 | width: 62.13vw; 14 | height: 20.27vw; 15 | } 16 | 17 | .btn-content { 18 | position: absolute; 19 | top: 50%; 20 | left: 50%; 21 | transform: translate(-50%, -50%); 22 | font-size: 5.6vw; 23 | color: #feeca3; 24 | } 25 | 26 | .bg-container { 27 | position: absolute; 28 | width: 100vw; 29 | height: 100%; 30 | overflow: hidden; 31 | background-size: 100% auto; 32 | } 33 | 34 | .bg-container image { 35 | position: absolute; 36 | width: 100vw; 37 | height: 100%; 38 | } 39 | 40 | @media screen and (min-aspect-ratio: 375/668) { 41 | .new-year { 42 | top: 127.73vw; 43 | left: 16.53vw; 44 | width: 66.93vw; 45 | height: 20vw; 46 | } 47 | 48 | .btn-warper { 49 | top: 149.33vw; 50 | left: 22.67vw; 51 | width: 54.67vw; 52 | height: 17.87vw; 53 | } 54 | 55 | .btn-content { 56 | font-size: 4.94vw; 57 | } 58 | } 59 | 60 | .btn-bg { 61 | width: 100%; 62 | height: 100%; 63 | } 64 | -------------------------------------------------------------------------------- /tiger-year-red-envelopes/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "setting": { 4 | "urlCheck": false, 5 | "es6": true, 6 | "enhance": true, 7 | "postcss": true, 8 | "preloadBackgroundData": false, 9 | "minified": true, 10 | "newFeature": false, 11 | "coverView": true, 12 | "nodeModules": true, 13 | "autoAudits": false, 14 | "showShadowRootInWxmlPanel": true, 15 | "scopeDataCheck": false, 16 | "uglifyFileName": false, 17 | "checkInvalidKey": true, 18 | "checkSiteMap": true, 19 | "uploadWithSourceMap": true, 20 | "compileHotReLoad": false, 21 | "lazyloadPlaceholderEnable": false, 22 | "useMultiFrameRuntime": true, 23 | "babelSetting": { 24 | "ignore": [], 25 | "disablePlugins": [], 26 | "outputPath": "" 27 | }, 28 | "enableEngineNative": false, 29 | "useIsolateContext": false, 30 | "userConfirmedBundleSwitch": false, 31 | "packNpmManually": false, 32 | "packNpmRelationList": [], 33 | "minifyWXSS": true, 34 | "disableUseStrict": false, 35 | "minifyWXML": true, 36 | "showES6CompileOption": false, 37 | "useCompilerPlugins": false, 38 | "condition": false, 39 | "ignoreUploadUnusedFiles": true 40 | }, 41 | "compileType": "miniprogram", 42 | "cloudfunctionTemplateRoot": "", 43 | "condition": { 44 | "miniprogram": { 45 | "list": [ 46 | { 47 | "name": "", 48 | "pathName": "Kivicube/pages/exprience/exprience", 49 | "query": "", 50 | "scene": null 51 | } 52 | ] 53 | } 54 | }, 55 | "editorSetting": { 56 | "tabIndent": "insertSpaces", 57 | "tabSize": 2 58 | }, 59 | "libVersion": "2.21.3", 60 | "packOptions": { 61 | "ignore": [], 62 | "include": [] 63 | }, 64 | "appid": "wx03800a762308862c" 65 | } -------------------------------------------------------------------------------- /tiger-year-red-envelopes/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } --------------------------------------------------------------------------------