Coder Social home page Coder Social logo

reaviz / reaflow Goto Github PK

View Code? Open in Web Editor NEW
1.9K 1.9K 115.0 9.05 MB

๐ŸŽฏ React library for building workflow editors, flow charts and diagrams. Maintained by @goodcodeus.

Home Page: https://reaflow.dev

License: Apache License 2.0

JavaScript 0.46% HTML 1.25% TypeScript 97.11% CSS 1.14% Shell 0.03%
diagrams elkjs flowchart hacktoberfest node-editor react reactjs visualizations workflow

reaflow's Introduction


Data visualization library for React

Open Collective backers and sponsors


REAVIZ is a modular chart component library that leverages React natively for rendering the components while using D3js under the hood for calculations. The library provides an easy way to get started creating charts without sacrificing customization ability.

๐Ÿš€ Quick Links

๐Ÿ’Ž Other Projects

  • Unify Viz - Premium offering 850+ Figma and React professionally designed data visualization components.
  • Reagraph - Open-source library for large webgl based network graphs.
  • Reablocks - Open-source component library for React based on Tailwind.
  • Reaflow - Open-source library for workflow and diagram graphs.

โœจ Features

Chart types include:

  • Bar Chart
    • Single Series Vertical / Horizontal
    • Multi Series Vertical / Horizontal
    • Stacked Vertical / Horizontal
    • Stacked Normalized Vertical / Horizontal
    • Stacked Diverging Vertical / Horizontal
    • Marimekko
    • Radial
    • Sparkline
    • Waterfall
  • Line Chart
    • Single Series
    • Multi Series
    • Stacked
    • Stacked Normalized
    • Radial
    • Sparklines
  • Area Chart
    • Single Series
    • Multi Series
    • Stacked
    • Stacked Normalized
    • Radial
    • Sparklines
  • Scatter Chart
    • Linear
    • Radial
  • Pie Chart
    • Standard
    • Exploded
    • Donut Chart
  • Sankey chart
  • Gauge
    • Radial
    • Linear
    • Stacked Radial
  • Map Chart
  • Heatmap
    • Standard
    • Year Calendar
    • Month Calendar
  • Venn Diagram
    • Standard
    • Euler
    • Fixed Euler
  • Bubble Chart
  • Treemap
  • Bar List
  • Meter
  • Spider / Radar
  • Funnel Chart

Additional features:

  • Legend
    • Discrete
    • Sequential
  • Axis
    • Linear
    • Radial
    • Advanced Label Positioning
  • Gestures
    • Pinch
    • Pan
    • Zoom
    • Move
  • Tooltip
    • Single Value
    • Grouped Values
  • Line/Area Series Symbols
  • Animations Enter/Update/Exit
  • Brush
  • Patterns
  • Gradients
  • Grid Lines
  • Mark Lines
  • BigInt Support
  • Auto Sizing
  • Bar Guidelines
  • Range Lines
  • Animated Counts
  • a11y Support for labels, roles and tabbing
  • SSR

๐Ÿ“ฆ Install

To use reaviz in your project, install it via npm/yarn:

npm i reaviz --save

then import a chart type into your JSX element:

import { BarChart } from 'reaviz';

const data = [
  { key: 'IDS', data: 14 },
  { key: 'Malware', data: 5 },
  { key: 'DLP', data: 18 }
];

const App = () => <BarChart width={350} height={250} data={data} />;

Checkout this demo live or visit the demos page to learn more!

๐Ÿ”ญ Development

If you want to run REAVIZ locally, its super easy!

  • Clone the repository
  • npm i
  • npm start
  • Browser opens to Storybook page

โค๏ธ Contributors & Credits

Thanks to Netlify for hosting!

Deploys by Netlify

Thanks to all our contributors!

reaflow's People

Contributors

ambarish-fe avatar amcdnl avatar aschwad avatar aykutsarac avatar bram209 avatar c0dk avatar dbismut avatar doix avatar emil14 avatar evgenoid avatar faizanu94 avatar ghsteff avatar im-amir avatar jweinstein92 avatar mindster-cru avatar mnttnm avatar nerevar123 avatar sharongrossman avatar stefanomagrassi avatar steffeydev avatar sudakatux avatar tk-fp avatar vadorequest avatar vhalushko avatar waseemmaya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reaflow's Issues

How to persist/share the `canvasRef` to child components using a (Recoil) store?

