Location>code7788 >text

Front-end using Konva visual designer (20) - performance optimization, UI beautification

Popularity:986 ℃/2024-08-08 12:39:46

This chapter shares performance optimization issues encountered with Konva and introduces UI beautification ideas.

At least 2 of you have given positive feedback and found that there are obvious performance issues with this example, one is a memory overflow issue and the other is a lagging issue, thanks for the heads up here.

Please give me a free Star!

If you find any bugs, please feel free to raise an Issue!

github source code

gitee source code

sample address (computing)

performance optimization

memory overflow

According to the official documentationKonva Class: Node The description:

remove(): remove a node from parent, but don't destroy. You can reuse the node later.
destroy(): remove and destroy a node. Kill it and delete forever! You should not reuse node after destroy().
If the node is a container (Group, Stage or Layer) it will destroy all children too.

In versions prior to this example, it was incorrect to use only remove(). Using only remove created huge amounts of instances that weren't cleared with each redraw, i.e., memory overflowed, causing the JS heap size to casually dry up to a few gigabytes.

[Simple Determination of Memory Overflow
leave for:Chrome -> Console kneading board -> More on the left side -> Performance monitor -> JS heap size
If the memory only goes up but not down, you can basically assume that there is a memory overflow.

In this example, most of the graphical instances are used and discarded, so after most of the removals are replaced with destory, the JS heap size will basically stay in the tens or hundreds of MB (depending on the complexity of the content).

Here is a reminder, in addition to the use of remove to pay attention to, there is also an easy to ignore the API to pay attention to, that is, Stage, Layer, Group's removeChildren(), if the child nodes are no longer useful, it is recommended to traverse the child nodes to destroy them first.

The initial state, as follows:

image

at a standstill

In previous versions of this example, all graphics were redraw whenever the screen needed to be changed, which led to significant lag in the interaction when too much material was loaded, especially when loading gifs, which were redrawing every frame.

Therefore, redraw must be able to selectively draw each layer, the main adjustments are as follows:

// redraw (optional)
  redraw(drawNames?: string[]) {
    const all = [
      , // Update the background
      , // Update the lines
      , // Update tiles
      , // Update scale
      , // update reference lines
      , // update preview
       // update the context menu
    ]

    if ((drawNames) && !) {
      // Selective draws should also be kept in order
      for (const name of all) {
        if ((name)) {
          [name].draw()
        }
      }
    } else {
      for (const name of all) {
        [name].draw()
      }
    }
  }

Here are a few details to consider:
1, pass which drawNames to redraw which groups of draws, unless you are in debug mode.
2. If you don't pass drawNames, you can redraw them all.
3. redraw should be executed in the order of all.

Examples:

  • When dragging the canvas:
([, , ])

Because this interaction only affects the background, scale, and preview draw.

  • Zoom in and out:
            ([
              ,
              ,
              ,
              ,
              
            ])

There are more draws affected at this point.

According to the characteristics of different interactions, do the necessary redraw processing, can be very good to improve the performance of interaction, reduce lag.

UI Beautification

Previously, the focus was on the canvas interaction, and the interface just got by.

Now that the infrastructure is basically stable, it's time to spruce up the ugly UI and simply beautify it:

image

Naive UI

For quick beautification, Naive UI is used here, which is more refreshing.

I've mostly spruced up the header and the material bar:

  • src/components/main-header
  • src/components/asset-bar

I won't post the exact code here, it's relatively simple.

mitt - Emitter

Previously, we passed in some methods as handlers for events in a configurable way, so we couldn't dynamically subscribe to them, which was too inconvenient.

Render has been modified to use mitt to give it the Emitter ability:

// summarize
import mitt, { type Emitter } from 'mitt'
// summarize
export class Render {
  // summarize
  protected emitter: Emitter<> = mitt()
  on: Emitter<>['on']
  off: Emitter<>['off']
  emit: Emitter<>['emit']
  // summarize
  constructor(stageEle: HTMLDivElement, config: ) {
    // summarize
     = ()
     = ()
     = ()
    // summarize
  }
}

It's easy to subscribe to events in an outside component, via a render instance, for example:

        ?.on('selection-change', (nodes: []) => {
             = nodes
        })

Thanks watching~

More Stars please!

source code (computing)

gitee source code

sample address (computing)