Как имитировать стиль фонового изображения CSS в холсте
Как имитировать стиль фонового изображения CSS в холсте

У автора есть открытый исходный кодWebинтеллектуальная картаmind-map,Недавно я столкнулся с проблемой при оптимизации эффекта фоновых изображений.,При отображении на странице передается фоновое изображение.cssиспользоватьbackground-imageоказанный,При экспорте он фактически обращается кcanvasэкспортировано на,Тогда будет проблема,cssФоновое изображение поддерживает более богатые эффекты.,Например, черезbackground-sizeУстановить размер,проходитьbackground-positionУстановить местоположение,проходитьbackground-repeatУстановить повтор,ноcanvasЯ нашел только одинcreatePattern()метод,И поддерживает только настройку эффектов повтора,Итак, какcanvasИмитировать определенныеcssА как насчет фоновых эффектов?,не уходи,Давайте попробуем вместе.

Первое, что я хочу объяснить, это то, что мы не будем совершенными и целостными.100%моделированиеcssвсе эффекты,потому чтоcssслишком мощный,Комбинации значений атрибутов очень гибкие.,И есть много видов,Существует много типов юнитов,Все будет лишь моделировать некоторые распространенные ситуации.,Устройство учитывает толькоpxи%

Прочтите эту статью,Вы, кстати, тоже можете его просмотретьcanvasизdrawImageметод,а такжеcss背景设置из几个свойствоиз用法。

Метод drawImage() холста

в общем,我们会использоватьcanvasизdrawImage()метод来绘制背景图片,Давайте сначала кратко рассмотрим этот метод.,Этот метод получает больше параметров:

Требуется всего три параметра.

Базовая структура и инструментальные методы

Основная логика Загрузить изображения,然后использоватьdrawImageметодрисовать картинки,Это не что иное, как основанное на различныхcssизсвойствоиценить来вычислитьdrawImageизпараметр,Таким образом, можно написать следующую базовую структуру функций:

Язык кода:javascript
копировать
const drawBackgroundImageToCanvas = (
  ctx,// контекст рисования на холсте
  width,// ширина холста
  height,// высота холста
  img,// URL изображения
  { backgroundSize, backgroundPosition, backgroundRepeat }// css, имитируйте только эти три типа
) => {
  // соотношение сторон холста
  let canvasRatio = width / height
  // Загрузить изображения
  let image = new Image()
  image.src = img
  image.onload = () => {
    // Ширина, высота и соотношение сторон изображения
    let imgWidth = image.width
    let imgHeight = image.height
    let imageRatio = imgWidth / imgHeight
    // рисовать картинки
    // Значения параметров метода drawImage
    let drawOpt = {
        sx: 0,
        sy: 0,
        swidth: imgWidth,// Нарисовать полную картину по умолчанию
        sheight: imgHeight,
        x: 0,
        y: 0,
        width: imgWidth,// Не масштабировать изображения по умолчанию
        height: imgHeight
    }
    // Вычислить на основе свойств и значений CSS...
    // рисовать картинки
    ctx.drawImage(image, drawOpt.sx, drawOpt.sy, drawOpt.swidth, drawOpt.sheight, drawOpt.x, drawOpt.y, drawOpt.width, drawOpt.height)
  }
}

Далее давайте рассмотрим некоторые функции инструмента.

Язык кода:javascript
копировать
// Преобразование строкового значения, разделенного пробелами, в массив чисел/единиц/значений.
const getNumberValueFromStr = value => {
  let arr = String(value).split(/\s+/)
  return arr.map(item => {
    if (/^[\d.]+/.test(item)) {
        // Номер + единица измерения
        let res = /^([\d.]+)(.*)$/.exec(item)
        return [Number(res[1]), res[2]]
    } else {
        // одно значение
        return item
    }
  })
}

