Skip to content

Commit

Permalink
update text
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesgeorgewilliams committed Aug 18, 2023
1 parent 5fd7c18 commit 85b2fc5
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 78 deletions.
170 changes: 96 additions & 74 deletions tutorials/cell-namespace.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,65 @@ <h1>Cell Namespace</h1>
</p>

<p>
How do we tell JointJS which namespace to use? There are 2 important options to be aware of when creating your diagrams. The
first is the <code>graph</code> option <a href="/docs/jointjs#dia.Graph.constructor" target="_blank"><code>cellNamespace</code></a>,
and the second is the <code>paper</code> option
<a href="/docs/jointjs#dia.Paper.prototype.options.cellViewNamespace" target="_blank"><code>cellViewNamespace</code></a>. In the
following example, for a cell of type <code>'standard.Rectangle'</code>, the <code>graph</code> looks up the
Let's begin by creating a simple, custom <code>Rectangle</code> definition which extends <code>joint.dia.Element</code>.
</p>

<pre><code>class Rectangle extends joint.dia.Element {
defaults() {
return {
...super.defaults,
type: 'Rectangle',
position: { x: 10, y: 10 },
attrs: {
body: {
width: 100,
height: 70
}
}
};
}

preinitialize() {
this.markup = joint.util.svg/* xml */ `
&lt;rect @selector="body" /&gt;
`;
}
}
</code></pre>

<p>
We will also declare a variable which will contain our shapes, and act as our cell namespace.
</p>

<pre><code>// Built-in JointJS shapes and our custom Rectangle are added
const namespace = { ...joint.shapes, Rectangle };
</code></pre>

<p>
If you want a little more organization and nesting in your cell namespace, you can define a <code>type</code> using dot notation,
and structure your shape definitions how you would like.
</p>

<pre><code>class Rectangle extends joint.dia.Element {
defaults() {
return {
...
type: 'custom.Rectangle',
...
};
}
...
}

const namespace = { ...joint.shapes, custom: { Rectangle }};
</code></pre>

<p>
Now that we have created a cell namespace, how do we tell JointJS which namespace to use? There are 2 important options to be aware
of when creating your diagrams. The first is the <code>graph</code> option
<a href="/docs/jointjs#dia.Graph.constructor" target="_blank"><code>cellNamespace</code></a>, and the second is the <code>paper</code>
option <a href="/docs/jointjs#dia.Paper.prototype.options.cellViewNamespace" target="_blank"><code>cellViewNamespace</code></a>. In
the following example, for a cell of type <code>'standard.Rectangle'</code>, the <code>graph</code> looks up the
<code>'joint.shapes.standard.Rectangle'</code> path to find the correct constructor. If you don't plan on creating custom shapes,
or playing around with namespaces, the following setup should be fine for your application.
</p>
Expand All @@ -64,62 +118,6 @@ <h1>Cell Namespace</h1>
});
</code></pre>

<p>
On the other hand, if you are feeling a little adventurous, and would like to create your own namespace, the next example may
interest you. Supposing you wanted to create a custom namespace which contains just 2 built-in JointJS shapes. How would you go about
this? Using destructuring, we could retrieve the shapes we want from the <code>joint.shapes.standard</code> namespace, and then add
the shapes to our <code>customNamespace</code> object.
</p>

<p>
While our custom namespace is just an object that contains our <code>Link</code> and <code>Rectangle</code> constructors,
the <code>type</code> property of each cell will still state the location as within the <code>standard</code> namespace upon making
an instance. In order to set up namespaces correctly, this is something we will have to address.
</p>

<p>
With the aim of updating the <code>type</code>, we take advantage of the
<a href="/docs/jointjs#dia.Element.prototype.prop" target="_blank""><code>prop()</code></a> method, so JointJS no longer looks for
the constructor within a namespace <code>standard</code>, but at the top level of our <code>customNamespace</code>. After the
addition of our <code>rect</code> element, if we were to overwrite the <code>graph</code> via <code>graph.toJSON()</code> passing it
the value returned from <code>graph.toJSON()</code>, no error would occur. We can take this as confirmation that our namespaces are
now set up correctly.
</p>

<pre><code>const { Rectangle, Link } = joint.shapes.standard;

const customNamespace = { Rectangle, Link };

const graph = new joint.dia.Graph({}, { cellNamespace: customNamespace });

const paper = new joint.dia.Paper({
...
cellViewNamespace: customNamespace
...
});

// Including `type: 'Rectangle'` when creating an instance would accomplish the same as using prop()
const rect = new Rectangle({
size: { width: 80, height: 50 },
position: { x: 10, y: 10 }
});

