Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 270 additions & 6 deletions build/NetV.js

Large diffs are not rendered by default.

100 changes: 42 additions & 58 deletions build/NetV.min.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions examples/arrow/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title>
</head>

<body>
<div id="main"></div>
</body>
<script src="../../build/NetV.js"></script>
<script src="index.js"></script>

</html>
48 changes: 48 additions & 0 deletions examples/arrow/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @author Xiaodong Zhao <zhaoxiaodong@zju.edu.cn>
* @description arrow example
*/
const testData = {
nodes: [
{
id: '0',
x: 300,
y: 100
},
{
id: '1',
x: 500,
y: 100
},
{
id: '2',
x: 400,
y: 400
}
],
links: [
{
source: '0',
target: '2',
style: {
arrowType: '->',
}
},
{
source: '1',
target: '2',
style: {
arrowType: '<-',
arrowOffset: 15,
arrowSize: 5,
arrowColor: { r: 0.8, g: 0.5, b: 0.2, a: 1 }
}
}
]
}

const netv = new NetV({
container: document.getElementById('main')
})
netv.data(testData)
netv.draw()
6 changes: 5 additions & 1 deletion src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export const link = {
style: {
shape: 'line',
strokeColor: { r: 0.4, g: 0.6, b: 0.8, a: 0.5 },
strokeWidth: 2
strokeWidth: 2,
arrowType: '-', // '-', '->', '<-', '<->' bidirectional not supported now
arrowColor: { r: 0.4, g: 0.6, b: 0.8, a: 1 },
arrowSize: 3,
arrowOffset: 15
}
}
15 changes: 13 additions & 2 deletions src/elements/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,19 @@ export default class Element {
})
}

const renderManager = this.$_core.$_renderer[`${type}Manager`]
this.$_changeRenderAttribute = renderManager.changeAttribute.bind(renderManager)
// TODO: Hard code. Is this OK? This's not OK.
let renderManagers = []
if (type === 'node') {
renderManagers = [this.$_core.$_renderer.nodeManager]
} else if (type === 'link') {
renderManagers = [
this.$_core.$_renderer.linkManager,
this.$_core.$_renderer.arrowManager
]
}
this.$_changeRenderAttribute = (...args) => {
renderManagers.forEach((manager) => manager.changeAttribute(...args))
}

