react-network-diagrams
Version:
390 lines (340 loc) • 19.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Node = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _propTypes = require("prop-types");
var _propTypes2 = _interopRequireDefault(_propTypes);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* Copyright (c) 2018, The Regents of the University of California,
* through Lawrence Berkeley National Laboratory (subject to receipt
* of any required approvals from the U.S. Dept. of Energy).
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
var Node = exports.Node = function (_React$Component) {
_inherits(Node, _React$Component);
function Node() {
_classCallCheck(this, Node);
return _possibleConstructorReturn(this, (Node.__proto__ || Object.getPrototypeOf(Node)).apply(this, arguments));
}
_createClass(Node, [{
key: "handMouseClick",
value: function handMouseClick(e) {
e.stopPropagation();
var id = this.props.id || this.props.name;
if (this.props.onSelectionChange) {
this.props.onSelectionChange("node", id);
}
}
}, {
key: "handleMouseOver",
value: function handleMouseOver() {}
}, {
key: "handleMouseDown",
value: function handleMouseDown(e) {
e.stopPropagation();
var id = this.props.id || this.props.name;
if (this.props.onMouseDown) {
this.props.onMouseDown(id, e);
}
}
}, {
key: "render",
value: function render() {
var _this2 = this;
var nodeClasses = "map-node";
var labelClasses = "map-node-label";
var styleModifier = "normal";
if (this.props.selected) {
styleModifier = "selected";
nodeClasses += " selected";
labelClasses += " selected";
}
if (this.props.muted) {
styleModifier = "muted";
nodeClasses += " muted";
labelClasses += " muted";
}
if (this.props.highlighted) {
styleModifier = "highlighted";
nodeClasses += " highlighted";
labelClasses += " highlighted";
}
var basicOffset = this.props.offset ? this.props.offset : this.props.radius * 1.33;
// 0.8 * font size? ish..
var fontOffset = 8;
var labelX = this.props.x;
var labelY = this.props.y;
var labelR = 0;
var textAnchor = "middle";
var rotate = "rotate(" + labelR + " " + labelX + ", " + labelY + ")";
var labelPosition = void 0;
if (_typeof(this.props.labelPosition) === "object") {
labelPosition = this.props.labelPosition.value;
} else {
labelPosition = this.props.labelPosition;
}
switch (labelPosition) {
case "left":
labelX -= basicOffset;
labelY += 5;
textAnchor = "end";
break;
case "right":
labelX += basicOffset;
labelY += 5;
textAnchor = "start";
break;
case "top":
labelY -= basicOffset;
break;
case "topright":
labelY -= basicOffset;
labelX += basicOffset;
textAnchor = "start";
break;
case "topleft":
labelY -= basicOffset;
labelX -= basicOffset;
textAnchor = "end";
break;
case "bottom":
labelY += basicOffset + fontOffset;
break;
case "bottomright":
labelY += basicOffset + fontOffset;
labelX += basicOffset;
textAnchor = "start";
break;
case "bottomleft":
labelY += basicOffset + fontOffset;
labelX -= basicOffset;
textAnchor = "end";
break;
case "bottomleftangled":
labelX += 2;
labelY += basicOffset + fontOffset;
labelR = -45;
rotate = "rotate(" + labelR + " " + labelX + ", " + labelY + ")";
textAnchor = "end";
break;
case "bottomrightangled":
labelX -= 2;
labelY += basicOffset + fontOffset;
labelR = 45;
rotate = "rotate(" + labelR + " " + labelX + ", " + labelY + ")";
textAnchor = "start";
break;
case "topleftangled":
labelY -= basicOffset;
labelR = 45;
rotate = "rotate(" + labelR + " " + labelX + ", " + labelY + ")";
textAnchor = "end";
break;
case "toprightangled":
labelY -= basicOffset;
labelR = -45;
rotate = "rotate(" + labelR + " " + labelX + ", " + labelY + ")";
textAnchor = "start";
break;
default:
break;
}
labelX += this.props.labelOffsetX;
labelY += this.props.labelOffsetY;
var nodeElement = void 0;
if (this.props.shape === "cloud") {
nodeClasses += " map-node-shape-cloud";
labelClasses += " map-node-label-cloud";
var cloudPath = "M" + this.props.x + "," + (this.props.y + 5);
cloudPath += "l-25,0 c-10,0 -10,-10 -5,-15";
cloudPath += "c5,-5 15,-5 15,0 c0,-15 25,-15 25,-5 c10,-10 25,15 10,20 Z";
nodeElement = _react2.default.createElement("path", {
d: cloudPath,
style: this.props.style[styleModifier],
className: nodeClasses
});
switch (this.props.labelPosition) {
case "top":
case "topright":
case "topleft":
labelY += 7;
break;
case "bottom":
case "bottomleft":
case "bottomright":
labelY -= 15;
break;
default:
break;
}
labelX -= 3;
} else if (this.props.shape === "square") {
nodeClasses += " map-node-shape-square";
labelClasses += " map-node-shape-square";
var x = this.props.x - this.props.radius;
var y = this.props.y - this.props.radius;
var width = 2 * this.props.radius;
nodeElement = _react2.default.createElement("rect", {
x: x,
y: y,
rx: this.props.rx,
ry: this.props.ry,
width: width,
height: width,
style: this.props.style[styleModifier],
className: nodeClasses
});
switch (this.props.labelPosition) {
case "left":
labelX -= 2;
break;
case "right":
labelX += 2;
break;
default:
break;
}
} else {
nodeClasses += " map-node-shape-circle";
labelClasses += " map-node-label-circle";
nodeElement = _react2.default.createElement("circle", {
cx: this.props.x,
cy: this.props.y,
r: this.props.radius,
style: this.props.style[styleModifier],
className: nodeClasses
});
}
if (this.props.label) {
return _react2.default.createElement(
"g",
{
onClick: function onClick(e) {
return _this2.handMouseClick(e);
},
onMouseOver: this.handleMouseOver,
onMouseDown: function onMouseDown(e) {
return _this2.handleMouseDown(e);
},
onMouseMove: this.handleMouseMove
},
nodeElement,
_react2.default.createElement(
"text",
{
x: labelX,
y: labelY,
textAnchor: textAnchor,
transform: rotate,
style: this.props.labelStyle[styleModifier],
className: labelClasses
},
this.props.label
)
);
} else {
return _react2.default.createElement(
"g",
{
onClick: function onClick(e) {
return _this2.handMouseClick(e);
},
onMouseOver: this.handleMouseOver,
onMouseDown: function onMouseDown(e) {
return _this2.handleMouseDown(e);
},
onMouseMove: this.handleMouseMove,
onMouseUp: this.handleMouseUp
},
nodeElement
);
}
}
}], [{
key: "spec",
/**
* Provides a spec for the editor UI to render properties
* for this node
*/
value: function spec() {
return [{ attr: "name", label: "Name", type: "text" }, { attr: "x", label: "Position x", type: "integer" }, { attr: "y", label: "Position y", type: "integer" }, { attr: "label_dx", label: "Label offset x", type: "integer" }, { attr: "label_dy", label: "Label offset y", type: "integer" }, {
attr: "label_position",
label: "Label position",
type: "choice",
options: [{ value: "top", label: "Top" }, { value: "bottom", label: "Bottom" }, { value: "left", label: "Left" }, { value: "right", label: "Right" }, { value: "topleft", label: "Top left" }, { value: "topright", label: "Top right" }, { value: "bottomleft", label: "Bottom left" }, { value: "bottomright", label: "Bottom right" }]
}];
}
}]);
return Node;
}(_react2.default.Component);
Node.propTypes = {
/** When the node shape is a `circle`, this controls the size of the node */
radius: _propTypes2.default.number,
/** Display the node as selected */
selected: _propTypes2.default.bool,
/** The shape of the node */
shape: _propTypes2.default.oneOf(["circle", "square", "cloud"]),
/**
* The style of the `<Node>` has two components, one for the
* node itself and one for the label (the label). Each group
* has three different possible options depending on the way the
* node should be rendered:
*
* * `normal` provides the standard view of the node
* * `selected` for when the node is moused over
* * `muted` for when the node is not selected.
*
* For example:
*
* ```
* const nodeStyle = {
* node: {
* normal: {fill: "none", stroke: "#DBDBDB", strokeWidth: 4},
* selected: {fill: "none", stroke: "#B1B1B1", strokeWidth: 6},
* muted: {fill: "none", stroke: "#DBDBDB", strokeWidth: 2, opacity: 0.6, cursor: "pointer"}
* },
* label: {
* normal: {fill: "#9D9D9D", fontSize: 10, fontFamily: "verdana, sans-serif"},
* selected: {fill: "#333",stroke: "none", fontSize: 11},
* muted: {fill: "#696969", stroke: "none", fontSize: 9, opacity: 0.6}
* }
* }
* ```
*/
style: _propTypes2.default.object,
isDragging: _propTypes2.default.bool,
/**
* Controls the x pixel offset from labelPosition
*/
labelOffsetX: _propTypes2.default.number,
/**
* Controls the y pixel offset from labelPosition
*/
labelOffsetY: _propTypes2.default.number,
/** When the node shape is a `square`, this controls the radius of corners. */
rx: _propTypes2.default.number,
/** When the node shape is a `square`, this controls the radius of corners. */
ry: _propTypes2.default.number
};
Node.defaultProps = {
radius: 5,
selected: false,
shape: "circle",
style: {},
isDragging: false,
labelOffsetX: 0,
labelOffsetY: 0,
rx: 0,
ry: 0
};