盒模型
类似于 DOM 元素,spritejs 的元素也有自己的“盒模型”,具体来说,是指一个sprite元素有内容、padding、border,它们依照标准的规则占据一定的可视区域,另外由于元素还有transform,因此还有一个特殊的boundingRect。
我们用一张图来表示sprite元素的盒模型:
属性sprite.contentSize
或innerSize
表示是元素内容的宽高,给元素设置attr('size', size)
改变的也是这个值。而在它外面是padding(如果有的话),再外面是border(如果有的话),它和padding、innerSize共同构成了元素的offsetSize以及originalRect。如果元素被旋转、缩放,那么它实际在canvas内占据的矩形则是boundingRect。我们看一下例子:
padding: 20
border: 5
rotate: 0
size: 100
contentSize: 100,100
clientSize: 140,140
offsetSize: 150,150
originalRect: -75,-75,150,150
boundingRect: -75,-75,150,150
originalRenderRect: 310,225,150,150
renderRect: 310,225,150,150
const scene = new Scene('#box-rect', {viewport: ['auto', 'auto'], resolution: [770, 600]});
const layer = scene.layer('fglayer');
const s1 = new Path();
s1.attr({
path: {
d: 'M0,0L0,1L1,1L1,0z',
transform: {scale: 100},
},
anchor: [0.5, 0.5],
fillColor: '#f77',
pos: [385, 300],
padding: [20, 20, 20, 20],
bgcolor: 'rgba(0, 0, 0, 0.3)',
border: [5, 'black'],
borderRadius: 10,
});
layer.append(s1);
const contentSize = document.getElementById('contentSize'),
clientSize = document.getElementById('clientSize'),
offsetSize = document.getElementById('offsetSize'),
originalRect = document.getElementById('originalRect'),
boundingRect = document.getElementById('boundingRect'),
originalRenderRect = document.getElementById('originalRenderRect'),
renderRect = document.getElementById('renderRect'),
paddingCtl = document.getElementById('paddingCtl'),
borderCtl = document.getElementById('borderCtl'),
rotateCtl = document.getElementById('rotateCtl'),
sizeCtl = document.getElementById('sizeCtl'),
paddingValue = document.getElementById('paddingValue'),
rotateValue = document.getElementById('rotateValue'),
sizeValue = document.getElementById('sizeValue'),
borderValue = document.getElementById('borderValue');
function box(rect) {
const [x, y, w, h] = rect;
return [...[x, y].map(Math.floor), ...[w, h].map(Math.ceil)];
}
function updateState() {
contentSize.innerHTML = s1.contentSize;
clientSize.innerHTML = s1.clientSize;
offsetSize.innerHTML = s1.offsetSize;
originalRect.innerHTML = box(s1.originalRect);
boundingRect.innerHTML = box(s1.boundingRect);
originalRenderRect.innerHTML = box(s1.originalRenderRect);
renderRect.innerHTML = box(s1.renderRect);
}
updateState();
paddingCtl.addEventListener('change', (evt) => {
const value = evt.target.value;
s1.attr('padding', value);
paddingValue.innerHTML = value;
updateState();
});
borderCtl.addEventListener('change', (evt) => {
const value = evt.target.value;
s1.attr('border', [value]);
borderValue.innerHTML = value;
updateState();
});
rotateCtl.addEventListener('change', (evt) => {
const value = evt.target.value;
s1.attr('rotate', [value]);
rotateValue.innerHTML = value;
updateState();
});
sizeCtl.addEventListener('change', (evt) => {
const value = evt.target.value;
const path = s1.attr('path');
path.transform.scale = value;
s1.attr({path});
sizeValue.innerHTML = value;
updateState();
});
注意一个细节,originalRect和boundingRect的坐标原点是sprite元素的anchor points,因为我们把anchor设为了[0.5, 0.5]所以我们看到的坐标起始点是负值。另外我们还可以直接拿到renderRect和originRect,对应元素transform之前和之后在画布上的实际坐标。