UNPKG

react-network-diagrams

Version:
325 lines (289 loc) 9.74 kB
/** * 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. */ import _ from "underscore"; import React from "react"; import PropTypes from "prop-types"; import { Connection } from "./Connection"; import { Endpoint } from "./Endpoint"; import { Navigate } from "./Navigate"; import { Directions } from "../js/constants"; /** * A component for drawing parallel sets of circuits. */ export class ParallelCircuit extends React.Component { renderCircuitTitle(title) { const titleStyle = { textAnchor: "left", fill: "#9D9D9D", fontFamily: "verdana, sans-serif", fontSize: 14 }; if (!this.props.hideTitle) { return ( <text className="circuit-title" key="circuit-title" style={titleStyle} x={this.props.titleOffsetX} y={this.props.titleOffsetY} > {title} </text> ); } else { return null; } } renderParentNavigation(parentId) { if (parentId) { return ( <g> <Navigate direction={Directions.NORTH} ypos={0} id={this.props.parentId} onSelectionChange={this.props.onSelectionChange} /> </g> ); } else { return null; } } renderDisabledOverlay(disabled) { if (disabled) { const overlayStyle = { fill: "#FDFDFD", fillOpacity: "0.65" }; return ( <rect className="circuit-overlay" style={overlayStyle} x="0" y="0" width={this.props.width} height={this.props.height} /> ); } else { return null; } } renderCircuitElements() { const elements = []; const x1 = this.props.margin; const x2 = this.props.width - this.props.margin; const y1 = this.props.height / 4; const y2 = y1; const memberList = this.props.memberList; // Push the two end points for the main circuit elements.push( <Endpoint x={x1} y={y1} key="a" style={this.props.endpointStyle} labelPosition={this.props.endpointLabelPosition} offset={this.props.endpointLabelOffset} label={this.props.endpointLabelA} /> ); elements.push( <Endpoint x={x2} y={y2} key="z" style={this.props.endpointStyle} labelPosition={this.props.endpointLabelPosition} offset={this.props.endpointLabelOffset} label={this.props.endpointLabelZ} /> ); const yOffset = 4; let offset = 0; if (memberList.length > 0) { offset = -(memberList.length - 1) * 0.5 - 1; } _.each(memberList, (member, memberIndex) => { offset += 1; const position = 18 * offset; elements.push( <Connection x1={x1} x2={x2} y1={y1} y2={y2} key={"circuit-" + memberIndex} style={member.styleProperties.style} lineShape={member.styleProperties.lineShape} label={member.circuitLabel} labelPosition={this.props.connectionLabelPosition} labelOffsetY={yOffset} noNavigate={member.styleProperties.noNavigate} navTo={member.navTo} position={position} onSelectionChange={this.props.onSelectionChange} /> ); }); return <g>{elements}</g>; } render() { const circuitContainer = { normal: { borderTopStyle: "solid", borderBottomStyle: "solid", borderWidth: 1, borderTopColor: "#FFFFFF", borderBottomColor: "#EFEFEF", width: "100%", height: this.props.height }, disabled: { width: "100%", height: this.props.height } }; let className = "circuit-container"; let svgStyle; if (this.props.disabled) { className += " disabled"; svgStyle = circuitContainer.disabled; } else { svgStyle = circuitContainer.normal; } const viewBox = `0 0 ${this.props.width} ${this.props.height}`; return ( <svg className={className} style={svgStyle} onClick={this._deselect}> <svg viewBox={viewBox} preserveAspectRatio="xMinYMin"> {this.renderCircuitTitle(this.props.title)} {this.renderCircuitElements()} {this.renderParentNavigation(this.props.parentId)} {this.renderDisabledOverlay(this.props.disabled)} </svg> </svg> ); } } ParallelCircuit.defaultProps = { width: 851, height: 250, disabled: false, titleOffsetX: 10, titleOffsetY: 15, margin: 100, noNavigate: false, lineShape: "linear" }; ParallelCircuit.propTypes = { /** The width of the circuit diagram */ width: PropTypes.number, /** The height of the circuit diagram */ height: PropTypes.number, /** The position of the title relative to the left side of the diagram */ titleOffsetX: PropTypes.number, /** The position of the title relative to the top of the diagram */ titleOffsetY: PropTypes.number, /** The blank margin around the diagram drawing */ margin: PropTypes.number, /** * Controls shape of the line but currenly only can be "linear". */ lineShape: PropTypes.oneOf(["linear"]), /** * To accurately display each of the member circuits, the concatenated circuit * requires an ordered array of circuit objects, where each object contains * the props to be used by the lower level connection and endpoint primitives. * Since the list renders sequentially, it assumes that the member circuits are in order. The list can be any length and needs to be constructed as such: * * ``` * const memberList = [ * { * styleProperties: darkFiberStyle, * endpointStyle: stylesMap.endpoint, * endpointLabelA: "Endpoint 1", * endpointLabelZ: "Endpoint 2", * circuitLabel: "Member 1", * navTo: "Member 1" * }, { * styleProperties: couplerStyle, * endpointStyle: stylesMap.endpoint, * endpointLabelA: "Endpoint 2", * endpointLabelZ: "Endpoint 3", * circuitLabel: "Member 2", * navTo: "Member 2" * }, { * styleProperties: leasedStyle, * endpointStyle: stylesMap.endpoint, * endpointLabelA: "Endpoint 3", * endpointLabelZ: "Endpoint 4", * circuitLabel: "Member 3", * navTo: "Member 3" * } * ]; * ``` */ memberList: PropTypes.array.isRequired, /** * Described the position of the connection label; accepts **"top"**, **"center"**, or **"bottom"** */ connectionLabelPosition: PropTypes.oneOf(["top", "center", "bottom"]), /** * The position of the label around the endpoint. */ endpointLabelPosition: PropTypes.oneOf([ "left", "right", "top", "topright", "topleft", "bottom", "bottomright", "bottomleft", "bottomleftangled", "bottomrightangled", "topleftangled", "toprightangled" ]), /** * This is the distance from the endpoint that the endpoint * label will be rendered. */ endpointLabelOffset: PropTypes.number, /** * The string to display in the top left corner of the diagram */ title: PropTypes.string, /** * Value that determines whether or not the upper left corner title is displayed */ hideTitle: PropTypes.bool, /** * Determines if the circuit view is muted. Typically used in * conjunction with `parentID` */ disabled: PropTypes.bool, /** * Callback function used to handle clicks. */ onSelectionChange: PropTypes.func, /** * Value that if provided, will render a small nav arrow that * when clicked, navigates to that element. Used mainly when we want * to show a parent / child relationship between two circuits. */ parentId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** * Boolean value that determines if the element uses the onSelectionChange * change and can be clicked */ noNavigate: PropTypes.bool };