Applet Canvas actual performance optimization

The following article is reprinted from totoro "applet Canvas performance optimization combat! "

Author: totoro

Links: https://blog.totoroxiao.com/canvas-perf-mini/

Source: https://blog.totoroxiao.com/

Copyright reserved by the authors. Commercial reprint please contact the author authorized, non-commercial reprint please indicate the source.

Tencent location-based services applet plug-in capability to provide micro-channel, focusing on (around) the map function to create a series of small plug-ins that can help developers to easily and quickly build small programs, is your map function to achieve the best partner. At present small micro-channel plug-ins provide route planning, subway map, maps, site selection and other services!

Case Background

demand:

Draw subway map in applet canvas components, including the subway map subway lines, the site icon, the site name and line of text, draw elements as lines, circles, images, text.
Supports drag to pan and pinch zoom.

problem:

Limited canvas performance of small programs, especially in the course of an interaction constantly redrawn trigger can cause serious Caton.

Basically

Without considering optimization, let us talk about how to draw and interaction.

Data Format

First look at the data, the data service returns each element is independent, including the coordinates of the elements of style and

// 线路数据
lineData = { path: [x0, y0, x1, y1, ...], strokeColor, strokeWidth }

// 站点数据:分为普通站点和换乘站点
// 普通站点绘制简单圆形
stationData = { x, y, r, fillColor, strokeColor, strokeWidth }
// 换乘站点绘制换乘图标(png图片)
stationData_transfer = { x, y, width, height }

// 线路名称
lineNameData = { text, x, y, fillColor }

// 站点名称
stationNameData = { text, x, y }

Drawing API

When drawing the drawing elements to traverse the array, according to the context element type setting style, drawing and filling. Interface Reference: https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.html

• Set style: setStrokeStyle, setFillStyle, setLineWidth, setFontSize

• Draw route: moveTo, lineTo, stroke

• Draw Site: moveTo, arc, stroke, fill

• Draw a picture: drawImage

• Draw Text: fillText

Interactive achieve

Interact major steps are as follows:

• achieved through bindtouchstart, bindtouchmove, bindtouchend users drag and pinch zoom listeners, get a dragging displacement vector, scaling, triggering redrawn.

By scale and translate implement zoom and pan without the use of data processing when the coordinates • Draw

The results finally obtained are as follows, length 42.82ms, real machine (iOS) Average rendering validation: turtle speed movement, a very large picture delay.

Optimization

Completely unaware canvas optimization students can take a look at: canvas optimization .

Canvas state changes to avoid unnecessary
reference Canvas Best Practices (performance papers) , a drawing context is a state machine, there is a certain change in state overhead. Canvas state changes here mainly refers to the change strokeStyle, fillStyle and other styles.

How to reduce the cost of this part of it? We can try to make the same style elements on the one-time drawing together. Look at the data suggests that many elements of the style is the same site, you can do first before drawing data aggregation, the combination of the same data into a data pattern:

function mergeStationData(mapStation) {
  let mergedData = {}

  mapStation.forEach(station => {
    let coord = `${station.x},${station.y},${station.r}`
    let stationStyle = `${station.fillColor}|${station.strokeColor}|${station.strokeWidth}`

    if (mergedData[stationStyle]) {
      mergedData[stationStyle].push(coord)
    } else {
      mergedData[stationStyle] = [coord]
    }
  })

  return mergedData
}

After the polymerization, 329 merger site data 24, effectively a 90% reduction of the cost to change redundancy status. Modify the test after it, when the average dropped to render long 20.48ms, real machine verification: some move a little faster, but the picture is still high latency.

The combined data need to pay attention, this scenario is not the site of another gland, the gland and if there is order, then, at the time of the merger can only merge adjacent and the same style data.

Reducing the draw was

• In addition to screening was drawn vision: when users enlarge the image, in fact, most have disappeared in the draw was outside the field of view, to avoid drawing elements outside the field of vision can save unnecessary overhead. Element is relatively easy to determine the point is outside the field of view of the site, the site name, the line name can be treated as a point element; line segment thereof can also be calculated in the field of view, it is more complex, where the first process is not . Sieve to get rid of out of sight of the drawn Test after it, rendering the average length of 17.02ms, real machine verification: same as above, there is not much change.

• In addition to the screen is too small to draw objects: when the user is reduced images, text and sites due to size is too small and can not quite clear, without affecting the user experience can be considered directly removed. According to the test, the final decision to remove text and display site when the ratio is less than 30%, the duration of the rendering of the level from 22.12ms, reduced to 9.68ms.

Reducing the redraw frequency

Although the average length has been rendered much lower, but still high in the interactive Shique delay, because every time ontouchmove rendering tasks will be added to the queue asynchronous, event triggered the number of times per second rendering capable of performing frequency is much higher than , resulting in a serious backlog of rendering tasks, continue to lag. RequestAnimationFrame generally used to solve this problem, there are no small program on the PC side, but can achieve their own reference micro letter applet using requestAnimationFrame :

const requestAnimationFrame = function (callback, lastTime) {
  var lastTime;
  if (typeof lastTime === 'undefined') {
    lastTime = 0
  }
  var currTime = new Date().getTime();
  var timeToCall = Math.max(0, 30 - (currTime - lastTime));
  lastTime = currTime + timeToCall;
  var id = setTimeout(function () {
    callback(lastTime);
  }, timeToCall);
  return id;
};

const cancelAnimationFrame = function (id) {
  clearTimeout(id);
};

PC side we generally will render distance control in about 16ms, but in a small program to take into account the performance limitations, and mobile terminal performance of each model vary, so here we leave some space, control 30ms, corresponds to around 30FPS.

But if you have been calling the cycle will cause unnecessary overhead at a standstill, so you can open separately, stop the animation when interacting beginning and end ontouchstart ontouchend:

animate(lastTime) {
  this.animateId = requestAnimationFrame((t) => {
    this.render()
    this.animate(t)
  }, lastTime)
},

stop() {
  cancelAnimationFrame(this.animateId)
}

After modifying the real machine to test: screen comparison process, a slight Caton, but it will not delay.

Additional

Since the present embodiment, the zoom and pan state is saved in the absolute state, scale, and translate it to be used together with the save and Restore; setTransform may be used directly to reset the matrix. In theory this should be able to save money, but what effect did the actual test, the average length rendered in 18.12ms. This issue needs to be studied.
Applet Avoid using setData save interface rendering independent data, in order to avoid redrawing the page.

Optimization Results

After the above optimization, rendering long time from 42 down to about 17ms, real machine verification at Andrews models generally very smooth, very good experience; ios models slightly Caton, and with the use of long-Caton became clear, the latter can be in-depth study is there a problem at memory management.

Guess you like

Origin www.cnblogs.com/Yi-Xiu/p/12030352.html