// generate style methods, e.g.: node.r(), link.strokeWidth()
Object.keys(this.$_style).forEach((key) => {
Expand Down
5 changes: 4 additions & 1 deletion src/elements/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ class Link extends Element {
public shape: (value?: interfaces.LinkShape) => interfaces.LinkShape
public strokeWidth: (value?: number) => number
public strokeColor: (value?: interfaces.Color) => interfaces.Color
public arrowColor: (value?: interfaces.Color) => interfaces.Color
public arrowSize: (value?: number) => number
public arrowOffset: (value?: number) => number
public arrowType: (value?: interfaces.LinkArrowType) => interfaces.LinkArrowType

public $_source: Node
public $_target: Node

private $_elementReservedKeys = new Set(['source', 'target', 'style'])

public constructor(core, linkData: interfaces.LinkData) {
super(core, linkData)

Expand Down
1 change: 1 addition & 0 deletions src/elements/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class Node extends Element {
this.$_core.$_renderer.increaseModifiedElementsCountBy(set.size)
for (const link of set) {
this.$_core.$_renderer.linkManager.changeAttribute(link, key)
this.$_core.$_renderer.arrowManager.changeAttribute(link, key)
}
}
})
Expand Down
1 change: 1 addition & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface NodeData {
}

export type LinkShape = 'line'
export type LinkArrowType = '-' | '->' | '<-'

export interface LinkStyle {
shape?: LinkShape
Expand Down
133 changes: 133 additions & 0 deletions src/renderer/elements/render-arrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/**
* @author Xiaodong Zhao <zhaoxiaodong@zju.edu.cn>
* @description Link used in renderer
*/
import { LinkManagerConfigs, ShaderSeries } from '../interfaces'
import Link from '../../elements/link'
import { RenderElementManager } from './render-element'

export class RenderArrowManager extends RenderElementManager {
/**
* create render arrow manager
* @param gl WebGL context
* @param params nessesary configs for arrow manager
* @param idTexture texture store elements id of each pixel
*/
public constructor(
gl: WebGL2RenderingContext,
params: LinkManagerConfigs,
shaders: ShaderSeries,
idTexture: WebGLTexture
) {
super(
/* webgl context */ gl,
// prettier-ignore
/* parameters */ {...params, instanceVerteces: [
-0.5, 0.5, 1.0,
-0.5, -0.5, 1.0,
0.5, 0., 1.0,
]},
/* shader series */ {
...shaders
},
/* idTexture */ idTexture
)
this.renderIdToElement = {}

this.attributes.forEach((attr) => {
if (attr.name === 'in_source') {
attr.extractAttributeValueFrom = (link: Link) => {
const sourcePosition = link.source().position()
return [sourcePosition.x, sourcePosition.y]
}
} else if (attr.name === 'in_target') {
attr.extractAttributeValueFrom = (link: Link) => {
const targetPosition = link.target().position()
return [targetPosition.x, targetPosition.y]
}
} else if (attr.name === 'in_strokeWidth') {
attr.extractAttributeValueFrom = (link: Link) => {
return [link.strokeWidth() * this.pixelRatio]
}
} else if (attr.name === 'in_color') {
attr.extractAttributeValueFrom = (link: Link) => {
const strokeColor = link.arrowColor()
return [strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a]
}
} else if (attr.name === 'in_size') {
attr.extractAttributeValueFrom = (link: Link) => {
const arrowSize = link.arrowSize()
return [arrowSize]
}
} else if (attr.name === 'in_offset') {
attr.extractAttributeValueFrom = (link: Link) => {
const arrowOffset = link.arrowOffset()
return [arrowOffset]
}
} else if (attr.name === 'in_type') {
attr.extractAttributeValueFrom = (link: Link) => {
const arrowType = link.arrowType()
if (arrowType === '->') return [1]
else if (arrowType === '<-') return [2]
else return [0]
}
}
})
}

/**
* refresh all position of edges
* @param links all link data
*/
public refreshPosition(links: Link[]) {
let count = 0 // TODO: useless count
links.forEach((link, i) => {
// TODO: consider link and render link attribute mapping
const source = link.source()
const sourcePosition = source.position()
this.attributes.get('in_source').array[2 * (count + i)] = sourcePosition.x
this.attributes.get('in_source').array[2 * (count + i) + 1] = sourcePosition.y

const target = link.target()
const targetPosition = target.position()
this.attributes.get('in_target').array[2 * (count + i)] = targetPosition.x
this.attributes.get('in_target').array[2 * (count + i) + 1] = targetPosition.y

// currently no need for color&renderId change
/*
this.attributes[LinkAttrKey.WIDTH].array[this.count + i] =
link.strokeWidth() * this.pixelRatio

const color = link.strokeColor()
this.attributes[LinkAttrKey.COLOR].array[4 * (this.count + i)] = color.r
this.attributes[LinkAttrKey.COLOR].array[4 * (this.count + i) + 1] = color.g
this.attributes[LinkAttrKey.COLOR].array[4 * (this.count + i) + 2] = color.b
this.attributes[LinkAttrKey.COLOR].array[4 * (this.count + i) + 3] = color.a

const renderIdColor = encodeRenderId(2 * (this.count + i) + 1) // NOTE: link render id, use odd integer
this.idAttributes.get('in_id').array[4 * (this.count + i)] = renderIdColor.r
this.idAttributes.get('in_id').array[4 * (this.count + i) + 1] = renderIdColor.g
this.idAttributes.get('in_id').array[4 * (this.count + i) + 2] = renderIdColor.b
this.idAttributes.get('in_id').array[4 * (this.count + i) + 3] = renderIdColor.a
*/
})

const sourceAttr = this.attributes.get('in_source')
const targetAttr = this.attributes.get('in_target')

const arr = [sourceAttr, targetAttr]

arr.forEach((attr) => {
if (!attr.isBuildIn) {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, attr.buffer)
this.gl.bufferSubData(
this.gl.ARRAY_BUFFER,
attr.size * count * attr.array.BYTES_PER_ELEMENT,
attr.array,
attr.size * count,
attr.size * links.length
)
}
})
}
}
9 changes: 8 additions & 1 deletion src/renderer/elements/render-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,14 @@ export class RenderElementManager {
})
}