The documentation at https://reaflow.dev/?path=/story/docs-advanced-refs--page explains a bit how to use the canvasRef, but the example is very light and isn't necessarily what a real app would do.

export const MyCanvas: FC = () => {
  const ref = useRef<CanvasRef | null>(null);

  useEffect(() => {
    // Refs give you ability to do things like:
    // ref.current?.centerCanvas()
  }, [ref]);

  return <Canvas ref={ref} />;
};

More specifically, how can I access the canvasRef from a component? (Node, Edge, etc.)

I tried to store it in a shared state, but it didn't work out.

type Props = {
  canvasRef: MutableRefObject<CanvasRef | null>;
}

const CanvasContainer: React.FunctionComponent<Props> = (props): JSX.Element | null => {
  const {
    canvasRef,
  } = props;
  const [persistedCanvasRef, setPersistedCanvasRef] = useRecoilState(canvasRefState);

  useEffect(() => {
    console.log('Persisting canvas ref', canvasRef);
    setPersistedCanvasRef(canvasRef as MutableRefObject<CanvasRef>);
  }, [canvasRef]);

  ...

  return (<Canvas ... />)
}

Calling setPersistedCanvasRef(canvasRef as MutableRefObject<CanvasRef>); throws the error TypeError: Cannot assign to read only property 'current' of object '#<Object>'.

import { MutableRefObject } from 'react';
import { CanvasRef } from 'reaflow';
import { atom } from 'recoil';

export const canvasRefState = atom<MutableRefObject<CanvasRef> | null>({
  key: 'canvasRefState',
  default: null,
});

I thought I could store the canvasRef and allow any component to subscribe to it to access its properties, but it seems I misunderstood something.

Another alternative I see is to pass down the canvasRef as props for Node and Edge components, but that's a bit ugly/heavy.

How would you recommended doing that?

`useSelection` hook `onKeyDown` event doesn't work with `foreignObject` - Multiple selection doesn't work when using a `foreignObject`

I'm submitting a...

[x] Bug report

The https://reaflow.dev/?path=/story/docs-helpers-selection--page

Reproduction

Online demo: https://poc-nextjs-reaflow-git-repro-selection-foreignobject.ambroise-dhenain.vercel.app/

Selecting one node works flawlessly (deletion, too), but selecting several using meta key (command on MacOS) doesn't allow multi select.

When removing all the <foreignObject> children of the InformationNode.tsx component, the multi-selection works flawlessly. It seems it's related to foreignObject somehow.

I tried passing the onKeyDown event to both foreignObject and the top-level div within it, but it doesn't do anything.

It's probably related to #45, but I don't see a simple workaround.

I feel like this is gonna be an issue for many things (using a foreignObject of the same dimensions as the Node), I wonder if you have any advice about how to make the developer experience better, while providing a good UX to the end-user. I'm thinking to do some kind of "header" that isn't tempered with the foreignObject, for dragging, selection, etc.

Minimal reproduction of the problem with instructions

Online PR: Vadorequest/rwa-faunadb-reaflow-nextjs-magic#2

Run locally:

  • git clone https://github.com/Vadorequest/poc-nextjs-reaflow.git
  • cd poc-nextjs-reaflow && git checkout repro-selection-foreignObject
  • yarn && yarn start

Version

reaflow: 3.0.5

v1

Features

Baseline features, currently none scheduled except basic rendering.

Core

  • Keyboard A11y
  • Hotkeys
  • Undo/Redo
  • Smart Hit Detection
  • Drag
  • Drop
  • Gestures
  • Auto fit
  • Complex Node Types ( foreign objects )
  • Selection of Node/Edge/Port/Nested
  • Validation on Connection
  • Events
  • Hide Nodes

Symbols

  • Node
  • Edge
  • Port
  • Remove
  • Arrow
  • Nested Nodes
  • Label
  • Loop
  • Add

Layout

  • Manual
  • Elk
  • Grid

Navigation

  • Zoom
  • Pan
  • Scroll

Addons

  • Context Menu
  • Minimap
  • Lasso
  • Editor

Other Libs

Feature request - Improve `addNodeAndEdge` utility to also bind edges to ports

At this time, the addNodeAndEdge utility helps us easily add a new node and link it to another node while creating the edge.

export declare function addNodeAndEdge(nodes: NodeData[], edges: EdgeData[], node: NodeData, toNode?: NodeData): {
    nodes: NodeData<any>[];
    edges: EdgeData<any>[];
};

