| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- // index.js
- // 获取应用实例
- import { VueLikePage } from "../../utils/page";
- import { CDN_URL, API_BASE_URL, VIDEO_BASE_URL, app } from "../../config/index";
- VueLikePage([], {
- data: {
- cdn_url: "",
- baseUrl: API_BASE_URL + "/",
- url_link: "",
- id: "1",
- type: "",
- loadCompele: false,
- filePath: "",
- projectid: '',
- isEditing: false,
- info: {
- resourceImg: {},
- banner: {},
- sceneTitleImg: {},
- recordTitleImg: {},
- rescan: {},
- activeSceneBdImg: {},
- },
- isZoom: false,
- ipsImgList: [],
- selectedIp: null,
- selectedIpIndex: -1,
- ipScaleX: 1,
- ipScaleY: 1,
- ipRotate: 0,
- ipConfirmed: false,
- ipLeft: 0,
- ipTop: 0,
- positionInitialized: false,
- canvasWidth: 375,
- canvasHeight: 600,
- widgetVisible: true,
- zoomScrollLeft: 0,
- scaleOrientation: ''
- },
- methods: {
- zoom() {
- this.setData({
- isZoom: !this.data.isZoom,
- selectedIp: null,
- selectedIpIndex: -1,
- ipScaleX: 1,
- ipScaleY: 1,
- ipRotate: 0,
- ipConfirmed: false,
- });
- },
- onLoad: function (options) {
- let { rdw, id, type, projectid } = options;
- if(!projectid){
- projectid = 'ZHS2409020-1';
- }
- this.initIpsList(projectid);
- this.getData(projectid);
- let link = "";
- if (type == "0") {
- link = `${VIDEO_BASE_URL}4dvedio/${rdw}.mp4`;
- } else {
- link = `${VIDEO_BASE_URL}4dpic/${rdw}.jpg`;
- // link='https://4dkk.4dage.com/fusion/test/file/797098a37e0c4588ae88f2ec4b1f12df.png'
- }
- this.setData({
- url_link: link,
- id,
- type,
- projectid,
- cdn_url: CDN_URL + "/" + projectid,
- });
- this.downloadF((data) => {
- this.setData({
- filePath: data,
- });
- });
- },
- initIpsList(projectid) {
- const list = [];
- for (let i = 1; i <= 44; i++) {
- list.push({
- name: String(i),
- imgUrl: `${CDN_URL}/ZHS2409020-1/ip/${i}.png`,
- });
- }
- this.setData({
- ipsImgList: list,
- });
- },
- loadcompele() {
- this.setData({
- loadCompele: true,
- });
- },
- cancel() {
- // wx.reLaunch({
- // url: "/pages/work/index",
- // });
- wx.navigateBack();
- },
- edit() {
- this.setData({
- isEditing: !this.data.isEditing,
- });
- },
- downloadF(cb = () => {}) {
- let link = this.data.url_link,
- m_type = "";
- if (this.data.type == "1") {
- m_type = "jpeg";
- } else {
- m_type = "video";
- }
- wx.downloadFile({
- url: link,
- success: (res) => {
- if (res.statusCode == "404") {
- return app.showAlert("作品暂未生成,请稍后再试", () => {
- wx.navigateBack();
- });
- }
- //判断是否为数组
- let typeType =
- Object.prototype.toString.call(res.header["Content-Type"]) ==
- "[object String]"
- ? res.header["Content-Type"]
- : res.header["Content-Type"][0];
- //判断不是xml文件
- if (typeType.indexOf(m_type) > -1) {
- cb(res.tempFilePath);
- }
- },
- fail: () => {
- app.showAlert("作品暂未生成,请稍后再试");
- },
- });
- this.setData({
- showModal: false,
- });
- },
- async generateImage() {
- wx.showLoading({ title: '生成中...', mask: true });
- try {
- const query = wx.createSelectorQuery();
- query.select('.w_video').boundingClientRect();
- if (this.data.selectedIp) {
- query.select('.ip-overlay').boundingClientRect();
- }
-
- const res = await new Promise(resolve => query.exec(resolve));
- const container = res[0];
- const overlay = this.data.selectedIp ? res[1] : null;
-
- if (!container) throw new Error('Cannot find container');
-
- let width = container.width;
- let height = container.height;
- if (this.data.isZoom) {
- const imgRes = await new Promise((resolve, reject) => {
- wx.getImageInfo({
- src: this.data.url_link,
- success: resolve,
- fail: reject
- })
- });
- width = imgRes.width;
- height = imgRes.height;
- }
- // Limit canvas size to avoid incomplete rendering on some devices
- const dpr = wx.getSystemInfoSync().pixelRatio;
- const maxCanvasSize = 4096;
- let scale = 1;
-
- if (width * dpr > maxCanvasSize || height * dpr > maxCanvasSize) {
- scale = Math.min(maxCanvasSize / (width * dpr), maxCanvasSize / (height * dpr));
- }
- const canvasWidth = width * scale;
- const canvasHeight = height * scale;
-
- await this._resetWidget(canvasWidth, canvasHeight);
- const widget = this.selectComponent('#widget');
- const mainUrl = this.data.url_link;
- let wxml = '';
- if (this.data.isZoom) {
- wxml = `
- <view class="container">
- <image class="main" src="${mainUrl}"></image>
- </view>
- `;
- } else {
- const bgUrl = this.data.info.resourceImg.bg ? (this.data.cdn_url + this.data.info.resourceImg.bg) : '';
- wxml = `
- <view class="container">
- <image class="bg" src="${bgUrl}"></image>
- ${(this.data.type != '0') ? `<image class="main" src="${mainUrl}"></image>` : ''}
- </view>
- `;
- }
- const style = {
- container: { width: canvasWidth, height: canvasHeight, position: 'relative', overflow: 'hidden' },
- bg: { width: canvasWidth, height: canvasHeight, position: 'absolute', left: 0, top: 0 },
- main: { width: canvasWidth, height: canvasHeight, position: 'absolute', left: 0, top: 0 }
- };
- await widget.renderToCanvas({ wxml, style });
- if (this.data.selectedIp && overlay) {
- const ctx = widget.ctx;
- const use2d = widget.data.use2dCanvas;
- const stickerUrl = this.data.selectedIp.imgUrl;
-
- // Get local path
- const stickerInfo = await new Promise((resolve, reject) => {
- wx.getImageInfo({
- src: stickerUrl,
- success: resolve,
- fail: reject
- })
- });
-
- let imgToDraw = stickerInfo.path;
- if (use2d) {
- const canvas = widget.canvas;
- const img = canvas.createImage();
- await new Promise((resolve, reject) => {
- img.onload = resolve;
- img.onerror = reject;
- img.src = stickerInfo.path;
- });
- imgToDraw = img;
- }
-
- const ratio = canvasWidth / container.width;
- const cx = ((overlay.left - container.left + overlay.width / 2) + (this.data.isZoom ? this.data.zoomScrollLeft : 0)) * ratio;
- const cy = (overlay.top - container.top + overlay.height / 2) * ratio;
- const overlayWidth = overlay.width * ratio;
- const overlayHeight = overlay.height * ratio;
-
- ctx.save();
- ctx.translate(cx, cy);
- ctx.rotate(this.data.ipRotate * Math.PI / 180);
- ctx.scale(this.data.ipScaleX, this.data.ipScaleY);
- ctx.drawImage(imgToDraw, -overlayWidth / 2, -overlayHeight / 2, overlayWidth, overlayHeight);
- ctx.restore();
-
- // If legacy, might need draw()
- if (!use2d) {
- await new Promise(resolve => ctx.draw(true, resolve));
- }
- }
-
- const { tempFilePath } = await widget.canvasToTempFilePath();
-
- // Save
- wx.saveImageToPhotosAlbum({
- filePath: tempFilePath,
- success: () => {
- wx.showModal({
- title: "提示",
- content: "已保存到相册,快去分享吧",
- showCancel: false,
- });
- },
- fail: (e) => {
- if (!(e.errMsg.indexOf("cancel") > -1)) {
- wx.showModal({
- title: "提示",
- content: "保存失败,请检查是否开启相册保存权限",
- showCancel: false,
- });
- }
- }
- });
- } catch (e) {
- console.error(e);
- wx.showToast({ title: '生成失败', icon: 'none' });
- } finally {
- wx.hideLoading();
- }
- },
- async _resetWidget(width, height) {
- this.setData({ widgetVisible: false });
- await new Promise(r => setTimeout(r, 50));
- this.setData({ canvasWidth: width, canvasHeight: height, widgetVisible: true });
- await new Promise(r => setTimeout(r, 120));
- },
- onZoomScroll(e) {
- this.setData({ zoomScrollLeft: e.detail.scrollLeft || 0 });
- },
- saveAlbum() {
- let type = this.data.type;
-
- if (this.data.projectid == 'ZHS2409020-1') {
- if (this.data.selectedIp && !this.data.ipConfirmed) {
- wx.showToast({
- title: '请先确认标签',
- icon: 'none'
- })
- return;
- }
- this.generateImage();
- return;
- }
- wx.showLoading({
- title: "保存中…",
- mask: true,
- });
- if (this.data.filePath) {
- let api =
- type == "0" ? "saveVideoToPhotosAlbum" : "saveImageToPhotosAlbum";
- wx[api]({
- filePath: this.data.filePath,
- success() {
- wx.showModal({
- title: "提示",
- content: "已保存到相册,快去分享吧",
- showCancel: false,
- });
- },
- fail: (e) => {
- if (!(e.errMsg.indexOf("cancel") > -1)) {
- wx.showModal({
- title: "提示",
- content:
- "保存失败,请检查是否开启相册保存权限,可在「右上角」 - 「设置」里查看",
- showCancel: false,
- });
- }
- },
- complete: () => {
- wx.hideLoading();
- },
- });
- }
- },
- // 横琴是ZHS2409020-1,替换
- getData(prjId = "ZHS2305758-1") {
- wx.showLoading({
- title: "资源加载中",
- });
- this.setData({
- cdn_url: CDN_URL + "/" + prjId,
- });
- wx.request({
- url: `${VIDEO_BASE_URL}project/4dage-sxb/${prjId}/config.json`,
- success: ({ data: { title, ...rest } }) => {
- this.setData(
- {
- info: rest,
- },
- () => {
- wx.hideLoading();
- }
- );
- wx.setNavigationBarTitle({
- title: title,
- });
- },
- });
- },
- selectIp(e) {
- const index = e.currentTarget.dataset.index;
- const item = this.data.ipsImgList[index];
- if (!item) return;
- this.setData({
- selectedIpIndex: index,
- selectedIp: item,
- ipScaleX: 1,
- ipScaleY: 1,
- ipRotate: 0,
- ipConfirmed: false,
- positionInitialized: false,
- }, () => {
- this.getOverlayRect();
-
- // Initialize position
- const query = wx.createSelectorQuery();
- query.select('.w_video').boundingClientRect();
- query.select('.ip-overlay').boundingClientRect();
- query.exec((res) => {
- const container = res[0];
- const overlay = res[1];
- if (container && overlay) {
- this.setData({
- ipLeft: overlay.left - container.left,
- ipTop: overlay.top - container.top,
- positionInitialized: true
- });
- }
- });
- });
- },
- dragStart(e) {
- if (this.data.ipConfirmed) return;
- const touch = e.touches[0];
- this.setData({
- dragStartX: touch.clientX,
- dragStartY: touch.clientY,
- startIpLeft: this.data.ipLeft,
- startIpTop: this.data.ipTop
- });
- },
- dragMove(e) {
- if (this.data.ipConfirmed) return;
- const touch = e.touches[0];
- const dx = touch.clientX - this.data.dragStartX;
- const dy = touch.clientY - this.data.dragStartY;
-
- this.setData({
- ipLeft: this.data.startIpLeft + dx,
- ipTop: this.data.startIpTop + dy
- });
- },
- getOverlayRect() {
- const query = wx.createSelectorQuery();
- query.select('.ip-overlay').boundingClientRect(rect => {
- if (rect) {
- this.setData({
- centerX: rect.left + rect.width / 2,
- centerY: rect.top + rect.height / 2
- });
- }
- }).exec();
- },
- rotateStart(e) {
- this.getOverlayRect();
- const touch = e.touches[0];
- const dx = touch.clientX - this.data.centerX;
- const dy = touch.clientY - this.data.centerY;
- const startAngle = Math.atan2(dy, dx) * 180 / Math.PI;
-
- this.setData({
- startRotateAngle: startAngle,
- baseIpRotate: this.data.ipRotate
- });
- },
- rotateMove(e) {
- const touch = e.touches[0];
- const dx = touch.clientX - this.data.centerX;
- const dy = touch.clientY - this.data.centerY;
- const currentAngle = Math.atan2(dy, dx) * 180 / Math.PI;
-
- const diff = currentAngle - this.data.startRotateAngle;
- let nextRotate = this.data.baseIpRotate + diff;
-
- this.setData({
- ipRotate: nextRotate
- });
- },
- scaleStart(e) {
- const touch = e.touches[0];
- this.setData({
- startX: touch.clientX,
- startY: touch.clientY,
- baseIpScaleX: this.data.ipScaleX,
- baseIpScaleY: this.data.ipScaleY,
- scaleOrientation: ''
- });
- },
- scaleMove(e) {
- const touch = e.touches[0];
- const dx = touch.clientX - this.data.startX;
- const dy = touch.clientY - this.data.startY;
- const factor = 0.005;
- let { scaleOrientation } = this.data;
- if (!scaleOrientation) {
- const adx = Math.abs(dx);
- const ady = Math.abs(dy);
- if (adx > ady && adx > 3) {
- scaleOrientation = 'x';
- } else if (ady >= adx && ady > 3) {
- scaleOrientation = 'y';
- } else {
- return;
- }
- this.setData({ scaleOrientation });
- }
- if (scaleOrientation === 'x') {
- let nextScaleX = this.data.baseIpScaleX + (-dx) * factor;
- if (nextScaleX < 0.2) nextScaleX = 0.2;
- if (nextScaleX > 4) nextScaleX = 4;
- this.setData({ ipScaleX: nextScaleX });
- } else {
- let nextScaleY = this.data.baseIpScaleY + (-dy) * factor;
- if (nextScaleY < 0.2) nextScaleY = 0.2;
- if (nextScaleY > 4) nextScaleY = 4;
- this.setData({ ipScaleY: nextScaleY });
- }
- },
-
- rotateIp() {
- // 兼容旧的点击事件,如果不需要可以删除,但保留也不会出错
- if (!this.data.selectedIp) return;
- const nextRotate = (this.data.ipRotate + 15) % 360;
- this.setData({
- ipRotate: nextRotate,
- });
- },
- scaleIp() {
- if (!this.data.selectedIp) return;
- let nextScaleX = this.data.ipScaleX + 0.25;
- let nextScaleY = this.data.ipScaleY + 0.25;
- if (nextScaleX > 2.5 || nextScaleY > 2.5) {
- nextScaleX = 1;
- nextScaleY = 1;
- }
- this.setData({
- ipScaleX: nextScaleX,
- ipScaleY: nextScaleY,
- });
- },
- deleteIp() {
- this.setData({
- selectedIp: null,
- selectedIpIndex: -1,
- ipScaleX: 1,
- ipScaleY: 1,
- ipRotate: 0,
- ipConfirmed: false,
- });
- },
- confirmIp() {
- if (!this.data.selectedIp) return;
- this.setData({
- ipConfirmed: true,
- });
- },
- },
- });
|