Skip to content

Commit

Permalink
allow middle click on nodes to go through
Browse files Browse the repository at this point in the history
  • Loading branch information
tlr committed Dec 8, 2024
1 parent 31ccec1 commit 0ac6152
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Dropped vue 2 support
- Improved ports offset calculation method
- Fixed ports continuous updates by using a computed property instead to trigger updates
- Allow middle click on nodes to go through
- Other - default drag threshold reduced to 2
- simplified nodes and groups structure (less divs)
- removed margin from groups and nodes as its no longer needed
Expand Down
93 changes: 58 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# vnodes
# Vnodes

Vue components to create svg interactive graphs, diagrams or node visual tools.

Expand All @@ -12,19 +12,36 @@ https://tiagolr.github.io/vnodes/
npm install vnodes
```

## Vnodes 2.0 is here!

With 2.0 the rendering method was changed, instead of having foreignObjects inside svg, the `screen` now uses different layers for svg and html while sinchronizing the transforms between them. This fixes issues with Safari that were partially patched by @metanas, the layout of nodes becomes simpler as there is no need to account for margins, clipping, lack of support of absolute positioning inside nodes or opacity in browsers based on WebKit.

Markers were also revamped among other changes, see CHANGELOG for more details.

### Get started
```html
<template>
<screen ref="screen">
<edge v-for="edge in graph.edges" :data="edge" :nodes="graph.nodes" :key="edge.id">
</edge>

<!-- html can be placed inside node, defaults to <div>{{node.id}}</div> -->
<node v-for="node in graph.nodes" :data="node" :key="node.id">
</node>
<!-- svg content can be placed in #edges template -->
<template #edges>
<edge v-for="edge in graph.edges" :data="edge" :nodes="graph.nodes" :key="edge.id">
</edge>
</template>

<!-- html content can be placed on #nodes template -->
<template #nodes>
<!-- nodes can have any html content, defaults to <div>{{node.id}}</div> -->
<node v-for="node in graph.nodes" :data="node" :key="node.id">
</node>
</template>
</screen>
</template>
```

Previously all svg and html nodes were placed inside screen default slot, in 2.0 that changed and it uses different layers for different types like `#nodes` (html), `#edges` (svg) and `#overlay` (svg).

The rest of the API remains the same but there were a few minor tweaks and changes.

```js
import { Screen, Node, Edge, graph } from 'vnodes'
export default {
Expand All @@ -49,15 +66,15 @@ export default {

## Components

Components are independent and can be imported separately.

### Screen

Svg wrapper with zoom, panning and other features.
Main container of html and svg content, handles zoom panning and applies the same transforms to all its layers.

```html
<screen>
<circle cx="50" cy="50" r="50" fill="red"/>
<template #edges>
<circle cx="50" cy="50" r="50" fill="red"/>
</template>
</screen>
```

Expand All @@ -66,7 +83,9 @@ Screen component uses [svg-pan-zoom](https://www.npmjs.com/package/svg-pan-zoom)
and screen takes options prop like this
```html
<screen :options="options">
<circle cx="50" cy="50" r="50" fill="red"/>
<template #edges>
<circle cx="50" cy="50" r="50" fill="red"/>
</template>
</screen>
```
you can refer to available options [here](https://www.npmjs.com/package/svg-pan-zoom#how-to-use)
Expand Down Expand Up @@ -98,25 +117,24 @@ you can refer to available options [here](https://www.npmjs.com/package/svg-pan-

### Node

Html wrapper for svg with additional features like, dragging and fitting contents.

Div containers with handlers for data updates based on dimensions and positioning, also provides dragging by default which can be disabled.

```html
<svg width="500" height="500">
<node :data="{
<node :data="{
id: 'test',
x: 100,
y: 100,
width: 250,
height: 150}">
<h1>My First Node!</h1>
</node>
</svg>
height: 150
}"
>
<h1>My First Node!</h1>
</node>
```

### Edge

Connects nodes using svg lines
Connects nodes using svg paths

```html
<edge :data="{
Expand Down Expand Up @@ -176,7 +194,7 @@ Surrounds a group of nodes with a rectangle, allows dragging multiple nodes.

### Port

Placed inside a node, automatically offsets edges to a their position inside the nodes html [Ports demo].
Placed inside a node, automatically offsets edges to a their position inside the nodes.

### Label

Expand Down Expand Up @@ -214,16 +232,21 @@ svg .edge {

### Markers

TODO
routing orth manh metro https://resources.jointjs.com/demos/routing
theme apply demo
markers demo
groups demo
edge api review
graph tools, nodes containing edge refs or adj list etc
graph layouts https://www.yworks.com/products/yfiles/features#layout
layered layouts https://github.com/erikbrinkman/d3-dag
layered layouts https://www.yworks.com/pages/layered-graph-layout
css animations demo/theme https://www.yworks.com/products/yfiles/features
https://www.edrawmax.com/online/en/
https://js.cytoscape.org/
There are two ways to create makers for eges, one is using [SVG markers](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/marker), creating definitions `<defs></defs>` in `#edges` slot and then assign them to edges using CSS. This was the previous default method of using markers.

In 2.0 the old markers helper was removed and a new `Marker.vue` component was added that provides embed svg markers which are a lot more versatile, here is how it can be used:

```html
<screen ref="screen">
<template #edges>
<edge v-for="edge in edges" :data="edge" :nodes="graph.nodes" :key="edge.id">
</edge>
<v-marker v-for="edge in edges" :edge="edge" :perc="100">
<rect x="0" y="0" width="10" height="10" :fill="markerColor">
</v-marker>
</template>
</screen>
```

The marker can be any svg content, the component handles rotations and translations to the correct place along the edge given a percentage `perc` and the edge to place on.
The svg content should be centered at the origin for the transforms to work properly, the `offset` property can be used to correct alignments.
11 changes: 7 additions & 4 deletions src/components/Group.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
class="node-group"
@mousedown="onMousedown"
@mousedown.left="onMousedown"
:style="groupStyle"
>
<slot>
Expand All @@ -25,7 +25,10 @@ export default {
type: Object,
default: () => ({ left: 10, right: 10, top: 10, bottom: 10 })
},
disableDrag: Boolean,
useDrag: { // use default drag behavior
type: Boolean,
default: true
},
},
computed: {
minX: vm => !vm.nodes.length ? 0 : vm.nodes.reduce((acc, node) => Math.min(acc, node.x), Infinity),
Expand Down Expand Up @@ -56,8 +59,8 @@ export default {
})
},
onMousedown (e) {
e.stopPropagation()
if (!this.disableDrag) {
if (this.useDrag) {
e.stopPropagation()
e.preventDefault();
this.startDrag(e);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Node.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
class="node"
@mousedown="onMousedown"
@mousedown.left="onMousedown"
@touchstart="onMousedown"
:style="nodeStyle"
>
Expand Down
1 change: 1 addition & 0 deletions src/components/Screen.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default {
zoomScaleSensitivity: 0.4,
minZoom: 0.1,
maxZoom: 5,
eventsListenerElement: this.$el,
onZoom: zoom => this.$emit('zoom', zoom),
onPan: pan => this.$emit('pan', pan),
onUserZoom: e => this.$emit('user-zoom', e),
Expand Down

0 comments on commit 0ac6152

Please sign in to comment.