Although, if ports are configured on both nodes, it should allow us to configure ports binding too.

At this time, if ports are defined on the nodes, they aren't being used, which generates something odd:
image

In a simple use-case, where both nodes have at most 1 port per side, it should be straightforward to automatically configure binding.

The toNode is the source and should be bound by its WEST port (when Canvas direction = 'RIGHT'), while the node is the destination and should be bound by its EAST port.

Things might get more complicated when a node has several ports in the same side, but I suggest having an auto strategy that binds to the first port it finds on the side the node should be bound.

We might have a 5th argument to addNodeAndEdge, such as:

addNodeAndEdge(nodes: NodeData[], edges: EdgeData[], node: NodeData, toNode?: NodeData, portsResolver: (node: NodeData, toNode?: NodeData) => {nodePorts: PortData[], toNodePorts: PortData[]}): {
    nodes: NodeData<any>[];
    edges: EdgeData<any>[];
};

If unspecified, the 5th argument would use the default implementation, which behaves as above mentioned (binding to the first port it finds on the expected side), providing a custom portsResolver would override this behaviour and allow for more customisation.

Does this feature request makes sense? Is it something that might be added natively? I believe it would ease usage of Ports by providing a sane default behavior, while allowing for extra customisation for non-covered use-cases.

Edges into nested nodes are taking unnecessary turns

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[X] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

Edges into a nested node are taking an unnecessary bezier turn. This only occurs if the Canvas has the property direction='UP' or direction='DOWN'.

Expected behavior

The edge should head straight towards the node.

Minimal reproduction of the problem with instructions

Example (note that the Canvas prop direction='DOWN' is the default direction):
<Canvas layoutOptions={ { 'elk.hierarchyHandling': 'INCLUDE_CHILDREN' } } nodes={[ { id: '1', text: '1' }, { id: '2', }, { id: '2.1', parent: '2', text: '2.1' }, { id: '3', text: '3' } ]} edges={[ { id: '1-2.1', from: '1', to: '2.1' }, { id: '1-3', from: '1', to: '3', } ]} />

grafik

Calling `setNodes` doesn't update nodes - Trying to make a Node height dynamic based on textarea input size

I'm submitting a...

[x] Bug report

I'm trying to make a node height update when the height of the textarea changes.

Video walkthrough: https://youtu.be/Ar_SKdDnAz8

image

image

Implementation of updateCurrentNode: https://github.com/Vadorequest/poc-nextjs-reaflow/blob/repro-textarea-dyn-height/src/components/PlaygroundContainer.tsx#L97-L113

Current behavior

Calling setNodes doesn't seem to update nodes every time. Sometimes it's "updated" (but the UI doesn't reflect the change, though).

I can't tell if it's a react issue (like, my code), or something related to Reaflow itself. What's weirdest is that the re-render doesn't propagate to children component (EditorContainer renders, but PlaygroundContainer doesn't seem so, but I can't explain why)

Also, I wonder if there is a utility function to update an existing node in an array of nodes.
I couldn't find any example/demo on how to do that.

I wonder if I need to use an actual state manager to avoid those kinds of issues.

Expected behavior

The state should update in EditorContainer every time the height of the textarea changes, and it should re-render all children components and recalculate the position of all the elements in the Canvas.

Minimal reproduction of the problem with instructions

Run locally:

  • git clone https://github.com/Vadorequest/poc-nextjs-reaflow.git
  • cd poc-nextjs-reaflow && git checkout repro-textarea-dyn-height
  • yarn && yarn start

Zooming

Add ability to:

  • Zoom In
  • Zoom Out
  • Fit into View
  • Zoom Programmatically through ref
  • Fit view on load
  • Pinch to zoom
  • CTRL+Mouse Wheel to zoom
  • Zoom should center on mouse/pinch center

Should use react-use-gestures

POC with Next.js and feedback

I'm building a POC using Next.js + Reaflow, hosted on Vercel.

It's open source (MIT), see https://github.com/Vadorequest/poc-nextjs-reaflow
Online demo hosted on Vercel at https://poc-nextjs-reaflow.vercel.app/

Here is a little feedback about using Reaflow:

  • framer-motion is a peer-dependency but it's not explicit on the README, I had to figure it out myself. Importing reaflow will crash the whole app if it's not installed.
    • This should be explicitly documented.
  • reaflow doesn't play well on the server (Next.js renders on both server + client) and should only be rendered on the client
    • This should be explicitly documented.
  • foreignObject and events, bad DX, no example (spent quite some time on this)
    • Could have a SB example
    • Using React Select doesn't work It's actually because of foreignObject and CSS display property, need to document how to workaround
    • Add DB demo or documentation as to why it doesn't work, workarounds, etc.

I'll add more feedback as my POC grows.


PR trackings (all the things I wanna do):

Features:

  • โœ๏ธ Initialize Undo/Redo with existing history - ๐ŸŽ‰ PR #69
  • Changing the Undo/Redo API (expose more internal variables + option to disable keyboard shortcuts)
  • โœ… Changing the Edge/Ports component API (adding children) - ๐ŸŽ‰ PR #76

Documentation:

Bug fixes:

  • โœ… TypeScript types (wrong types and inconsistent naming) - ๐ŸŽ‰ PR: #63

Using `foreignObject` "steals" all `Node` events (onEnter, etc.) - How to forward events when using foreignObject?

I'm submitting a...

[x] Other

Current behavior

I'm confused about how foreignObjects are meant to be used. The issue I noticed is foreignObject appear on top of the rect and thus "steals" all events assigned to the rect.

In practice, this means our nodes cannot benefit from the native features such as dragging and creating connections. Also, stuff like focusing/selecting doesn't apply either. (because we're targeting the foreignObject, not the rect)

