애플릿 캔버스 실제 성능 최적화

다음 문서는 토토로 "애플릿 캔버스 성능 최적화 전투에서 다시 인쇄됩니다! "

작성자 : totoro

링크 : https://blog.totoroxiao.com/canvas-perf-mini/

출처 : https://blog.totoroxiao.com/

저작권은 저자에 의해 소유. 상업 무단 전재 공인 저자에 문의하시기 바랍니다, 소스가 표시 비상업적 무단 전재하시기 바랍니다.

텐센트 위치 기반 서비스 애플릿 플러그인 쉽게 개발자를 도와 신속 작은 프로그램을 구축 할 수있는 작은 플러그인의 시리즈를 만들 수 (약)지도 기능에 초점을 맞추고, 마이크로 채널을 제공하는 기능, 최고의 파트너를 달성하기 위해지도 기능입니다. 현재 작은 마이크로 채널 플러그인을 제공에서 경로 계획, 지하철 노선도,지도, 부지 선정 및 기타 서비스를!

사례 배경

요구 사항 :

선, 원, 이미지, 텍스트 등의 요소를 그릴, 지하철지도 지하철 라인, 사이트 아이콘, 사이트 이름과 텍스트의 라인을 포함 애플릿 캔버스 구성 요소에 지하철지도를 그립니다.
지원은 이동 및 확대 핀치 드래그.

문제 :

특히 상호 작용을 지속적으로 다시 그려 트리거의 과정에서 작은 프로그램의 제한 캔버스 성능은 심각한 Caton가 발생할 수 있습니다.

근본적으로

최적화를 고려하지 않고, 우리가 그릴과 상호 작용하는 방법에 대해 얘기해 보자.

데이터 형식

스타일의 요소의 좌표를 포함한 데이터, 각 요소는 독립적 인 데이터 서비스의 반환에 첫 모습

// 线路数据
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 }

드로잉 API

도면 요소를 그릴 때 드로잉 및 충전, 콘텍스트 요소 타입 설정 스타일에있어서, 상기 어레이를 통과한다. 인터페이스 참조 : https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.html

• 설정 스타일 : setStrokeStyle, setFillStyle, setLineWidth, setFontSize

의 moveTo,에 lineTo, 뇌졸중 : 경로를 그리기 •

사이트를 그리기 • :의 moveTo, 아크, 뇌졸중, 채우기

그림을 그리기 • :의 drawImage를

텍스트 그리기 • : fillText를

인터랙티브 달성

상호 작용하는 주요 단계는 다음과 같습니다 :

• bindtouchstart, bindtouchmove, bindtouchend 사용자가 드래그를 통해 달성 청취자를 줌 꼬집어하는 드래그 변위 벡터, 스케일링, 트리거링 다시 그려을 얻을.

규모에 의해 번역 줌을 구현하고 좌표 그리기 • 때 데이터 처리를 사용하지 않고 이동

거북이 속도 운동, 아주 큰 그림 지연 : 마지막으로 얻어진 결과는 길이 42.82ms, 실제 기계 (아이폰 OS) 평균 렌더링 검증, 다음입니다.

최적화

: 완전히 인식 캔버스 최적화 학생들은 한 번 봐 걸릴 수 있습니다 캔버스 최적화 .

캔버스 상태 불필요한 피하기 위해 변경
기준 캔버스 용례 (성능 논문) 상태 오버 헤드의 특정 변화가, 드로잉 컨텍스트 상태 머신이다. 캔버스 상태는 주로 여기 변경 변경 strokeStyle, fillStyle에서는 다른 스타일을 의미합니다.

어떻게이 부분의 비용을 줄이기 위해? 우리가 함께 한 시간 드로잉 같은 스타일 요소를 만들기 위해 노력하고 있습니다. 데이터를 봐 스타일의 많은 요소가 같은 사이트, 당신은 데이터 통합, 데이터 패턴에 동일한 데이터의 조합을 그리기 전에 먼저 할 수 있음을 시사한다 :

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
}

중합 329 합병 사이트 데이터 (24), 변경, 이중화 상태로 비용 효과적으로 90 % 감소 후. 조금 더 빠른 일부 이동,하지만 그림은 여전히 ​​높은 대기 시간 : 평균 긴 20.48ms, 실제 기계 검증을 렌더링 감소 할 때, 그 후 테스트를 수정합니다.

