You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 01:45:04