У автора есть открытый исходный код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
背景设置из几个свойствоиз用法。
в общем,我们会использоватьcanvas
изdrawImage()
метод来绘制背景图片,Давайте сначала кратко рассмотрим этот метод.,Этот метод получает больше параметров:
Требуется всего три параметра.
Основная логика Загрузить изображения,然后использоватьdrawImage
методрисовать картинки,Это не что иное, как основанное на различныхcss
изсвойствоиценить来вычислитьdrawImage
изпараметр,Таким образом, можно написать следующую базовую структуру функций:
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)
}
}
Далее давайте рассмотрим некоторые функции инструмента.
// Преобразование строкового значения, разделенного пробелами, в массив чисел/единиц/значений.
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']
форма。
// ширина шкалы
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
Стиль следующий:
.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
из进行一下处理,Реализация следующая:
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)
}
}
}
Эффект следующий:
Эффект установки двух значений:
background-size: 300px 400px;
Рассчитывается процент позиционируемой области относительно фона. Первое значение задает процент ширины,Второе значение задает процент высоты. Если задано только одно значение,第二个по умолчанию为auto(автоматический)。например设置了50% 80%
,意思是将图片缩放到背景区域из50%
宽度и80%
высокий。
css
Стиль следующий:
.cssBox {
background-image: url('/1.jpg');
background-repeat: no-repeat;
background-size: 50% 80%;
}
Реализация также очень проста,существовать前面из基础上判断一下единица是否是%
,是из话就按照canvas
из宽高来вычислить图片要显示из宽高,Второе значение не установлено илиauto
,Как и раньше, он также адаптируется в соответствии с соотношением сторон изображения.
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
Стиль следующий:
.cssBox {
background-image: url('/3.jpeg');
background-repeat: no-repeat;
background-size: cover;
}
этот Реализация также очень проста,根据图片из宽高比иcanvas
из宽高比判断,到底是缩放图片из宽度иcanvas
из宽度一致,还是缩放图片извысокийиcanvas
извысокий一致。
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
стиль:
.cssBox {
background-image: url('/1.jpg');
background-repeat: no-repeat;
background-size: contain;
}
实现刚好иcover
типиз实现反过来Вот и все,если图片из宽高比大于canvas
из宽高比,Чтобы отобразить картинку полностью,让图片из宽度иcanvas
из宽度一致,Высокая адаптивность.
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
стиль:
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-position: 50% 50%;
}
В реализации нам нужно использовать толькоdrawImage
методизimg
、x、y
три параметра,Ширина и высота изображения не будут масштабироваться.,根据比例分别算出существоватьcanvas
и图片上верно应из距离,他们из差ценить即为图片существоватьcanvas
上显示из位置。
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
стиль:
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-position: 50px 150px;
}
Эта реализация проще,Передайте значение непосредственно вdrawImage
изx、y
параметр Вот и все。
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]
}
}
也就是проходитьleft
、top
之类из关键词进行组合,например:left top
、center center
、center bottom
ждать。可以看做是特殊из%
ценить,Поэтому нам нужно всего лишь написать сопоставление, чтобы сопоставить эти ключевые слова с процентными значениями.
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-position: right bottom;
}
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
组合использовать会发生什么情况。
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-size: cover;
background-position: right bottom;
}
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundSize: 'cover',
backgroundPosition: 'right bottom'
})
Результат следующий:
непоследовательный,Почему это?,Давайте разберемся,首先существовать处理background-size
рассчитаетdrawImage
параметр中изwidth、height
,也就是图片существоватьcanvas
中显示из宽高,исуществовать处理background-position
时会用到图片из宽高,Но мы по-прежнему передаем исходную ширину и высоту изображения.,Посчитайте это такконечно是有问题из,Измените его:
// Имитировать фоновое положение
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-repeat
:background-image
не будет повторятьсяДалее мы реализуем эти ситуации.
Сначала определите, превышают ли ширина и высота изображения область фона.,是из话就不需要Плитка,Не нужно с этим иметь дело,另外ценить为no-repeat
Никакой обработки не требуется:
// Имитировать фоновое повторение
handleBackgroundRepeat({
backgroundRepeat,
drawOpt,
imgWidth: drawOpt.width,
imgHeight: drawOpt.height,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
可以看到这里我们传из图片из宽高也是经background-size
вычислить后из图片显示宽高。
// Имитировать фоновое повторение
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
из支持,когдаcanvas
из宽度大于图片из宽度,Так Плитка горизонтально Рисовать,Рисунок вызывается неоднократноdrawImage
метод,Так что это еще надо передатьctx
、image
Указанные параметрыhandleBackgroundRepeat
метод,另外еслиhandleBackgroundRepeat
метод里进行了绘制,Исходный метод рисования больше не нужно вызывать:
// Имитировать фоновое повторение
// Если рисование выполняется в 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
)
}
Метод рисования извлекается в метод для облегчения повторного использования.
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
из处理也是类似из:
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
ценить,То есть повторяйте и по горизонтали, и по вертикали:
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
стиль:
.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
из初始ценить Вот и все。
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-size
、background-position
、background-repeat
三个свойствоиз部分效果,完整源码существоватьhttps://github.com/wanglin2/simulateCSSBackgroundInCanvas。