Loading...
Yoga 是 Facebook 提供的跨平台布局引擎,基于 Flex,属性和 CSS Flex 完全一致,因此也可以阅读 MDN flex 布局的基本概念 获取更多概念知识。
示例:
该插件使用 yoga-layout-prebuilt,包体积较大,后续我们会使用自己开发的轻量版布局引擎。
首先注册插件:
import { Renderer } from '@antv/g-canvas';import { Plugin } from '@antv/g-plugin-yoga';const renderer = new Renderer();renderer.registerPlugin(new Plugin());
通过 display: 'flex'
可以声明一个图形使用 Flex 布局。目前我们仅支持 Rect 和 Group 两类图形作为 Flex 容器:
// 声明一个容器const container = new Rect({style: {width: 500, // 尺寸height: 300,display: 'flex', // 声明使用 flex 布局justifyContent: 'center', // 居中alignItems: 'center', // 居中x: 0,y: 0,fill: '#C6E5FF',},});canvas.appendChild(container);// 声明子元素,不需要手动设置位置,由布局引擎计算const node1 = new Rect({style: {fill: 'white',width: 100,height: 100,},});const node2 = new Rect({style: {fill: 'white',width: 100,height: 100,},});container.appendChild(node1);container.appendChild(node2);
不同的属性支持的单位也不同,例如 number
类型的绝对像素值、'100%'
字符串类型的百分比以及特殊含义的 'auto'
。
使用 display: 'flex'
可以声明一个 Flex 容器,容器内所有直系子元素按照布局引擎计算结果进行布局,暂时仅支持 Rect 和 Group 作为容器:
// 或者使用 Group// const container = new Group({const container = new Rect({style: {width: 500, // 尺寸height: 300,display: 'flex', // 声明使用 flex 布局justifyContent: 'center', // 居中alignItems: 'center', // 居中x: 0, // 容器局部坐标系下位置y: 0,fill: '#C6E5FF', // 其他样式属性},});
容器内子元素无类型限制,例如下图中可以看到 Image 也可以按照计算结果正常布局。
另外容器支持嵌套,例如上图中 Node1 自身也是一个 Flex 容器,因此其中的文本可以水平垂直居中。
Layout 属性用于设置自身在容器中的布局效果,例如相对于已有结果进行调整。
支持以下取值,可以配合 top / right / botton / left 使用,和 CSS 完全一致:
relative
默认值,相对于正常布局位置absolute
相对于父容器进行绝对定位下左图中 Node1 使用 relative
,下右图使用 absolute
进行绝对定位:
支持绝对值与百分比,例如 { top: 10 }
、{ top: '50%' }
。当传入百分比字符串时,相对于父元素的尺寸。
例如下图中 Node1 使用 absolute
进行绝对定位,top
和 left
设置为 10:
下图中 Node1 使用 absolute
进行绝对定位,top
取 '50%'
,即父元素高度的一半:
下图中 Node1 使用 absolute
进行绝对定位,top
取 -50
:
设置自身宽高尺寸。默认值为 'auto'
。
支持百分比和绝对值,取百分比时相对于父元素尺寸。
例如下图中 Node1 设置了一个稍大一些的长宽:
最大最小约束,优先级高于其他属性。可以配合 flexGrow 使用。
默认值为 NaN,即无约束。支持百分比和绝对值,取百分比时相对于父元素尺寸,例如 { minWidth: 50% }
。
例如下图 Node1 设置了 { flexGrow: 1, maxWidth: 50% }
,因此它最多只能占据父元素宽度的一半:
数据类型为 [number | string, number | string, number | string, number | string]
,一次性设置上右下左的 padding。
支持以下取值,可参考 CSS padding 属性:
10
'50%'
,取百分比时相对于自身的宽度例如以下两种写法等价:
{padding: [10, 0, 10, 0],}{paddingTop: 10,paddingRight: 0,paddingBottom: 10,paddingLeft: 0,}
数据类型为 number | string
,统一设置上右下左的 padding。
单独设置上右下左的 padding。
type PixelsOrPercentage = number | string;type YogaSize = PixelsOrPercentage | 'auto';
数据类型为 [YogaSize, YogaSize, YogaSize, YogaSize]
,一次性设置上右下左的 margin。
支持以下取值,可参考 CSS margin 属性:
10
-50
'50%'
'-20%'
,取百分比时相对于父元素的宽度'auto'
,让布局引擎选择合适的外边距,可实现元素居中例如下图中 Node1 分别设置了 marginRight: 10
和 marginLeft: -50
:
下图展示了 marginTop: '50%'
的效果,以父元素宽度(500)为基准:
下图展示了 margin: [0, 'auto', 0, 'auto']
的效果,让元素水平居中:
数据类型为 YogaSize
,统一设置上右下左的 margin。详见 margin。
单独设置上右下左的 margin。详见 margin。
暂不支持。
来自 MDN 的说明
使用 flex 布局时,首先想到的是两根轴线:主轴和交叉轴。主轴由
flexDirection
定义,另一根轴垂直于它。
支持以下取值:
下左图为默认效果,下右图为 column
:
来自 MDN 的说明:
虽然 flexbox 是一维模型,但可以使我们的 flex 项目应用到多行中。 在这样做的时候,您应该把每一行看作一个新的 flex 容器。 任何空间分布都将在该行上发生,而不影响该空间分布的其他行。
支持以下取值:
在该示例中,可以点击 appendChild
按钮向容器中添加子元素。下左图展示了容器默认 no-wrap
的效果(注意由于不允许换行,子元素在宽度上被压缩了),下右图设置为 wrap
自动换行:
该属性是处理子元素在主轴上增加空间的问题。当 Flex 容器首次分配完子元素空间之后,如果还有剩余空间,它会按照这些子元素的 flexGrow 属性进行二次分配。
默认值为 0,支持大于等于 0 的取值,作为分配剩余空间的权重。
例如下图中,Node1 和 Node2 都设置了初始大小 { width: 100, height: 100 }
,但 Node1 额外设置了 { flexGrow: 1 }
,因此它将占据容器主轴上的全部剩余空间(总宽度 500 - Node2 宽度 100 = 400),效果上看就被“拉长”了:
如果想让 Node1 和 Node2 平分空间,可以在 Node2 上也设置 { flexGrow: 1 }
。
可以在该示例中调整以观察效果。特别适合实现“自适应”布局,当容器宽度发生修改时,剩余空间也跟着改变。
另外,剩余空间的分配也会考虑到子元素上 min/maxWidth/Height 这样的约束条件,在该示例中,Node1 同时设置了 { maxWidth: 200 }
,因此即使容器还有更多剩余空间,也不会分配给它(注意下图右侧容器的空白部分):
同样,当剩余空间不足时,minWidth
也能做为一个下限,例如下图中 Node1 最小宽度设置为 50,因此即使容器宽度仅有 100,也将保证它的展示宽度:
该属性是处理子元素收缩的问题。如果容器中没有足够排列元素的空间,那么可以把子元素的 flexShrink 属性设置为正整数来缩小它所占空间到 flexBasis 以下。与 flexGrow 属性一样,可以赋予不同的值来控制子元素收缩的程度,即给 flexShrink 属性赋予更大的数值可以比赋予小数值的同级元素收缩程度更大。
默认值为 1,支持大于等于 0 的取值。
例如下图当容器宽度不足以容纳 Node1 和 Node2 设置的初始宽度时,会按照 flexShrink 进行缩放,两个字节点都设置为 1 因此缩放程度一致:
来自 MDN 的说明
在考虑这几个属性的作用之前,需要先了解一下 可用空间 available space 这个概念。
定义了该元素在主轴上的默认空间大小。
默认值为 NaN。
来自 MDN 的说明
flexbox 的一个关键特性是能够设置 flex 元素沿主轴方向和交叉轴方向的对齐方式,以及它们之间的空间分配。
该属性用来使元素在主轴方向上对齐。
支持以下枚举值:
在该示例中,展示了 center
/ space-between
/ space-around
的效果:
该属性可以使元素在交叉轴方向对齐。
支持以下枚举值:
下图为 center
效果:
用于子元素覆盖容器中已有的 alignItems 的值:
在下图中,容器设置的 alignItems
为默认值 stretch
,但 Node1 可以通过 alignSelf: center
让自身脱离原本 Node2 和 Node3 的布局效果:
容器如何分配子元素周围空间,只有当 flexWrap 取值为 wrap
时生效:
支持以下枚举值:
在该示例中,依次展示了 center
/ space-between
/ space-around
效果:
支持,每个容器内单独计算布局并影响内部的子元素。
暂不支持。如果容器本身不需要被渲染,应该使用 Group。以上例子为了更好地展示容器尺寸,我们选择了 Rect。
setPosition/setLocalPosition()
调整位置吗?一旦容器使用了 Flex,它内部的子元素都应该使用 Flex 相关属性进行定位。虽然不禁止使用 setPosition
,但它显然会和布局引擎的计算结果冲突。
支持。但不同属性使用百分比的参考值并不相同。
例如 width/height 相对于父元素的宽高:
{width: '100%',height: '50%'}
目前 Text 已经支持多行文本,自动换行,但需要用户手动设置 wordWrapWidth
,超出后换行。
在 Flex 布局中,当文本作为子元素时,无需用户手动设置文本行宽,只需要开启 wordWrap
,配合 width
即可:
const text = new Text({style: {fontFamily: 'PingFang SC',fontSize: 32,fill: '#1890FF',text: '这是测试文字,这是测试文字,这是测试文字,这是测试文字',wordWrap: true, // 开启自动换行width: '100%', // 行宽},});
在该示例中,可以随时改变需要换行文本的行宽,下图为 width: '100%'
的效果:
Flex 布局新增了很多新属性,例如 padding margin 等,在 CSS 中是可以对这些属性进行动画的。
目前支持了部分属性,在该示例中可以查看:
node1.animate([{ top: 0, left: 0, width: 100, marginAll: 0, paddingLeft: 0 },{ top: 100, left: 100, width: 200, marginAll: 20, paddingLeft: 50 },],{duration: 1000,easing: 'cubic-bezier(0.250, 0.460, 0.450, 0.940)',fill: 'both',iterations: Infinity,direction: 'alternate-reverse',},);
需要指定一个平面,然后才能应用 Yoga 这样的 2D 布局引擎。
例如 react-three-flex 中使用 xy
yz
xz
。