Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reimplement Image Icon's in v7 & FontBook class #80

Merged
merged 48 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
be5e058
add ImageIcon to icon class
mggower Nov 2, 2023
c733b63
fix reference bug when updating label background size
mggower Nov 2, 2023
642982a
include image icon in label example
mggower Nov 2, 2023
5291690
generate FontBook class with static methods for installing bitmap fonts
mggower Nov 2, 2023
e6e8b9f
implement FontBook class to manage font loading
mggower Nov 3, 2023
f2538de
use consistent variable names in Icon class
mggower Nov 6, 2023
7383173
use FontFaceObserver to load browser fonts
mggower Nov 7, 2023
ad2ec78
use PIXI.Assets to load image icons
mggower Nov 7, 2023
36c0b98
fix large render perf bug with promises
mggower Nov 8, 2023
94fc274
cache image icon promises
mggower Nov 8, 2023
4c6ebb1
cleanup assets PR
mggower Nov 8, 2023
616906c
consider label bounds when culling offscreen nodes
mggower Nov 6, 2023
7d4dbe4
bugfix: reset transformed property on label
mggower Nov 6, 2023
87766f1
adress pr feedback
mggower Nov 17, 2023
cf58e98
resolve perf issues with `getBounds` from label
mggower Nov 17, 2023
921a732
improve issues with BitmapText placement
mggower Nov 17, 2023
56bc075
Bump msgpackr from 1.9.9 to 1.10.1
dependabot[bot] Dec 28, 2023
b98942f
Bump vite from 4.5.0 to 4.5.2
dependabot[bot] Jan 20, 2024
bd44cfe
add async util
jameslaneconkling Feb 5, 2024
a11a6b7
add in FontLoader and AssetLoader to reduce promises
mggower Feb 5, 2024
e066662
AssetLoader to manage all asset loading
mggower Feb 6, 2024
8929bcc
implement FontLoader for node labels
mggower Feb 6, 2024
cb1b30d
implement asset loading on node icon
mggower Feb 6, 2024
a038c64
implement edge labels
mggower Feb 6, 2024
fb086f0
remove loaders from FontBook
mggower Feb 6, 2024
2c9db14
Merge branch 'feature/assets' into feature/label-culling
mggower Feb 6, 2024
96093f1
perf improvements on label culling
mggower Feb 6, 2024
0f8c540
remove label bounds utils
mggower Feb 6, 2024
52c95b8
clean up label/background methods+utils
mggower Feb 7, 2024
ca17d3d
cleanup node methods
mggower Feb 7, 2024
b90730b
Merge pull request #83 from sayari-analytics/feature/label-culling
jameslaneconkling Feb 12, 2024
06df657
types/ and utils/ directory to organize export entry
mggower Feb 8, 2024
9c8fe9e
update object types
mggower Feb 8, 2024
55d814e
init: TextTexture + Text object to replace Label
mggower Feb 8, 2024
0010ec3
replace Label class with Text class to be used for other use cases
mggower Feb 9, 2024
8a253d0
manage font loading in `Text`
mggower Feb 9, 2024
be3a5d7
load assets in Icon class
mggower Feb 9, 2024
909fbfe
cancel method in `Text` to unsubscribe
mggower Feb 9, 2024
fcc0949
align TextIcon with TextStyle
mggower Feb 9, 2024
cc24ebf
standardize interface for textures with `Texture` type
mggower Feb 12, 2024
47d3fa6
reduce list of generic font families
mggower Feb 12, 2024
97c8d56
include loading state and enable `cancel` method on loaders
mggower Feb 12, 2024
dd327fe
fix return type on `image` method
mggower Feb 12, 2024
3c8cab0
Merge pull request #97 from sayari-analytics/feature/text
mggower Feb 12, 2024
2adc49e
resolve conflicts
mggower Feb 12, 2024
cd1067f
standardize render object lifecycle and mounting patterns
mggower Feb 12, 2024
ad0ba22
address Text perf rendering issues
mggower Feb 12, 2024
86576a6
sync applyLabel in node/edge renderers
mggower Feb 13, 2024
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
2 changes: 2 additions & 0 deletions examples/assets/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const person = `data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTZweCIgaGVpZ2h0PSIxNnB4IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogc2tldGNodG9vbCA2My4xICgxMDEwMTApIC0gaHR0cHM6Ly9za2V0Y2guY29tIC0tPgogICAgPHRpdGxlPkNDNEQ2NkYzLTg3QTktNEIxQy1CRjNBLUMwQUY0RjQ5OTM1MTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggc2tldGNodG9vbC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNOCwtNS4wMDAwMDAwNmUtMDggQzEwLjI5NzUwNDYsLTUuMDAwMDAwMDZlLTA4IDEyLjE2LDEuODYyNDk1NCAxMi4xNiw0LjE1OTk5OTk4IEMxMi4xNiw2LjQ1NzUwNDU1IDEwLjI5NzUwNDYsOC4zMiA4LDguMzIgQzUuNzAyNDk1NDMsOC4zMiAzLjgzOTk5OTk3LDYuNDU3NTA0NTUgMy44Mzk5OTk5Nyw0LjE1OTk5OTk4IEMzLjgzOTk5OTk3LDEuODYyNDk1NCA1LjcwMjQ5NTQzLC01LjAwMDAwMDA2ZS0wOCA4LC01LjAwMDAwMDA2ZS0wOCBaIE04LDAuOTk5OTk5OTU2IEM2LjI1NDc4MDE4LDAuOTk5OTk5OTU2IDQuODM5OTk5OTgsMi40MTQ3ODAxNiA0LjgzOTk5OTk4LDQuMTU5OTk5OTggQzQuODM5OTk5OTgsNS45MDUyMTk4IDYuMjU0NzgwMTgsNy4zMiA4LDcuMzIgQzkuNzQ1MjE5ODEsNy4zMiAxMS4xNiw1LjkwNTIxOTggMTEuMTYsNC4xNTk5OTk5OCBDMTEuMTYsMi40MTQ3ODAxNiA5Ljc0NTIxOTgxLDAuOTk5OTk5OTU2IDgsMC45OTk5OTk5NTYgWiBNOCw5LjYwMDAwMDAxIEMxMS41OTI1NTI4LDkuNjAwMDAwMDEgMTQuMjIyNzIzOCwxMS4yNDk2MjM1IDE1Ljg5MDUxMywxNC41NDg4NzA2IEMxNS45NjEyMTg2LDE0LjY4ODc0MTUgMTUuOTk4MDU3MywxNC44NDMyNzM2IDE1Ljk5ODA1NzMsMTUgQzE1Ljk5ODA1NzMsMTUuNTEyODIzMyAxNS42MTIwMjY2LDE1LjkzNTQ4NDQgMTUuMTE0NywxNS45OTMyNjc2IEwxNC45OTgwODE3LDE2LjAwMDAwMDEgTDEuMDAxNDIxNjQsMTYuMDAwMDAwMSBDMC44NDQ2NTczODUsMTYuMDAwMDAwMSAwLjY5MDA4ODgzNCwxNS45NjMxNDQ4IDAuNTUwMTkwODEzLDE1Ljg5MjQwODggQzAuMDU3MzE5OTIwNCwxNS42NDMyMDA5IC0wLjE0MDIwNzk1NiwxNS4wNDE2MjcyIDAuMTA5MDExNDIxLDE0LjU0ODc2MjEgQzEuNzc3MTU3MDYsMTEuMjQ5NTg3NCA0LjQwNzQ4NjU5LDkuNjAwMDAwMDEgOCw5LjYwMDAwMDAxIFogTTgsMTAuNiBDNC44OTE3MDY2OSwxMC42IDIuNjQ5NDIyNzgsMTEuOTQzMzQ2MiAxLjE0ODk4NjUzLDE0LjcxNzc5IEwxLjAwMTk5OTk2LDE0Ljk5OSBMMTQuOTk4MDM3NiwxNSBMMTQuODUwNTE4MSwxNC43MTc3OTI5IEMxMy4zNTA0MTI1LDExLjk0MzM0NzUgMTEuMTA4MzAyMywxMC42IDgsMTAuNiBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkVudGl0eS9wZXJzb25fcmVndWxhciI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgIDwvbWFzaz4KICAgICAgICAgICAgPHVzZSBpZD0icGVyc29uIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8ZyBpZD0iY29sb3JzL2FhX2ljb25fZGFyayIgbWFzaz0idXJsKCNtYXNrLTIpIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgICAgIDxyZWN0IGlkPSJpY29uX2RhcmsiIHg9IjAiIHk9IjAiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PC9yZWN0PgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=`
export const company = `data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTZweCIgaGVpZ2h0PSIxNnB4IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogc2tldGNodG9vbCA2My4xICgxMDEwMTApIC0gaHR0cHM6Ly9za2V0Y2guY29tIC0tPgogICAgPHRpdGxlPkI0RTRGQ0FGLTdCMzctNERCNy1BRUFGLTdGRDY0RUE0QzQwQTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggc2tldGNodG9vbC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMC45OTk5OTk5NSwxNi4wMDAwMDAxIEMwLjQ0NzcxNTIwMywxNi4wMDAwMDAxIC01LjAwMDAwMDA2ZS0wOCwxNS41NTIyODQ3IC01LjAwMDAwMDA2ZS0wOCwxNSBMLTUuMDAwMDAwMDZlLTA4LDQuODM5OTk5OTcgQy01LjAwMDAwMDA2ZS0wOCw0LjI4NzcxNTIzIDAuNDQ3NzE1MjAzLDMuODM5OTk5OTcgMC45OTk5OTk5NSwzLjgzOTk5OTk3IEwzLjk5OTk5OTk1LDMuODM5OTk5OTcgTDMuOTk5OTk5OTcsMC45OTk5OTk5NSBDMy45OTk5OTk5NywwLjQ0NzcxNTIwMyA0LjQ0NzcxNTIzLC00Ljk5OTk3NjYxZS0wOCA0Ljk5OTk5OTk3LC00Ljk5OTk3NjYxZS0wOCBMMTEsLTQuOTk5OTc2NjFlLTA4IEMxMS41NTIyODQ3LC00Ljk5OTk3NjYxZS0wOCAxMiwwLjQ0NzcxNTIwMyAxMiwwLjk5OTk5OTk1IEwxMiw0Ljk5OTk5OTk4IEwxMiw0Ljk5OTk5OTk4IEwxNSw0Ljk5OTk5OTk4IEMxNS41NTIyODQ3LDQuOTk5OTk5OTggMTYsNS40NDc3MTUyMyAxNiw1Ljk5OTk5OTk4IEwxNiwxNSBDMTYsMTUuNTUyMjg0NyAxNS41NTIyODQ3LDE2IDE1LDE2IEwwLjk5OTk5OTk1LDE2LjAwMDAwMDEgWiBNMTEsMC45OTk5OTk5NTYgTDQuOTk5OTk5OTgsMC45OTk5OTk5NTYgTDQuOTk5OTk5OTgsMTUgTDUuOTk5OTk5OTksMTUgTDUuOTk5OTk5OTksMTUgTDUuOTk5OTk5OTksMTEuMjQgQzUuOTk5OTk5OTksMTAuNjg3NzE1MyA2LjQ0NzcxNTI0LDEwLjI0IDYuOTk5OTk5OTksMTAuMjQgTDguOTk5OTk5OTksMTAuMjQgQzkuNTUyMjg0NzYsMTAuMjQgOS45OTk5OTk5OSwxMC42ODc3MTUzIDkuOTk5OTk5OTksMTEuMjQgTDkuOTk5OTk5OTksMTUgTDExLDE1IEwxMSwwLjk5OTk5OTk1NiBaIE04Ljk5OTk5OTk5LDExLjI0IEw2Ljk5OTk5OTk5LDExLjI0IEw2Ljk5OTk5OTk5LDE1IEw4Ljk5OTk5OTk5LDE1IEw4Ljk5OTk5OTk5LDExLjI0IFogTTMuOTk5OTk5OTYsNC44Mzk5OTk5OCBMMC45OTk5OTk5NTYsNC44Mzk5OTk5OCBMMC45OTk5OTk5NTYsMTUgTDMuOTk5OTk5OTYsMTQuOTk5IEwzLjk5OTk5OTk2LDQuODM5OTk5OTggWiBNMTUsNS45OTk5OTk5OSBMMTIsNS45OTk5OTk5OSBMMTIsMTUgTDE1LDE1IEwxNSw1Ljk5OTk5OTk5IFoiIGlkPSJwYXRoLTEiPjwvcGF0aD4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJTeW1ib2xzIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iRW50aXR5L2NvbXBhbnlfcmVndWxhciI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9Im5vbmUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8dXNlIGlkPSJDb21iaW5lZC1TaGFwZSIgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPGcgaWQ9ImNvbG9ycy9hYV9pY29uX2RhcmsiIG1hc2s9InVybCgjbWFzay0yKSIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8cmVjdCBpZD0iaWNvbl9kYXJrIiB4PSIwIiB5PSIwIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPjwvcmVjdD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+`
Binary file added examples/assets/person.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 12 additions & 5 deletions examples/native/src/labels/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import * as Renderer from '@trellis/renderers/webgl'
import * as Graph from '@trellis/index'
import * as Collide from '@trellis/layout/collide'
import { person } from '../../../assets/icons'