It's reproductible with the Storybook demo
https://reaflow.dev/?path=/story/demos-nodes--foreign-objects

So, how are we supposed to forward events (onEnter, etc.) from our Node to the underlying foreignObject child?

Events such as onClick can be applied to foreignObject easily, but other like onEnter/onLeave cannot.

Expected behavior

This might be a feature request, or a documentation issue. But how should we make our nodes behave properly when using a foreignObject as children? Ideally, we should still be able to draw connections when using foreignObject.

Also, this is particularly impactful for drag and drop, because onEnter/onLeave can't be used.

Repro

https://reaflow.dev/?path=/story/demos-nodes--foreign-objects

Because foreignObject is being used, it's not possible to create a connection from a node.
When modifying the DOM directly, (inverting react and foreignObject) it's then possible to receive onEnter/onLeave events, but the foreignObject is hidden behind.

Ideas

One way to go around this issue is to have the rect appear on top (after in DOM) of the foreignObject, but make it unclickable (point-events:none or opacity:1) maybe?

Edges/Ports should support `children` property (similar to Nodes)

Currently, the Edge component doesn't support the children property. (or, actually, it does, but does nothing with it)

I think the Edge children should behave similarly to the Nodes, and accept either a component or a function that returns a react component.

I can make a PR for this.

`framer-motion` dependency duplicated in both `dependencies` and `devDependencies`

framer-motion is listed in both. It shouldn't.

image

Maybe it should be listed as peerDependency?

Also, why are react and react-dom listed in devDependencies? Shouldn't they be listed in dependencies instead? (they're peer-dependencies, but aren't optional)

My understanding of peerDependencies might be lacking, but I feel something isn't right there.

Version: 3.0.13

Context Menu

Figure out best way to do a context menu on a node.

Adding a Node between two nodes in group doesn't work as expected

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

upsertNode method doesn't use parent property from first edge when creating new edges, so when you add a Node between the other nodes with a parent - edges disappear from the parent node which is confusing.

Expected behavior

Node adds and edges are updated according to the siblings

Minimal reproduction of the problem with instructions

StackBlitz reproduction

  • Step 1
    Click on plus icon to see the results

What is the motivation / use case for changing the behavior?

Environment


Libs:
- react version: 17.0.1
- reaflow version: 2.6.3


Browser:
- [x] Edge version 87.0.664.75 (Official build) (64-bit)
 

Nuke SCSS

No need for SCSS - just use PostCSS + PostCSS Nested Rules.

Add adjustable padding for nested nodes

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

Currently, nested nodes will have default padding of 50px for all sides
'elk.padding': '[left=50, top=50, right=50, bottom=50]',

Expected behavior

I have some custom node contents and nested nodes are rendered on top of the contents. Currently, I cannot adjust the position of the nested nodes dynamically and therefore I would like to set the padding within the nodeProps.

I will create a PR for this soon, just wanted to have a corresponding ticket.

Zooming using Ref doesn't work right