console.log(rect.prop('type')); // standard.Rectangle
rect.prop('type', 'Rectangle');
console.log(rect.prop('type')); // Rectangle

rect.addTo(graph);

// No error occurs as `type` is now `Rectangle`
graph.fromJSON(graph.toJSON());
</code></pre>

<p>
If we were to continue using <code>'standard.Rectangle'</code> as our <code>type</code> above, this would result in a common JointJS
error. If you see the dreaded <code>Uncaught Error: dia.ElementView: markup required</code> appearing in your console, it's likely
your namespace is not set up correctly, and JointJS cannot find the correct shape.
</p>

<h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">A More Detailed Look</h2>

<p>
Expand All @@ -138,15 +136,10 @@ <h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">A Mo
</p>

<p>
Afterwards, taking advantage of
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign" target="_blank"><code>Object.assign()</code></a>,
the properties of <code>customNamespace</code> are copied to our <code>namespace</code> object. As a result,
<code>standard</code> and <code>custom</code> are both defined at the same level in our <code>namespace</code> object.
</p>

<p>
Lastly, we make sure that <code>namespace</code> is set as the value of our <code>cellNamespace</code> and <code>cellViewNamespace</code>
options respectively.
Afterwards, we also place our new <code>custom</code> namespace which contains our custom shape definition <code>RectangleTwoLabels</code>
alongside our built-in shapes. As a result, <code>standard</code> and <code>custom</code> are both defined at the same level in our
<code>namespace</code> object. Lastly, we make sure that <code>namespace</code> is set as the value of our <code>cellNamespace</code>
and <code>cellViewNamespace</code> options respectively.
</p>

<pre><code>class RectangleTwoLabels extends joint.shapes.standard.Rectangle {
Expand All @@ -166,10 +159,7 @@ <h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">A Mo
}
}

const namespace = { ...joint.shapes };
const customNamespace = { custom: { RectangleTwoLabels }};

Object.assign(namespace, customNamespace);
const namespace = { ...joint.shapes, custom: { RectangleTwoLabels }};

const graph = new joint.dia.Graph({}, { cellNamespace: namespace });

Expand Down Expand Up @@ -223,6 +213,12 @@ <h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">A Mo
<div class="paper" id="paper-cell-namespace"></div>
<p>JointJS source code: <a href="js/cell-namespace.js" target="_blank">cell-namespace.js</a></p>

<p>
Discovering your cell namespaces are not organized correctly should result in a common JointJS error. If you see the dreaded
<code>Uncaught Error: dia.ElementView: markup required</code> appearing in your console, it's likely
your namespace is not set up correctly, and JointJS cannot find the correct shape.
</p>

<h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">Don't Forget Custom Views!</h2>

<p>
Expand Down Expand Up @@ -304,6 +300,32 @@ <h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">Don'
rectangleInput.addTo(graph);
</code></pre>

<h2 style="font-size:19px;text-align:initial;text-transform:none;margin:0;">Quick Validation Tips</h2>

<p>
If you are experimenting with cell namespaces, you may like to perform some quick validation, or double-check exactly what
<code>type</code> values you are working with. Taking advantage of the
<a href="/docs/jointjs#dia.Element.prototype.prop" target="_blank""><code>prop()</code></a> method on both Elements & Links allows you
to quickly access the <code>type</code> value, so it can be useful to keep track of where your shapes are located.
</p>

<pre><code>const rect = new Rectangle({
size: { width: 80, height: 50 },
position: { x: 10, y: 10 }
});

console.log(rect.prop('type')); // standard.Rectangle
</code></pre>

<p>
A concise way to check if your namespaces are set up correctly is to overwrite the <code>graph</code> via <code>graph.toJSON()</code>
passing it the value returned from <code>graph.toJSON()</code>. If no error occurs, you can be more confident that your namespaces are
organized correctly.
</p>

<pre><code>graph.fromJSON(graph.toJSON());
</code></pre>

<p>
That's all we will cover in this tutorial. Thanks for staying with us if you got this far, and we hope you will have more confidence
when working with cell namespaces in JointJS. If you would like to explore any of the features mentioned here in more detail, you
Expand Down
5 changes: 1 addition & 4 deletions tutorials/js/cell-namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
}
}

const namespace = { ...joint.shapes };
const customNamespace = { custom: { RectangleTwoLabels }};

Object.assign(namespace, customNamespace);
const namespace = { ...joint.shapes, custom: { RectangleTwoLabels }};

const graph = new joint.dia.Graph({}, { cellNamespace: namespace });

Expand Down

0 comments on commit 85b2fc5

Please sign in to comment.