Рубрики
Без рубрики

“Почему еще никто не использует {вставьте вашу любимую функцию}? ” Рисунок на холсте – часть 1

“Почему никто уже не использовал это для этого?” Привет всем, Бьюсь об заклад, я не единственный w … с меткой холста, JavaScript, рисунок, Drawithme.

” Почему никто уже не использовал это для этого? “

Привет всем,

Бьюсь об заклад, я не единственный, у кого есть такие мысли. Я был в сообществе веб -разработчиков уже почти 12 лет, и я обнаружил, что думаю об этом несколько раз.

Отказ от ответственности: мой письменный английский отстой, я пытаюсь улучшить, пожалуйста, будьте нежными

Каждый раз, когда появляется новая крупная веб -функция, например, Canvas или Webassembly, для меня неизбежно начинать Immagine всевозможные новые приложения, которые теперь возможны. Тогда (почти) никто из них не оживает. Возможно, они просто менее крутые, чем то, как они мне кажутся, но мне нечего было потерять, и я разработал один из них.

Если бы мне пришлось выбрать одну веб -функцию в качестве моей любимой, Canvas выиграл бы руки вниз.

ИМХО Это самая недооцененная функция, которую мы имеем сейчас, и с этой серией статей я хочу поделиться тем, что я придумал до сих пор, надеясь, что больше людей увидят потенциал Canvas, как и я.

Потому что для меня реальный потенциал в холсте – это не то, что мы, разработчики, можем показать пользователям через него, но то, что пользователи могут вернуть нам, используя его. Полон в сети в мобильную эпоху действительно может быть окончательным вводом для всего, что не является простым текстом, номером или логическим.

Моя цель – достичь самых реалистичных опыта рисования.

Спойлер:

Давайте начнем с нуля. Canvas, мы все знаем основы:

// canvas creation
const myCanvas = document.createElement('canvas')
const ctx = myCanvas.getContext('2d')
myCanvas.width = 400
myCanvas.height = 150
container.appendChild(myCanvas)

// rect
ctx.fillStyle = 'rgb(255, 0, 0)'
ctx.fillRect(10, 10, 100, 80)

// circle
ctx.beginPath()
ctx.fillStyle = 'rgb(0, 0, 255)'
ctx.lineJoin = 'round'
ctx.lineCap = 'round'
ctx.arc(200, 50, 40, 0, 2 * Math.PI, true)
ctx.fill()

// image
ctx.drawImage(myImg, 280, 10, 80, 80)

Нам очень понадобятся эти основы, так почему бы не инкапсулировать их (с еще несколькими вариантами):

const drawSquare = (destinationContext, x, y, alpha, size, color, rotation = 0) => {
  const halfSize = size / 2
  destinationContext.globalAlpha = alpha
  destinationContext.fillStyle = color
  if (rotation % 90) {
    destinationContext.translate(x, y)
    destinationContext.rotate(rotation)
    destinationContext.fillRect(-halfSize, -halfSize, size, size)
    destinationContext.rotate(-rotation)
    destinationContext.translate(-x, -y)
  } else {
    destinationContext.fillRect(x - halfSize, y - halfSize, size, size)
  }
}

const drawCircle = (destinationContext, x, y, alpha, size, color) => {
  destinationContext.beginPath()
  destinationContext.fillStyle = color
  destinationContext.globalAlpha = alpha
  destinationContext.lineJoin = 'round'
  destinationContext.lineCap = 'round'
  destinationContext.arc(x, y, size / 2, 0, 2 * Math.PI, true)
  destinationContext.fill()
}

const drawImage = (destinationContext, x, y, alpha, size, image, rotation = 0) => {
  const halfSize = size / 2
  destinationContext.globalAlpha = alpha
  if (rotation % 360) {
    destinationContext.translate(x, y)
    destinationContext.rotate(rotation)
    destinationContext.drawImage(image, -halfSize, -halfSize, size, size)
    destinationContext.rotate(-rotation)
    destinationContext.translate(-x, -y)
  } else {
    destinationContext.drawImage(image, Math.round(x - halfSize), Math.round(y - halfSize), size, size)
  }
}