I can't seem to reproduce this inside the storybook but when I have the following configuration, the zoom doesn't seem to work as expected.

<Canvas
              ref={canvasRef}
              fit={true}
              maxZoom={0}

Default Port Drag

Add ability to pick a port as the default on node shape drag if multiple ports defined.

Feature request - Built-in utility to center the canvas around a node

From #62 (comment)

I'd like to center the canvas on a specific node (not necessarily zoom in/out, but re-center the viewport around the target)

Is there an utility for this? Are there examples for this?

Maybe it'd be built-in and provided through the canvasRef?

Use case: Auto-center on a node, when node is created.

Motivations:

  • When the layout changes (because ELK changes where nodes are displayed), it'd be less confusing because it'd center the canvas around the newly created node (currently, it's confusing because the node is sometimes moved elsewhere after being created)
  • Ease the creation of multiple nodes (in series), because the screen would follow automatically instead of having the user move the canvas around, most efficient on smaller screens.
  • Might help when using autofocus because the created node would always be visible (might avoid the canvas to jump to the starting area) - See #61

Custom Dragging

Add ability to allow users to custom drag around nodes and save the x/y.

onNodeLink is not called for linking multiple nested nodes

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x ] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

onNodeLink is not called for children of nested nodes.

Slightly longer explanation:
When I have two nested nodes, each with child nodes, and I try to draw an edge between child nodes of different parents (in the picture, Child 1.2 -> Child 2.1), onNodeLinkCheck is called, but onNodeLink never gets called. I have verified that I return true from onNodeLinkCheck for these two child nodes.

Expected behavior

The desired behavior is that no matter the nodes, if onNodeLinkCheck returns true, onNodeLink should be called

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

In my application, I only allow linking of parent nodes, so I need to be able to detect if a user is starting/completing an edge from anywhere in a nested node. Currently, the solution works if I do link dragging on the excess space between the child node border and inside of the nested parent border, but that is not intuitive to the user.

Environment


Libs:
- react version: 16.13.1
- realflow version: 2.4.4


Browser:
- [ x ] Chrome (desktop) version 86.0.4240.198
 

Others:

`addNodeAndEdge` fails when `toNode` doesn't exist - Layout Error: Error: org.eclipse.elk.graph.json.JsonImportException: An edge must have a source node

I'm trying to Have one node with two ports.

When clicking on the left port, it should create a node on the left side, and an edge between both nodes.

When clicking on the right port, it should create a node on the right side, and an edge between both nodes.

At this time, creating a node on the right side works as expected, while creating a node on the left side fails with the below error:

react_devtools_backend.js:2430 Layout Error: Error: org.eclipse.elk.graph.json.JsonImportException: An edge must have a source node (edge id: '71c3b121-67f9-11eb-a26e-2df7202d09f2-6be10a00-67f9-11eb-a26e-2df7202d09f2').
    at Dld.Mx [as Wd] (elk.bundled.js?6920:6253)
    at Dld.Sx [as _d] (elk.bundled.js?6920:6253)
    at Dld.Kx (elk.bundled.js?6920:2734)
    at Dld.Vx (elk.bundled.js?6920:1337)
    at new Dld (elk.bundled.js?6920:1385)
    at Fmd (elk.bundled.js?6920:6198)
    at Nld (elk.bundled.js?6920:5092)
    at Bmd (elk.bundled.js?6920:5412)
    at Iqd (elk.bundled.js?6920:5889)
    at h.dispatch (elk.bundled.js?6920:6188)
    at h.saveDispatch (elk.bundled.js?6920:6188)
    at eval (elk.bundled.js?6920:6189)

Here's the code, I basically reverse the fromNode and toNode depending on the port's side.

<Port
  onClick={(event: React.MouseEvent<SVGGElement, MouseEvent>, port: PortData) => {
    const onBlockClick: OnBlockClick = (nodeType: BaseNodeType) => {
      console.log('onBlockClick', nodeType);
      const NodeComponent = nodeType === 'question' ? QuestionNode : InformationNode;
      const newNode = createNodeFromDefaultProps(NodeComponent.getDefaultNodeProps());
      const fromNode: BaseNodeData = port.side === 'EAST' ? newNode : node;
      const toNode: BaseNodeData = port.side === 'EAST' ? node : newNode;
      const results = addNodeAndEdge(cloneDeep(nodes), cloneDeep(edges), fromNode, toNode);
      console.log('addNodeAndEdge fromNode', fromNode, 'toNode', toNode, 'results', results);

      setNodes(results.nodes);
      setEdges(results.edges);
    };

    setBlockPickerMenu({
      isDisplayed: true, // Toggle on click XXX change later, should toggle but not easy to test when toggle is on
      onBlockClick,
    });
  }}
  {...rest}
