在线流程图和思维导图开发技术详解(二)
一、項(xiàng)目概述
二、項(xiàng)目架構(gòu)
三、幾何計(jì)算難點(diǎn)
四、鼠標(biāo)事件處理
五、數(shù)據(jù)保存與導(dǎo)出
六、文本處理
二、項(xiàng)目架構(gòu)
2.1 系統(tǒng)架構(gòu)
項(xiàng)目系統(tǒng)架構(gòu)如下圖所示:
UI元素即HTML DOM元素。項(xiàng)目打開時(shí),畫面雖然是一片空白的,但實(shí)際上UI元素并不空白。一些可復(fù)用不需動(dòng)態(tài)創(chuàng)建的元素可預(yù)先定義好。例如選擇框、對(duì)齊線等,出現(xiàn)的時(shí)候它們只是位置發(fā)生了改變,不需動(dòng)態(tài)創(chuàng)建,可預(yù)先定義好,節(jié)省開銷。
UI元素使用ID標(biāo)注(Vue里使用ref),然后注冊(cè)到UI管理器中。后面對(duì)UI管理器中相應(yīng)的對(duì)象進(jìn)行修改時(shí),UI元素就會(huì)發(fā)生改變。
對(duì)UI元素的所有操作,例如動(dòng)一下鼠標(biāo)、點(diǎn)一下按鈕、按一下鍵盤,所有的這些事件都會(huì)交給事件處理器處理。事件處理器包括鼠標(biāo)事件、基本編輯事件、畫布事件、圖元屬性改變事件、分組操作事件、鎖定操作事件、層次操作事件等。
事件處理器不會(huì)對(duì)UI直接產(chǎn)生作用,它們會(huì)調(diào)用各種管理器去完成任務(wù)。每種元素都會(huì)有一個(gè)管理器,包括畫布、光標(biāo)、歷史記錄、整圖、選擇、狀態(tài)、選框、文字、變換等。
管理器中會(huì)使用到一些比較復(fù)雜的操作或計(jì)算,這些功能由工具類提供。例如幾何計(jì)算、思維導(dǎo)圖位置計(jì)算、path數(shù)據(jù)生成等。
管理器最后會(huì)對(duì)UI管理器進(jìn)行操作,達(dá)到改變UI的最終效果。
以下,我們以鼠標(biāo)點(diǎn)擊一個(gè)矩形為例,說明框架的運(yùn)行細(xì)節(jié)。
HTML中定義了一個(gè)選擇框,包括一個(gè)虛線矩形和八個(gè)實(shí)線小矩形。
上述圖元注冊(cè)到UI管理器中。
當(dāng)鼠標(biāo)點(diǎn)擊矩形時(shí),觸發(fā)了MouseDown事件,這個(gè)事件會(huì)調(diào)用鼠標(biāo)事件處理器。
鼠標(biāo)事件處理器利用目標(biāo)工具類,判斷當(dāng)前鼠標(biāo)點(diǎn)擊了什么目標(biāo)。
鼠標(biāo)事件處理器利用狀態(tài)管理器獲取當(dāng)前狀態(tài),繼而改變當(dāng)前狀態(tài)。
鼠標(biāo)事件處理器利用光標(biāo)管理器修改當(dāng)前光標(biāo)。
鼠標(biāo)事件處理器利用選框管理器,顯示選擇框。
選框管理器調(diào)用UI管理器中注冊(cè)的元素,把選擇框顯示出來。
2.2 圖元數(shù)據(jù)定義
圖元數(shù)據(jù)描述是本項(xiàng)目開發(fā)的一個(gè)難點(diǎn)。圖元數(shù)據(jù)的特點(diǎn)包括:
(1)圖元種類眾多,每種圖元有自己獨(dú)特的屬性。
(2)某些種類的圖元存在公共的屬性。例如矩形、圖片的位置都是通過一個(gè)矩形來描述的。
(3)管理器對(duì)圖元有共同的操作。例如把圖片數(shù)據(jù)轉(zhuǎn)化為可視HTML,鼠標(biāo)拖動(dòng)時(shí)的平移動(dòng)作等。這些操作在圖元內(nèi)部的實(shí)現(xiàn)并不一致。
(4)圖元存在一些即使而不需要保存的屬性,例如是否選中,這是一個(gè)不需要保存,每次打開時(shí)都有默認(rèn)值的屬性。
在本項(xiàng)目中,圖元具有以下的數(shù)據(jù)定義:
class Component {public id: string = "";public type: ComponentType = "rect";public props: { [key: string]: string } = {};public connectAnchors: Array<AnchorDirPos> = []; }這就是圖元的基類。可以看到,屬性是相當(dāng)少的。在這里,需要說明幾種跟TypeScript語法相關(guān)的設(shè)計(jì)特性:
(1)圖元基類只有屬性,沒有方法。這是因?yàn)閳D元需要進(jìn)行復(fù)制操作,復(fù)制時(shí)方法是無法實(shí)現(xiàn)的。
(2)很多特有的屬性被設(shè)計(jì)到props屬性中,這是一個(gè)Object。實(shí)際上Map也能實(shí)現(xiàn)相同的功能,但因?yàn)镸ap同樣不能被復(fù)制,所以使用Object。props中只存放字符串類型的屬性,其他屬性(例如位置)如果使用字符串,還需要轉(zhuǎn)換,浪費(fèi)資源。
對(duì)于存在公共屬性的圖元,定義了繼承Component的新的基類。例如,用矩形去描述位置的圖元,都繼承于以下的基類:
class RectPositionComponent extends Component {public position: Rect = new Rect(0, 0, 0, 0);public originPosition: Rect = new Rect(0, 0, 0, 0); ?public mindChildren1: Array<MindElement> = [];public mindChildren2: Array<MindElement> = []; ?public constructor() {super(); ?this.props[PreDefine.MindType] = PreDefine.DefaultMindType;} }在這里,我們可以看到,這個(gè)類有一個(gè)position屬性,它是一個(gè)矩形。還有一個(gè)originPosition屬性,是用在變換圖元時(shí)標(biāo)記原始位置的屬性。
這個(gè)基類還描述了思維導(dǎo)圖的數(shù)據(jù)結(jié)構(gòu)。本項(xiàng)目的思維導(dǎo)圖,只能在矩形類型的圖元下創(chuàng)建。思維導(dǎo)圖存在樹在兩側(cè)的展示方式,所以有兩棵樹(mindChildren1和mindChildren2)去描述思維導(dǎo)圖的結(jié)點(diǎn)。
以下是矩形類的定義:
class RectComponent extends RectPositionComponent {public constructor() {super(); ?this.type = "rect";this.id = CommonFunc.GetId(); ?this.props[PreDefine.Fill] = PreDefine.DefaultFill;this.props[PreDefine.Stroke] = PreDefine.DefaultStroke;this.props[PreDefine.StrokeWidth] = PreDefine.DefaultStrokeWidth;this.props[PreDefine.StrokeDash] = PreDefine.DefaultStrokeDash;this.props[PreDefine.CornerRadius] = PreDefine.DefaultCornerRadius; ?this.props[PreDefine.TextHorAlign] = PreDefine.DefaultTextHorAlign;this.props[PreDefine.TextVerAlign] = PreDefine.DefaultTextVerAlign;this.props[PreDefine.FontFamily] = PreDefine.DefaultFontFamily;this.props[PreDefine.FontSize] = PreDefine.DefaultFontSize;this.props[PreDefine.FontColor] = PreDefine.DefaultFontColor;this.props[PreDefine.FontBold] = PreDefine.DefaultFontBold;this.props[PreDefine.FontUnderline] = PreDefine.DefaultFontUnderline;} ?public textPos: AnchorPos = new AnchorPos();public textExist: boolean = false;public textHtml: string = ""; }矩形的樣式,需要通過填充顏色、描邊寬度等屬性去定義。另外,矩形中還有文字,文字又有字體大小、字體顏色等屬性。這些屬性都在圖元初始化時(shí)添加到props屬性中。而文字的位置等屬性,由于其存在一定的數(shù)據(jù)結(jié)構(gòu),如果定義在props中,還需要轉(zhuǎn)化,浪費(fèi)資源,所以獨(dú)立定義。事實(shí)上,這種區(qū)分定義還有一個(gè)重要原因,就是在菜單中能修改的屬性都在props中。
對(duì)圖元的操作由一個(gè)接口去定義。以下是該接口的部分方法:
interface IComponentOperate {ChangeId(): void;Create(obj: unknown): void; ?Html(): string;UpdateHtml(): void;DeleteHtml(): void; ?Move(diagramX: number, diagramY: number): void;MoveOffset(offsetX: number, offsetY: number): void;UpdateInnerPosition(): void;MarkOrigin(): void;ChangeCoordinate(origin: Rect, target: Rect): void; }Html()方法是返回圖元的HTML內(nèi)容。例如矩形使用一個(gè)<rect>標(biāo)簽定義,形狀一般使用<path>標(biāo)簽定義,而圖片使用<image>標(biāo)簽定義。又如,UpdateInnerPosition()方法一般是用在組類型的圖元上的。一個(gè)組進(jìn)行變換之后,其內(nèi)部的所有圖元都要跟隨變換。但矩形這種圖形,內(nèi)容并沒有子,也就不需要執(zhí)行額外的操作。
操作方法跟圖元,通過圖元的ID和類型進(jìn)行綁定。圖元的類型確定了接口實(shí)例化的方法類,而方法類要處理哪個(gè)圖元,又通過ID去確定。
總結(jié)
以上是生活随笔為你收集整理的在线流程图和思维导图开发技术详解(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html鼠标悬浮缩放,CSS3鼠标悬浮过
- 下一篇: 签到活动随笔