cssизсвойствоценить为字符串或数字тип,например100px 100% auto,Неудобно использовать напрямую.,Так что конвертируйте в[[100, 'px'], [100, '%'], 'auto']форма。

Язык кода:javascript
копировать
// ширина шкалы
const zoomWidth = (ratio, height) => {
    // w / height = ratio
    return ratio * height
}

// высота масштабирования
const zoomHeight = (ratio, width) => {
  // width / h = ratio
  return width / ratio
}

Рассчитайте масштабированную ширину или высоту на основе исходных пропорций и новой ширины или высоты.

Имитировать свойство размера фона

по умолчаниюbackground-repeatизценить为repeat,Давайте сначала не будем рассматривать дублирование.,Поэтому сначала установите его наno-repeat

background-size Атрибут используется для установки размера фонового изображения. Он может принимать четыре типа значений. Давайте смоделируем его по очереди.

тип длины

Установите высоту и ширину фонового изображения. Первое значение задает ширину, а второе значение устанавливает высоту. Если задано только одно значение, второе по умолчанию равно auto(автоматический)。

cssСтиль следующий:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/1.jpg');
    background-repeat: no-repeat;
    background-size: 300px;
}

Если установлено только одно значение, оно представляет фактическую ширину отображения фонового изображения. Если высота не установлена, она автоматически масштабируется в соответствии с соотношением сторон изображения. Эффект следующий:

существоватьcanvas中моделирование很简单,необходимо передатьdrawImageметод四个параметр:img、x、y、width、height,imgРепрезентативное изображение,x、y代表существовать画布上放置图片из位置,никаких специальных настроек,Видимо это0、0,width、heightПредставляет масштабирование изображения до указанного размера.,еслиbackground-sizeпередается только одно значение,ТакwidthУстановите его непосредственно на это значение,иheight则根据图片из长宽比进行вычислить,Если переданы два значения,Так分别把两个ценить传给width、heightВот и все,Кроме того, значение должно бытьautoиз进行一下处理,Реализация следующая:

Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundSize: '300px'
})

const drawBackgroundImageToCanvas = () =>{
    // ...
    image.onload = () => {
        // ...
        // Имитировать размер фона
        handleBackgroundSize({
            backgroundSize, 
            drawOpt, 
            imageRatio
        })
        // ...
    }
}

// Имитировать размер фона
const handleBackgroundSize = ({ backgroundSize, drawOpt, imageRatio }) => {
    if (backgroundSize) {
      // Преобразовать значение в массив
      let backgroundSizeValueArr = getNumberValueFromStr(backgroundSize)
      // Оба значения являются автоматическими, что эквивалентно не установке
      if (backgroundSizeValueArr[0] === 'auto' && backgroundSizeValueArr[1] === 'auto') {
        return
      }
      // Ширина изображения
      let newNumberWidth = -1
      if (backgroundSizeValueArr[0]) {
        if (Array.isArray(backgroundSizeValueArr[0])) {
            // Номер + единица измерениятип
            drawOpt.width = backgroundSizeValueArr[0][0]
            newNumberWidth = backgroundSizeValueArr[0][0]
        } else if (backgroundSizeValueArr[0] === 'auto') {
            // автоматический тип, то оно будет адаптировано в соответствии с исходным соотношением сторон изображения в соответствии с установленной новой высотой.
            if (backgroundSizeValueArr[1]) {
                drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])
            }
        }
      }
      // Установите высоту изображения
      if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
        // Номер + единица измерениятип
        drawOpt.height = backgroundSizeValueArr[1][0]
      } else if (newNumberWidth !== -1) {
        // Если высота изображения не установлена ​​или установлено значение «авто», исходное соотношение сторон изображения будет адаптировано в соответствии с установленной новой шириной.
        drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
      }
    }
}

Эффект следующий:

Эффект установки двух значений:

Язык кода:javascript
копировать
background-size: 300px 400px;

процентный тип

