JointJS Petri网库所token不渲染,缺少TOKENS标识如何解决?
解决方法
方案1:扩展原生pn.Place类,内置TOKENS标识和渲染逻辑
JointJS内置的pn.Place默认未启用token渲染的标识位,你可以自定义扩展类补充该能力:
// 定义TOKENS标识位,取128与官方内置标识位不冲突 const TOKENS = 128; // 扩展原生Place类 class CustomPlace extends joint.shapes.pn.Place { // 将TOKENS加入标识集合 static flags = { ...joint.shapes.pn.Place.flags, TOKENS }; defaults() { return { ...super.defaults, type: 'pn.Place', tokens: 0 }; } // 重写更新方法,监听token属性变更 update(cell: any, opts: any) { super.update(cell, opts); if (opts.propertyPath === 'tokens' || (opts.changes && opts.changes.tokens)) { this.renderTokens(); } return this; } // 实现token渲染逻辑 private renderTokens() { const tokenCount = this.model.get('tokens'); const tokensGroup = this.el.querySelector('.tokens'); if (!tokensGroup) return; // 清空原有内容 tokensGroup.innerHTML = ''; // 添加官方预定义的数量类名 tokensGroup.className = `tokens ${tokenCount > 3 ? 'alot' : ['zero', 'one', 'two', 'three'][tokenCount]}`; // 数量≤3时渲染圆点,>3时显示数字 if (tokenCount <= 3) { const xPositions = tokenCount === 1 ? [25] : tokenCount === 2 ? [19, 31] : [16, 25, 34]; xPositions.forEach(x => { const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('r', '5'); circle.setAttribute('fill', '#7a7e9b'); circle.setAttribute('transform', `translate(${x}, 25)`); tokensGroup.appendChild(circle); }); } else { const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', '25'); text.setAttribute('y', '30'); text.setAttribute('text-anchor', 'middle'); text.setAttribute('fill', '#fe854c'); text.setAttribute('font-size', '20'); text.textContent = tokenCount.toString(); tokensGroup.appendChild(text); } } }
使用时将你代码中new PetriView.pn.Place替换为new CustomPlace,原有配置参数无需修改。
方案2:全局监听属性变更,手动触发渲染
如果不想修改原有的Place实例化逻辑,可以直接给graph添加属性监听:
// 初始化graph后添加该监听逻辑 PetriView.graph.on('change:tokens', (placeModel) => { if (placeModel.get('type') !== 'pn.Place') return; const placeView = PetriView.paper.findViewByModel(placeModel); const tokenCount = placeModel.get('tokens'); const tokensGroup = placeView.el.querySelector('.tokens'); if (!tokensGroup) return; // 此处复用方案1中的renderTokens核心逻辑即可 tokensGroup.innerHTML = ''; tokensGroup.className = `tokens ${tokenCount > 3 ? 'alot' : ['zero', 'one', 'two', 'three'][tokenCount]}`; // 剩余渲染逻辑和方案1完全一致 });
额外排查点
如果上述方案仍未生效,先确认你引入的是JointJS完整版,部分精简构建版本会砍掉Petri网的默认token渲染相关逻辑,替换为完整版依赖即可。如果遇到TypeScript类型报错,添加如下类型声明即可:
declare module 'jointjs' { namespace shapes.pn { interface Place { flags: { TOKENS: number }; } } }
内容的提问来源于stack exchange,提问作者SlimJim
相关产品推荐
相关产品推荐

