L'auteur a mis en open source une mind-map web mind -map . Récemment, j'ai rencontré un problème lors de l'optimisation de l'effet de l'image d'arrière-plan. Lorsqu'elle est affichée sur la page, l'image d'arrière-plan est rendue à css
l'aide de , mais lorsqu'elle est exportée, elle est en fait dessiné vers le haut. Ensuite, il y aura un problème, l'image d'arrière-plan de l'image d'arrière-plan prend en charge des effets plus riches, tels que la définition de la taille, de la position et de la répétition, mais l'auteur n'a trouvé qu'une seule méthode et ne prend en charge que la définition de la répétition effet, alors comment simuler un certain En ce qui concerne l'effet de fond, ne partez pas, essayons-le ensemble ensuite.background-image
canvas
css
background-size
background-position
background-repeat
canvas
createPattern()
canvas
css
La première chose à expliquer est qu'il ne 100%
simulera pas css
parfaitement et complètement tous les effets, car il css
est trop puissant, la combinaison des valeurs d'attributs est très flexible, et il en existe de nombreux types, parmi lesquels il existe de nombreux types d'unités, ainsi, seules certaines situations courantes seront simulées et seules les unités seront prises en px
compte %
.
Après avoir lu cet article, vous pouvez également revoir la canvas
méthode drawImage
et css
l'utilisation de plusieurs attributs définis en arrière-plan d'ailleurs.
La méthode drawImage() de canvas
En général, nous utiliserons canvas
la drawImage()
méthode pour dessiner l'image de fond. Voyons d'abord cette méthode. Cette méthode reçoit plus de paramètres :
Seuls trois paramètres sont requis.
Cadre et outils de base
La logique de base consiste à charger l'image, puis à utiliser drawImage
la méthode pour dessiner l'image, qui n'est rien de plus que des paramètres css
calculés en fonction de divers attributs et valeurs drawImage
, de sorte que le cadre de base suivant de la fonction peut être écrit :
const drawBackgroundImageToCanvas = (
ctx,// canvas绘图上下文
width,// canvas宽度
height,// canvas高度
img,// 图片url
{
backgroundSize, backgroundPosition, backgroundRepeat }// css样式,只模拟这三种
) => {
// canvas的宽高比
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)
}
}
Ensuite, regardons quelques fonctions de l'outil.
// 将以空格分隔的字符串值转换成成数字/单位/值数组
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
La valeur d'attribut de est une chaîne ou un type numérique, par exemple 100px 100% auto
, il n'est pas pratique de l'utiliser directement, il est donc converti en [[100, 'px'], [100, '%'], 'auto']
formulaire.
// 缩放宽度
const zoomWidth = (ratio, height) => {
// w / height = ratio
return ratio * height
}
// 缩放高度
const zoomHeight = (ratio, width) => {
// width / h = ratio
return width / ratio
}
Calculez la largeur ou la hauteur mise à l'échelle en fonction du rapport d'origine et de la nouvelle largeur ou hauteur.
Simuler la propriété background-size
background-repeat
La valeur par défaut est repeat
, nous ne considérons pas le cas de duplication, alors réglez-la sur no-repeat
.
background-size
L'attribut est utilisé pour définir la taille de l'image d'arrière-plan et peut accepter quatre types de valeurs, qui sont simulées à tour de rôle.
type de longueur
Définissez la hauteur et la largeur de l'image d'arrière-plan. La première valeur définit la largeur et la seconde définit la hauteur. Si une seule valeur est donnée, la seconde par défaut est auto (automatique).
css
Le style est le suivant :
.cssBox {
background-image: url('/1.jpg');
background-repeat: no-repeat;
background-size: 300px;
}
Si une seule valeur est définie, elle représente la largeur réelle de l'affichage de l'image d'arrière-plan. Si la hauteur n'est pas définie, elle sera automatiquement mise à l'échelle en fonction du rapport d'aspect de l'image. L'effet est le suivant :
La simulation dans canvas
est très simple, et quatre paramètres doivent être passés à drawImage
la méthode : img、x、y、width、height
, img
représentant l'image, x、y
représentant la position de placement de l'image sur le canevas, il n'y a pas de réglage spécial, évidemment, 0、0
cela width、height
représente le zoom de l'image à la valeur spécifiée taille, si background-size
une seule valeur est transmise, alors width
réglez-la directement sur cette valeur, et height
calculez en fonction du rapport d'aspect de l'image. Si deux valeurs sont transmises, alors transmettez les deux valeurs séparément width、height
. De plus, vous avez besoin pour auto
traiter la valeur, comme suit :
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundSize: '300px'
})
const drawBackgroundImageToCanvas = () =>{
// ...
image.onload = () => {
// ...
// 模拟background-size
handleBackgroundSize({
backgroundSize,
drawOpt,
imageRatio
})
// ...
}
}
// 模拟background-size
const handleBackgroundSize = ({
backgroundSize, drawOpt, imageRatio }) => {
if (backgroundSize) {
// 将值转换成数组
let backgroundSizeValueArr = getNumberValueFromStr(backgroundSize)
// 两个值都为auto,那就相当于不设置
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') {
// 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) {
// 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应
drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
}
}
}
L'effet est le suivant :
L'effet de la définition de deux valeurs :
background-size: 300px 400px;
type de pourcentage
Le pourcentage de la zone localisée par rapport à l'arrière-plan sera calculé. La première valeur définit le pourcentage de largeur, la seconde valeur définit le pourcentage de hauteur. Si une seule valeur est donnée, la seconde par défaut est auto (automatique). Par exemple, s'il est défini 50% 80%
, cela signifie que l'image sera mise à l'échelle en fonction 50%
de la largeur et 80%
de la hauteur de la zone d'arrière-plan.
css
Le style est le suivant :
.cssBox {
background-image: url('/1.jpg');
background-repeat: no-repeat;
background-size: 50% 80%;
}
La mise en œuvre est également très simple. Sur la base de ce qui précède, jugez si l'unité est %
, si oui, canvas
calculez la largeur et la hauteur de l'image à afficher en fonction de la largeur et de la hauteur de l'image. La deuxième valeur n'est pas définie ou est, auto
comme avant, il est également basé sur le rapport d'aspect de l'image à adapter.
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundSize: '50% 80%'
})
handleBackgroundSize({
backgroundSize,
drawOpt,
imageRatio,
canvasWidth: width,// 传参新增canvas的宽高
canvasHeight: height
})
// 模拟background-size
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 {
// 其他都认为是px单位
drawOpt.width = backgroundSizeValueArr[0][0]
newNumberWidth = backgroundSizeValueArr[0][0]
}
} else if (backgroundSizeValueArr[0] === 'auto') {
// auto类型,那么根据设置的新高度以图片原宽高比进行自适应
if (backgroundSizeValueArr[1]) {
if (backgroundSizeValueArr[1][1] === '%') {
// 高度为%单位
drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0] / 100 * canvasHeight)
} else {
// 其他都认为是px单位
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 {
// 其他都认为是px单位
drawOpt.height = backgroundSizeValueArr[1][0]
}
} else if (newNumberWidth !== -1) {
// 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应
drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
}
}
}
L'effet est le suivant :
type de couverture
background-size
Défini pour signifier que cover
l'image conservera son format d'image d'origine et mis à l'échelle à la taille minimale qui couvrira complètement la zone de positionnement de l'arrière-plan. Notez que l'image ne sera pas déformée.
css
Le style est le suivant :
.cssBox {
background-image: url('/3.jpeg');
background-repeat: no-repeat;
background-size: cover;
}
Cette mise en œuvre est également très simple. Selon le rapport d'aspect de l'image et le canvas
rapport d'aspect de l'image, si la largeur de l'image agrandie est canvas
la même que la largeur de l'image, ou la hauteur de l'image canvas
est la même que la hauteur de l'image.
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundSize: 'cover'
})
handleBackgroundSize({
backgroundSize,
drawOpt,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio// 参数增加canvas的宽高比
})
const handleBackgroundSize = ({
backgroundSize,
drawOpt,
imageRatio,
canvasWidth,
canvasHeight,
canvasRatio
}) => {
// ...
// 值为cover
if (backgroundSizeValueArr[0] === 'cover') {
if (imageRatio > canvasRatio) {
// 图片的宽高比大于canvas的宽高比,那么图片高度缩放到和canvas的高度一致,宽度自适应
drawOpt.height = canvasHeight
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
} else {
// 否则图片宽度缩放到和canvas的宽度一致,高度自适应
drawOpt.width = canvasWidth
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
}
return
}
// ...
}
L'effet est le suivant :
contenir le type
background-size
Le définir sur contain
type signifie que l'image conservera toujours le rapport d'aspect d'origine et qu'elle sera mise à l'échelle à la taille maximale adaptée à la zone de positionnement de l'arrière-plan, c'est-à-dire que l'image sera affichée complètement, mais elle ne couvrira pas nécessairement l'arrière-plan horizontalement et verticalement. Il peut y avoir un espace vide dans une direction.
css
style:
.cssBox {
background-image: url('/1.jpg');
background-repeat: no-repeat;
background-size: contain;
}
L'implémentation cover
est à l'opposé de l'implémentation du type. Si le rapport d'aspect de l'image est supérieur au rapport d' canvas
aspect de l'image, afin de rendre l'image entièrement affichée, la largeur de l'image canvas
est cohérente avec la largeur de l'image, et la hauteur est auto-adaptative.
const handleBackgroundSize = () => {
// ...
// 值为contain
if (backgroundSizeValueArr[0] === 'contain') {
if (imageRatio > canvasRatio) {
// 图片的宽高比大于canvas的宽高比,那么图片宽度缩放到和canvas的宽度一致,高度自适应
drawOpt.width = canvasWidth
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
} else {
// 否则图片高度缩放到和canvas的高度一致,宽度自适应
drawOpt.height = canvasHeight
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
}
return
}
}
L'effet est le suivant :
background-size
La simulation ici est terminée, jetons un coup d'œil background-position
.
Simuler la propriété background-position
Regardez d'abord background-size
la situation où il n'est pas défini.
background-position
La propriété est utilisée pour définir la position de départ de l'image d'arrière-plan, la valeur par défaut est 0% 0%
, elle prend également en charge plusieurs types de valeurs différents, voyez-les une par une.
type de pourcentage
La première valeur définit la position horizontale et la deuxième valeur définit la position verticale. Le coin supérieur gauche est 0%0%
, le coin inférieur droit est 100%100%
, si une seule valeur est définie, la deuxième valeur par défaut est 50%
, par exemple, elle est définie sur 50% 60%
, ce qui signifie aligner 50% 60%
la position de l'image avec la position de la zone d'arrière-plan , et pour exemple , représentant le point central de l'image et le centre des points de la zone d'arrière-plan coïncident.50% 60%
50% 50%
css
style:
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-position: 50% 50%;
}
En termes de mise en œuvre, il suffit d'utiliser les trois paramètres de drawImage
la méthode La largeur et la hauteur de l'image ne seront pas mises à l'échelle, et la distance correspondant à l'image est calculée selon le rapport Leur différence est la position de la image affichée sur l'image.img
x、y
canvas
canvas
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundPosition: '50% 50%'
})
const drawBackgroundImageToCanvas = () => {
// ...
// 模拟background-position
handleBackgroundPosition({
backgroundPosition,
drawOpt,
imgWidth,
imgHeight,
canvasWidth: width,
canvasHeight: height
})
// ...
}
// 模拟background-position
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
}
}
}
}
L'effet est le suivant :
type de longueur
La première valeur représente la position horizontale et la deuxième valeur représente la position verticale. Le coin supérieur gauche est 0 0
. L'unité peut être px
ou toute autre css
unité, bien sûr, nous ne considérons que px
. Si une seule valeur est spécifiée, les autres seront 50%
. Ainsi, vous pouvez mélanger %
et assortir px
.
css
style:
.cssBox {
background-image: url('/2.jpg');
background-repeat: no-repeat;
background-position: 50px 150px;
}
Cette implémentation est plus simple, il suffit de passer la valeur directement au drawImage
paramètre x、y
.
drawBackgroundImageToCanvas(ctx, width, height, this.img, {
backgroundPosition: '50px 150px'
})
// 模拟background-position
const handleBackgroundPosition = ({
}) => {
// ...
// 水平位置
if (backgroundPositionValueArr[0][1] === '%') {
// ...
} else {
// 其他单位默认都为px
drawOpt.x = backgroundPositionValueArr[0][0]
}
// 垂直位置
if (backgroundPositionValueArr[1][1] === '%') {
// ...
} else {
// 其他单位默认都为px
drawOpt.y = backgroundPositionValueArr[1][0]
}
}
type de mot-clé
C'est-à-dire combiner des mots - clés tels que , left
, etc. Il peut être considéré comme une valeur spéciale, nous n'avons donc qu'à écrire un mappage pour mapper ces mots-clés à des valeurs en pourcentage.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
})
// ...
}
Combiné avec background-size
Enfin, nous regardons background-size
ce qui se passe lorsqu'il est combiné avec et .
.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'
})
Le résultat est le suivant :
Incohérent, pourquoi ? Faisons le tri. D'abord, le traitement background-size
calculera drawImage
les paramètres width、height
, c'est-à-dire canvas
la largeur et la hauteur de l'image qui y est affichée, et background-position
la largeur et la hauteur de l'image seront utilisées dans le traitement, mais ce que nous passons est toujours l'image La largeur et la hauteur d'origine de , bien sûr il y a un problème avec ce calcul, modifiez-le :
// 模拟background-position
handleBackgroundPosition({
backgroundPosition,
drawOpt,
imgWidth: drawOpt.width,// 改为传计算后的图片的显示宽高
imgHeight: drawOpt.height,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
Maintenant, regardez à nouveau l'effet :
Simuler la propriété background-repeat
background-repeat
L'attribut est utilisé pour définir comment mosaïquer l'objet background-image
. La valeur par défaut repeat
est, c'est-à-dire que lorsque l'image est plus petite que la zone d'arrière-plan, elle se répétera verticalement et horizontalement par défaut. Il existe plusieurs valeurs facultatives :
repeat-x
: seule la position horizontale répétera l'image d'arrière-planrepeat-y
: Seule la position verticale répétera l'image d'arrière-planno-repeat
:background-image
ne se répétera pas
Ensuite, nous implémentons ces situations.
sans répétition
Tout d'abord, jugez si la largeur et la hauteur de l'image sont plus grandes que la zone d'arrière-plan. Si c'est le cas, il n'est pas nécessaire de mosaïquer ou de traiter, et l'autre valeur n'a pas besoin d'être traitéeno-repeat
:
// 模拟background-repeat
handleBackgroundRepeat({
backgroundRepeat,
drawOpt,
imgWidth: drawOpt.width,
imgHeight: drawOpt.height,
imageRatio,
canvasWidth: width,
canvasHeight: height,
canvasRatio
})
Vous pouvez voir que la largeur et la hauteur de l'image que nous téléchargeons ici sont également la background-size
largeur et la hauteur d'affichage de l'image calculées.
// 模拟background-repeat
const handleBackgroundRepeat = ({
backgroundRepeat,
drawOpt,
imgWidth,
imgHeight,
canvasWidth,
canvasHeight,
}) => {
if (backgroundRepeat) {
// 将值转换成数组
let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)
// 不处理
if (backgroundRepeatValueArr[0] === 'no-repeat' || (imgWidth >= canvasWidth && imgHeight >= canvasHeight)) {
return
}
}
}
répéter-x
Ensuite, ajoutez repeat-x
la prise en charge de la paire. Lorsque canvas
la largeur est supérieure à la largeur de l'image, la mosaïque horizontale sera dessinée et le dessin appellera la drawImage
méthode à plusieurs reprises, il est donc nécessaire de transmettre ctx
des image
paramètres à handleBackgroundRepeat
la méthode. De plus, si handleBackgroundRepeat
le dessin est effectué dans la méthode, la méthode de dessin d'origine n'est pas nécessaire d'appeler :
// 模拟background-repeat
// 如果在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
)
}
La méthode de dessin est extraite dans une méthode pour une réutilisation facile.
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
}
}
// ...
}
Chaque fois que le x
paramètre de position de placement de l'image est mis à jour jusqu'à ce que canvas
la largeur dépasse.
répéter
La bonne repeat-y
manipulation est similaire :
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
}
}
// ...
}
répéter
Et enfin repeat
la valeur, qui se répète à la fois horizontalement et verticalement :
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
}
}
De gauche à droite, il est tracé colonne par colonne, horizontalement jusqu'à la largeur x
excédentaire canvas
et verticalement jusqu'à la hauteur y
excédentaire .canvas
Combinaison avec background-size, background-position
Enfin, regardez la combinaison avec les deux premiers attributs.
css
style:
.cssBox {
background-image: url('/4.png');
background-repeat: repeat;
background-size: 50%;
background-position: 50% 50%;
}
L'effet est le suivant :
La taille de l'image est correcte, mais la position est incorrecte. La css
meilleure façon de le faire est de commencer par background-position
positionner une image en fonction de la valeur de , puis de la mettre en mosaïque, mais nous ignorons évidemment cette situation et 0 0
commençons à dessiner à partir de la position à chaque fois.
Connaissant le principe, la solution est aussi très simple, elle handleBackgroundPosition
a été calculée dans la méthode x、y
, c'est-à-dire la position de placement de la première image avant le pavage :
Nous avons seulement besoin de calculer combien d'images peuvent être carrelées à gauche et en haut, et de calculer la position de la première image dans les directions horizontale et verticale comme valeur x、y
initiale du cycle suivant.
const handleBackgroundRepeat = ({
}) => {
// 保存在handleBackgroundPosition中计算出来的x、y
let ox = drawOpt.x
let oy = drawOpt.y
// 计算ox和oy能平铺的图片数量
let oxRepeatNum = Math.ceil(ox / imgWidth)
let oyRepeatNum = Math.ceil(oy / imgHeight)
// 计算ox和oy第一张图片的位置
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
// ...
}
}
}
}
fin
Cet article réalise simplement certains des effets des trois attributs canvas
simulés dans , et . Le code source complet css
se trouve sur https://github.com/wanglin2/simulateCSSBackgroundInCanvas .background-size
background-position
background-repeat