Рассчитывается процент позиционируемой области относительно фона. Первое значение задает процент ширины,Второе значение задает процент высоты. Если задано только одно значение,第二个по умолчанию为auto(автоматический)。например设置了50% 80%,意思是将图片缩放到背景区域из50%宽度и80%высокий。

cssСтиль следующий:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/1.jpg');
    background-repeat: no-repeat;
    background-size: 50% 80%;
}

Реализация также очень проста,существовать前面из基础上判断一下единица是否是%,是из话就按照canvasиз宽高来вычислить图片要显示из宽高,Второе значение не установлено илиauto,Как и раньше, он также адаптируется в соответствии с соотношением сторон изображения.

Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundSize: '50% 80%'
})

handleBackgroundSize({
    backgroundSize,
    drawOpt,
    imageRatio,
    canvasWidth: width,// Передайте параметры, чтобы добавить ширину и высоту холста.
    canvasHeight: height
})

// Имитировать размер фона
const handleBackgroundSize = ({ backgroundSize, drawOpt, imageRatio, canvasWidth, canvasHeight }) => {
  if (backgroundSize) {
    // ...
    // Ширина изображения
    let newNumberWidth = -1
    if (backgroundSizeValueArr[0]) {
      if (Array.isArray(backgroundSizeValueArr[0])) {
        // Номер + единица измерениятип
        if (backgroundSizeValueArr[0][1] === '%') {
            // %, тогда высота отображения изображения равна проценту от холста.
            drawOpt.width = backgroundSizeValueArr[0][0] / 100 * canvasWidth
            newNumberWidth = drawOpt.width
        } else {
            // Остальные считаются единицами пикселей.
            drawOpt.width = backgroundSizeValueArr[0][0]
            newNumberWidth = backgroundSizeValueArr[0][0]
        }
      } else if (backgroundSizeValueArr[0] === 'auto') {
        // автоматический тип, то оно будет адаптировано в соответствии с исходным соотношением сторон изображения в соответствии с установленной новой высотой.
        if (backgroundSizeValueArr[1]) {
            if (backgroundSizeValueArr[1][1] === '%') {
                // Высота в % единицы
                drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0] / 100 * canvasHeight)
            } else {
                // Остальные считаются единицами пикселей.
                drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])
            }
        }
      }
    }
    // Установите высоту изображения
    if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
      // Номер + единица измерениятип
      if (backgroundSizeValueArr[1][1] === '%') {
        // Высота в % единицы
        drawOpt.height = backgroundSizeValueArr[1][0] / 100 * canvasHeight
      } else {
        // Остальные считаются единицами пикселей.
        drawOpt.height = backgroundSizeValueArr[1][0]
      }
    } else if (newNumberWidth !== -1) {
      // Если высота изображения не установлена ​​или установлено значение «авто», исходное соотношение сторон изображения будет адаптировано в соответствии с установленной новой шириной.
      drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
    }
  }
}

Эффект следующий:

тип крышки

background-sizeустановлен наcoverРепрезентативное изображение会保持原来из宽高比,и масштабирован до наименьшего размера, который полностью покроет область позиционирования фона.,Уведомление,Картина не будет деформироваться.

cssСтиль следующий:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/3.jpeg');
    background-repeat: no-repeat;
    background-size: cover;
}

этот Реализация также очень проста,根据图片из宽高比иcanvasиз宽高比判断,到底是缩放图片из宽度иcanvasиз宽度一致,还是缩放图片извысокийиcanvasизвысокий一致。

Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundSize: 'cover'
})

handleBackgroundSize({
    backgroundSize,
    drawOpt,
    imageRatio,
    canvasWidth: width,
    canvasHeight: height,
    canvasRatio// Увеличение параметра сторон холста
})

