JointJS: Dynamic shape namespace

by Roman Bruckner

HTML

<html>
  <head>
    <link
      rel="stylesheet"
      type="text/css"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
    />
  </head>

  <body>
    <!-- content -->
    <div id="paper1" class="paper-container"></div>
    <div id="paper2" class="paper-container"></div>
    <!-- dependencies -->
    <script src="https://cdn.jsdelivr.net/npm/@joint/[email protected]/dist/joint.min.js"></script>
  </body>
</html>

CSS

.paper-container {
  border: 1px solid black;
  margin: 10px;
}

JavaScript

const { util, shapes, dia } = joint

const MyRectangle = shapes.standard.Rectangle.define("MyRectangle", {
  attrs: {
    body: {
      fill: "lightblue",
      stroke: "blue",
      strokeWidth: 2,
    },
    label: {
      fill: "black",
    },
  },
})

const shapeNamespace1 = { standard: { ...shapes.standard }, MyRectangle }
const graph1 = new dia.Graph({}, { cellNamespace: shapeNamespace1 })
const paper1 = new dia.Paper({
  el: document.getElementById("paper1"),
  width: 400,
  height: 400,
  model: graph1,
  cellViewNamespace: shapeNamespace1,
})

const shapeNamespace2 = { standard: { ...shapes.standard } }
const graph2 = new dia.Graph({}, { cellNamespace: shapeNamespace2 })
const paper2 = new dia.Paper({
  el: document.getElementById("paper2"),
  width: 400,
  height: 400,
  model: graph2,
  cellViewNamespace: shapeNamespace2,
})

const graphJSON = {
  cells: [
    {
      type: "MyRectangle",
      baseType: "standard.Rectangle",
      position: {
        x: 120,
        y: 20,
      },
      size: {
        width: 90,
        height: 54,
      },
      id: "9a38ced0-13b5-4842-b69a-0b0b1a3f4f7d",
      z: 1,
    },
    {
      type: "MyRectangle",
      baseType: "standard.Rectangle",
      position: {
        x: 170,
        y: 180,
      },
      size: {
        width: 90,
        height: 54,
      },
      id: "833fbae0-c5c3-4f5d-83ba-5f8eb2fec056",
      z: 2,
    },
    {
      type: "MyLink",
      baseType: "standard.Link",
      source: {
        id: "9a38ced0-13b5-4842-b69a-0b0b1a3f4f7d",
      },
      target: {
        id: "833fbae0-c5c3-4f5d-83ba-5f8eb2fec056",
      },
      id: "b4e9bd9f-af42-49b4-9ea3-0a53fdb33ad8",
      z: 3,
    },
  ],
}

function verifyShapeDefinition(shapeJSON, shapeNamespace) {
  const { type, baseType } = shapeJSON
  const ShapeConstructor = util.getByPath(shapeNamespace, type, ".")
  if (ShapeConstructor) return
  const BaseShapeConstructor = util.getByPath(shapeNamespace, baseType, ".")
  if (!BaseShapeConstructor)...