>  기사  >  웹 프론트엔드  >  HTML5 캔버스는 그리기 프로그램을 구현합니다(코드 포함).

HTML5 캔버스는 그리기 프로그램을 구현합니다(코드 포함).

不言
不言원래의
2018-08-01 13:49:114202검색

이 글은 HTML5 캔버스 구현 그리기 프로그램(코드 포함)을 소개합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

프로젝트 소개

전체 프로젝트는 두 부분으로 나누어집니다

  1. 시나리오
    캔버스 제어, 이벤트 모니터링 및 애니메이션 처리를 담당하는 장면

  2. Elf
    Elf는 그릴 수 있는 모든 캔버스 요소를 나타냅니다. #🎜 🎜#

데모 데모 주소

프로젝트 기능# 🎜🎜 ####강력한 확장 성#### #####스프라이트 마법사 구현#🎜🎜 ## ## ####부모 클래스#🎜🎜 ## 🎜🎜#
class Element {
  constructor(options = {
    fillStyle: 'rgba(0,0,0,0)',
    lineWidth: 1,
    strokeStyle: 'rgba(0,0,0,255)'
  }) {
    this.options = options
  }
  setStyle(options){
    this.options =  Object.assign(this.options. options)
  }
}

속성:

options는 모든 도면 속성을 저장합니다#🎜🎜 ##🎜 🎜#

fillStyle: 그림을 채우는 데 사용되는 색상, 그라데이션 또는 패턴을 설정하거나 반환합니다.
  1. 스트로크 스타일: 설정 또는 획에 사용된 색상, 그라데이션 또는 패턴을 반환합니다.
  • lineWidth: 현재 선 너비를 설정하거나 반환합니다.

  • # 🎜🎜# getContext("2d") 개체의 모든 기본 속성이 사용됩니다. 여기에는 이 세 가지 속성만 나열되며 필요한 경우 확장할 수 있습니다.
    • 필요한 경우 계속 확장 가능
    • 메서드 :

    • setStyle 메서드는 현재 스프라이트의 속성을 재설정하는 데 사용됩니다.
  • #🎜🎜 ##🎜🎜 #필요하다면 계속 확장하세요

모든 엘프는 Element 클래스를 상속받습니다.
  1. Subclass