const handleBackgroundSize = ({
  backgroundSize,
  drawOpt,
  imageRatio,
  canvasWidth,
  canvasHeight,
  canvasRatio
}) => {
    // ...
    // Значение является покрытием
    if (backgroundSizeValueArr[0] === 'cover') {
        if (imageRatio > canvasRatio) {
            // 图片из宽高比大于соотношение сторон холста,Затем высота изображения масштабируется так, чтобы соответствовать высоте холста.,Адаптивная ширина
            drawOpt.height = canvasHeight
            drawOpt.width = zoomWidth(imageRatio, canvasHeight)
        } else {
            // В противном случае Ширина изображения缩放到иcanvasиз宽度一致,Высокая адаптивность
            drawOpt.width = ширина холста
            drawOpt.height = ZoomHeight(imageRatio, CanvasWidth)
        }
        возвращаться
    }
    // ...
}

Эффект следующий:

содержать тип

background-sizeустановлен наcontainтип表示图片还是会保持原有из宽高比,И масштабируйте его до максимального размера, который соответствует области позиционирования фона.,То есть картинка будет отображаться полностью,Но он не обязательно охватывает как горизонтальное, так и вертикальное направления фона.,В определенном направлении может быть пустое пространство.

cssстиль:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/1.jpg');
    background-repeat: no-repeat;
    background-size: contain;
}

实现刚好иcoverтипиз实现反过来Вот и все,если图片из宽高比大于canvasиз宽高比,Чтобы отобразить картинку полностью,让图片из宽度иcanvasиз宽度一致,Высокая адаптивность.

Язык кода:javascript
копировать
const handleBackgroundSize = () => {
    // ...
    // Значение содержит
    if (backgroundSizeValueArr[0] === 'contain') {
        if (imageRatio > canvasRatio) {
            // 图片из宽高比大于соотношение сторон холста,Так Ширина изображения缩放到иcanvasиз宽度一致,высокий自适应
            drawOpt.width = canvasWidth
            drawOpt.height = zoomHeight(imageRatio, canvasWidth)
        } else {
            // В противном случае высота изображения масштабируется в соответствии с высотой холста, а ширина становится адаптивной.
            drawOpt.height = canvasHeight
            drawOpt.width = zoomWidth(imageRatio, canvasHeight)
        }
        return
    }
}

Эффект следующий:

Прямо здесьbackground-sizeизмоделирование就结束了,посмотрим дальшеbackground-position

Имитировать свойство фоновой позиции

Не смотрите сначала настройкиbackground-sizeиз情况。

background-positionсвойство用于设置背景图像из起始位置,по умолчаниюценить为 0% 0%,Он также поддерживает несколько различных типов значений.,Посмотрите один за другим.

процентный тип

первый набор значенийгоризонтальное положение,Настройка второго значениявертикальное положение。Верхний левый угол это0%0%,В правом нижнем углу находится100%100%,Если установлено только одно значение,第二个по умолчанию为50%,напримерустановлен на50% 60%,意思是将图片из50% 60%位置и背景区域из50% 60%Выровнять положение,又например50% 50%,Это означает, что центральная точка изображения совпадает с центральной точкой области фона.

cssстиль:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/2.jpg');
    background-repeat: no-repeat;
    background-position: 50% 50%;
}

В реализации нам нужно использовать толькоdrawImageметодизimgx、yтри параметра,Ширина и высота изображения не будут масштабироваться.,根据比例分别算出существоватьcanvasи图片上верно应из距离,他们из差ценить即为图片существоватьcanvas上显示из位置。

Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundPosition: '50% 50%'
})

const drawBackgroundImageToCanvas = () => {
    // ...
    // Имитировать фоновое положение
    handleBackgroundPosition({
      backgroundPosition,
      drawOpt,
      imgWidth,
      imgHeight,
      canvasWidth: width,
      canvasHeight: height
    })
    // ...
}

