输出改紫、循环改青,绿和红留给起止框、选中和标错。存下来的 Mermaid 里循环也标成 decision,画之前按「有箭头从后面绕回来」认出循环,历史提交的图也按新颜色画。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
179d5fa67d
commit
0916015405
2 files changed
+37
-12
No files matched your search
@@ -2,22 +2,28 @@ import { PLACEHOLDER, type LaidNode } from './layout'
|
||||
|
||||
/**
|
||||
* 框的颜色和形状:画流程图的画布(index.vue)和只看的图(FlowchartView.vue)共用一份,
|
||||
* 两边才长得一样
|
||||
* 两边才长得一样。题面里的 Mermaid 图在 useMermaid.ts 另有一份,改颜色两边一起改。
|
||||
*
|
||||
* 输入 / 输出 / 处理 / 判断 / 循环各一种颜色;绿和红不给框用 —— 绿是起止框和选中,红是标错
|
||||
*/
|
||||
|
||||
type Paint = { fill: string; stroke: string; text: string }
|
||||
|
||||
const LIGHT: Record<string, Paint> = {
|
||||
terminal: { fill: '#eef8f2', stroke: '#18a058', text: '#0c6b3b' },
|
||||
io: { fill: '#eef4fd', stroke: '#2f6bc4', text: '#1d4f9c' },
|
||||
input: { fill: '#eef4fd', stroke: '#2f6bc4', text: '#1d4f9c' },
|
||||
output: { fill: '#f4effc', stroke: '#8a55c9', text: '#5d2f99' },
|
||||
process: { fill: '#ffffff', stroke: '#7d828a', text: '#1f2225' },
|
||||
decision: { fill: '#fdf5e6', stroke: '#d08a1c', text: '#8a5200' },
|
||||
if: { fill: '#fdf5e6', stroke: '#d08a1c', text: '#8a5200' },
|
||||
while: { fill: '#e8f6f8', stroke: '#1590a6', text: '#0b5e6e' },
|
||||
}
|
||||
const DARK: Record<string, Paint> = {
|
||||
terminal: { fill: 'rgba(24,160,88,0.16)', stroke: '#3fbf7f', text: '#8fe0b4' },
|
||||
io: { fill: 'rgba(70,130,220,0.18)', stroke: '#5b8fdc', text: '#a9c6f2' },
|
||||
input: { fill: 'rgba(70,130,220,0.18)', stroke: '#5b8fdc', text: '#a9c6f2' },
|
||||
output: { fill: 'rgba(150,100,215,0.2)', stroke: '#a57ee0', text: '#d2bcf4' },
|
||||
process: { fill: '#26272b', stroke: '#8a8f98', text: '#e6e7ea' },
|
||||
decision: { fill: 'rgba(208,138,28,0.18)', stroke: '#e0a040', text: '#f2cd8c' },
|
||||
if: { fill: 'rgba(208,138,28,0.18)', stroke: '#e0a040', text: '#f2cd8c' },
|
||||
while: { fill: 'rgba(30,160,185,0.18)', stroke: '#3cb4c8', text: '#9edce6' },
|
||||
}
|
||||
|
||||
export function useFlowPaint() {
|
||||
@@ -25,9 +31,7 @@ export function useFlowPaint() {
|
||||
function paint(kind: LaidNode['kind']) {
|
||||
const paints = isDark.value ? DARK : LIGHT
|
||||
if (kind === 'start' || kind === 'end') return paints.terminal!
|
||||
if (kind === 'input' || kind === 'output') return paints.io!
|
||||
if (kind === 'if' || kind === 'while') return paints.decision!
|
||||
return paints.process!
|
||||
return paints[kind] ?? paints.process!
|
||||
}
|
||||
const lineColor = computed(() => (isDark.value ? '#8a8f98' : '#7d828a'))
|
||||
return { isDark, paint, lineColor }
|
||||
|
||||
@@ -10,16 +10,16 @@ const semanticNodeClasses = ['startNode', 'endNode', 'startEnd', 'input', 'outpu
|
||||
|
||||
const displayStyleId = 'oj-mermaid-display-style'
|
||||
|
||||
/** 框的颜色:[class, 底色, 边框]。pele 把 `class n0 startNode` 原样挂在节点的 <g> 上 */
|
||||
/** 框的颜色:[class, 底色, 边框],和画布的 FlowchartEditor/paint.ts 一致。pele 把 `class n0 startNode` 原样挂在节点的 <g> 上 */
|
||||
const nodeColors: [string, string, string][] = [
|
||||
['startNode', '#eef8f2', '#18a058'],
|
||||
['startEnd', '#eef8f2', '#18a058'],
|
||||
['endNode', '#eef8f2', '#18a058'],
|
||||
['input', '#eef4fd', '#2f6bc4'],
|
||||
['output', '#eef4fd', '#2f6bc4'],
|
||||
['output', '#f4effc', '#8a55c9'],
|
||||
['process', '#ffffff', '#7d828a'],
|
||||
['decision', '#fdf5e6', '#d08a1c'],
|
||||
['loop', '#fdf5e6', '#d08a1c'],
|
||||
['loop', '#e8f6f8', '#1590a6'],
|
||||
['oj-node-palette-0', '#dbeafe', '#2563eb'],
|
||||
['oj-node-palette-1', '#ccfbf1', '#0d9488'],
|
||||
['oj-node-palette-2', '#ede9fe', '#7c3aed'],
|
||||
@@ -74,6 +74,27 @@ ${nodeColors
|
||||
|
||||
const svgNamespace = 'http://www.w3.org/2000/svg'
|
||||
|
||||
/**
|
||||
* 契约的 flowToMermaid 把判断和循环都标成 decision(库里存的提交、参考图都是这样),
|
||||
* 两者要分颜色,只能在画之前认出循环:有箭头从后面的框绕回来的 decision 就是循环
|
||||
*/
|
||||
function markLoops(code: string) {
|
||||
const order = new Map<string, number>()
|
||||
const backTargets = new Set<string>()
|
||||
for (const line of code.split('\n')) {
|
||||
const head = /^\s*(\w+)/.exec(line)?.[1]
|
||||
if (head && head !== 'flowchart' && head !== 'graph' && head !== 'class' && !order.has(head)) order.set(head, order.size)
|
||||
const edge = /^\s*(\w+)\b.*?-->(?:\|[^|]*\|)?\s*(\w+)/.exec(line)
|
||||
if (!edge) continue
|
||||
const [, from, to] = edge
|
||||
if (!order.has(to!)) order.set(to!, order.size)
|
||||
if (order.get(from!)! > order.get(to!)!) backTargets.add(to!)
|
||||
}
|
||||
return code.replace(/^(\s*class\s+)(\w+)(\s+)decision\s*$/gm, (line, pre: string, id: string, gap: string) =>
|
||||
backTargets.has(id) ? `${pre}${id}${gap}loop` : line,
|
||||
)
|
||||
}
|
||||
|
||||
function applyFlowchartDisplayStyle(container: HTMLElement) {
|
||||
container.classList.add('oj-mermaid-surface')
|
||||
|
||||
@@ -124,7 +145,7 @@ export function useMermaid() {
|
||||
try {
|
||||
// pele/lazy 按图的类型现拉对应的模块,题目里绝大多数是流程图,只拉那一块
|
||||
const { renderAsync } = await import('pele/lazy')
|
||||
const { svg } = await renderAsync(mermaidCode, {
|
||||
const { svg } = await renderAsync(markLoops(mermaidCode), {
|
||||
// 量字宽用页面真实的字体,否则框会比字窄或宽
|
||||
fontFamily: getComputedStyle(container).fontFamily,
|
||||
// 题目是老师写的、提交是学生写的,图里的链接和外链图片一律不画
|
||||
|
||||
Reference in new issue
Block a user