feat: md-pins allow numbers
This commit is contained in:
@@ -10,10 +10,31 @@ interface PinsState {
|
||||
pins: Pin[];
|
||||
rawSrc: string;
|
||||
isFixed: boolean;
|
||||
labelStart: string;
|
||||
}
|
||||
|
||||
// 生成标签 A-Z, AA-ZZ, AAA-ZZZ ...
|
||||
export function generateLabel(index: number): string {
|
||||
// 判断 labelStart 是否为数字
|
||||
function isNumericLabelStart(start: string): boolean {
|
||||
return /^\d+$/.test(start);
|
||||
}
|
||||
|
||||
// 生成字母标签 A-Z, AA-ZZ, AAA-ZZZ ... 从指定起始值开始
|
||||
export function generateAlphaLabel(index: number, startLabel: string = 'A'): string {
|
||||
const startOffset = alphaLabelToIndex(startLabel);
|
||||
return indexToAlphaLabel(index + startOffset);
|
||||
}
|
||||
|
||||
// 将字母标签转换为索引 (A=0, B=1, ..., Z=25, AA=26, ...)
|
||||
export function alphaLabelToIndex(label: string): number {
|
||||
let index = 0;
|
||||
for (let i = 0; i < label.length; i++) {
|
||||
index = index * 26 + (label.charCodeAt(i) - 64);
|
||||
}
|
||||
return index - 1;
|
||||
}
|
||||
|
||||
// 将索引转换为字母标签 (0=A, 1=B, ..., 25=Z, 26=AA, ...)
|
||||
export function indexToAlphaLabel(index: number): string {
|
||||
const labels: string[] = [];
|
||||
let num = index;
|
||||
|
||||
@@ -26,12 +47,18 @@ export function generateLabel(index: number): string {
|
||||
return labels.join('');
|
||||
}
|
||||
|
||||
// 解析 pins 字符串 "A:30,40 B:10,30" -> Pin[]
|
||||
// 生成数字标签,从指定起始值开始
|
||||
export function generateNumberLabel(index: number, startNum: number): string {
|
||||
return String(startNum + index);
|
||||
}
|
||||
|
||||
// 解析 pins 字符串 "A:30,40 B:10,30" 或 "1:30,40 2:10,30" -> Pin[]
|
||||
export function parsePins(pinsStr: string): Pin[] {
|
||||
if (!pinsStr) return [];
|
||||
|
||||
const pins: Pin[] = [];
|
||||
const regex = /([A-Z]+):(\d+),(\d+)/g;
|
||||
// 支持任意非空白字符作为标签(不仅限于大写字母)
|
||||
const regex = /([^:\s]+):(\d+),(\d+)/g;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(pinsStr)) !== null) {
|
||||
@@ -51,28 +78,52 @@ export function formatPins(pins: Pin[]): string {
|
||||
}
|
||||
|
||||
// 找到最早未使用的标签
|
||||
export function findNextUnusedLabel(pins: Pin[]): string {
|
||||
export function findNextUnusedLabel(pins: Pin[], labelStart: string): string {
|
||||
const usedLabels = new Set(pins.map(p => p.label));
|
||||
|
||||
let index = 0;
|
||||
while (true) {
|
||||
const label = generateLabel(index);
|
||||
if (!usedLabels.has(label)) {
|
||||
return label;
|
||||
if (isNumericLabelStart(labelStart)) {
|
||||
// 数字标签模式
|
||||
const startNum = parseInt(labelStart);
|
||||
let index = 0;
|
||||
while (true) {
|
||||
const label = generateNumberLabel(index, startNum);
|
||||
if (!usedLabels.has(label)) {
|
||||
return label;
|
||||
}
|
||||
index++;
|
||||
if (index > 10000) break; // 安全限制
|
||||
}
|
||||
} else {
|
||||
// 字母标签模式
|
||||
let index = 0;
|
||||
while (true) {
|
||||
const label = generateAlphaLabel(index, labelStart);
|
||||
if (!usedLabels.has(label)) {
|
||||
return label;
|
||||
}
|
||||
index++;
|
||||
if (index > 10000) break; // 安全限制
|
||||
}
|
||||
index++;
|
||||
if (index > 10000) break; // 安全限制
|
||||
}
|
||||
|
||||
return generateLabel(pins.length);
|
||||
// 回退值
|
||||
if (isNumericLabelStart(labelStart)) {
|
||||
return generateNumberLabel(pins.length, parseInt(labelStart));
|
||||
}
|
||||
return generateAlphaLabel(pins.length, labelStart);
|
||||
}
|
||||
|
||||
// 创建 store 实例
|
||||
export function createPinsStore(initialPinsStr: string = "", initialFixed: boolean = false) {
|
||||
export function createPinsStore(
|
||||
initialPinsStr: string = "",
|
||||
initialFixed: boolean = false,
|
||||
initialLabelStart: string = "A"
|
||||
) {
|
||||
const [state, setState] = createStore<PinsState>({
|
||||
pins: parsePins(initialPinsStr),
|
||||
rawSrc: "",
|
||||
isFixed: initialFixed
|
||||
isFixed: initialFixed,
|
||||
labelStart: initialLabelStart
|
||||
});
|
||||
|
||||
const setRawSrc = (src: string) => {
|
||||
@@ -80,7 +131,7 @@ export function createPinsStore(initialPinsStr: string = "", initialFixed: boole
|
||||
};
|
||||
|
||||
const addPin = (x: number, y: number) => {
|
||||
const label = findNextUnusedLabel(state.pins);
|
||||
const label = findNextUnusedLabel(state.pins, state.labelStart);
|
||||
setState("pins", [...state.pins, { x, y, label }]);
|
||||
};
|
||||
|
||||
@@ -92,7 +143,8 @@ export function createPinsStore(initialPinsStr: string = "", initialFixed: boole
|
||||
|
||||
const getCopyText = () => {
|
||||
const pinsStr = formatCurrentPins();
|
||||
return `:md-pins[${state.rawSrc}]{pins="${pinsStr}" fixed}`;
|
||||
const labelStartAttr = state.labelStart !== 'A' ? ` labelStart="${state.labelStart}"` : '';
|
||||
return `:md-pins[${state.rawSrc}]{pins="${pinsStr}" fixed${labelStartAttr}`;
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user