mirror of
https://github.com/waiting0324/obsidian-code-note.git
synced 2026-07-22 07:30:24 +00:00
優化代碼塊高度
This commit is contained in:
parent
0cb31d67fa
commit
2675392b97
2 changed files with 199 additions and 177 deletions
|
|
@ -1,66 +1,66 @@
|
||||||
import hljs from 'highlight.js';
|
import hljs from 'highlight.js';
|
||||||
import { Utils, CodeData } from './Utils'
|
import {Utils, CodeData} from './Utils'
|
||||||
|
|
||||||
const myUtils = new Utils()
|
const myUtils = new Utils()
|
||||||
|
|
||||||
class CodeBlockShape {
|
class CodeBlockShape {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根據 CodeData 對象 獲取 AntV 的 HTML 對象集合
|
* 根據 CodeData 對象 獲取 AntV 的 HTML 對象集合
|
||||||
* @param codeData CodeData 對象
|
* @param codeData CodeData 對象
|
||||||
* @returns HTML 對象集合
|
* @returns HTML 對象集合
|
||||||
*/
|
*/
|
||||||
public createCodeBlockShape(codeData: CodeData) {
|
public createCodeBlockShape(codeData: CodeData) {
|
||||||
|
|
||||||
// 結果對象集合
|
// 結果對象集合
|
||||||
let result = []
|
let result = []
|
||||||
|
|
||||||
// 將 CodeData 中的每個 func 的 code 轉換成 AntV 的 HTML 對象
|
// 將 CodeData 中的每個 func 的 code 轉換成 AntV 的 HTML 對象
|
||||||
let codeDataFuncs = codeData.funcs
|
let codeDataFuncs = codeData.funcs
|
||||||
for (const codeDataFunc of codeDataFuncs) {
|
for (const codeDataFunc of codeDataFuncs) {
|
||||||
|
|
||||||
// 獲取 代碼塊字串,並分割成行
|
// 獲取 代碼塊字串,並分割成行
|
||||||
let codeText = codeDataFunc.code
|
let codeText = codeDataFunc.code
|
||||||
let codeTextLines = codeText.split('\n')
|
let codeTextLines = codeText.split('\n')
|
||||||
|
|
||||||
// 計算代碼塊所需高度
|
// 獲取 代碼塊所需高度
|
||||||
const blockHeight = codeTextLines.length * 15 + 40;
|
let blockHeight = myUtils.getTextHeight(codeDataFunc.code) + 20;
|
||||||
|
|
||||||
// 計算代碼塊所需寬度
|
// 計算代碼塊所需寬度
|
||||||
let blockWidth = 0
|
let blockWidth = 0
|
||||||
for (let i = 0; i < codeTextLines.length; i++) {
|
for (let i = 0; i < codeTextLines.length; i++) {
|
||||||
blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px ui-sans-serif") + 60)
|
blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px") + 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 構建 HTML 對象
|
// 構建 HTML 對象
|
||||||
const htmlShape = {
|
const htmlShape = {
|
||||||
id: myUtils.getCodeBlockShapeId(codeData.className, codeDataFunc.name),
|
id: myUtils.getCodeBlockShapeId(codeData.className, codeDataFunc.name),
|
||||||
x: 800,
|
x: 800,
|
||||||
y: 100,
|
y: 100,
|
||||||
width: blockWidth,
|
width: blockWidth,
|
||||||
height: blockHeight,
|
height: blockHeight,
|
||||||
shape: 'html',
|
shape: 'html',
|
||||||
attrs: {
|
attrs: {
|
||||||
body: {
|
body: {
|
||||||
fill: 'white',
|
fill: 'white',
|
||||||
stroke: '#666',
|
stroke: '#666',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
html() {
|
html() {
|
||||||
const wrap = document.createElement('div')
|
const wrap = document.createElement('div')
|
||||||
wrap.innerHTML = '<pre style="padding-left: 20px">' + hljs.highlight(codeText, { language: 'java' }).value + '</pre>'
|
wrap.innerHTML = '<pre style="padding-left: 20px">' + hljs.highlight(codeText, {language: 'java'}).value + '</pre>'
|
||||||
return wrap
|
return wrap
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 將 HTML 對象加入到返回結果中
|
// 將 HTML 對象加入到返回結果中
|
||||||
result.push(htmlShape)
|
result.push(htmlShape)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export { CodeBlockShape }
|
export {CodeBlockShape}
|
||||||
|
|
|
||||||
280
src/Utils.ts
280
src/Utils.ts
|
|
@ -1,167 +1,189 @@
|
||||||
|
import hljs from "highlight.js";
|
||||||
|
|
||||||
type CodeData = {
|
type CodeData = {
|
||||||
className: string, // 類名稱
|
className: string, // 類名稱
|
||||||
funcs: CodeDataFunc[] // 函數名稱 與 代碼塊字串 集合
|
funcs: CodeDataFunc[] // 函數名稱 與 代碼塊字串 集合
|
||||||
}
|
}
|
||||||
|
|
||||||
type CodeDataFunc = {
|
type CodeDataFunc = {
|
||||||
name: string, // 函數名稱
|
name: string, // 函數名稱
|
||||||
code: string // 代碼塊字串
|
code: string // 代碼塊字串
|
||||||
calls: CodeDataFuncCall[] // 調用的函數集合
|
calls: CodeDataFuncCall[] // 調用的函數集合
|
||||||
}
|
}
|
||||||
|
|
||||||
type CodeDataFuncCall = {
|
type CodeDataFuncCall = {
|
||||||
className: string, // 類名稱
|
className: string, // 類名稱
|
||||||
functionName: string // 函數名稱
|
functionName: string // 函數名稱
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CLASS_SHAPE_ID_TAG: string = "class-";
|
export const CLASS_SHAPE_ID_TAG: string = "class-";
|
||||||
export const CODE_BLOCK_ID_TAG: string = 'code-block-';
|
export const CODE_BLOCK_ID_TAG: string = 'code-block-';
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 計算字串寬度
|
* 計算字串寬度
|
||||||
*/
|
*/
|
||||||
tCanvas: any = null;
|
tCanvas: any = null;
|
||||||
public getTextWidth(text: string, font: string = '13px ui-sans-serif') {
|
public getTextWidth(text: string, font: string) {
|
||||||
// re-use canvas object for better performance
|
// re-use canvas object for better performance
|
||||||
const canvas = this.tCanvas || (this.tCanvas = document.createElement('canvas'));
|
const canvas = this.tCanvas || (this.tCanvas = document.createElement('canvas'));
|
||||||
const context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
context.font = font;
|
context.font = font + ' ui-sans-serif';
|
||||||
return context.measureText(text).width;
|
return context.measureText(text).width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根據 代碼塊字串 解析出 CodeData 對象
|
* 計算 HTML 代碼塊的高度
|
||||||
* @param codeBlockText 代碼塊字串
|
* @param codeText
|
||||||
* @returns CodeData 對象
|
*/
|
||||||
*/
|
public getTextHeight(codeText: string) {
|
||||||
public parseCodeData(codeBlockText: string): CodeData {
|
|
||||||
|
|
||||||
// 類名、方法名 的 標示符
|
// 創建一個新容器,將 HTML 代碼加入到容器中
|
||||||
const classTag = '@class'
|
let node = document.createElement('div');
|
||||||
const functionTag = '@function'
|
node.innerHTML = '<pre style="padding-left: 20px">' + hljs.highlight(codeText, {language: 'java'}).value + '</pre>';
|
||||||
const callTag = '@call'
|
document.body.appendChild(node);
|
||||||
|
|
||||||
let codeLines = codeBlockText.split('\n')
|
// 計算 容器高度
|
||||||
|
let height: number = parseInt(global.getComputedStyle(node).height.split('px')[0]);
|
||||||
|
|
||||||
// 取得 註釋塊 的代碼
|
// 移除容器
|
||||||
let commentLines = []
|
document.body.removeChild(node);
|
||||||
for (let i = 0; i < codeLines.length; i++) {
|
|
||||||
let codeLine = codeLines[i]
|
|
||||||
|
|
||||||
// 找到註釋開頭,則從當前行開始,加入到註釋塊列表中
|
return height;
|
||||||
if (codeLine.indexOf('/**') != -1) {
|
}
|
||||||
commentLines.push(codeLine)
|
|
||||||
}
|
|
||||||
else if (commentLines.length > 0) {
|
|
||||||
commentLines.push(codeLine)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 當碰到第一個多行註釋的結尾,則跳出循環
|
/**
|
||||||
if (codeLine.indexOf('*/') != -1) {
|
* 根據 代碼塊字串 解析出 CodeData 對象
|
||||||
break
|
* @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 className = ''
|
||||||
let functionName = ''
|
let functionName = ''
|
||||||
let calls: CodeDataFuncCall[] = []
|
let calls: CodeDataFuncCall[] = []
|
||||||
|
|
||||||
commentLines.forEach((comment) => {
|
commentLines.forEach((comment) => {
|
||||||
|
|
||||||
// 獲取 類名
|
// 獲取 類名
|
||||||
if (comment.indexOf(classTag) != -1) {
|
if (comment.indexOf(classTag) != -1) {
|
||||||
className = comment.substring(comment.indexOf(classTag) + classTag.length).trim()
|
className = comment.substring(comment.indexOf(classTag) + classTag.length).trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 獲取 方法名
|
// 獲取 方法名
|
||||||
if (comment.indexOf(functionTag) != -1) {
|
if (comment.indexOf(functionTag) != -1) {
|
||||||
functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim()
|
functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 獲取 調用的函數
|
// 獲取 調用的函數
|
||||||
if (comment.indexOf(callTag) != -1) {
|
if (comment.indexOf(callTag) != -1) {
|
||||||
let callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim()
|
let callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim()
|
||||||
calls.push({
|
calls.push({
|
||||||
className: callStr.substring(0, callStr.indexOf('@')).trim(),
|
className: callStr.substring(0, callStr.indexOf('@')).trim(),
|
||||||
functionName: callStr.substring(callStr.indexOf('@') + 1).trim()
|
functionName: callStr.substring(callStr.indexOf('@') + 1).trim()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 封裝結果
|
// 封裝結果
|
||||||
let result: CodeData = {
|
let result: CodeData = {
|
||||||
className: className,
|
className: className,
|
||||||
funcs: [{
|
funcs: [{
|
||||||
name: functionName,
|
name: functionName,
|
||||||
code: codeBlockText,
|
code: codeBlockText,
|
||||||
calls: calls
|
calls: calls
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 獲取 類聲明 的 圖形Id
|
* 獲取 類聲明 的 圖形Id
|
||||||
* @param className 類名
|
* @param className 類名
|
||||||
* @param functionName 方法名
|
* @param functionName 方法名
|
||||||
* @param type Id 的類型
|
* @param type Id 的類型
|
||||||
* @returns 圖形Id
|
* @returns 圖形Id
|
||||||
*/
|
*/
|
||||||
public getClassShapeId(className: string, functionName: string, type: 'class' | 'function'): string {
|
public getClassShapeId(className: string, functionName: string, type: 'class' | 'function'): string {
|
||||||
if (type == 'class') {
|
if (type == 'class') {
|
||||||
return CLASS_SHAPE_ID_TAG + className
|
return CLASS_SHAPE_ID_TAG + className
|
||||||
} else if (type == 'function') {
|
} else if (type == 'function') {
|
||||||
return CLASS_SHAPE_ID_TAG + className + '-' + functionName
|
return CLASS_SHAPE_ID_TAG + className + '-' + functionName
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 獲取 代碼塊 的 圖形Id
|
* 獲取 代碼塊 的 圖形Id
|
||||||
* @param className 類名
|
* @param className 類名
|
||||||
* @param functionName 方法名
|
* @param functionName 方法名
|
||||||
* @returns 圖形Id
|
* @returns 圖形Id
|
||||||
*/
|
*/
|
||||||
public getCodeBlockShapeId(className: string, functionName: string): string {
|
public getCodeBlockShapeId(className: string, functionName: string): string {
|
||||||
return CODE_BLOCK_ID_TAG + className + '-' + functionName
|
return CODE_BLOCK_ID_TAG + className + '-' + functionName
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 將擁有相同 ClassName 的 CodeDataFunc 合併到一起
|
* 將擁有相同 ClassName 的 CodeDataFunc 合併到一起
|
||||||
* @param codeDatas 要進行合併的 CodeData 集合
|
* @param codeDatas 要進行合併的 CodeData 集合
|
||||||
* @returns 合併後的 CodeData 集合
|
* @returns 合併後的 CodeData 集合
|
||||||
*/
|
*/
|
||||||
public mergeCodeDatas(codeDatas: CodeData[]): CodeData[] {
|
public mergeCodeDatas(codeDatas: CodeData[]): CodeData[] {
|
||||||
|
|
||||||
// 對有相同 className 的 CodeData 的 func 進行合併
|
// 對有相同 className 的 CodeData 的 func 進行合併
|
||||||
let classNameToCodeData = new Map()
|
let classNameToCodeData = new Map()
|
||||||
codeDatas.forEach((codeData: CodeData) => {
|
codeDatas.forEach((codeData: CodeData) => {
|
||||||
|
|
||||||
// 如果在 Map 中已存在相應的 CodeData,則將 func 進行合併
|
// 如果在 Map 中已存在相應的 CodeData,則將 func 進行合併
|
||||||
if (classNameToCodeData.has(codeData.className)) {
|
if (classNameToCodeData.has(codeData.className)) {
|
||||||
let tempCodeData = classNameToCodeData.get(codeData.className) as CodeData
|
let tempCodeData = classNameToCodeData.get(codeData.className) as CodeData
|
||||||
tempCodeData.funcs.push(codeData.funcs[0])
|
tempCodeData.funcs.push(codeData.funcs[0])
|
||||||
}
|
}
|
||||||
// 如果在 Map 中還沒有相應的 CodeData,則將當前 CodeData 加入到 Map 中
|
// 如果在 Map 中還沒有相應的 CodeData,則將當前 CodeData 加入到 Map 中
|
||||||
else {
|
else {
|
||||||
classNameToCodeData.set(codeData.className, codeData)
|
classNameToCodeData.set(codeData.className, codeData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 封裝返回結果
|
// 封裝返回結果
|
||||||
let result: CodeData[] = []
|
let result: CodeData[] = []
|
||||||
for (let codeData of Array.from(classNameToCodeData.values())) {
|
for (let codeData of Array.from(classNameToCodeData.values())) {
|
||||||
result.push(codeData)
|
result.push(codeData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export { Utils, CodeData, CodeDataFunc }
|
export {Utils, CodeData, CodeDataFunc}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue