Added center to interface

pull/33/head
Khwaja 3 months ago
parent 315c80c03d
commit 6e6a4cc175

@ -11,10 +11,10 @@ import "../Common/Forms/Tables.css";
import Footer from "./Footer";
import React, { useState } from "react";
import {CircularData} from "./CircularData";
import { defaultPlant, defaultProduct } from "./defaults";
import { defaultPlant, defaultProduct, defaultCenter } from "./defaults";
import PipelineBlock from "./PipelineBlock";
import '@xyflow/react/dist/style.css';
import { CircularPlant } from "./CircularData";
import { CircularPlant, CircularCenter} from "./CircularData";
declare global {
interface Window {
nextX: number;
@ -25,7 +25,8 @@ declare global {
const CaseBuilder = () => {
const [circularData, setCircularData] = useState<CircularData> ( {
plants: {},
products: {}
products: {},
centers: {}
});
const onClear = () => {};
@ -97,6 +98,39 @@ const CaseBuilder = () => {
};
const onAddCenter = () => {
setCircularData(prev => {
const name = prompt("Center name");
if (!name || name in prev.centers) return prev;
const [x,y] = randomPosition();
const next = {
...prev,
centers: {
...prev.centers,
[name]: { ...defaultCenter, id:name, x, y, outputs: []}
}
};
return next;
});
};
const onSetCenterInput = (centerName: string, productName: string) => {
setCircularData((prev) => {
const center = prev.centers[centerName];
if (!center) return prev;
return {
...prev,
centers: {
...prev.centers,
[centerName]: { ...center, input: productName},
},
};
});
};
const onSetPlantInput = (plantName: string, productName: string) => {
setCircularData((prevData: CircularData) => {
@ -135,43 +169,46 @@ const CaseBuilder = () => {
};
const onAddPlantOutput = (plantName: string, productName: string) => {
setCircularData((prevData) => {
const plant = prevData.plants[plantName];
const onAddPlantOutput = (plantName: string, productName: string) => {
setCircularData(prevData => {
const plant = prevData.plants[plantName];
if (!plant) return prevData;
const updatedPlant: CircularPlant = {
...plant,
outputs: {
...plant.outputs,
[productName]: 0,
},
};
// Build a new array of outputs, avoiding duplicates
const newOutputs = plant.outputs.includes(productName)
? plant.outputs
: [...plant.outputs, productName];
// Return updated state with outputs as an array
return {
...prevData,
plants: {
...prevData.plants,
[plantName]: updatedPlant,
[plantName]: {
...plant,
outputs: newOutputs,
},
},
};
});
};
const onAddCenterOutput = (centerName: string, productName: string) => {
setCircularData((prev) => {
const center = prev.centers[centerName];
if (!center) return prev;
const updatedOutputs = [...center.output, productName];
return {
...prev,
centers: {
...prev.centers,
[centerName]: { ...center, output: updatedOutputs},
},
};
});
};
@ -199,6 +236,20 @@ const onAddPlantOutput = (plantName: string, productName: string) => {
};
const onMoveCenter = (centerName: string, x: number, y: number) => {
setCircularData((prev) => {
const center = prev.centers[centerName];
if (!center) return prev;
return {
...prev,
centers: {
...prev.centers,
[centerName]: { ...center,x,y},
},
};
});
};
return (
<div>
<Header onClear={onClear} onSave={onSave} onLoad={onLoad} />
@ -214,6 +265,11 @@ const onAddPlantOutput = (plantName: string, productName: string) => {
products={circularData.products}
onSetPlantInput={onSetPlantInput}
onAddPlantOutput={onAddPlantOutput}
onAddCenter= {onAddCenter}
onAddCenterInput={onSetCenterInput}
onAddCenterOutput={onAddCenterOutput}
onMoveCenter={onMoveCenter}
centers={circularData.centers}
/>
</div>
</div>

@ -3,7 +3,7 @@ export interface CircularPlant {
x: number;
y: number;
inputs: string[];
outputs: Record<string, number>;
outputs: string[];
}
@ -16,8 +16,18 @@ export interface CircularProduct {
export interface CircularData {
plants: Record<string, CircularPlant>;
products: Record<string, CircularProduct>;
centers: Record<string, CircularCenter>;
}
export interface CircularCenter {
id: string;
x: number;
y: number;
//single input, multiple outputs
input?: string;
output: string[];
}

@ -1,24 +1,57 @@
// NodesAndEdges.tsx
import React from 'react';
import { Position, NodeProps, Handle } from '@xyflow/react';
import { Handle, Position, NodeProps } from '@xyflow/react';
import styles from './PipelineBlock.module.css';
export interface CustomNodeData {
label: string;
type: 'plant' | 'product';
type: 'plant' | 'product' | 'center';
}
export default function CustomNode({ data }: NodeProps<any>) {
const nodeStyle =
data.type === 'plant'
? styles.PlantNode: styles.ProductNode;
export default function CustomNode({ data, isConnectable }: NodeProps<Node<CustomNodeData>>) {
const typeClass =
data.type === 'plant' ? styles.PlantNode :
data.type === 'product' ? styles.ProductNode:
styles.CenterNode;
return (
<div className={`${styles.node} ${nodeStyle}`}>
{data.type === 'plant' && (
<Handle type="target" position={Position.Left} style={{ background: '#555' }} />
)}
<div>{data.label}</div>
<Handle type="source" position={Position.Right} style={{ background: '#555' }} />
<div className={`${styles.node} ${typeClass}`}>
<Handle
type="target"
position={Position.Left}
isConnectable={isConnectable}
style={{ background: '#555' }}
/>
<div>{data.label}</div>
<Handle
type="source"
position={Position.Right}
isConnectable={isConnectable}
style={{ background: '#555' }}
/>
</div>
);
};
}

@ -6,14 +6,16 @@
}
.PlantNode,
.ProductNode {
.ProductNode,
.CenterNode {
border-color: rgba(0, 0, 0, 0.8) !important;
color: black !important;
font-size: 13px !important;
border-width: 1px !important;
border-radius: 6px !important;
box-shadow: 0px 2px 4px -3px black !important;
width: 100px !important;
width: 100%;
height: 100%;
}
.PlantNode {
@ -23,3 +25,7 @@
.ProductNode {
background-color: #e6e6e6 !important;
}
.CenterNode {
background-color: #d3a610;
}

@ -1,4 +1,4 @@
import { CircularPlant, CircularProduct } from "./CircularData";
import { CircularPlant, CircularProduct, CircularCenter } from "./CircularData";
import { Node, Edge } from "@xyflow/react";
import styles from "./PipelineBlock.module.css";
import { ReactFlow, Background, Controls,MarkerType } from '@xyflow/react';
@ -13,12 +13,18 @@ import CustomNode, { CustomNodeData }from "./NodesAndEdges";
interface PipelineBlockProps {
onAddPlant: () => void;
onAddProduct: () => void;
onAddCenter: () => void;
onMovePlant: (name: string , x: number, y: number) => void;
onMoveProduct: (name: string, x: number, y: number) => void;
onMoveCenter: (name: string, x: number, y: number) => void;
onSetPlantInput: (plantName:string, productName: string) => void;
onAddPlantOutput: (plantName: string, productName: string) => void;
onAddCenterInput: (plantName: string, productName: string) => void;
onAddCenterOutput: (plantName: string, productName: string) => void;
products: Record<string, CircularProduct>;
plants: Record<string, CircularPlant>;
centers: Record<string, CircularCenter>;
}
const onNodeDoubleClick = () => {};
@ -46,6 +52,13 @@ const PipelineBlock: React.FC<PipelineBlockProps> = (props) => {
props.onAddPlantOutput(source, target);
}
else if (sourceType === "product" && targetType === "center") {
props.onAddCenterInput(target, source);
}
else if (sourceType === "center" && targetType === "product") {
props.onAddCenterOutput(source, target);
}
};
const onNodeDragStop =(_:any, node: Node) => {
@ -56,9 +69,11 @@ const onNodeDragStop =(_:any, node: Node) => {
if (data.type === "product") {
props.onMoveProduct(id, position.x, position.y);
}
if (data.type === "center") {
props.onMoveCenter(id, position.x, position.y);
}
};
for (const [productName, product] of Object.entries(props.products) as [string, CircularProduct][]) {
if(!product.x || !product.y) hasNullPositions = true;
mapNameToType[productName] = "product";
@ -69,7 +84,7 @@ const onNodeDragStop =(_:any, node: Node) => {
position: { x:product.x, y:product.y}
});
}
console.log("ALL PLANTS:", props.plants);
for (const [plantName, plant] of Object.entries(props.plants) as [string, CircularPlant][]) {
if(!plant.x || !plant.y) hasNullPositions = true;
mapNameToType[plantName] = "plant";
@ -94,20 +109,49 @@ const onNodeDragStop =(_:any, node: Node) => {
});
}
/**for (const outputProduct of plant.inputs){
for (const outputProduct of plant.outputs ?? []) {
edges.push({
id: `${plantName}-${outputProduct}`,
source: plantName,
target: outputProduct,
animated: true,
style: { stroke: "black" },
style: { stroke: 'black' },
markerEnd: { type: MarkerType.ArrowClosed },
});
}
*/
}
}
for (const [centerName, center] of Object.entries(props.centers)) {
mapNameToType[centerName] = "center";
nodes.push({
id: centerName,
type: "default",
data: { label: centerName, type: "center"},
position: {x: center.x, y: center.y},
});
if (center.input) {
edges.push({
id: `${center.input}-${centerName}`,
source: center.input,
target:centerName,
style: { stroke: "black"},
markerEnd: { type: MarkerType.ArrowClosed},
});
}
for (const out of center.output) {
edges.push({
id: `${centerName}-${out}`,
source: centerName,
target:out,
style: { stroke: "black"},
markerEnd: { type: MarkerType.ArrowClosed},
});
}
}
useEffect(() => {
if (hasNullPositions) onLayout();
@ -116,11 +160,11 @@ const onNodeDragStop =(_:any, node: Node) => {
return (
<>
<Section title="Pipeline" />
<Card>
<div className={styles.PipelineBlock}>
<ReactFlow
<>
<Section title="Pipeline" />
<Card>
<div className={styles.PipelineBlock}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodeDoubleClick={onNodeDoubleClick}
@ -133,41 +177,46 @@ return (
minZoom={0.5}
snapToGrid={true}
preventScrolling={false}
nodeTypes={{default: CustomNode}}
>
<Background />
<Controls showInteractive={false} />
</ReactFlow>
</div>
<div style={{ textAlign: "center", marginTop: "1rem" }}>
<button
nodeTypes={{ default: CustomNode }}
>
<Background />
<Controls showInteractive={false} />
</ReactFlow>
</div>
<div style={{ textAlign: "center", marginTop: "1rem" }}>
<button
style={{ margin: "0 8px" }}
onClick={props.onAddProduct}
>
>
Add product
</button>
<button
</button>
<button
style={{ margin: "0 8px" }}
onClick={props.onAddPlant}
>
>
Add plant
</button>
<button
</button>
<button
style={{ margin: "0 8px" }}
onClick={props.onAddCenter}
>
Add center
</button>
<button
style={{ margin: "0 8px" }}
onClick={onLayout}
>
>
Auto Layout
</button>
<button
</button>
<button
style={{ margin: "0 8px" }}
title="Drag from one connector to another to create links between products and plants. Double click to rename an element. Click an element to select and move it. Press the [Delete] key to remove it."
>
title="Drag from one connector to another to create links between products, plants, and centers. Double click to rename an element. Click an element to select and move it. Press the [Delete] key to remove it."
>
?
</button>
</div>
</Card>
</>
</button>
</div>
</Card>
</>
);
};
export default PipelineBlock;

@ -1,4 +1,4 @@
import { CircularPlant, CircularProduct } from "./CircularData";
import { CircularData, CircularPlant, CircularProduct, CircularCenter } from "./CircularData";
export interface DefaultProduct extends CircularProduct{
x: number;
@ -10,16 +10,35 @@ export interface DefaultPlant extends CircularPlant{
y: number;
}
export interface DefaultCenter extends CircularPlant{
x: number;
y: number;
}
export const defaultProduct: DefaultProduct = {
"id": "",
id: "",
x: 0,
y: 0,
};
export const defaultPlant: CircularPlant = {
"id": "",
id: "",
x: 0,
y: 0,
inputs : [],
outputs: {},
outputs: [],
};
export const defaultCenter: CircularCenter = {
id: "",
x: 0,
y: 0,
output: [],
};
export const DefaultData: CircularData = {
products: {},
plants: {},
centers: {}
};

Loading…
Cancel
Save