/>

Here's a screenshot of what happens.

image

After much testing, I'm fairly confident the issue comes from the addNodeAndEdge helper, it probably wasn't intended for this use case.

The results.nodes returned by addNodeAndEdge shows that it tries to add twice the same node id (fromNode), instead of creating the toNode.

Undo/Redo calling history() throws "TypeError: Cannot read property '_history' of undefined"

Current behavior

  const {
    undo,
    redo,
    canUndo,
    canRedo,
    history,
  } = useUndo({
    nodes,
    edges,
    onUndoRedo: (state: UndoRedoEvent) => {
      console.log('Undo / Redo', state);

      setCanvasDataset({
        nodes: state?.nodes || [],
        edges: state?.edges || [],
      });
    },
    maxHistory: Infinity,
  });

  console.log('Undo / Redo history', history());

image

It seems this is undefined.

    history() {
        return this._history;
    }

The other features and functions works correctly, though. Only history() is affected.

Expected behavior

Should return the history.

Version

reaflow 3.0.13

Is there a way to add custom properties to nodes?

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[X ] Other... Please describe:

Is there a way to add custom properties to nodes?

What is the motivation / use case for changing the behavior?

I have different types of nodes, which i would like to display based on their type. I have seen in one example that i could differentiate via the id - but this is not feasible in my case. By providing a type property to the node, i could style the nodes independently. Also, i need to trigger different functionality when i interact with the nodes based on their types.

Using `autofocus=true` in textarea within `foreignObject` causes the viewport to jump when there are many nodes

I'm submitting a...

[x] Bug report

Current behavior

https://youtu.be/CtXphmb_Nkk

I'm trying to use autofocus={true} in a textarea. It works fine at the beginning, but when there are too many nodes created then the viewport jumps back to the left (maybe it tries to center the viewport?)

I'm not sure what's causing this, seems to happen when the input that is being autofocused isn't visible in the viewport.

Expected behavior

It should center the viewport onto the newly created element.

Or maybe I could force centering the right element?

version

Reaflow 3.0.8

Fix edge position when dragging from node

When you drag from a node w/ a port it puts the arrow in the middle.

image

however if you drag from the port itself it works as expected.

image

this is because the position is coming from the port itself rather than a calculated position. Need to figure out how to make react-use-gesture use that instead of the elm itis using.

Links in code of a storybook story contains "random" links

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[] Bug report  
[ ] Performance issue
[ ] Feature request
[X] Documentation issue or request
[ ] Other... Please describe:

Current behavior

In the code section of stories, there are links to other stories, which not really make sense to me. So if I inspect code and want to copy it, the links are kind of annoying.

Expected behavior

The code of a story should not link into other stories.

Minimal reproduction of the problem with instructions

  1. Navigate to https://reaflow.dev/?path=/story/demos-nested--nested-edges
  2. Checkout the code and see links into other stories

grafik

I wrote this story in the documentation myself and this behaviour seems to come from storybook - not from the actual story code.

Minimap

Make a mini-map for navigation

React select component displays/hides itself randomly (as `foreignObject`)

I'm submitting a...

[x] Bug report

The https://react-select.com/ component doesn't display properly when used as a foreignObject.

Current behavior

Self-explaining: https://youtu.be/sdxopzlwOlI

Live demo: https://poc-nextjs-reaflow-cyvd75jn0.vercel.app/
(need to create Question block)

Expected behavior

Should display properly and allow using controls.

Reproduction

import Select from 'react-select';

...

const choiceTypes = [
  {
    value: `text`,
    label: `Text`,
  },
  {
    value: `single-quick-reply`,
    label: `Single quick reply`,
  },
];
const [selectedChoiceType, setSelectedChoiceType] = useState<OptionTypeBase | undefined>(undefined);

return(
	  <foreignObject
	    width={500}
	    height={500}
	    x={0}
	    y={0}
	  >
	    <Select
	      className={'select select-simple'}
	      isMulti={false}
	      value={selectedChoiceType}
	      options={choiceTypes}
	      onChange={(selectedChoice: OptionTypeBase, action: { action: string }): void => {
	        setSelectedChoiceType(selectedChoice);
	      }}
	    />
	  </foreignObject>
);

