JointJS - Playground
prevent contextmenu.
https://github.com/clientIO/joint/issues/2658
by Roman Bruckner
HTML
<link rel="stylesheet" type="text/css" href="sample.css" />
<div class="toolbar">
<button id="btn-create-part">Create Element</button>
<button id="btn-create-port">Create Port (Square)</button>
<span id="status"></span>
</div>
<div id="paper"></div>
<script src="https://cdn.jsdelivr.net/npm/@joint/[email protected]/dist/joint.min.js"></script>
<!-- Sample Logic -->
<script src="sample.js"></script>
CSS
body {
font-family: sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.toolbar {
padding: 10px;
background: #f0f0f0;
border-bottom: 1px solid #ccc;
display: flex;
gap: 10px;
align-items: center;
}
#paper {
flex: 1;
overflow: auto;
background: #f7f7f7;
position: relative;
}
button {
padding: 8px 12px;
cursor: pointer;
}
/* Port Styling */
.joint-port-body {
stroke: #333;
fill: #fff;
stroke-width: 1;
}
.joint-port-label {
font-size: 10px;
font-family: Arial, sans-serif;
fill: #333;
}
/* Resize Handle */
.resize-handle {
fill: #333;
stroke: #fff;
stroke-width: 1;
cursor: nwse-resize;
display: none;
/* Hidden by default, shown on selection */
}
.joint-element.selected .resize-handle {
display: block;
}
JavaScript
const { dia, shapes, util } = joint;
// 1. Initialize Graph and Paper
const graph = new dia.Graph();
const paper = new dia.Paper({
model: graph,
el: document.getElementById("paper"),
width: "100%",
height: "100%",
background: { color: "#F8F9FA" },
gridSize: 10,
drawGrid: true,
async: true,
defaultConnectionPoint: {
name: "rectangle",
// args: { useModelGeometry: true },
},
interactive: { linkMove: false },
linkPinning: false,
validateConnection: function (
cellViewS,
magnetS,
cellViewT,
magnetT,
end,
linkView,
) {
if (cellViewS === cellViewT) return false;
return cellViewT.model.isElement() || magnetT !== undefined;
},
// defaultConnectionPoint: { name: 'rectangle', args: { useModelGeometry: true }},
interactive: { linkMove: false },
measureNode: function (el, view) {
if (el === view.el) {
return { x: 0, y: 0, ...view.model.size() };
}
return V(el).getBBox();
},
});
// 2. State Management
let selectedView = null;
let selectedPortId = null;
let selectedPortLabelId = null; // New: Track selected label
let drawingLink = null;
let isResizing = false;
let resizeStartPosition = null;
let resizeStartSize = null;
let draggingPort = null;
let draggingPortLabel = null;
let selectedPortView = null;
let resizingPort = null;
let resizingPortStart = null;
const defaultPortGroups = {
"left-port-group": {
position: { name: "absolute", args: { x: 0, y: 0 } },
attrs: {
// should not be here (custom attributes should be one level up)
// z: "auto",
// show: true,
// direction: "",
// Connect directly to the body (don't include the label)
portRoot: {
magnetSelector: 'portBody',
},
portLabel: {
fontSize: 12,
dominantBaseline: "hanging",
lineHeight: 16,
displayEmpty: true,
},
portBody: {
...