From 2675392b9763e58b964e83ea39e413b4bf0a585c Mon Sep 17 00:00:00 2001 From: Waiting Date: Fri, 10 Mar 2023 23:30:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=84=AA=E5=8C=96=E4=BB=A3=E7=A2=BC=E5=A1=8A?= =?UTF-8?q?=E9=AB=98=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CodeBlockShape.ts | 96 +++++++-------- src/Utils.ts | 280 +++++++++++++++++++++++------------------- 2 files changed, 199 insertions(+), 177 deletions(-) diff --git a/src/CodeBlockShape.ts b/src/CodeBlockShape.ts index 9c14e69..942696c 100644 --- a/src/CodeBlockShape.ts +++ b/src/CodeBlockShape.ts @@ -1,66 +1,66 @@ import hljs from 'highlight.js'; -import { Utils, CodeData } from './Utils' +import {Utils, CodeData} from './Utils' const myUtils = new Utils() class CodeBlockShape { - /** - * 根據 CodeData 對象 獲取 AntV 的 HTML 對象集合 - * @param codeData CodeData 對象 - * @returns HTML 對象集合 - */ - public createCodeBlockShape(codeData: CodeData) { + /** + * 根據 CodeData 對象 獲取 AntV 的 HTML 對象集合 + * @param codeData CodeData 對象 + * @returns HTML 對象集合 + */ + public createCodeBlockShape(codeData: CodeData) { - // 結果對象集合 - let result = [] + // 結果對象集合 + let result = [] - // 將 CodeData 中的每個 func 的 code 轉換成 AntV 的 HTML 對象 - let codeDataFuncs = codeData.funcs - for (const codeDataFunc of codeDataFuncs) { + // 將 CodeData 中的每個 func 的 code 轉換成 AntV 的 HTML 對象 + let codeDataFuncs = codeData.funcs + for (const codeDataFunc of codeDataFuncs) { - // 獲取 代碼塊字串,並分割成行 - let codeText = codeDataFunc.code - let codeTextLines = codeText.split('\n') + // 獲取 代碼塊字串,並分割成行 + let codeText = codeDataFunc.code + let codeTextLines = codeText.split('\n') - // 計算代碼塊所需高度 - const blockHeight = codeTextLines.length * 15 + 40; + // 獲取 代碼塊所需高度 + let blockHeight = myUtils.getTextHeight(codeDataFunc.code) + 20; - // 計算代碼塊所需寬度 - let blockWidth = 0 - for (let i = 0; i < codeTextLines.length; i++) { - blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px ui-sans-serif") + 60) - } + // 計算代碼塊所需寬度 + let blockWidth = 0 + for (let i = 0; i < codeTextLines.length; i++) { + blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px") + 60) + } - // 構建 HTML 對象 - const htmlShape = { - id: myUtils.getCodeBlockShapeId(codeData.className, codeDataFunc.name), - x: 800, - y: 100, - width: blockWidth, - height: blockHeight, - shape: 'html', - attrs: { - body: { - fill: 'white', - stroke: '#666', - } - }, - html() { - const wrap = document.createElement('div') - wrap.innerHTML = '
' + hljs.highlight(codeText, { language: 'java' }).value + '
' - return wrap - }, - } + // 構建 HTML 對象 + const htmlShape = { + id: myUtils.getCodeBlockShapeId(codeData.className, codeDataFunc.name), + x: 800, + y: 100, + width: blockWidth, + height: blockHeight, + shape: 'html', + attrs: { + body: { + fill: 'white', + stroke: '#666', + } + }, + html() { + const wrap = document.createElement('div') + wrap.innerHTML = '
' + hljs.highlight(codeText, {language: 'java'}).value + '
' + return wrap + }, + } - // 將 HTML 對象加入到返回結果中 - result.push(htmlShape) - } + // 將 HTML 對象加入到返回結果中 + result.push(htmlShape) + } - return result; - } + return result; + } } -export { CodeBlockShape } +export {CodeBlockShape} diff --git a/src/Utils.ts b/src/Utils.ts index ad84d50..8f7f34c 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,167 +1,189 @@ +import hljs from "highlight.js"; + type CodeData = { - className: string, // 類名稱 - funcs: CodeDataFunc[] // 函數名稱 與 代碼塊字串 集合 + className: string, // 類名稱 + funcs: CodeDataFunc[] // 函數名稱 與 代碼塊字串 集合 } type CodeDataFunc = { - name: string, // 函數名稱 - code: string // 代碼塊字串 - calls: CodeDataFuncCall[] // 調用的函數集合 + name: string, // 函數名稱 + code: string // 代碼塊字串 + calls: CodeDataFuncCall[] // 調用的函數集合 } type CodeDataFuncCall = { - className: string, // 類名稱 - functionName: string // 函數名稱 + className: string, // 類名稱 + functionName: string // 函數名稱 } export const CLASS_SHAPE_ID_TAG: string = "class-"; export const CODE_BLOCK_ID_TAG: string = 'code-block-'; + class Utils { - /** - * 計算字串寬度 - */ - tCanvas: any = null; - public getTextWidth(text: string, font: string = '13px ui-sans-serif') { - // re-use canvas object for better performance - const canvas = this.tCanvas || (this.tCanvas = document.createElement('canvas')); - const context = canvas.getContext('2d'); - context.font = font; - return context.measureText(text).width; - } + /** + * 計算字串寬度 + */ + tCanvas: any = null; + public getTextWidth(text: string, font: string) { + // re-use canvas object for better performance + const canvas = this.tCanvas || (this.tCanvas = document.createElement('canvas')); + const context = canvas.getContext('2d'); + context.font = font + ' ui-sans-serif'; + return context.measureText(text).width; + } - /** - * 根據 代碼塊字串 解析出 CodeData 對象 - * @param codeBlockText 代碼塊字串 - * @returns CodeData 對象 - */ - public parseCodeData(codeBlockText: string): CodeData { + /** + * 計算 HTML 代碼塊的高度 + * @param codeText + */ + public getTextHeight(codeText: string) { - // 類名、方法名 的 標示符 - const classTag = '@class' - const functionTag = '@function' - const callTag = '@call' + // 創建一個新容器,將 HTML 代碼加入到容器中 + let node = document.createElement('div'); + node.innerHTML = '
' + hljs.highlight(codeText, {language: 'java'}).value + '
'; + document.body.appendChild(node); - let codeLines = codeBlockText.split('\n') + // 計算 容器高度 + let height: number = parseInt(global.getComputedStyle(node).height.split('px')[0]); - // 取得 註釋塊 的代碼 - let commentLines = [] - for (let i = 0; i < codeLines.length; i++) { - let codeLine = codeLines[i] + // 移除容器 + document.body.removeChild(node); - // 找到註釋開頭,則從當前行開始,加入到註釋塊列表中 - if (codeLine.indexOf('/**') != -1) { - commentLines.push(codeLine) - } - else if (commentLines.length > 0) { - commentLines.push(codeLine) - } + return height; + } - // 當碰到第一個多行註釋的結尾,則跳出循環 - if (codeLine.indexOf('*/') != -1) { - break - } - } + /** + * 根據 代碼塊字串 解析出 CodeData 對象 + * @param codeBlockText 代碼塊字串 + * @returns CodeData 對象 + */ + public parseCodeData(codeBlockText: string): CodeData { + + // 類名、方法名 的 標示符 + const classTag = '@class' + const functionTag = '@function' + const callTag = '@call' + + let codeLines = codeBlockText.split('\n') + + // 取得 註釋塊 的代碼 + let commentLines = [] + for (let i = 0; i < codeLines.length; i++) { + let codeLine = codeLines[i] + + // 找到註釋開頭,則從當前行開始,加入到註釋塊列表中 + if (codeLine.indexOf('/**') != -1) { + commentLines.push(codeLine) + } else if (commentLines.length > 0) { + commentLines.push(codeLine) + } + + // 當碰到第一個多行註釋的結尾,則跳出循環 + if (codeLine.indexOf('*/') != -1) { + break + } + } - // 從 註釋塊 中獲取 類名、方法名、調用的函數集合 - let className = '' - let functionName = '' - let calls: CodeDataFuncCall[] = [] + // 從 註釋塊 中獲取 類名、方法名、調用的函數集合 + let className = '' + let functionName = '' + let calls: CodeDataFuncCall[] = [] - commentLines.forEach((comment) => { + commentLines.forEach((comment) => { - // 獲取 類名 - if (comment.indexOf(classTag) != -1) { - className = comment.substring(comment.indexOf(classTag) + classTag.length).trim() - } + // 獲取 類名 + if (comment.indexOf(classTag) != -1) { + className = comment.substring(comment.indexOf(classTag) + classTag.length).trim() + } - // 獲取 方法名 - if (comment.indexOf(functionTag) != -1) { - functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim() - } + // 獲取 方法名 + if (comment.indexOf(functionTag) != -1) { + functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim() + } - // 獲取 調用的函數 - if (comment.indexOf(callTag) != -1) { - let callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim() - calls.push({ - className: callStr.substring(0, callStr.indexOf('@')).trim(), - functionName: callStr.substring(callStr.indexOf('@') + 1).trim() - }) - } + // 獲取 調用的函數 + if (comment.indexOf(callTag) != -1) { + let callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim() + calls.push({ + className: callStr.substring(0, callStr.indexOf('@')).trim(), + functionName: callStr.substring(callStr.indexOf('@') + 1).trim() + }) + } - }) + }) - // 封裝結果 - let result: CodeData = { - className: className, - funcs: [{ - name: functionName, - code: codeBlockText, - calls: calls - }] - } + // 封裝結果 + let result: CodeData = { + className: className, + funcs: [{ + name: functionName, + code: codeBlockText, + calls: calls + }] + } - return result - } + return result + } - /** - * 獲取 類聲明 的 圖形Id - * @param className 類名 - * @param functionName 方法名 - * @param type Id 的類型 - * @returns 圖形Id - */ - public getClassShapeId(className: string, functionName: string, type: 'class' | 'function'): string { - if (type == 'class') { - return CLASS_SHAPE_ID_TAG + className - } else if (type == 'function') { - return CLASS_SHAPE_ID_TAG + className + '-' + functionName - } - return '' - } + /** + * 獲取 類聲明 的 圖形Id + * @param className 類名 + * @param functionName 方法名 + * @param type Id 的類型 + * @returns 圖形Id + */ + public getClassShapeId(className: string, functionName: string, type: 'class' | 'function'): string { + if (type == 'class') { + return CLASS_SHAPE_ID_TAG + className + } else if (type == 'function') { + return CLASS_SHAPE_ID_TAG + className + '-' + functionName + } + return '' + } - /** - * 獲取 代碼塊 的 圖形Id - * @param className 類名 - * @param functionName 方法名 - * @returns 圖形Id - */ - public getCodeBlockShapeId(className: string, functionName: string): string { - return CODE_BLOCK_ID_TAG + className + '-' + functionName - } + /** + * 獲取 代碼塊 的 圖形Id + * @param className 類名 + * @param functionName 方法名 + * @returns 圖形Id + */ + public getCodeBlockShapeId(className: string, functionName: string): string { + return CODE_BLOCK_ID_TAG + className + '-' + functionName + } - /** - * 將擁有相同 ClassName 的 CodeDataFunc 合併到一起 - * @param codeDatas 要進行合併的 CodeData 集合 - * @returns 合併後的 CodeData 集合 - */ - public mergeCodeDatas(codeDatas: CodeData[]): CodeData[] { + /** + * 將擁有相同 ClassName 的 CodeDataFunc 合併到一起 + * @param codeDatas 要進行合併的 CodeData 集合 + * @returns 合併後的 CodeData 集合 + */ + public mergeCodeDatas(codeDatas: CodeData[]): CodeData[] { - // 對有相同 className 的 CodeData 的 func 進行合併 - let classNameToCodeData = new Map() - codeDatas.forEach((codeData: CodeData) => { + // 對有相同 className 的 CodeData 的 func 進行合併 + let classNameToCodeData = new Map() + codeDatas.forEach((codeData: CodeData) => { - // 如果在 Map 中已存在相應的 CodeData,則將 func 進行合併 - if (classNameToCodeData.has(codeData.className)) { - let tempCodeData = classNameToCodeData.get(codeData.className) as CodeData - tempCodeData.funcs.push(codeData.funcs[0]) - } - // 如果在 Map 中還沒有相應的 CodeData,則將當前 CodeData 加入到 Map 中 - else { - classNameToCodeData.set(codeData.className, codeData) - } - }) + // 如果在 Map 中已存在相應的 CodeData,則將 func 進行合併 + if (classNameToCodeData.has(codeData.className)) { + let tempCodeData = classNameToCodeData.get(codeData.className) as CodeData + tempCodeData.funcs.push(codeData.funcs[0]) + } + // 如果在 Map 中還沒有相應的 CodeData,則將當前 CodeData 加入到 Map 中 + else { + classNameToCodeData.set(codeData.className, codeData) + } + }) - // 封裝返回結果 - let result: CodeData[] = [] - for (let codeData of Array.from(classNameToCodeData.values())) { - result.push(codeData) - } + // 封裝返回結果 + let result: CodeData[] = [] + for (let codeData of Array.from(classNameToCodeData.values())) { + result.push(codeData) + } - return result - } + return result + } } -export { Utils, CodeData, CodeDataFunc } +export {Utils, CodeData, CodeDataFunc}