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

Circle, Rectangle, and Line annotations #98

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

mggower
Copy link
Collaborator

@mggower mggower commented Feb 15, 2024

closes #90

Screenshot 2024-02-15 at 3 08 41 PM

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to abstract some geometry render logic so there is less duplicative logic between annotations and nodes/edges


node: Node
fill: Circle
strokes?: CircleStrokes
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conditionally rendering strokes until an object is visible is a perf boost. should consider doing the same for fills

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaces nodeFill

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaces nodeStrokes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up not using this in favor of Texture.WHITE but kept it around in case there is use for it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moves to utils/webgl

@@ -141,11 +137,14 @@ export type RectangleAnnotation = AnnotationBase<'rectangle'> & {
style: AnnotationStyle
}

export type TextAnnotation = AnnotationBase<'text'> & {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modeling annotations by geometry and removed TextAnnotation. It is more straight forward to just allow shapes to be filled with text via a content prop if desired.

Base automatically changed from feature/assets to master February 26, 2024 11:39
}

for (const annotation of this.annotations) {
if (lookup[annotation.id] === undefined && this.lookup[annotation.id]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the second this.lookup[annotation.id] condition not be necessary? e.g.

for (const annotation of this.annotations) {
  if (lookup[annotation.id] === undefined) {
    annotation.delete()
  }
}

?

render() {
const isVisible = this.visible()

if (isVisible && this.annotation.content && !this.text) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other renderer classes initialize and teardown objects in the update method, and only move/mount/unmount in the renderer. my hunch is that that's a better pattern than initialing Text here, and LineStrokes below. might be missing something, though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In large graphs, there is a sizable effort put on the app to instantiate required objects in each object's renderer; in most of these renderers the resulting object is not visible so the load is unnecessary. There are cases where instantiating 5K+ PIXI.Text objects simultaneously actually leads to crashes. We gain a substantial boost in performance if we lazily create these objects until the moment they are first needed.

It makes sense to me to align this logic with the render's animation frame because this is where we apply the object's position (inclusive of any interpolation) as well as addressing culling/visibility. This allows us to reduce the times we are required to call the visible method.

There is potentially an argument for deferring this lazy instantiation to the RenderObject themselves (i.e. Text, LineStrokes, etc.). However, this would still require creating an internal class instance for every object yet this is likely less of a lift than instantiating any PIXI instance.

Copy link
Collaborator Author

@mggower mggower Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could rework visible to optionally accept arguments x, y similar to EdgeRenderer so this logic is moved to update

The issue with moving this lazy creation to update is that this only executes when the object changes, not when the viewport changes. This means sometimes the RenderObject will not be created on the frame it becomes visible.

const shouldStrokesMount = isVisible && this.renderer.zoom > MIN_STROKE_ZOOM

if (shouldStrokesMount && !this.strokes && this.annotation.style.stroke) {
this.strokes = new LineStrokes(this.renderer.annotationsContainer, this.fill, this.annotation.style.stroke).moveTo(this.x, this.y)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

const isVisible = this.visible()

if (isVisible && this.annotation.content && !this.text) {
this.text = new Text(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, feels like initializing (and tearing down) the Text object here, and the RectangleStrokes object below, should happen in the update method. and only mounting/unmounting/moving/resizing should happen at render time.

private hitArea: EdgeHitArea
private strokes?: LineStrokes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the new LineStrokes object used to support edges with multiple strokes, so an extension of the edge style spec (which currently only supports a single line)? Cool if so.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes exactly. There is probably some fine tuning to be done here, such as wrapping additional strokes around arrows etc.

const strokesShouldMount = isVisible && this.renderer.zoom > MIN_STROKE_ZOOM

if (strokesShouldMount && !this.strokes && this.edge.style?.stroke) {
this.strokes = new LineStrokes(this.renderer.edgesContainer, this.lineSegment, this.edge.style.stroke).moveTo(this.x0, this.y0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, feels like this should be created/torn down in the update method, and only positioned here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Re-implement annotations in Trellis@next
2 participants