this.gl.drawArraysInstanced(this.gl.TRIANGLE_STRIP, 0, 4, this.count)
// TODO: need more proper way to get this attribute
const instanceAttribute = this.attributes.get('inVertexPos')
this.gl.drawArraysInstanced(
this.gl.TRIANGLE_STRIP,
0,
instanceAttribute.array.length / instanceAttribute.size,
this.count
)

// draw id
this.gl.blendFunc(this.gl.ONE, this.gl.ZERO)
Expand Down
24 changes: 23 additions & 1 deletion src/renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

import * as nodeShaders from './shaders/node-shader'
import * as linkShaders from './shaders/link-shader'
import * as arrowShaders from './shaders/arrow-shader'
import { RenderNodeManager } from './elements/render-node'
import Node from '../elements/node'
import Link from '../elements/link'
import { RenderLinkManager } from './elements/render-link'
import { RenderArrowManager } from './elements/render-arrow'
import { Transform, Position } from '../interfaces'
import { RendererConfigs } from './interfaces'
import { Color } from '../interfaces'
Expand All @@ -19,6 +21,7 @@ const MODIFIED_ELEMENTS_COUNT_UPPER_THRESHOLD = 100 // when modifiedElementCount
export class Renderer {
public nodeManager: RenderNodeManager
public linkManager: RenderLinkManager
public arrowManager: RenderArrowManager

public modifiedElementsCount = 0 // record modified link num to control lazy update
public shouldLazyUpdate = false // flag to control lazy update
Expand Down Expand Up @@ -77,6 +80,13 @@ export class Renderer {
idFragment: linkShaders.idFragment.connect()
}

const arrowShaderSeriels = {
vertex: arrowShaders.vertex.connect(),
fragment: arrowShaders.fragment.connect(),
idVertex: arrowShaders.idVertex.connect(),
idFragment: arrowShaders.idFragment.connect()
}

this.nodeManager = new RenderNodeManager(
this.gl,
{ width, height, limit: nodeLimit },
Expand All @@ -89,6 +99,13 @@ export class Renderer {
linkShaderSeriels,
this.idTexture
)

this.arrowManager = new RenderArrowManager(
this.gl,
{ width, height, limit: linkLimit },
arrowShaderSeriels,
this.idTexture
)
}

/**
Expand Down Expand Up @@ -140,11 +157,13 @@ export class Renderer {
*/
public addLinks(links: Link[]) {
this.linkManager.addData(links)
this.arrowManager.addData(links)
}

public setTransform(transform: Transform) {
this.nodeManager.setTransform(transform)
this.linkManager.setTransform(transform)
this.arrowManager.setTransform(transform)
}

/**
Expand All @@ -155,7 +174,9 @@ export class Renderer {
// TODO: not only position needs to be refreshed, but also other styles
this.nodeManager.refreshPosition(this.getAllNodes())

this.linkManager.refreshPosition(this.getAllLinks())
const links = this.getAllLinks()
this.linkManager.refreshPosition(links)
this.arrowManager.refreshPosition(links)
this.shouldLazyUpdate = false
this.modifiedElementsCount = 0
}
Expand All @@ -173,6 +194,7 @@ export class Renderer {
)
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
this.linkManager.draw()
this.arrowManager.draw()
this.nodeManager.draw()
}

Expand Down
Loading