결합 된 데이터는이 시나리오가 다른 선, 글 랜드의 사이트가 아닙니다, 관심을 지불 할 필요가 순서가있는 경우, 다음, 합병시에만 인접 같은 스타일 데이터를 병합 할 수 있습니다.

추첨을 줄이면했다

• 검사 외에 비전 그려진 : 사용자는 이미지를 확대 할 때 연신 외부 시야이었다에서, 실제로, 대부분의 불필요한 오버 헤드를 저장할 수있는 시야 밖에 드로잉 요소를 피하기 위해, 사라졌다. 첫 번째 과정이 아닌 곳에는 더 복잡 선분 이들도 시야에서 산출 될 수 요소는 점 사이트, 사이트 명칭, 광고 이름 점 요소로 취급 할 수의 시야 밖에 결정하는 비교적 쉬운 . 체는 17.02ms, 실제 기계 검증의 평균 길이 렌더링, 그 뒤에 그려진 시험의 시야 밖으로 제거하기 : 위와 동일, 많은 변화가 없습니다.

• 화면에 추가하여 객체를 그리는 너무 작 : 사용자 인해 크기에 이미지, 텍스트 및 사이트를 감소 될 때 너무 작고 매우 직접 제거 간주 될 수있는 사용자 경험에 영향을주지 않고, 지울 수 없습니다. 비율이 30 % 미만, 9.68ms로 감소 22.12ms에서 레벨의 렌더링의 지속 기간 인 경우 시험 법에 따라, 최종 결정은 텍스트 및 디스플레이 위치를 제거한다.

다시 그리기 주파수를 감소

렌더링 작업 ontouchmove마다 큐 비동기에 추가되기 때문에, 평균 길이가 훨씬 낮은 렌더링, 여전히 높은 인터랙티브 Shique 지연되었지만, 일정 주파수를 수행 할 수있는 제 2 묘화 당 횟수를 훨씬 초과한다 트리거 렌더링 작업의 심각한 백 로그의 결과로, 지연에 계속. RequestAnimationFrame는 일반적으로 PC 측에 더 작은 프로그램이없는이 문제를 해결하는 데 사용하지만, 자신의 기준 달성 할 수 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 측면 우리는 일반적으로 16ms 약에 거리 컨트롤을 렌더링하지만 작은 프로그램으로 계정에 성능 제한을하고, 각 모델의 휴대 단말기 성능은 우리가 30FPS 주변에 약간의 공간을 제어 30ms의, 대응을 떠나, 그래서 여기에 다릅니다.

그러나 당신이 별도로 열고 시작을 상호 작용할 때 애니메이션을 중지하고 ontouchend ontouchstart 종료 할 수 있도록, 정지에서 불필요한 오버 헤드가 발생합니다 싸이클 호출 된 경우 :

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

stop() {
  cancelAnimationFrame(this.animateId)
}

화면 비교 과정, 약간의 Caton하지만이 지연되지 않습니다 테스트에 실제 기계를 수정 한 후.

부가적인

본 실시하기 때문에, 줌 및 팬 상태 절대 상태, 스케일로 저장하고 퇴피 병용 및 복원되도록 변환되어 사용해 setTransform 행렬을 다시 직접적으로 사용될 수있다. 이론적으로이 비용을 절감 할 수 있지만, 어떤 영향을하면 실제 시험, 18.12ms에서 렌더링의 평균 길이를했다한다. 이 문제는 연구 할 필요가있다.
위해, 독립적 인 데이터를 렌더링 인터페이스 저장 사항 setData를 사용하여 애플릿을 피 페이지를 다시 그릴 방지 할 수 있습니다.

최적화 결과

위의 최적화 후 약 17ms로 (42) 아래에서 오랜 시간을 렌더링, 앤드류스 모델에서 실제 기계 검증은 일반적으로 아주 좋은 경험을 부드럽게, IOS 모델 약간 Caton, 그리고 긴 Caton이 분명 해졌다의 사용으로, 후자가 될 수 있습니다 심층 연구 메모리 관리에 문제가있는 것입니다.

추천

출처www.cnblogs.com/Yi-Xiu/p/12030352.html