怎样设网站,郑州全面恢复正常,大连建设执业资格注册中心网站,狮城app更多网站一、插入形状
插入形状有两种情况#xff0c;一种是插入固定的形状#xff0c;
一种是插入自定义的形状。 插入固定的形状时#xff0c;跟上一篇文章 绘制文本框 是一样一样的#xff0c;都是调用的 mainStore.setCreatingElement() 方法#xff0c;只不多传的类型不一…一、插入形状
插入形状有两种情况一种是插入固定的形状
一种是插入自定义的形状。 插入固定的形状时跟上一篇文章 绘制文本框 是一样一样的都是调用的 mainStore.setCreatingElement() 方法只不多传的类型不一样。还有插入线条也是类似的。
mainStore.setCreatingElement({type: shape,data: shape,
})所以咱们那接下来主要看插入自定义形状时的代码执行流程
1、点击
Popover triggerclick v-model:valueshapeMenuVisible styleheight: 100%; :offset10template #contentPopoverMenuItem center click() { drawCustomShape(); shapeMenuVisible false }自由绘制/PopoverMenuItem/templateIconDown classarrow /
/Popoversrc/views/Editor/CanvasTool/index.vue
// 绘制自定义任意多边形
const drawCustomShape () {mainStore.setCreatingCustomShapeState(true)shapePoolVisible.value false
}src/store/main.ts
setCreatingCustomShapeState(state: boolean) {this.creatingCustomShape state
},有了 creatingCustomShape下面的组件就会显示
ShapeCreateCanvasv-ifcreatingCustomShapecreateddata insertCustomShape(data)
/2、mousedown
src/views/Editor/Canvas/ShapeCreateCanvas.vue 触发 created 方法
const addPoint (e: MouseEvent) {const { pageX, pageY } getPoint(e)isMouseDown.value trueif (closed.value) emit(created, getCreateData())else points.value.push([pageX, pageY])document.onmouseup () {isMouseDown.value false}
}3、created
src/views/Editor/Canvas/index.vue 插入任意多边形
// 插入自定义任意多边形
const insertCustomShape (data: CreateCustomShapeData) {const {start,end,path,viewBox,} dataconst position formatCreateSelection({ start, end })if (position) {const supplement: PartialPPTShapeElement {}if (data.fill) supplement.fill data.fillif (data.outline) supplement.outline data.outline// 创建形状元素createShapeElement(position, { path, viewBox }, supplement)}// 清除 creatingCustomShapemainStore.setCreatingCustomShapeState(false)
}4、mousemove
src/views/Editor/Canvas/ShapeCreateCanvas.vue 如果鼠标按下添加 points就会形成折线的效果。 可以看到只要起点和终点比较近就算闭合了防止对不上
const updateMousePosition (e: MouseEvent) {// 如果鼠标按下则添加点if (isMouseDown.value) {const { pageX, pageY } getPoint(e, true)points.value.push([pageX, pageY])mousePosition.value nullreturn}// 更新鼠标位置const { pageX, pageY } getPoint(e)mousePosition.value [pageX, pageY]// 判断是否闭合if (points.value.length 2) {const [firstPointX, firstPointY] points.value[0]if (Math.abs(firstPointX - pageX) 5 Math.abs(firstPointY - pageY) 5) {closed.value true}else closed.value false}else closed.value false
}根据鼠标位置 mousePosition 计算 path
const path computed(() {let d for (let i 0; i points.value.length; i) {const point points.value[i]if (i 0) d M ${point[0]} ${point[1]} else d L ${point[0]} ${point[1]} }if (points.value.length mousePosition.value) {d L ${mousePosition.value[0]} ${mousePosition.value[1]}}return d
})模版中的 path 元素随之更新
svg overflowvisiblepath:dpath stroke#d14424 :fillclosed ? rgba(226, 83, 77, 0.15) : none stroke-width2 /path
/svg5、取消绘制的按键绑定
const keydownListener (e: KeyboardEvent) {const key e.key.toUpperCase()if (key KEYS.ESC) close()if (key KEYS.ENTER) create()
}
onMounted(() {message.success(点击绘制任意形状首尾闭合完成绘制按 ESC 键或鼠标右键取消按 ENTER 键提前完成, {duration: 0,})document.addEventListener(keydown, keydownListener)
})以及鼠标右键也会取消绘制
contextmenu.stop.preventclose()const close () {mainStore.setCreatingCustomShapeState(false)
}二、插入图片
src/views/Editor/CanvasTool/index.vue 插入图片也是一个自定义组件
FileInput changefiles insertImageElement(files)IconPicture classhandler-item v-tooltip插入图片 /
/FileInput这个组件里面实现上传功能的是 input 标签
input classinputtypefile nameupload refinputRef :acceptaccept change$event handleChange($event)上传之后插入图片元素
const insertImageElement (files: FileList) {const imageFile files[0]if (!imageFile) returngetImageDataURL(imageFile).then(dataURL createImageElement(dataURL))
}src/utils/image.ts
获取图片宽高的方法相比大家都挺熟悉的
/*** 获取图片的原始宽高* param src 图片地址*/
export const getImageSize (src: string): PromiseImageSize {return new Promise(resolve {const img document.createElement(img)img.src srcimg.style.opacity 0document.body.appendChild(img)img.onload () {const imgWidth img.clientWidthconst imgHeight img.clientHeightimg.onload nullimg.onerror nulldocument.body.removeChild(img)resolve({ width: imgWidth, height: imgHeight })}img.onerror () {img.onload nullimg.onerror null}})
}获取图片宽高之后创建图片元素通过 left 和 top 将图片水平垂直居中 src/hooks/useCreateElement.ts
/*** 创建图片元素* param src 图片地址*/
const createImageElement (src: string) {getImageSize(src).then(({ width, height }) {const scale height / widthif (scale viewportRatio.value width VIEWPORT_SIZE) {width VIEWPORT_SIZEheight width * scale}else if (height VIEWPORT_SIZE * viewportRatio.value) {height VIEWPORT_SIZE * viewportRatio.valuewidth height / scale}createElement({type: image,id: nanoid(10),src,width,height,left: (VIEWPORT_SIZE - width) / 2,top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,fixedRatio: true,rotate: 0,})})
}复习一下创建元素的方法会把元素放到当前幻灯片的元素列表中
// 创建插入一个元素并将其设置为被选中元素
const createElement (element: PPTElement, callback?: () void) {// 添加元素到元素列表slidesStore.addElement(element)// 设置被选中元素列表mainStore.setActiveElementIdList([element.id])if (creatingElement.value) mainStore.setCreatingElement(null)setTimeout(() {// 设置编辑器区域为聚焦状态mainStore.setEditorareaFocus(true)}, 0)if (callback) callback()// 添加历史快照addHistorySnapshot()
}三、插入图表
插入图表的方法其实也差不多就是往当前的幻灯片里添加一个图表对象。不过这里就不讲前面怎么添加元素了讲讲后面怎么展示元素吧。先来看一下图表元素的数据
const newElement: PPTChartElement {type: chart,id: nanoid(10),chartType: CHART_TYPES[type],left: 300,top: 81.25,width: 400,height: 400,rotate: 0,themeColor: [theme.value.themeColor],gridColor: theme.value.fontColor,data: {labels: [类别1, 类别2, 类别3, 类别4, 类别5],legends: [系列1],series: [[12, 19, 5, 2, 18],],},
}是这个元素对元素列表进行循环的 src/views/Editor/Canvas/index.vue
EditableElement v-for(element, index) in elementList :keyelement.id:elementInfoelement:elementIndexindex 1:isMultiSelectactiveElementIdList.length 1:selectElementselectElement:openLinkDialogopenLinkDialogv-show!hiddenElementIdList.includes(element.id)
/src/views/Editor/Canvas/EditableElement.vue 这个组件中通过动态组件的方式控制显示哪个元素
component:iscurrentElementComponent:elementInfoelementInfo:selectElementselectElement:contextmenuscontextmenus
/componentconst currentElementComponent computedunknown(() {const elementTypeMap {[ElementTypes.IMAGE]: ImageElement,[ElementTypes.TEXT]: TextElement,[ElementTypes.SHAPE]: ShapeElement,[ElementTypes.LINE]: LineElement,[ElementTypes.CHART]: ChartElement,[ElementTypes.TABLE]: TableElement,[ElementTypes.LATEX]: LatexElement,[ElementTypes.VIDEO]: VideoElement,[ElementTypes.AUDIO]: AudioElement,}return elementTypeMap[props.elementInfo.type] || null
})我们的目标就是 ChartElementsrc/views/components/element/ChartElement/index.vue 然后图表那一小块是这个src/views/components/element/ChartElement/Chart.vue图表是通过 chartist 库实现的
import { BarChart, LineChart, PieChart } from chartist