See code: https://github.com/Vadorequest/poc-nextjs-reaflow/blob/e667230cdaeab25360576e66d92ddb9ff3cada5e/src/components/nodes/QuestionNode.tsx#L127-L135

Version

Using reaflow 3.0.2

Feature request - Initialize Undo/Redo with existing history

It'd be great to be able to load an external history upon initializing the undo/redo feature.

It's already supported by the Undoo lib, through the import(history) API, so it should be trivial to implement.
https://github.com/fabioricali/undoo#undooimporthistory--undoo

I suppose changing the UndoProps by adding a initialHistory prop would do the trick:

export interface UndoProps {
  nodes: NodeData[];
  edges: EdgeData[];
  maxHistory?: number;
  disabled?: boolean;
  onUndoRedo: (state: UndoRedoEvent) => void;
  initialHistory?: { nodes: NodeData[]; edges: EdgeData[]};
}

And then, instead of

const manager = useRef<Undoo>(
new Undoo({
maxLength: maxHistory
})
);
:

  const undoo = new Undoo({
      maxLength: maxHistory
    });

  const manager = useRef<Undoo>(undoo);
  manager.import({nodes, edges});

I guess that'd be it?

Port Alignment Support

At this time, the Port type only supports the alignment='CENTER'.

export interface PortData {
  /**
   * Unique ID of the port.
   */
  id: string;

  /**
   * Port is disabled.
   */
  disabled?: boolean;

  /**
   * Height of the port.
   */
  height: number;

  /**
   * Width of the port.
   */
  width: number;

  /**
   * Whether the port is visually hidden or not.
   */
  hidden?: boolean;

  /**
   * Classname for the port.
   */
  className?: string;

  /**
   * Alignment of the port.
   */
  alignment?: 'CENTER';

  /**
   * Side the port is located.
   */
  side: PortSide;
}

It'd be great if the alignment would support more modes (top, bottom, etc.).
Alternatively, a fixed mode where we could set the % relative to one of the borders would be great. Something like alignment: 'FIXED' and alignmentMargin: '75%'

Feature request - Add children to `Add` component - Or another way to create a component at the same position

I could really use a menu when clicking on a connection Add component.

image

When clicking on "+", display a custom component.

Here's what I've done for now instead:
image