const GREEN = '#91AD49'
const GREEN_LIGHT = '#C6D336'
const DARK_GREEN = '#607330'

const IMAGE_ICON: Graph.ImageIcon = {
type: 'imageIcon',
url: person,
scale: 0.66
}

const TEXT_ICON: Graph.TextIcon = {
type: 'textIcon',
family: 'sans-serif',
fontFamily: 'sans-serif',
fontWeight: '400',
fontSize: 14,
color: '#fff',
weight: '400',
text: '!',
size: 14
text: '!'
}

const NODE_STYLE: Graph.NodeStyle = {
color: GREEN,
icon: TEXT_ICON,
icon: IMAGE_ICON,
stroke: [{ width: 2, color: GREEN_LIGHT }],
label: {
position: 'right',
Expand Down
13 changes: 5 additions & 8 deletions examples/native/src/perf/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,25 @@ const sampleCoordinatePlane = function* (count: number, step: number, sample: nu
const PURPLE = '#7A5DC5'
const LIGHT_PURPLE = '#CAD'
const ARIAL_PINK = 'ArialPink'
const TEXT_ICON: Graph.TextIcon = { type: 'textIcon', text: 'T', fontFamily: 'sans-serif', fontSize: 14, color: '#fff', fontWeight: '400' }

const NODE_STYLE: Graph.NodeStyle = {
color: PURPLE,
stroke: [{ width: 2, color: LIGHT_PURPLE }],
icon: { type: 'textIcon', text: 'T', family: 'sans-serif', size: 14, color: '#fff', weight: '400' },
icon: TEXT_ICON,
label: {
position: 'top',
fontName: ARIAL_PINK,
fontFamily: ['Arial', 'sans-serif'],
margin: 2,
background: {
color: '#f66',
opacity: 0.5
}
fontFamily: 'Arial, sans-serif',
margin: 2
}
}

const NODE_HOVER_STYLE: Graph.NodeStyle = {
color: '#f66',
stroke: [{ width: 2, color: '#fcc' }],
label: { position: 'bottom', color: '#fcc' },
icon: { type: 'textIcon', text: 'L', family: 'sans-serif', size: 14, color: '#fff', weight: '400' }
icon: TEXT_ICON
}

const EDGE_STYLE: Graph.EdgeStyle = {
Expand Down
25 changes: 4 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TWO_PI } from './renderers/webgl/utils'
import type { TrellisIcon } from './renderers/webgl/textures/icons'
import type { LabelStyle } from './renderers/webgl/objects/label'
import type { Stroke } from './types'

Expand Down Expand Up @@ -26,36 +27,17 @@ export type Edge = {
style?: EdgeStyle
}

export type TextIcon = {
type: 'textIcon'
family: string
text: string
color: string
size: number
weight?: '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'
offsetX?: number
offsetY?: number
}

export type ImageIcon = {
type: 'imageIcon'
url: string
scale?: number
offsetX?: number
offsetY?: number
}

export type NodeStyle = {
color?: string
icon?: TextIcon | ImageIcon
icon?: TrellisIcon
stroke?: Stroke[]
badge?: {
position: number
radius: number
color: string
stroke?: string
strokeWidth?: number
icon?: TextIcon | ImageIcon
icon?: TrellisIcon
}[]
label?: LabelStyle
}
Expand Down Expand Up @@ -382,3 +364,4 @@ export const angle = (x0: number, y0: number, x1: number, y1: number) => {
// exports
export type { Stroke } from './types'
export type { LabelStyle, LabelBackgroundStyle, LabelPosition, FontWeight, TextAlign } from './renderers/webgl/objects/label'
export type { TrellisIcon, TextIcon, ImageIcon } from './renderers/webgl/textures/icons'
3 changes: 2 additions & 1 deletion src/renderers/webgl/edge.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MIN_EDGES_ZOOM, MIN_INTERACTION_ZOOM, Renderer } from '.'
import { type Renderer } from '.'
import { MIN_EDGES_ZOOM, MIN_INTERACTION_ZOOM } from './utils'
import { movePoint } from './utils'
import { NodeRenderer } from './node'
import * as Graph from '../..'
Expand Down
14 changes: 3 additions & 11 deletions src/renderers/webgl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { NodeRenderer } from './node'
import { EdgeRenderer } from './edge'
import { ArrowTexture } from './textures/arrow'
import { CircleTexture } from './textures/circle'
import { Font } from './textures/font'
import { interpolate } from '../../utils'
import { logUnknownEdgeError } from './utils'
import { ObjectManager } from './objectManager'
import { TextIconTexture } from './textures/textIcon'
import { TextIconTexture, ImageIconTexture } from './textures/icons'

export type Keys = { altKey?: boolean; ctrlKey?: boolean; metaKey?: boolean; shiftKey?: boolean }
export type MousePosition = { x: number; y: number; clientX: number; clientY: number }
Expand Down Expand Up @@ -99,14 +98,6 @@ export const defaultOptions = {
dragInertia: 0.88
}

// TODO - make configurable
export const MIN_LABEL_ZOOM = 0.25
jameslaneconkling marked this conversation as resolved.
Show resolved Hide resolved
export const MIN_NODE_STROKE_ZOOM = 0.3
export const MIN_NODE_ICON_ZOOM = 0.3
export const MIN_INTERACTION_ZOOM = 0.15
export const MIN_EDGES_ZOOM = 0.1
export const MIN_ZOOM = 3

export class Renderer {
width: number
height: number
Expand Down Expand Up @@ -140,7 +131,6 @@ export class Renderer {
edgeArrowObjectManager = new ObjectManager(1000)
labelObjectManager = new ObjectManager(2000)
interactionObjectManager = new ObjectManager(2000)
font = new Font()
eventSystem: EventSystem
nodes: Graph.Node[] = []
nodeRenderersById: Record<string, NodeRenderer> = {}
Expand All @@ -154,6 +144,7 @@ export class Renderer {
circle: CircleTexture
arrow: ArrowTexture
textIcon: TextIconTexture
imageIcon: ImageIconTexture
draggedNode?: NodeRenderer
hoveredNode?: NodeRenderer

Expand Down Expand Up @@ -232,6 +223,7 @@ export class Renderer {
this.circle = new CircleTexture(this)
this.arrow = new ArrowTexture(this)
this.textIcon = new TextIconTexture(this)
this.imageIcon = new ImageIconTexture()
this.eventSystem = new EventSystem(this.app.renderer)
this.eventSystem.domElement = view
this.root.eventMode = 'static' // 'passive' // TODO - add viewport events to interactionContainer
Expand Down
23 changes: 12 additions & 11 deletions src/renderers/webgl/node.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { MIN_LABEL_ZOOM, MIN_INTERACTION_ZOOM, MIN_NODE_STROKE_ZOOM, MIN_NODE_ICON_ZOOM } from './utils'
import { FederatedPointerEvent } from 'pixi.js'
import { MIN_LABEL_ZOOM, MIN_INTERACTION_ZOOM, MIN_NODE_STROKE_ZOOM, Renderer, MIN_NODE_ICON_ZOOM } from '.'
import { type Renderer } from '.'
import * as Graph from '../..'
import { Label } from './objects/label'
import { NodeFill } from './objects/nodeFill'
Expand Down Expand Up @@ -50,20 +51,20 @@ export class NodeRenderer {
this.renderer.labelObjectManager.delete(this.label)
this.labelMounted = false
this.label = undefined
} else if (!this.label.equals(node.label, node.style?.label)) {
} else {
this.label.update(node.label, node.style?.label)
}

if (this.icon === undefined) {
if (node.style?.icon) {
this.icon = new Icon(this.renderer.nodesContainer, this.renderer.textIcon, this.fill, node.style.icon)
if (node.style?.icon !== undefined) {
this.icon = new Icon(this.renderer.nodesContainer, this.renderer.textIcon, this.renderer.imageIcon, this.fill, node.style.icon)
}
} else if (node.style?.icon === undefined) {
this.icon.delete()
this.iconMounted = false
this.icon = undefined
} else {
if (node.style?.icon === undefined) {
this.icon.delete()
this.iconMounted = false
this.icon = undefined
}
this.icon.update(node.style.icon)
}

/**
Expand Down Expand Up @@ -504,8 +505,8 @@ export class NodeRenderer {
if (this.label !== undefined) {
this.label.moveTo(this.x, this.y, this.strokes.radius)
}
if (this.icon && node.style?.icon) {
this.icon.update(this.x, this.y, node.style.icon)
if (this.icon !== undefined) {
this.icon.moveTo(this.x, this.y)
}
this.hitArea.update(x, y, radius)
}
Expand Down
81 changes: 53 additions & 28 deletions src/renderers/webgl/objects/icon.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,64 @@
import { TextIconTexture, ImageIconTexture, TrellisIcon, TextIcon, ImageIcon } from '../textures/icons'
import { Container, Sprite } from 'pixi.js'
import { NodeFill } from './nodeFill'
import { TextIconTexture } from '../textures/textIcon'
import * as Graph from '../../..'
import * as Trellis from '../../../'

// TODO - support image icons
export class Icon {
mounted = false

private x?: number
private y?: number
private container: Container
private textIconTexture: TextIconTexture
private imageIconTexture: ImageIconTexture
private nodeFill: NodeFill
private style: Graph.TextIcon | Graph.ImageIcon
private style: TrellisIcon
private icon: Sprite

constructor(container: Container, textIconTexture: TextIconTexture, nodeFill: NodeFill, style: Graph.TextIcon | Graph.ImageIcon) {
constructor(
container: Container,
textIconTexture: TextIconTexture,
imageIconTexture: ImageIconTexture,
nodeFill: NodeFill,
style: TrellisIcon
) {
this.container = container
this.textIconTexture = textIconTexture
this.imageIconTexture = imageIconTexture
this.nodeFill = nodeFill

this.icon = this.createIcon(style)
this.icon = this.create(style)
this.style = style
}

update(x: number, y: number, style: Graph.TextIcon | Graph.ImageIcon) {
if (!Graph.equals(this.style, style)) {
update(style: TrellisIcon) {
if (!Trellis.equals(this.style, style)) {
const isMounted = this.mounted

this.delete()
this.icon = this.createIcon(style)
this.style = style
this.icon = this.create(style)

if (isMounted) {
this.mount()
}
this.style = style
}

this.icon.x = this.style.offsetX ?? 0 + x
this.icon.y = this.style.offsetY ?? 0 + y
return this
}

moveTo(_x: number, _y: number) {
const x = _x + (this.style.offset?.x ?? 0)
const y = _y + (this.style.offset?.y ?? 0)

if (x !== this.x) {
this.x = x
this.icon.x = x
}

if (y !== this.y) {
this.y = y
this.icon.y = y
}

return this
}
Expand Down Expand Up @@ -64,22 +88,23 @@ export class Icon {
return undefined
}

private createIcon(style: Graph.TextIcon | Graph.ImageIcon): Sprite {
let icon: Sprite

if (style.type === 'textIcon') {
icon = new Sprite(this.textIconTexture.create(style.text, style.family, style.size, style.weight ?? 'normal', style.color))
icon.anchor.set(0.5)
icon.scale.set(1 / this.textIconTexture.scaleFactor)
} else if (style.type === 'imageIcon') {
// TODO
icon = new Sprite(this.textIconTexture.create('?', 'sans-serif', 12, 'normal', 0x000000))
icon.anchor.set(0.5)
} else {
icon = new Sprite(this.textIconTexture.create('?', 'sans-serif', 12, 'normal', 0x000000))
icon.anchor.set(0.5)
}
private create(style: TrellisIcon) {
const icon = style.type === 'textIcon' ? this.createTextIcon(style) : this.createImageIcon(style)
icon.anchor.set(0.5)
icon.x = this.x ?? 0
icon.y = this.y ?? 0
return icon
}

private createTextIcon(style: TextIcon) {
const icon = new Sprite(this.textIconTexture.create(style))
icon.scale.set(1 / this.textIconTexture.scaleFactor)
return icon
}

private createImageIcon(style: ImageIcon) {
const sprite = new Sprite(this.imageIconTexture.create(style))
sprite.scale.set(style.scale ?? 1)
return sprite
}
}
Loading
Loading