하위 클래스는 각 elf 요소의 특정 구현입니다. 여기서는 Circle 요소의 구현을 소개합니다.
class Circle extends Element {
  // 定位点的坐标(这块就是圆心),半径,配置对象
  constructor(x, y, r = 0, options) {
    // 调用父类的构造函数
    super(options)
    this.x = x
    this.y = y
    this.r = r
  }
  // 改变元素大小
  resize(x, y) {
    this.r = Math.sqrt((this.x - x) ** 2 + (this.y - y) ** 2)
  }
  // 移动元素到新位置,接收两个参数,新的元素位置
  moveTo(x, y) {
    this.x = x
    this.y = y
  }
  // 判断点是否在元素中,接收两个参数,点的坐标
  choose(x, y) {
    return ((x - this.x) ** 2 + (y - this.y) ** 2) < (this.r ** 2)
  }
  // 偏移,计算点和元素定位点的相对偏移量(ofsetX, offsetY)
  getOffset(x, y) {
    return {
      x: x - this.x,
      y: y - this.y
    }
  }
  // 绘制元素实现,接收一个ctx对象,将当前元素绘制到指定画布上
  draw(ctx) {
    // 取到绘制所需属性
    let {
      fillStyle,
      strokeStyle,
      lineWidth
    } = this.options
    // 开始绘制beginPath() 方法开始一条路径,或重置当前的路径
    ctx.beginPath()
    // 设置属性
    ctx.fillStyle = fillStyle
    ctx.strokeStyle = strokeStyle
    ctx.lineWidth = lineWidth
    // 画圆
    ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)
    // 填充颜色
    ctx.stroke()
    ctx.fill()
    // 绘制完成
  }
  // 验证函数,判断当前元素是否满足指定条件,此处用来检验是否将元素添加到场景中。
  validate() {
    return this.r >= 3
  }
}
  • arc() 메서드는 호/곡선을 만듭니다(원 또는 부분 원을 만드는 데 사용됨)

  • x 원 중심의 x 좌표 .

  • y 원 중심의 y 좌표입니다.

    r 원의 반경입니다.

    sAngle 시작 각도(라디안)입니다. (호 원의 3시 위치는 0도입니다.)

    • eAngle 라디안 단위로 측정된 끝 각도입니다.

    • 반시계방향 선택사항. 플롯을 시계 반대 방향으로 그릴지 시계 방향으로 그릴지를 지정합니다. 거짓 = 시계 방향, 참 = 시계 반대 방향.

    • 참고:

    • 생성자의 형식 매개변수 두 개만 필요하며, 이는 앵커 포인트입니다. 좌표.

    • 다른 모든 형식 매개변수에는 기본값이 있어야 합니다.

    • 모든 메소드의 호출 타이밍

    캔버스에 요소를 그릴 때 resize 메소드를 호출합니다.

    • 요소를 이동할 때 moveTo 메소드를 호출하세요.

    • choose는 현재 요소가 선택되었는지 확인하기 위해 마우스를 누를 때 호출됩니다.

    getOffset은 선택한 위치를 결정하기 위해 요소를 선택할 때 호출됩니다.

    • draw 그리기 함수는 장면에 요소를 그릴 때 호출됩니다.

    • 장면 장면 구현

    • 속성 소개
    • # 🎜🎜 #####rreee#🎜🎜 ## ## #####이벤트 로직#🎜🎜 ## #####
    class Sence {
      constructor(id, options = {
        width: 600,
        height: 400
      }) {
        // 画布属性
        this.canvas = document.querySelector('#' + id)
        this.canvas.width = options.width
        this.canvas.height = options.height
        this.width = options.width
        this.height = options.height
        // 绘图的对象
        this.ctx = this.canvas.getContext('2d')
        // 离屏canvas
        this.outCanvas = document.createElement('canvas')
        this.outCanvas.width = this.width
        this.outCanvas.height = this.height
        this.outCtx = this.outCanvas.getContext('2d')
        // 画布状态
        this.stateList = {
          drawing: 'drawing',
          moving: 'moving'
        }
        this.state = this.stateList.drawing
        // 鼠标状态
        this.mouseState = {
        // 记录鼠标按下时的偏移量
          offsetX: 0,
          offsetY: 0,
          down: false, //记录鼠标当前状态是否按下
          target: null //当前操作的目标元素
        }
        // 当前选中的精灵构造器
        this.currentSpriteConstructor = null
        // 存储精灵
        let sprites = []
        this.sprites = sprites
        /* .... */
      }
    }
    #🎜🎜 ######메소드 소개# 🎜🎜#
  • class Sence {
      constructor(id, options = {
        width: 600,
        height: 400
      }) {
      /* ... */
      // 监听事件
        this.canvas.addEventListener('contextmenu', (e) => {
          console.log(e)
        })
        // 鼠标按下时的处理逻辑
        this.canvas.addEventListener('mousedown', (e) => {
        // 只有左键按下时才会处理鼠标事件
          if (e.button === 0) {
          // 鼠标的位置
            let x = e.offsetX
            let y = e.offsetY
            // 记录鼠标是否按下
            this.mouseState.down = true
            // 创建一个临时target
            // 记录目标元素
            let target = null
            if (this.state === this.stateList.drawing) {
            // 判断当前有没有精灵构造器,有的话就构造一个对应的精灵元素
              if (this.currentSpriteConstructor) {
                target = new this.currentSpriteConstructor(x, y)
              }
            } else if (this.state === this.stateList.moving) {
              let sprites = this.sprites
              // 遍历所有的精灵,调用他们的choose方法,判断有没有被选中
              for (let i = sprites.length - 1; i >= 0; i--) {
                if (sprites[i].choose(x, y)) {
                  target = sprites[i]
                  break;
                }
              }
              
              // 如果选中的话就调用target的getOffset方法,获取偏移量
              if (target) {
                let offset = target.getOffset(x, y)
                this.mouseState.offsetX = offset.x
                this.mouseState.offsetY = offset.y
              }
            }
            // 存储当前目标元素
            this.mouseState.target = target
            // 在离屏canvas保存除目标元素外的所有元素
            let ctx = this.outCtx
            // 清空离屏canvas
            ctx.clearRect(0, 0, this.width, this.height)
            // 将目标元素外的所有的元素绘制到离屏canvas中
            this.sprites.forEach(item => {
              if (item !== target) {
                item.draw(ctx)
              }
            })
            if(target){
                // 开始动画
                this.anmite()
            }
          }
        })
        this.canvas.addEventListener('mousemove', (e) => {
        //  如果鼠标按下且有目标元素,才执行下面的代码
          if (this.mouseState.down && this.mouseState.target) {
            let x = e.offsetX
            let y = e.offsetY
            if (this.state === this.stateList.drawing) {
            // 调用当前target的resize方法,改变大小
              this.mouseState.target.resize(x, y)
            } else if (this.state === this.stateList.moving) {
            // 取到存储的偏移量
              let {
                offsetX, offsetY
              } = this.mouseState
              // 调用moveTo方法将target移动到新的位置
              this.mouseState.target.moveTo(x - offsetX, y - offsetY)
            }
          }
        })
        document.body.addEventListener('mouseup', (e) => {
          if (this.mouseState.down) {
          // 将鼠标按下状态记录为false
            this.mouseState.down = false
            if (this.state === this.stateList.drawing) {
            // 调用target的validate方法。判断他要不要被加到场景去呢
              if (this.mouseState.target.validate()) {
                this.sprites.push(this.mouseState.target)
              }
            } else if (this.state === this.stateList.moving) {
              // 什么都不做
            }
          }
        })
      }
    }
    추천 관련 글:
  • canvasQR 코드 및 이미지 합성 코드 구현 방법

    #🎜 🎜 #
  • HTML5 Canvas는 대화형 지하철 노선도를 구현합니다

    위 내용은 HTML5 캔버스는 그리기 프로그램을 구현합니다(코드 포함).의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.