TypeScript 및 Vue가 있는 반응형 캔버스

또는 걱정을 멈추고 맞춤 지시문을 사랑하는 방법을 배웠습니다.



내 "내가 붙어있는 것"시리즈의 또 다른! 이 특정 문제에 대한 해결책은 아마도 명백할 정도로 다소 간단했지만, 그것에 도달하는 것은 나에게 우회적인 과정이었기 때문에 이것이 어쨌든 누군가에게 유용하기를 바랍니다.

Vuedirectives을 제공하여 템플릿을 스크립트에 연결합니다. 대부분의 경우 이것으로 충분하지만 canvas 요소를 제어하려면 낮은 수준의 DOM 액세스가 필요합니다. <canvas>v-model를 지원하지 않으므로 ViewModel과 자체 동기화를 유지할 수 있는 방식으로 렌더링을 위해 요소에 데이터를 전달하는 다른 방법이 필요합니다.

운 좋게도 그들은 그것을 생각했습니다. custom directives을 사용하여 우리 자신의 동작을 정의할 수 있는 템플릿에 대한 자체 템플릿v-something을 만들 수 있습니다.

이 코드는 선택한 "TypeScript"옵션과 클래스 스타일 구성 요소 구문을 사용하여 Vue CLI 3.0에서 만든 프로젝트에 맞게 작성되었습니다. 다른 구성과 함께 사용하는 것이 간단해야 합니다. 여기서 핵심은 지시문 자체입니다. 전체 구문은 문서 링크를 참조하세요.

우리는 최소한의 단일 파일 클래스 기반 구성 요소로 작업할 것입니다.

<template>
  <div class="rxcanvas">
    <span>{{ size }}</span>
    <input type="range" min="1" max="100" step="5" id="size" v-model="size">
    <label for="size">- Size</label>
    <p><canvas></canvas></p>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import Dot from "@/dot"; // defined below

@Component
export default class RxCanvas extends Vue {
  private data() {
    return {
      size: 10
    };
  }

  // computed property
  get dot(): Dot {
    return new Dot(this.$data.size);
  }
}
</script>

<style scoped>
</style>



Dot 클래스는 대상에 대한 Canvas 요소가 주어졌을 때 자신을 그리는 것을 알고 있습니다.

// dot.ts
export default class Dot {
    private readonly color: string = "#000";
    constructor(private radius: number) { }
    public draw(canvas: HTMLCanvasElement): void {
        // resize canvas to dot size
        const canvasDim = this.radius * 2;
        canvas.width = canvasDim;
        canvas.height = canvasDim;

        // get context for drawing
        const ctx = canvas.getContext('2d')!;

        // start with a blank slate
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // find the centerpoint
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;

        // create the shape
        ctx.beginPath();
        ctx.arc(centerX, centerY, this.radius, 0, 2 * Math.PI, false);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.stroke();
    }
}


우리가 원하는 동작, 즉 슬라이더 입력과 동기화된 적절한 크기의 캔버스를 얻으려면 단순히 숫자를 범핑하는 것보다 각 변경 사항에서 실행하려는 로직이 조금 더 있습니다. 우리는 Dot 클래스 안에 모든 논리를 숨겼습니다. Dot.draw(el)는 필요한 모든 작업을 수행하는 방법을 알고 있습니다. 변경 사항이 있을 때마다 이 메서드를 자동으로 실행하기만 하면 됩니다.

우선 템플릿의 캔버스 요소에 바로 지시문을 던질 수 있습니다. 이미 관련 데이터를 알고 있습니다.

<canvas v-draw="dot"></canvas>


이 예에서 사용자 지정 지시문은 draw 입니다. 원하는 대로 이름을 지정할 수 있습니다. 모든 지시어에는 v- 접두어가 붙습니다. 우리는 "dot" 클래스에 정의된 계산 속성인 RxCanvas 를 전달하고 있습니다. 이렇게 하면 size가 변경될 때마다 이 계산된 속성이 올바른 크기의 새 도트를 생성합니다.

커스텀 디렉티브는 Vue 컴포넌트에서 정의됩니다. vue-property-decorator 를 사용할 때 데코레이터 옵션에 배치할 수 있습니다.

@Component({
  directives: {
    "draw": function(canvasElement, binding) {
    // casting because custom directives accept an `Element` as the first parameter
      binding.value.draw(canvasElement as HTMLCanvasElement);
    }
  }
})
export default class RxCanvas extends Vue {
    // data(), dot(), etc
}


...그리고 그게 다야! binding.value는 계산된 속성에서 얻은 실제 값Dot을 포함합니다. 이 구문은 우리가 사용하는 각 후크를 철자하지 않고 정의를 압축할 수 있도록 하는 지시문에 사용할 수 있는 약어를 활용합니다. 대부분의 경우 이 기능의 사용자는 bindupdate 에서 동일한 논리가 발생하기를 원한다는 점을 인정하고 후크 함수를 포함하는 개체 대신 지시문에 대한 논리로 함수를 정의하면 기본적으로 해당 동작을 얻습니다. . 속기를 사용하지 않고 이 논리를 다음과 같이 정의합니다.

directives: {
    draw: {
      bind: function(canvasElement: Element, binding: VNodeDirective) {
        binding.value.draw(canvasElement as HTMLCanvasElement);
      },
      update: function(canvasElement, binding) {
        binding.value.draw(canvasElement as HTMLCanvasElement);
      }
    }
}

bind 규칙은 구성 요소 생성 시 정확히 한 번 실행되며 update 규칙은 VNode 클래스에서 생성된 RxCanvas 인스턴스에 변경 사항이 있을 때마다 발생합니다. 여기에는 해당 data 에 대한 변경 사항이 포함됩니다. 이렇게 철자를 쓰는 것은 장황하고 반복적입니다. 가능하면 속기를 사용하세요.

이 사용자 지정 지시문은 RxCanvas 구성 요소에서만 사용할 수 있습니다. 여러 구성 요소에서 사용하려면 전역으로 정의하십시오.

// index.ts
Vue.directive('draw': function(canvasElement, binding) {
      binding.value.draw(canvasElement as HTMLCanvasElement);
});


후자!

좋은 웹페이지 즐겨찾기