А затем используйте это:

drawSquare(ctx, 50, 150, 0.5, 80, 'rgb(255, 0, 0)', 30)
drawSquare(ctx, 110, 150, 0.7, 80, 'rgb(0, 255, 255)', -40)

drawCircle(ctx, 200, 150, 0.9, 50, 'rgb(255, 0, 0)')
drawCircle(ctx, 240, 150, 0.9, 60, 'rgb(255, 255, 0)')
drawCircle(ctx, 270, 150, 0.9, 70, 'rgb(0, 255, 255)')

drawImage(ctx, 350, 150, 0.6, 60, myImg, 45)

Обратите внимание, что я дал практически ту же подпись всем из них. Это будет очень полезно позже.

Итак, теперь мы готовы нарисовать что -то на экране на сенсорном вводе (Да Я использую сенсорный ввод в этом примере, он будет почти таким же с мышью вниз/перемещение).

const defaultToolSize = 20
const currentToolColor = 'rgb(255, 0, 0)'

const handleTouch = (e) => {
  const x = e.touches[0].clientX - myCanvas.offsetLeft
  const y = e.touches[0].clientY - myCanvas.offsetTop
  const alpha = e.touches[0].force || 1
  drawCircle(ctx, x, y, alpha, defaultToolSize, currentToolColor)
}

myCanvas.addEventListener('touchstart', handleTouch)
myCanvas.addEventListener('touchmove', handleTouch)

Хорошо, это что -то. Мы уже можем увидеть скелет того, что станет нашей линией.

Что если бы мы адаптировали размер, основанный на давлении силы?

const defaultToolSize = 20
const sizeForceFactor = 2

const handleTouch = (e) => {
  const x = e.touches[0].clientX - myCanvas.offsetLeft
  const y = e.touches[0].clientY - myCanvas.offsetTop
  const force = e.touches[0].force || 1
  const size = defaultToolSize + (defaultToolSize * force)
  drawCircle(ctx, x, y, force size, currentToolColor)
}

А почему не адаптировать размер на основе скорости перемещения сенсорного движения?

const sizeSpeedFactor = 5
const speedFactorLengthUnit = 200
let lastTouch = {
  x: -1,
  y: -1,
  force: 0,
}

// a bit of math
const round = (n, d = 0) => {
  const m = d ? Math.pow(10, d) : 1
  return Math.round(n * m) / m
}
const getDistanceBetweenTwoPoints = (x1, y1, x2, y2, decimals = 0) => 
  round(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), decimals)

const handleTouch = (e) => {
  const x = e.touches[0].clientX - myCanvas.offsetLeft
  const y = e.touches[0].clientY - myCanvas.offsetTop
  const force = e.touches[0].force || 1
  const distance = lastTouch.x >= 0 ? getDistanceBetweenTwoPoints(lastTouch.x, lastTouch.y, x, y) : 0
  const size = defaultToolSize +
    (defaultToolSize * force) +
    (defaultToolSize * sizeSpeedFactor * Math.min(distance / speedFactorLengthUnit, 1))

  drawCircle(ctx, x, y, force, size, currentToolColor)
  lastTouch = { x, y, force }
}

Мы могли бы пойти дальше и использовать склонность стилуса, чтобы адаптировать размер и альфа, но пока этого достаточно. Я буду обращаться с этим в другой раз.

Начиная с этой простой точки, мы создадим реалистичную линию.

Это все сейчас, я действительно надеюсь, что эта тема может заинтересовать некоторых из вас. Я провел много времени, преследуя цель воспроизведения бумажного опыта в Интернете, и я надеюсь, что это может быть полезно в будущем.

Пожалуйста, оставьте комментарий, если вам нравится эта тема. Я был бы рад ответить.

Спасибо за ваше время! Увидимся в следующем посте

Оригинал: “https://dev.to/alessandrocipolletti/why-nobody-in-using-insert-your-favourite-feature-yet-drawing-on-a-canvas-part-1-2ib2”