// Имитировать фоновое положение
const handleBackgroundPosition = ({
  backgroundPosition,
  drawOpt,
  imgWidth,
  imgHeight,
  canvasWidth,
  canvasHeight
}) => {
  if (backgroundPosition) {
    // Преобразовать значение в массив
    let backgroundPositionValueArr = getNumberValueFromStr(backgroundPosition)
    if (Array.isArray(backgroundPositionValueArr[0])) {
      if (backgroundPositionValueArr.length === 1) {
        // Если установлено только одно значение, второе по умолчанию равно 50 %.
        backgroundPositionValueArr.push([50, '%'])
      }
      // горизонтальное положение
      if (backgroundPositionValueArr[0][1] === '%') {
        // Единица измерения: %
        let canvasX = (backgroundPositionValueArr[0][0] / 100) * canvasWidth
        let imgX = (backgroundPositionValueArr[0][0] / 100) * imgWidth
        // Рассчитать разницу
        drawOpt.x = canvasX - imgX
      }
      // вертикальное положение
      if (backgroundPositionValueArr[1][1] === '%') {
        // Единица измерения: %
        let canvasY = (backgroundPositionValueArr[1][0] / 100) * canvasHeight
        let imgY = (backgroundPositionValueArr[1][0] / 100) * imgHeight
        // Рассчитать разницу
        drawOpt.y = canvasY - imgY
      }
    }
  }
}

Эффект следующий:

тип длины

Первое значение представляетгоризонтальное положение,Второе значение представляетвертикальное положение。Верхний левый угол это0 0。Устройство может бытьpxили любой другойcssединица,конечно,мы рассматриваем толькоpx。если仅指定了一个ценить,Другие значения будут50%。所以你可以混合использовать%иpx

cssстиль:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/2.jpg');
    background-repeat: no-repeat;
    background-position: 50px 150px;
}

Эта реализация проще,Передайте значение непосредственно вdrawImageизx、yпараметр Вот и все。

Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundPosition: '50px 150px'
})

// Имитировать фоновое положение
const handleBackgroundPosition = ({}) => {
    // ...
    // горизонтальное положение
    if (backgroundPositionValueArr[0][1] === '%') {
        // ...
    } else {
        // Другие единицы измерения по умолчанию — пиксели.
        drawOpt.x = backgroundPositionValueArr[0][0]
    }
    // вертикальное положение
    if (backgroundPositionValueArr[1][1] === '%') {
        // ...
    } else {
        // Другие единицы измерения по умолчанию — пиксели.
        drawOpt.y = backgroundPositionValueArr[1][0]
    }
}

Тип ключевого слова

也就是проходитьlefttop之类из关键词进行组合,например:left topcenter centercenter bottomждать。可以看做是特殊из%ценить,Поэтому нам нужно всего лишь написать сопоставление, чтобы сопоставить эти ключевые слова с процентными значениями.

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/2.jpg');
    background-repeat: no-repeat;
    background-position: right bottom;
}
Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundPosition: 'right bottom'
})

// Сопоставление ключевого слова с процентным значением
const keyWordToPercentageMap = {
  left: 0,
  top: 0,
  center: 50,
  bottom: 100,
  right: 100
}

const handleBackgroundPosition = ({}) => {
    // ...
    // Преобразуйте ключевые слова в проценты
    backgroundPositionValueArr = backgroundPositionValueArr.map(item => {
      if (typeof item === 'string') {
        return keyWordToPercentageMap[item] !== undefined
          ? [keyWordToPercentageMap[item], '%']
          : item
      }
      return item
    })
    // ...
}

В сочетании с размером фона

最后我们来看看иbackground-size组合использовать会发生什么情况。

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/2.jpg');
    background-repeat: no-repeat;
    background-size: cover;
    background-position: right bottom;
}
Язык кода:javascript
копировать
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
    backgroundSize: 'cover',
    backgroundPosition: 'right bottom'
})

Результат следующий:

непоследовательный,Почему это?,Давайте разберемся,首先существовать处理background-sizeрассчитаетdrawImageпараметр中изwidth、height,也就是图片существоватьcanvas中显示из宽高,исуществовать处理background-position时会用到图片из宽高,Но мы по-прежнему передаем исходную ширину и высоту изображения.,Посчитайте это такконечно是有问题из,Измените его:

Язык кода:javascript
копировать
// Имитировать фоновое положение
handleBackgroundPosition({
    backgroundPosition,
    drawOpt,
    imgWidth: drawOpt.width,// Перейдите к рассчитанной ширине и высоте изображения.
    imgHeight: drawOpt.height,
    imageRatio,
    canvasWidth: width,
    canvasHeight: height,
    canvasRatio
})

Теперь посмотрим на эффект:

Имитировать свойство повторения фона

background-repeatСвойства используются для установки того, как Плиткаверно象изbackground-imageсвойство,по умолчаниюценить为repeat,То есть, когда изображение меньше области фона, оно по умолчанию будет повторяться по вертикали и горизонтали.,Также есть несколько необязательных значений:

  • repeat-x:толькогоризонтальное положение Фоновое изображение будет повторяться.
  • repeat-y:тольковертикальное положение Фоновое изображение будет повторяться.
  • no-repeatbackground-imageне будет повторяться

Далее мы реализуем эти ситуации.

no-repeat

Сначала определите, превышают ли ширина и высота изображения область фона.,是из话就不需要Плитка,Не нужно с этим иметь дело,另外ценить为no-repeatНикакой обработки не требуется:

Язык кода:javascript
копировать
// Имитировать фоновое повторение
handleBackgroundRepeat({
    backgroundRepeat,
    drawOpt,
    imgWidth: drawOpt.width,
    imgHeight: drawOpt.height,
    imageRatio,
    canvasWidth: width,
    canvasHeight: height,
    canvasRatio
})

可以看到这里我们传из图片из宽高也是经background-sizeвычислить后из图片显示宽高。

Язык кода:javascript
копировать
// Имитировать фоновое повторение
const handleBackgroundRepeat = ({
  backgroundRepeat,
  drawOpt,
  imgWidth,
  imgHeight,
  canvasWidth,
  canvasHeight,
}) => {
    if (backgroundRepeat) {
        // Преобразовать значение в массив
        let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)
        // Не обработано
        if (backgroundRepeatValueArr[0] === 'no-repeat' || (imgWidth >= canvasWidth && imgHeight >= canvasHeight)) {
            return
        }
    }
}

repeat-x

Далее добавьте паруrepeat-xиз支持,когдаcanvasиз宽度大于图片из宽度,Так Плитка горизонтально Рисовать,Рисунок вызывается неоднократноdrawImageметод,Так что это еще надо передатьctximageУказанные параметрыhandleBackgroundRepeatметод,另外еслиhandleBackgroundRepeatметод里进行了绘制,Исходный метод рисования больше не нужно вызывать:

Язык кода:javascript
копировать
// Имитировать фоновое повторение
// Если рисование выполняется в handleBackgroundRepeat, будет возвращено значение true.
let notNeedDraw = handleBackgroundRepeat({
    ctx,
    image,
    ...
})
if (!notNeedDraw) {
    drawImage(ctx, image, drawOpt)
}

// По параметрам рисуем картинки
const drawImage = (ctx, image, drawOpt) => {
  ctx.drawImage(
    image,
    drawOpt.sx,
    drawOpt.sy,
    drawOpt.swidth,
    drawOpt.sheight,
    drawOpt.x,
    drawOpt.y,
    drawOpt.width,
    drawOpt.height
  )
}

Метод рисования извлекается в метод для облегчения повторного использования.

Язык кода:javascript
копировать
const handleBackgroundRepeat = ({}) => {
    // ...
    // Плитка горизонтально
    if (backgroundRepeatValueArr[0] === 'repeat-x') {
      if (canvasWidth > imgWidth) {
        let x = 0
        while (x < canvasWidth) {
          drawImage(ctx, image, {
            ...drawOpt,
            x
          })
          x += imgWidth
        }
        return true
      }
    }
    // ...
}