Right now, I'm displaying a list of components at the bottom to pick from, but it's not so easy:

  • I decided to use an absolute position, but ideally, I'd prefer to display this at the spot it was clicked. But, I don't know what are the x/y of the "Add" (they're not exposed). Even though they were exposed, I'd have a hard time converting it to an absolute css position (top/left/bottom/right).
  • Using an absolute position is easier. I thought about using another element within the canvas, but that'd have to be a node, right? And this doesn't really make sense, it'd be some kind of temporary node ๐Ÿค” and it'd move all other nodes/edges upon display. So, using something displayed in absolute position seemed better.

Eventually, what I'm trying to achieve is something of the sort: https://youtu.be/frihIydsxAg
Basically, click on the Add element, display a menu, click on an element and get the new node added.

I feel like I can't do this at this time because:

  • Add doesn't allow defining children, this might be the easiest way to position an element in the Canvas at the right position, that displays on top of other elements and wouldn't need to redraw the whole canvas.
  • Expose x/y in the onAdd of the Edge component
    • Current signature is onAdd?: (event: React.MouseEvent<SVGGElement, MouseEvent>, edge: EdgeData) => void;, might become something like onAdd?: (event: React.MouseEvent<SVGGElement, MouseEvent>, edge: EdgeData, meta: { x:number; y:number }) => void;

I don't think I can easily achieve the above at this time.
Would it make sense to add native support for this?

Collapse Nodes

Add ability to expand/collapse nodes ( collapsing a node, should collapse its children )

Is there a public roadmap?

Is there a roadmap somewhere? What are your plans regarding this library? Are there things you need help on?

I'm gonna do a POC using Next.js, I haven't tried your lib yet. ๐Ÿ˜ƒ

Rendering parent node label when using nested nodes

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

I can't seem to find a way of rendering labels for the parent node of a nested node.

Expected behavior

A label should be displayed for the parent node.

What is the motivation / use case for changing the behavior?

Having a label on a parent node is quite a common use case when using graphs for documenting for instance cloud infrastructure

Edges towards nested Nodes are rendered behind the parent Node

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[X] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Current behavior

Edges to nested nodes are rendered behind the parent of the nested Node. If the parent node has a fill, the edge is hidden.

Expected behavior

Edges should be always rendered at the very front.

Minimal reproduction of the problem with instructions

Note, that the fill has some opacity to visualize the problem. This example will be in the storybook in the docs soon (#30).
grafik

Code to reproduce:

const nodeDimensions : any = {
    typeA: {
      width: 190,
      height: 150
    },
    typeB:{
      width: 80,
      height: 80
    }
  }
  
const nodes: NodeData[]= [
    { 
      id: '1', 
      text: '1',
    },
    { 
      id: '2',
      label: 'A',
      name: 'Process XYZ',
      description: 'Description of XYZ',
      // describes padding for nested nodes
      nodePadding: [120, 50, 50, 50],
      ...nodeDimensions.typeA
    },
    { 
      id: '2.1',
      parent: '2',
      label: 'B',
      name: 'Task 1',
      ...nodeDimensions.typeB
    },
    { 
      id: '2.2', 
      parent: '2', 
      label: 'B',
      name: 'Task 2',
      ...nodeDimensions.typeB
    },
    { 
      id: '3',
      text: '3'
    }
  ];`

const edges: EdgeData[] = [
    {
      id: '1-2.1', 
      from: '1', 
      to: '2.1' 
    }, 
    { 
      id: '2.1-2.2', 
      parent: '2',
      from: '2.1', 
      to: '2.2' 
    }, 
    { 
      id: '2.2-3', 
      from: '2.2', 
      to: '3' 
    },
  ];

function prepareNode(node){
    const data = node.properties;
    switch (data.label){
      case 'A':
        return (
          <Node style={{fill: 'lightgreen', opacity: 0.8}}>
            <div style={{textAlign: "center"}}>
              <h4>{data.name}</h4>
              <p>{data.description}</p>
            </div>
          </Node>
        )
      case 'B':
        return (
          <Node style={{fill: 'lightyellow'}}>
            <div style={{textAlign: "center"}}>
              <h4>{data.name}</h4>
            </div>
          </Node>
        )
      default:
        return (
          <Node/>
        )
    }
  }

return (
    <div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
      <Canvas
        // required to enable edges from/to nested nodes
        layoutOptions={{'elk.hierarchyHandling':'INCLUDE_CHILDREN'}}
        direction='RIGHT'
        nodes={nodes}
        edges={edges}
        node={(node: NodeProps) => prepareNode(node)}
      />
    </div>
  );

Undo doesn't handle mass undos, history gets partially lost

I'm submitting a...

[x] Bug report

Current behavior

When using undo/redo, when using the cmd+z shortcut, if we keep pressing on it then the history gets messed up somehow and we cannot do cmd+shift+z more than once/twice.

When doing cmd+z multiple time (not spamming) then it works as expected.

Expected behavior

It should work the same way whether spamming cmd+z or not.

Environment

reaflow 3.0.5

Draw edge to nested node from other hierarchy level

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[] Other... Please describe:

Is there a way to draw edges to nested nodes as in the elk docs?

Current behavior

Providing the nested node as edge target does not work - the edge will not show.

Expected behavior

Would be best to just provide the id of the node and edges are automatically also drawn towards nested elements.

Example

nodes={[
  {
    id: '1',
    text: '1'
  },
  {
    id: '2',
    text: '2'
  },
  {
    id: '2.1',
    text: '2.1',
    parent: '2'
  },
  {
    id: '3',
    text: '3'
  }
]}
edges={[
  {
    id: '1-2',
    from: '1',
    to: '2.1'
  },
  {
    id: '2-3',
    from: '2',
    to: '3'
  }
]}

image

What is the motivation / use case for changing the behavior?

I would like to display nested nodes within one node and nodes from the "outside" should directly impact these nested nodes. Therefore, I need to display a direct edge towards the nested nodes.

Since we provide a parents (and no children) property, maybe we should resolve this by using the id of the nested node directly. ELKs approach is to traverse by the parents until the child is reached like edge source -> outside.inside.n1, but i think their approach is not feasible for us, no?

@amcdnl could you share some thoughts on this? If you think this is a good "first ticket", i will try to implement it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.