From 985be943cacc582ad807f36aeb675ece4279c012 Mon Sep 17 00:00:00 2001 From: pipipi-pikachu Date: Fri, 1 Jul 2022 21:17:47 +0800 Subject: [PATCH] doc: add docs --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +- README.md | 105 +------ doc/Canvas.md | 66 +++++ doc/CustomElement.md | 412 +++++++++++++++++++++++++++ doc/DirectoryAndData.md | 37 +++ doc/Q&A.md | 59 ++++ 6 files changed, 582 insertions(+), 100 deletions(-) create mode 100644 doc/Canvas.md create mode 100644 doc/CustomElement.md create mode 100644 doc/DirectoryAndData.md create mode 100644 doc/Q&A.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 64894f2a..7023c294 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,4 +19,5 @@ assignees: '' **环境信息** 如有必要,可包含以下部分: 1. 系统环境(Mac or Windows) -2. 浏览器环境(如:Chrome v89.0.4389.114) \ No newline at end of file +2. 浏览器环境(如:Chrome v89.0.4389.114) +3. 如拉取后无法运行,请提供相关异常指向的依赖及其版本信息 \ No newline at end of file diff --git a/README.md b/README.md index f0cf9488..27156d74 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ 2. 本项目的目标受众是有【Web 幻灯片】开发需求的开发者,提供的链接只是一个演示地址,并不能作为工具使用,也不提供任何在线服务。 如果你只是需要一个服务或工具,可以选择更优秀和成熟的产品,例如:[石墨文档](https://shimo.im/)、[金山文档](https://www.kdocs.cn/)、[Slidev](https://sli.dev/)、[revealjs](https://revealjs.com/) 等。 3. 本项目是基于 DOM 的渲染方案,好处是简单。但是相比 Canvas 渲染的方案,在复杂场景下性能会存在一定的差距,所以如果你对性能有较高的要求,本项目可能不是一个好的参考方向。 +4. 这里总结了一些[常见问题](https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md),第一次提 Issues 和 PR 时,务必提前阅读此文档。 # 🚀 项目运行 @@ -133,113 +134,19 @@ npm run serve - 播放预览 -# 💡 常见问题 -**Q. 为什么xxx快捷键没有作用?** - -A. 部分快捷键需要聚焦到指定区域才会生效,例如焦点在左边缩略图列表才能使用操作页面的快捷键,焦点在画布区域才能使用操作元素的快捷键。 - -**Q. 为什么粘贴没有作用?** - -A. 请注意允许浏览器访问系统剪贴板。 - -**Q. 为什么浏览器刷新或重新打开后,之前做的PPT没有了?** - -A. 该演示项目是纯前端部署的,不会保存数据。 - -**Q. 如何调整幻灯片页面的顺序?** - -A. 按住左侧缩略图可进行拖拽调整顺序。 - -**Q. 为什么插入图片后会出现操作卡顿的情况?** - -A. 由于本演示项目不依赖后端,插入本地图片实际引用的是Base64,导致数据体积非常大,在真正的生产环境中应该上传图片后引用图片地址,就不会出现这样的情况了。 - -**Q. 为什么应用预置主题后没有效果?** - -A. 设置预置主题的作用是使新添加的元素和页面应用主题样式,不会对已有的元素和页面生效,您可以使用“应用主题到全部”功能,将当前主题应用到全部页面中。 - -**Q. 设置在线字体不生效?** - -A. 设置在线字体时会下载对应的字体文件,该文件较大,需要等待下载完成后才会应用新的字体。 - -**Q. 关于导入导出PPTX文件** - -A. 作为一个在线幻灯片应用,导出、导入 PPTX 文件是非常重要的功能,但是经过调研发现,该功能实现起来的复杂度远超过了预期。由于个人能力和时间有限,这部分功能只能借助第三方的轮子来完成。 - -目前导出功能主要基于 [PptxGenJS](https://github.com/gitbrent/PptxGenJS/) 完成,能够实现大多数基本元素的导出,但还有非常多的缺陷需要一点点完善。同时需要知晓的是:1、该功能依赖 PptxGenJS,对于该库本身无法实现的部分(如动画),本项目也无能为力;2、导出功能的目标只是【导出样式尽可能一致的元素】,而不是一比一将网页还原到PPT,一些样式差异是必然存在的。 - -导入功能目前暂时没有合适的解决方案,还在调研和观望中。如果有感兴趣或做过相关内容的朋友,欢迎来 issues 中讨论。 - -> PS. 我做了一个 [pptx转json](https://github.com/pipipi-pikachu/pptx2json) 的实验,可做参考。 - -同时补充一点,本项目不是 office PPT 的专属在线编辑器,本质上与 office PPT 没有任何关系。【导入/导出 ppt 文件】只是项目的一个功能而非目的。 - -**Q. 视频元素支持哪些格式?** - -A. 本项目只提供最基础的视频能力,正常状态下可以播放video标签本身支持的格式。 - -此外,可以额外引入 [hls.js](https://github.com/video-dev/hls.js) 或 [flv.js](https://github.com/Bilibili/flv.js) 来支持对应的格式(.m3u8 .flv),你只需要在项目中引入对应的文件(如cdn)即可,无需其他配置。 - -**Q. 关于导入JSON文件** - -A. 首先,出于安全等原因,个人并不建议将这种功能在前端直接暴露给用户,或者说用户根本就不应该接触到JSON这种格式(甚至导出JSON功能的初衷也只是为了方便开发)。如果真的有相关的需求,请自行在服务端实现,核心在于做好进行数据的校验,前端实现也是一样。 - -**Q. 打印 / 导出 PDF 样式与实际有出入** - -A. 请注意在浏览器弹出的打印窗口调整相关的设置。建议:设置边距为【默认】、取消勾选【页眉和页脚】、勾选【背景图形】 - -**Q. 为什么移动端不支持 xxx 功能?** - -A. 首先需要明确的一点,就是移动端无论怎么做,体验上都是必然大不如 PC 端的。因此个人将移动端定位为:简单进行一些临时处理的应急使用。真正的设计/制作幻灯片应在电脑上使用完整的功能。如实在有移动端的特殊需求,可尝试在移动端使用电脑模式打开(当然,体验会更槽糕),或者开发者自己进行二次开发。 - - # 📅 后续规划 -## 重要功能规划 - 组合元素重构:能够支持组合元素进行旋转、缩放、整体执行动画等; - 添加强化版基础形状:支持调整圆角矩形弧度、调整三角形顶点位置等操作; - 移动端简单编辑支持; - 导入本地PPTX文件; - -## 项目规划 - 将 Vue CLI 更换到 Vite 生态; -- 开发文档; -# 📁 项目目录结构 -``` -├── assets // 静态资源 -│ ├── fonts // 在线字体文件 -│ └── styles // 样式 -│ ├── antd.scss // antd默认样式覆盖 -│ ├── font.scss // 在线字体定义 -│ ├── global.scss // 通用全局样式 -│ ├── mixin.scss // scss全局混入 -│ ├── variable.scss // scss全局变量 -│ └── prosemirror.scss // ProseMirror 富文本默认样式 -├── components // 与业务逻辑无关的通用组件 -├── configs // 配置文件,如:画布尺寸、字体、动画配置、快捷键配置、预置形状、预置线条等数据。 -├── hooks // 供多个组件(模块)使用的 hooks 方法 -├── mocks // mocks 数据 -├── plugins // 自定义的 Vue 插件 -├── types // 类型定义文件 -├── store // Pinia store,参考:https://pinia.vuejs.org/ -├── utils // 通用的工具方法 -└── views // 业务组件目录,分为 `编辑器` 和 `播放器` 两个部分。 - ├── components // 公用的业务组件 - ├── Editor // 编辑器模块 - ├── Screen // 播放器模块 - └── Mobile // 移动端模块 -``` - - -# 💿 数据 -幻灯片的数据主要由 `slides` 和 `theme` 两部分组成。 -> 换句话说,在实际的生产环境中,一般只需要存储这两项数据即可。 - -- `slides` 表示幻灯片页面数据,包括每一页的ID、元素内容、备注、背景、动画、切页方式等信息 -- `theme` 表示幻灯片主题数据,包括背景色、主题色、字体颜色、字体等信息 - -具体类型的定义可见:[https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts](https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts) +# 🎯 开发 +目前没有完整的开发文档,但下面这些文档可能会对你有一些帮助: +- [项目目录与数据结构](https://github.com/pipipi-pikachu/PPTist/blob/master/doc/DirectoryAndData.md) +- [画布与元素的基本原理](https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Canvas.md) +- [如何自定义一个元素](https://github.com/pipipi-pikachu/PPTist/blob/master/doc/CustomElement.md) # 💻 贡献代码 diff --git a/doc/Canvas.md b/doc/Canvas.md new file mode 100644 index 00000000..1cef00c7 --- /dev/null +++ b/doc/Canvas.md @@ -0,0 +1,66 @@ +## 画布与元素 + +#### 编辑器的基本结构 +``` +└──编辑器 + ├── 顶部菜单里 + ├── 左侧导航栏 + ├── 右侧导航栏 + ├── 中上部插入/工具栏 + ├── 底部输入栏 + └── 画布 + ├── 可视区域 + │ ├── 可编辑元素 + │ └── 鼠标选框 + │ + └── 画布工具 + ├── 参考线 + ├── 标尺 + ├── 元素操作节点层(如拖拽缩放点) + ├── 吸附对齐线 + └── 可视区域背景 +``` + +#### 画布的基本原理 +我们把关注点放在相对复杂的【画布】部分。画布中的每一个元素都由一组数据来描述,例如: +```typescript +interface PPTBaseElement { + id: string; + left: number; + top: number; + width: number; + height: number; +} +``` +顾名思义,`left` 表示元素距离画布左上角的位置,`width` 表示元素的宽度,以此类推。 +重点需要知道的是:可视区域默认以 宽1000像素 、高562.5像素为基础比例。即无论画布和可视区域实际大小是多少,一个 `{ width: 1000px, height: 562.5px, left: 0, top: 0 }` 的元素一定会正好铺满整个可视区域。 +具体实现的方法很简单:假设可视区域的实际宽度为 1200px ,计算出此时的缩放比为 1200 / 1000 = 1.2 ,然后将可视区域内的元素全部缩放到 1.2 倍即可。 +同理【缩略图】 和 【放映页面】 其实上就是一个实际大小更小或更大的可视区域。 + +#### 画布内的元素 +除了上述中的位置和尺寸信息,还可以携带更多的数据,以一个文本元素为例: +```typescript +interface PPTTextElement { + type: 'text'; + id: string; + left: number; + top: number; + lock?: boolean; + groupId?: string; + width: number; + height: number; + link?: string; + content: string; + rotate: number; + defaultFontName: string; + defaultColor: string; + outline?: PPTElementOutline; + fill?: string; + lineHeight?: number; + wordSpace?: number; + opacity?: number; + shadow?: PPTElementShadow; +} +``` +你可以定义一个 `rotate` 来表示文本框旋转的角度、定义一个 `opacity` 来表示文本框的透明度 等。在实现时只需要按照你所定义的数据来渲染元素组件即可,而编辑元素的本质就是在修改这些数据。 +以上就是一个画布最基本的组成了。 diff --git a/doc/CustomElement.md b/doc/CustomElement.md new file mode 100644 index 00000000..42b9c67a --- /dev/null +++ b/doc/CustomElement.md @@ -0,0 +1,412 @@ +## 如何自定义一个元素 + +我们以【网页元素】为例,来梳理下自定义一个元素的过程。 +> 完整代码在 https://github.com/pipipi-pikachu/PPTist/tree/document-demo + +### 编写新元素的结构与配置 +首先需要定义这个元素的结构,并添加该元素类型 +```typescript +// types/slides.ts + +export const enum ElementTypes { + TEXT = 'text', + IMAGE = 'image', + SHAPE = 'shape', + LINE = 'line', + CHART = 'chart', + TABLE = 'table', + LATEX = 'latex', + VIDEO = 'video', + AUDIO = 'audio', + FRAME = 'frame', // add +} + +// add +export interface PPTFrameElement extends PPTBaseElement { + type: 'frame' + id: string; + left: number; + top: number; + width: number; + height: number; + url: string; // 网页链接地址 +} + +// 修改 PPTElement Type +export type PPTElement = PPTTextElement | PPTImageElement | PPTShapeElement | PPTLineElement | PPTChartElement | PPTTableElement | PPTLatexElement | PPTVideoElement | PPTAudioElement | PPTFrameElement +``` + +在配置文件中添加新元素的中文名,以及最小尺寸: +```typescript +// configs/element + +export const ELEMENT_TYPE_ZH = { + text: '文本', + image: '图片', + shape: '形状', + line: '线条', + chart: '图表', + table: '表格', + video: '视频', + audio: '音频', + frame: '网页', // add +} + +export const MIN_SIZE = { + text: 20, + image: 20, + shape: 15, + chart: 200, + table: 20, + video: 250, + audio: 20, + frame: 200, // add +} +``` + +### 编写新元素组件 +然后开始编写该元素的组件: +```html + + + + + + + +``` + +此外我们需要另一个不带编辑功能的基础版组件,用于缩略图/放映模式下显示: +```html + + + + + + + +``` + +在这里你可能会发现,这两个组件非常相似,确实如此,对于比较简单的元素组件来说,可编辑版和不可编辑版是高度一致的,不可编辑版可能仅仅是少了一些方法而已。但是对于比较复杂的元素组件,两者的差异就会比较大了(具体可以比较文本元素和图片元素的两版),因此,你可以自行判断是否将二者合并抽象为一个组件,这里不过多展开。 + +编写完元素组件,我们需要把它用在需要的地方,具体可能包括: + +- 缩略图元素组件 `views/components/ThumbnailSlide/ThumbnailElement.vue` +- 放映元素组件 `views/Screen/ScreenElement.vue` +- 可编辑元素组件 `views/Editor/Canvas/EditableElement.vue` +- 移动端可编辑元素组件 `views/Mobile/MobileEditor/MobileEditableElement.vue` + +一般来说,前两者使用不可编辑版,后两者使用可编辑版。 +这里仅以画布中的可编辑元素组件为例: +```html + + + +``` + +在画布的可编辑元素中,还需要为元素添加操作节点 `Operate`(一般包括八个缩放点、四条边线、一个旋转点),对于特殊的元素(如线条的操作节点明显与其他不同)你可以自己编写该组件,但是一般情况下可以直接使用已经编写好的通用操作节点: +```html + + + +``` + +### 编写右侧元素编辑面板 +接下来需要为元素添加一个样式面板。当选中元素时,右侧工具栏会自动聚焦到该面板,你需要在这里添加一些你认为需要的设置项来操作元素本身,只需要记住一点:修改元素实际是修改元素的数据,也就是最开始定义的结构中的各个字段。 +另外,修改元素后不要忘了将操作添加到历史记录。 +```html + + + + + +``` +```html + +``` + +### 创建元素 +这是自定义一个新元素的最后一步。首先编写一个创建元素的方法: +```typescript +// src\hooks\useCreateElement.ts + +const createFrameElement = (url: string) => { + createElement({ + type: 'frame', + id: nanoid(10), + width: 800, + height: 480, + rotate: 0, + left: (VIEWPORT_SIZE - 800) / 2, + top: (VIEWPORT_SIZE * viewportRatio.value - 480) / 2, + url, + }) +} +``` +然后在插入工具栏中使用: +```html + + + + + +``` +点击【插入网页】按钮,你就会看到一个网页元素被添加到画布中了。 + +### 总结 +至此就是自定义一个元素的基本流程了。整个过程比较繁琐,但并不复杂,重点在于元素结构的定义与元素组件的编写,这决定了新元素将具备怎样的能力与外表。而其他的部分仅依葫芦画瓢即可。 +除此之外,还有一些非必须的调整:比如你希望导出能够支持新元素,则需要在导出相关的方法中进行扩展;比如你希望主题功能能够应用在新元素上,则需要在主题相关的方法中进行扩展,以此类推。 diff --git a/doc/DirectoryAndData.md b/doc/DirectoryAndData.md new file mode 100644 index 00000000..8ec29ddc --- /dev/null +++ b/doc/DirectoryAndData.md @@ -0,0 +1,37 @@ +## 项目目录与数据结构 + +### 项目目录结构 +``` +├── assets // 静态资源 +│ ├── fonts // 在线字体文件 +│ └── styles // 样式 +│ ├── antd.scss // antd默认样式覆盖 +│ ├── font.scss // 在线字体定义 +│ ├── global.scss // 通用全局样式 +│ ├── mixin.scss // scss全局混入 +│ ├── variable.scss // scss全局变量 +│ └── prosemirror.scss // ProseMirror 富文本默认样式 +├── components // 与业务逻辑无关的通用组件 +├── configs // 配置文件,如:画布尺寸、字体、动画配置、快捷键配置、预置形状、预置线条等数据。 +├── hooks // 供多个组件(模块)使用的 hooks 方法 +├── mocks // mocks 数据 +├── plugins // 自定义的 Vue 插件 +├── types // 类型定义文件 +├── store // Pinia store,参考:https://pinia.vuejs.org/ +├── utils // 通用的工具方法 +└── views // 业务组件目录,分为 `编辑器` 和 `播放器` 两个部分。 + ├── components // 公用的业务组件 + ├── Editor // 编辑器模块 + ├── Screen // 播放器模块 + └── Mobile // 移动端模块 +``` + + +### 数据 +幻灯片的数据主要由 `slides` 和 `theme` 两部分组成。 +> 换句话说,在实际的生产环境中,一般只需要存储这两项数据即可。 + +- `slides` 表示幻灯片页面数据,包括每一页的ID、元素内容、备注、背景、动画、切页方式等信息 +- `theme` 表示幻灯片主题数据,包括背景色、主题色、字体颜色、字体等信息 + +具体类型的定义可见:[https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts](https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts) \ No newline at end of file diff --git a/doc/Q&A.md b/doc/Q&A.md new file mode 100644 index 00000000..8ba29ba2 --- /dev/null +++ b/doc/Q&A.md @@ -0,0 +1,59 @@ +## 常见问题 + +**Q. 为什么xxx快捷键没有作用?** + +A. 部分快捷键需要聚焦到指定区域才会生效,例如焦点在左边缩略图列表才能使用操作页面的快捷键,焦点在画布区域才能使用操作元素的快捷键。 + +**Q. 为什么粘贴没有作用?** + +A. 请注意允许浏览器访问系统剪贴板。 + +**Q. 为什么浏览器刷新或重新打开后,之前做的PPT没有了?** + +A. 该演示项目是纯前端部署的,不会保存数据。 + +**Q. 如何调整幻灯片页面的顺序?** + +A. 按住左侧缩略图可进行拖拽调整顺序。 + +**Q. 为什么插入图片后会出现操作卡顿的情况?** + +A. 由于本演示项目不依赖后端,插入本地图片实际引用的是Base64,导致数据体积非常大,在真正的生产环境中应该上传图片后引用图片地址,就不会出现这样的情况了。 + +**Q. 为什么应用预置主题后没有效果?** + +A. 设置预置主题的作用是使新添加的元素和页面应用主题样式,不会对已有的元素和页面生效,您可以使用“应用主题到全部”功能,将当前主题应用到全部页面中。 + +**Q. 设置在线字体不生效?** + +A. 设置在线字体时会下载对应的字体文件,该文件较大,需要等待下载完成后才会应用新的字体。 + +**Q. 关于导入导出PPTX文件** + +A. 作为一个在线幻灯片应用,导出、导入 PPTX 文件是非常重要的功能,但是经过调研发现,该功能实现起来的复杂度远超过了预期。由于个人能力和时间有限,这部分功能只能借助第三方的轮子来完成。 + +目前导出功能主要基于 [PptxGenJS](https://github.com/gitbrent/PptxGenJS/) 完成,能够实现大多数基本元素的导出,但还有非常多的缺陷需要一点点完善。同时需要知晓的是:1、该功能依赖 PptxGenJS,对于该库本身无法实现的部分(如动画),本项目也无能为力;2、导出功能的目标只是【导出样式尽可能一致的元素】,而不是一比一将网页还原到PPT,一些样式差异是必然存在的。 + +导入功能目前暂时没有合适的解决方案,还在调研和观望中。如果有感兴趣或做过相关内容的朋友,欢迎来 issues 中讨论。 + +> PS. 我做了一个 [pptx转json](https://github.com/pipipi-pikachu/pptx2json) 的实验,可做参考。 + +同时补充一点,本项目不是 office PPT 的专属在线编辑器,本质上与 office PPT 没有任何关系。【导入/导出 ppt 文件】只是项目的一个功能而非目的。 + +**Q. 视频元素支持哪些格式?** + +A. 本项目只提供最基础的视频能力,正常状态下可以播放video标签本身支持的格式。 + +此外,可以额外引入 [hls.js](https://github.com/video-dev/hls.js) 或 [flv.js](https://github.com/Bilibili/flv.js) 来支持对应的格式(.m3u8 .flv),你只需要在项目中引入对应的文件(如cdn)即可,无需其他配置。 + +**Q. 关于导入JSON文件** + +A. 首先,出于安全等原因,个人并不建议将这种功能在前端直接暴露给用户,或者说用户根本就不应该接触到JSON这种格式(甚至导出JSON功能的初衷也只是为了方便开发)。如果真的有相关的需求,请自行在服务端实现,核心在于做好进行数据的校验,前端实现也是一样。 + +**Q. 打印 / 导出 PDF 样式与实际有出入** + +A. 请注意在浏览器弹出的打印窗口调整相关的设置。建议:设置边距为【默认】、取消勾选【页眉和页脚】、勾选【背景图形】 + +**Q. 为什么移动端不支持 xxx 功能?** + +A. 首先需要明确的一点,就是移动端无论怎么做,体验上都是必然大不如 PC 端的。因此个人将移动端定位为:简单进行一些临时处理的应急使用。真正的设计/制作幻灯片应在电脑上使用完整的功能。如实在有移动端的特殊需求,可尝试在移动端使用电脑模式打开(当然,体验会更槽糕),或者开发者自己进行二次开发。 \ No newline at end of file