update
This commit is contained in:
parent
7f301cadfd
commit
c218a4ba5a
|
@ -1,4 +1,4 @@
|
||||||
const DEFAULT_COLOR = '#888'
|
const DEFAULT_COLOR = '#41464b'
|
||||||
|
|
||||||
export const DEFAULT_TEXT = {
|
export const DEFAULT_TEXT = {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
@ -6,12 +6,10 @@ export const DEFAULT_TEXT = {
|
||||||
top: 0,
|
top: 0,
|
||||||
width: 300,
|
width: 300,
|
||||||
height: 0,
|
height: 0,
|
||||||
padding: 5,
|
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.5,
|
||||||
segmentSpacing: 5,
|
segmentSpacing: 5,
|
||||||
textType: 'content',
|
content: '请输入内容',
|
||||||
content: '<div>“单击此处添加文本”</div>',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_IMAGE = {
|
export const DEFAULT_IMAGE = {
|
||||||
|
@ -27,25 +25,6 @@ export const DEFAULT_SHAPE = {
|
||||||
lockRatio: false,
|
lockRatio: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SHAPE_LINE = {
|
|
||||||
type: 'shape',
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: DEFAULT_COLOR,
|
|
||||||
fill: 'rgba(0, 0, 0, 0)',
|
|
||||||
lockRatio: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DEFAULT_ICON = {
|
|
||||||
type: 'icon',
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
width: 80,
|
|
||||||
height: 80,
|
|
||||||
color: DEFAULT_COLOR,
|
|
||||||
lockRatio: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DEFAULT_LINE = {
|
export const DEFAULT_LINE = {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
style: 'solid',
|
style: 'solid',
|
||||||
|
@ -62,14 +41,6 @@ export const DEFAULT_CHART = {
|
||||||
height: 500,
|
height: 500,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_IFRAME = {
|
|
||||||
type: 'iframe',
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
width: 800,
|
|
||||||
height: 480,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DEFAULT_TABLE = {
|
export const DEFAULT_TABLE = {
|
||||||
type: 'table',
|
type: 'table',
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|
|
@ -18,12 +18,10 @@ export const slides: Slide[] = [
|
||||||
borderColor: '#5b7d89',
|
borderColor: '#5b7d89',
|
||||||
fill: 'rgba(220,220,220,0.8)',
|
fill: 'rgba(220,220,220,0.8)',
|
||||||
shadow: '1px 1px 3px rgba(10,10,10,.5)',
|
shadow: '1px 1px 3px rgba(10,10,10,.5)',
|
||||||
padding: 10,
|
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.5,
|
||||||
segmentSpacing: 10,
|
segmentSpacing: 10,
|
||||||
isLock: false,
|
isLock: false,
|
||||||
textType: 'title',
|
|
||||||
content: '<div style=\'text-align: center;\'><span style=\'font-size: 28px;\'><span style=\'color: rgb(232, 107, 153); font-weight: bold;\'>一段测试文字</span>,字号固定为<span style=\'font-weight: bold; font-style: italic; text-decoration-line: underline;\'>28px</span></span></div>',
|
content: '<div style=\'text-align: center;\'><span style=\'font-size: 28px;\'><span style=\'color: rgb(232, 107, 153); font-weight: bold;\'>一段测试文字</span>,字号固定为<span style=\'font-weight: bold; font-style: italic; text-decoration-line: underline;\'>28px</span></span></div>',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -79,12 +77,10 @@ export const slides: Slide[] = [
|
||||||
width: 220,
|
width: 220,
|
||||||
height: 188,
|
height: 188,
|
||||||
rotate: 0,
|
rotate: 0,
|
||||||
padding: 10,
|
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.5,
|
||||||
segmentSpacing: 10,
|
segmentSpacing: 10,
|
||||||
isLock: false,
|
isLock: false,
|
||||||
textType: 'content',
|
|
||||||
content: '<div>😀 😐 😶 😜 🔔 ⭐ ⚡ 🔥 👍 💡 🔰 🎀 🎁 🥇 🏅 🏆 🎈 🎉 💎 🚧 ⛔ 📢 ⌛ ⏰ 🕒 🧩 🎵 📎 🔒 🔑 ⛳ 📌 📍 💬 📅 📈 📋 📜 📁 📱 💻 💾 🌏 🚚 🚡 🚢💧 🌐 🧭 💰 💳 🛒</div>',
|
content: '<div>😀 😐 😶 😜 🔔 ⭐ ⚡ 🔥 👍 💡 🔰 🎀 🎁 🥇 🏅 🏆 🎈 🎉 💎 🚧 ⛔ 📢 ⌛ ⏰ 🕒 🧩 🎵 📎 🔒 🔑 ⛳ 📌 📍 💬 📅 📈 📋 📜 📁 📱 💻 💾 🌏 🚚 🚡 🚢💧 🌐 🧭 💰 💳 🛒</div>',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { MutationTypes } from './constants'
|
||||||
import { State } from './state'
|
import { State } from './state'
|
||||||
import { Slide, PPTElement } from '@/types/slides'
|
import { Slide, PPTElement } from '@/types/slides'
|
||||||
import { FONT_NAMES } from '@/configs/fontName'
|
import { FONT_NAMES } from '@/configs/fontName'
|
||||||
import { isSupportFontFamily } from '@/utils/index'
|
import { isSupportFontFamily } from '@/utils/fontFamily'
|
||||||
|
|
||||||
interface AddSlidesData {
|
interface AddSlidesData {
|
||||||
index?: number;
|
index?: number;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
export type ElementType = 'text' | 'image' | 'shape' | 'line' | 'chart' | 'table'
|
||||||
|
|
||||||
export interface PPTElementBaseProps {
|
export interface PPTElementBaseProps {
|
||||||
elId: string;
|
elId: string;
|
||||||
isLock: boolean;
|
isLock: boolean;
|
||||||
|
@ -51,8 +53,6 @@ export interface PPTShapeElement extends PPTElementBaseProps, PPTElementSizeProp
|
||||||
rotate?: number;
|
rotate?: number;
|
||||||
opacity?: number;
|
opacity?: number;
|
||||||
shadow?: string;
|
shadow?: string;
|
||||||
text?: string;
|
|
||||||
textAlign?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PPTLineElement extends PPTElementBaseProps {
|
export interface PPTLineElement extends PPTElementBaseProps {
|
||||||
|
@ -73,7 +73,7 @@ export interface PPTChartElement extends PPTElementBaseProps, PPTElementSizeProp
|
||||||
data: Object;
|
data: Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableCell {
|
export interface TableElementCell {
|
||||||
colspan: number;
|
colspan: number;
|
||||||
rowspan: number;
|
rowspan: number;
|
||||||
content: string;
|
content: string;
|
||||||
|
@ -85,7 +85,7 @@ export interface PPTTableElement extends PPTElementBaseProps, PPTElementSizeProp
|
||||||
theme: string;
|
theme: string;
|
||||||
rowSizes: number[];
|
rowSizes: number[];
|
||||||
colSizes: number[];
|
colSizes: number[];
|
||||||
data: TableCell[][];
|
data: TableElementCell[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PPTElement = PPTTextElement |
|
export type PPTElement = PPTTextElement |
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import Clipboard from 'clipboard'
|
||||||
|
|
||||||
|
// 复制文本到剪贴板
|
||||||
|
export const copyText = (text: string) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const fakeElement = document.createElement('button')
|
||||||
|
const clipboard = new Clipboard(fakeElement, {
|
||||||
|
text: () => text,
|
||||||
|
action: () => 'copy',
|
||||||
|
container: document.body,
|
||||||
|
})
|
||||||
|
clipboard.on('success', e => {
|
||||||
|
clipboard.destroy()
|
||||||
|
resolve(e)
|
||||||
|
})
|
||||||
|
clipboard.on('error', e => {
|
||||||
|
clipboard.destroy()
|
||||||
|
reject(e)
|
||||||
|
})
|
||||||
|
document.body.appendChild(fakeElement)
|
||||||
|
fakeElement.click()
|
||||||
|
document.body.removeChild(fakeElement)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取剪贴板
|
||||||
|
export const readClipboard = () => {
|
||||||
|
if(navigator.clipboard) {
|
||||||
|
navigator.clipboard.readText().then(text => {
|
||||||
|
if(!text) return { err: '剪贴板为空或者不包含文本' }
|
||||||
|
return { text }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { err: '浏览器不支持或禁止访问剪贴板' }
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import padStart from 'lodash/padStart'
|
||||||
|
|
||||||
|
// 生成随机码
|
||||||
|
export const createRandomCode = (len = 6) => {
|
||||||
|
const charset = `_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`
|
||||||
|
const maxLen = charset.length
|
||||||
|
let ret = ''
|
||||||
|
for(let i = 0; i < len; i++) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * maxLen)
|
||||||
|
ret += charset[randomIndex]
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数字补足位数,例如将6补足3位 -> 003
|
||||||
|
export const fillDigit = (digit: number, len: number) => {
|
||||||
|
return padStart('' + digit, len, '0')
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
import CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
|
const CRYPTO_KEY = 'zxc_ppt_online_editor'
|
||||||
|
|
||||||
|
// 加密函数
|
||||||
|
export const encrypt = (msg: string) => {
|
||||||
|
return CryptoJS.AES.encrypt(msg, CRYPTO_KEY).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密函数
|
||||||
|
export const decrypt = (ciphertext: string) => {
|
||||||
|
const bytes = CryptoJS.AES.decrypt(ciphertext, CRYPTO_KEY)
|
||||||
|
return bytes.toString(CryptoJS.enc.Utf8)
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 判断用户的操作系统是否安装了某字体
|
||||||
|
export const isSupportFontFamily = (fontFamily: string) => {
|
||||||
|
if(typeof fontFamily !== 'string') return false
|
||||||
|
const arial = 'Arial'
|
||||||
|
if(fontFamily.toLowerCase() === arial.toLowerCase()) return true
|
||||||
|
const a = 'a'
|
||||||
|
const size = 100
|
||||||
|
const width = 100
|
||||||
|
const height = 100
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
|
if(!ctx) return false
|
||||||
|
|
||||||
|
canvas.width = width
|
||||||
|
canvas.height = height
|
||||||
|
ctx.textAlign = 'center'
|
||||||
|
ctx.fillStyle = 'black'
|
||||||
|
ctx.textBaseline = 'middle'
|
||||||
|
|
||||||
|
const getDotArray = (_fontFamily: string) => {
|
||||||
|
ctx.clearRect(0, 0, width, height)
|
||||||
|
ctx.font = `${size}px ${_fontFamily}, ${arial}`
|
||||||
|
ctx.fillText(a, width / 2, height / 2)
|
||||||
|
const imageData = ctx.getImageData(0, 0, width, height).data
|
||||||
|
return [].slice.call(imageData).filter(item => item !== 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDotArray(arial).join('') !== getDotArray(fontFamily).join('')
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
// 进入全屏
|
||||||
|
export const enterFullscreen = document.documentElement.requestFullscreen
|
||||||
|
|
||||||
|
// 退出全屏
|
||||||
|
export const exitFullscreen = document.exitFullscreen
|
||||||
|
|
||||||
|
// 判断是否全屏
|
||||||
|
export const isFullscreen = () => document.fullscreenEnabled
|
|
@ -0,0 +1,42 @@
|
||||||
|
interface ImageSize {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取图片的原始宽高
|
||||||
|
export const getImageSize = (imgUrl: string): Promise<ImageSize> => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const img = document.createElement('img')
|
||||||
|
img.src = imgUrl
|
||||||
|
img.style.opacity = '0'
|
||||||
|
document.body.appendChild(img)
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
const imgWidth = img.clientWidth
|
||||||
|
const imgHeight = img.clientHeight
|
||||||
|
|
||||||
|
img.onload = null
|
||||||
|
img.onerror = null
|
||||||
|
|
||||||
|
document.body.removeChild(img)
|
||||||
|
|
||||||
|
resolve({ width: imgWidth, height: imgHeight })
|
||||||
|
}
|
||||||
|
|
||||||
|
img.onerror = () => {
|
||||||
|
img.onload = null
|
||||||
|
img.onerror = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取图片文件的dataURL
|
||||||
|
export const getImageDataURL = (file: File): Promise<string> => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.addEventListener('load', () => {
|
||||||
|
resolve(reader.result as string)
|
||||||
|
})
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,209 +0,0 @@
|
||||||
import padStart from 'lodash/padStart'
|
|
||||||
import Clipboard from 'clipboard'
|
|
||||||
import CryptoJS from 'crypto-js'
|
|
||||||
|
|
||||||
const CRYPTO_KEY = 'zxc_ppt_online_editor'
|
|
||||||
|
|
||||||
// 生成随机数
|
|
||||||
export const createRandomNumber = (min: number, max: number) => {
|
|
||||||
return Math.floor(min + Math.random() * (max - min))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成随机码
|
|
||||||
export const createRandomCode = (len = 6) => {
|
|
||||||
const charset = `_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`
|
|
||||||
const maxLen = charset.length
|
|
||||||
let ret = ''
|
|
||||||
for(let i = 0; i < len; i++) {
|
|
||||||
const randomIndex = Math.floor(Math.random() * maxLen)
|
|
||||||
ret += charset[randomIndex]
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成uuid
|
|
||||||
export const createUUID = () => {
|
|
||||||
const url = URL.createObjectURL(new Blob())
|
|
||||||
const uuid = url.toString()
|
|
||||||
URL.revokeObjectURL(url)
|
|
||||||
return uuid.substr(uuid.lastIndexOf('/') + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前日期字符串
|
|
||||||
export const getDateTime = (format = 'yyyy-MM-dd hh:mm:ss') => {
|
|
||||||
const date = new Date()
|
|
||||||
|
|
||||||
const formatMap = {
|
|
||||||
'y+': date.getFullYear(),
|
|
||||||
'M+': date.getMonth() + 1,
|
|
||||||
'd+': date.getDate(),
|
|
||||||
'h+': date.getHours(),
|
|
||||||
'm+': date.getMinutes(),
|
|
||||||
's+': date.getSeconds(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const item of Object.keys(formatMap)) {
|
|
||||||
if(new RegExp('(' + item + ')').test(format)) {
|
|
||||||
const formated = (formatMap[item] + '').length < RegExp.$1.length ? padStart('' + formatMap[item], RegExp.$1.length, '0') : formatMap[item]
|
|
||||||
format = format.replace(RegExp.$1, formated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return format
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数字转中文,如1049 -> 一千零四十九
|
|
||||||
export const digitalToChinese = (n: number) => {
|
|
||||||
const str = n + ''
|
|
||||||
const len = str.length - 1
|
|
||||||
const idxs = ['', '十', '百', '千']
|
|
||||||
const num = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
|
|
||||||
return str.replace(/([1-9]|0+)/g, ($, $1, idx) => {
|
|
||||||
const pos = len - idx
|
|
||||||
if($1 !== 0) {
|
|
||||||
if(idx === 0 && $1 === 1 && idxs[pos] === '十') return idxs[pos]
|
|
||||||
return num[$1] + idxs[pos]
|
|
||||||
}
|
|
||||||
if(idx + $1.length >= str.length) return ''
|
|
||||||
return '零'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数字补足位数,例如将6补足3位 -> 003
|
|
||||||
export const fillDigit = (digit: number, len: number) => {
|
|
||||||
return padStart('' + digit, len, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进入全屏
|
|
||||||
export const enterFullscreen = () => {
|
|
||||||
const docElm = document.documentElement
|
|
||||||
docElm.requestFullscreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 退出全屏
|
|
||||||
export const exitFullscreen = document.exitFullscreen
|
|
||||||
|
|
||||||
// 判断是否全屏
|
|
||||||
export const isFullscreen = () => document.fullscreenEnabled
|
|
||||||
|
|
||||||
// 判断用户的操作系统是否安装了某字体
|
|
||||||
export const isSupportFontFamily = (fontFamily: string) => {
|
|
||||||
if(typeof fontFamily !== 'string') return false
|
|
||||||
const arial = 'Arial'
|
|
||||||
if(fontFamily.toLowerCase() === arial.toLowerCase()) return true
|
|
||||||
const a = 'a'
|
|
||||||
const size = 100
|
|
||||||
const width = 100
|
|
||||||
const height = 100
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
|
|
||||||
if(!ctx) return false
|
|
||||||
|
|
||||||
canvas.width = width
|
|
||||||
canvas.height = height
|
|
||||||
ctx.textAlign = 'center'
|
|
||||||
ctx.fillStyle = 'black'
|
|
||||||
ctx.textBaseline = 'middle'
|
|
||||||
|
|
||||||
const getDotArray = (_fontFamily: string) => {
|
|
||||||
ctx.clearRect(0, 0, width, height)
|
|
||||||
ctx.font = `${size}px ${_fontFamily}, ${arial}`
|
|
||||||
ctx.fillText(a, width / 2, height / 2)
|
|
||||||
const imageData = ctx.getImageData(0, 0, width, height).data
|
|
||||||
return [].slice.call(imageData).filter(item => item !== 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return getDotArray(arial).join('') !== getDotArray(fontFamily).join('')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取图片的原始宽高
|
|
||||||
export const getImageSize = (imgUrl: string) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const img = document.createElement('img')
|
|
||||||
img.src = imgUrl
|
|
||||||
img.style.opacity = '0'
|
|
||||||
document.body.appendChild(img)
|
|
||||||
|
|
||||||
img.onload = () => {
|
|
||||||
const imgWidth = img.clientWidth
|
|
||||||
const imgHeight = img.clientHeight
|
|
||||||
|
|
||||||
img.onload = null
|
|
||||||
img.onerror = null
|
|
||||||
|
|
||||||
document.body.removeChild(img)
|
|
||||||
|
|
||||||
resolve({ imgWidth, imgHeight })
|
|
||||||
}
|
|
||||||
|
|
||||||
img.onerror = () => {
|
|
||||||
img.onload = null
|
|
||||||
img.onerror = null
|
|
||||||
|
|
||||||
reject('图片加载失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制文本到剪贴板
|
|
||||||
export const copyText = (text: string) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const fakeElement = document.createElement('button')
|
|
||||||
const clipboard = new Clipboard(fakeElement, {
|
|
||||||
text: () => text,
|
|
||||||
action: () => 'copy',
|
|
||||||
container: document.body,
|
|
||||||
})
|
|
||||||
clipboard.on('success', e => {
|
|
||||||
clipboard.destroy()
|
|
||||||
resolve(e)
|
|
||||||
})
|
|
||||||
clipboard.on('error', e => {
|
|
||||||
clipboard.destroy()
|
|
||||||
reject(e)
|
|
||||||
})
|
|
||||||
document.body.appendChild(fakeElement)
|
|
||||||
fakeElement.click()
|
|
||||||
document.body.removeChild(fakeElement)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取剪贴板
|
|
||||||
export const readClipboard = () => {
|
|
||||||
if(navigator.clipboard) {
|
|
||||||
navigator.clipboard.readText().then(text => {
|
|
||||||
if(!text) return { err: '剪贴板为空或者不包含文本' }
|
|
||||||
return { text }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return { err: '浏览器不支持或禁止访问剪贴板' }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加密函数
|
|
||||||
export const encrypt = (msg: string) => {
|
|
||||||
return CryptoJS.AES.encrypt(msg, CRYPTO_KEY).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解密函数
|
|
||||||
export const decrypt = (ciphertext: string) => {
|
|
||||||
const bytes = CryptoJS.AES.decrypt(ciphertext, CRYPTO_KEY)
|
|
||||||
return bytes.toString(CryptoJS.enc.Utf8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取DOM节点样式
|
|
||||||
export const getStyle = (el: HTMLElement, style: string) => {
|
|
||||||
if(!el) return null
|
|
||||||
return window.getComputedStyle(el, null).getPropertyValue(style)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查元素是否处在可视区域内
|
|
||||||
export const checkElementInViewport = (el: HTMLElement) => {
|
|
||||||
const rect = el.getBoundingClientRect()
|
|
||||||
return (
|
|
||||||
rect.top >= 0 &&
|
|
||||||
rect.left >= 0 &&
|
|
||||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
||||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -46,6 +46,7 @@ import { State } from '@/store/state'
|
||||||
import { MutationTypes } from '@/store/constants'
|
import { MutationTypes } from '@/store/constants'
|
||||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||||
|
import { getImageDataURL } from '@/utils/image'
|
||||||
|
|
||||||
import useDropImage from '@/hooks/useDropImage'
|
import useDropImage from '@/hooks/useDropImage'
|
||||||
|
|
||||||
|
@ -67,7 +68,11 @@ export default defineComponent({
|
||||||
|
|
||||||
const dropImageFile = useDropImage(viewportRef)
|
const dropImageFile = useDropImage(viewportRef)
|
||||||
watch(dropImageFile, () => {
|
watch(dropImageFile, () => {
|
||||||
console.log(dropImageFile.value)
|
if(dropImageFile.value) {
|
||||||
|
getImageDataURL(dropImageFile.value).then(dataURL => {
|
||||||
|
console.log(dataURL)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const viewportStyles = reactive({
|
const viewportStyles = reactive({
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
import { createRandomCode } from '@/utils/common'
|
||||||
|
import { getImageSize } from '@/utils/image'
|
||||||
|
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||||
|
import { TableElementCell } from '@/types/slides'
|
||||||
|
import {
|
||||||
|
DEFAULT_IMAGE,
|
||||||
|
DEFAULT_TEXT,
|
||||||
|
DEFAULT_SHAPE,
|
||||||
|
DEFAULT_LINE,
|
||||||
|
DEFAULT_CHART,
|
||||||
|
DEFAULT_TABLE,
|
||||||
|
} from '@/configs/defaultElement'
|
||||||
|
|
||||||
|
interface CommonElementPosition {
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LineElementPosition {
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
start: [number, number];
|
||||||
|
end: [number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertImage = (imgUrl: string) => {
|
||||||
|
getImageSize(imgUrl).then(({ width, height }) => {
|
||||||
|
const scale = width / height
|
||||||
|
|
||||||
|
if(scale < VIEWPORT_ASPECT_RATIO && width > VIEWPORT_SIZE) {
|
||||||
|
width = VIEWPORT_SIZE
|
||||||
|
height = width * scale
|
||||||
|
}
|
||||||
|
else if(height > VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO) {
|
||||||
|
height = VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO
|
||||||
|
width = height / scale
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...DEFAULT_IMAGE,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
imgUrl,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertChart = (chartType: string, data: Object) => {
|
||||||
|
return {
|
||||||
|
...DEFAULT_CHART,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
chartType,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertTable = (rowCount: number, colCount: number) => {
|
||||||
|
const row: TableElementCell[] = new Array(colCount).fill({ colspan: 1, rowspan: 1, content: '' })
|
||||||
|
const data: TableElementCell[][] = new Array(rowCount).fill(row)
|
||||||
|
|
||||||
|
const DEFAULT_CELL_WIDTH = 80
|
||||||
|
const DEFAULT_CELL_HEIGHT = 35
|
||||||
|
const DEFAULT_BORDER_WIDTH = 2
|
||||||
|
|
||||||
|
const colSizes: number[] = new Array(colCount).fill(DEFAULT_CELL_WIDTH)
|
||||||
|
const rowSizes: number[] = new Array(rowCount).fill(DEFAULT_CELL_HEIGHT)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...DEFAULT_TABLE,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
width: colCount * DEFAULT_CELL_WIDTH + DEFAULT_BORDER_WIDTH,
|
||||||
|
height: rowCount * DEFAULT_CELL_HEIGHT + DEFAULT_BORDER_WIDTH,
|
||||||
|
colSizes,
|
||||||
|
rowSizes,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertText = (position: CommonElementPosition) => {
|
||||||
|
const { left, top, width, height } = position
|
||||||
|
return {
|
||||||
|
...DEFAULT_TEXT,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertShape = (position: CommonElementPosition, svgCode: string) => {
|
||||||
|
const { left, top, width, height } = position
|
||||||
|
return {
|
||||||
|
...DEFAULT_SHAPE,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
svgCode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertLine = (position: LineElementPosition, marker: [string, string], lineType: string) => {
|
||||||
|
const { left, top, start, end } = position
|
||||||
|
|
||||||
|
return {
|
||||||
|
...DEFAULT_LINE,
|
||||||
|
elId: createRandomCode(),
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
marker,
|
||||||
|
lineType,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { createRandomCode } from '@/utils/index'
|
import { createRandomCode } from '@/utils/common'
|
||||||
import { PPTElement } from '@/types/slides'
|
import { PPTElement } from '@/types/slides'
|
||||||
|
|
||||||
// 组合元素(为当前所有激活元素添加一个相同的groupId)
|
// 组合元素(为当前所有激活元素添加一个相同的groupId)
|
||||||
|
|
|
@ -17,7 +17,8 @@ import { computed, defineComponent, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { State } from '@/store/state'
|
import { State } from '@/store/state'
|
||||||
import { KEYCODE } from '@/configs/keyCode'
|
import { KEYCODE } from '@/configs/keyCode'
|
||||||
import { decrypt } from '@/utils/index'
|
import { decrypt } from '@/utils/crypto'
|
||||||
|
import { getImageDataURL } from '@/utils/image'
|
||||||
|
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
|
||||||
|
@ -151,7 +152,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
const pasteImageFile = (imageFile: File) => {
|
const pasteImageFile = (imageFile: File) => {
|
||||||
console.log(imageFile)
|
getImageDataURL(imageFile).then(dataURL => {
|
||||||
|
console.log(dataURL)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const pasteText = (text: string) => {
|
const pasteText = (text: string) => {
|
||||||
|
|
Loading…
Reference in New Issue