每次更新图片из放置位置xпараметр,пока за пределамиcanvasиз宽度。

repeat-y

верноrepeat-yиз处理也是类似из:

Язык кода:javascript
копировать
const handleBackgroundRepeat = ({}) => {
    // ...
    // вертикальная плитка
    if (backgroundRepeatValueArr[0] === 'repeat-y') {
      if (canvasHeight > imgHeight) {
        let y = 0
        while (y < canvasHeight) {
          drawImage(ctx, image, {
            ...drawOpt,
            y
          })
          y += imgHeight
        }
        return true
      }
    }
    // ...
}

repeat

Последнее, чтоrepeatценить,То есть повторяйте и по горизонтали, и по вертикали:

Язык кода:javascript
копировать
const handleBackgroundRepeat = ({}) => {
    // ...
    // Плитка
    if (backgroundRepeatValueArr[0] === 'repeat') {
      let x = 0
      while (x < canvasWidth) {
        if (canvasHeight > imgHeight) {
          let y = 0
          while (y < canvasHeight) {
            drawImage(ctx, image, {
              ...drawOpt,
              x,
              y
            })
            y += imgHeight
          }
        }
        x += imgWidth
      }
      return true
    }
}

слева направо,Рисовать столбец за столбцом,Нарисуйте горизонтально, чтобыxвнеcanvasиз宽度为止,Нарисуйте вертикально, чтобыyвнеcanvasизвысокий为止。

В сочетании с размером фона и положением фона

Наконец, давайте также посмотрим на комбинацию первых двух атрибутов.

cssстиль:

Язык кода:javascript
копировать
.cssBox {
    background-image: url('/4.png');
    background-repeat: repeat;
    background-size: 50%;
    background-position: 50% 50%;
}

Эффект следующий:

Размер изображения правильный,Но местоположение неверное,cssиз做法应该是先根据background-positionизценить定位一张图片,Затем передвигайтесь,И мы явно проигнорировали эту ситуацию,каждый раз из0 0Позиция начинает рисовать。

Поймите принцип,Решение тоже очень простое,существоватьhandleBackgroundPositionметод中已经вычислить出了x、y,То есть нет никакого Плитка前第一张图片из放置位置:

我们只要вычислить出左边и上边还способный Плиткасколько фотографий,Рассчитайте положение первого изображения в горизонтальном и вертикальном направлениях.,作为后续循环изx、yиз初始ценить Вот и все。

Язык кода:javascript
копировать
const handleBackgroundRepeat = ({}) => {
    // Сохраните x, y, рассчитанные в handleBackgroundPosition.
    let ox = drawOpt.x
    let oy = drawOpt.y
    // вычислитьoxиoyспособный Плиткаиз图片数量
    let oxRepeatNum = Math.ceil(ox / imgWidth)
    let oyRepeatNum = Math.ceil(oy / imgHeight)
    // Рассчитайте положение первой картинки быка и ой
    let oxRepeatX = ox - oxRepeatNum * imgWidth 
    let oxRepeatY = oy - oyRepeatNum * imgHeight
    // Используйте oxRepeatX и oxRepeatY в качестве начальных значений x и y для последующих циклов.
    // ...
    // Плитка
    if (backgroundRepeatValueArr[0] === 'repeat') {
      let x = oxRepeatX
      while (x < canvasWidth) {
        if (canvasHeight > imgHeight) {
          let y = oxRepeatY
          // ...
        }
      }
    }
}

окончание

本文简单实现了一下существоватьcanvas中моделированиеcssизbackground-sizebackground-positionbackground-repeat三个свойствоиз部分效果,完整源码существоватьhttps://github.com/wanglin2/simulateCSSBackgroundInCanvas

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода