DSL 定义
DSL 是描述一个 VStory 作品的 JSON 格式。其中定义了这个作品中使用了哪些元素,以及相关配置。描述了这个作品是如何编排的,什么元素在什么时刻做了什么行为。关于 DSL 的快速实战入门请参考一份基础的 DSL。本节教程将详细介绍 DSL 的具体定义。
描述一个作品,我们需要讲清楚两件事:
- 一个是这个作品的组成部分,也就是这个作品由什么元素组成的。
- 一个是这个作品的编排,也就是这些元素是怎么组成作品的画面,以及不同时刻这些元素做了什么行为。 通过上述两块描述,我们就可以完成一个作品的定义。
在 DSL 定义中,作品的组成部分也就是元素的定义,是在characters数组中定义的。作品的编排是通过acts数组来定义的。
我们的 acts 定义参考了戏剧的架构:在戏剧中,“幕”和“场面”是两个非常重要的概念,用于划分和组织剧本的结构。
- 幕:在戏剧中,幕(Act)是剧本的主要部分,用于划分戏剧的大段落。一部戏剧通常包含两幕或更多,每一幕都有其独特的主题和冲突。幕的划分可以帮助观众理解剧情的发展和角色的变化。在实际表演中,每一幕之间通常会有短暂的休息,以便更换舞台布景或让演员更换服装。
- 场面:场面(Scene)是幕的子集,它进一步细化了剧本的结构。一幕通常包含多个场面,每个场面都在特定的时间和地点发生。场面的切换通常意味着角色、地点或时间的变化。在剧本中,场面的划分可以帮助读者或观众更好地理解剧情的流动。
我们的 acts 定义也是由幕(Act) -> 场面(Scene) -> 行为(action)这样的定义
结构
DSL 是一个 JSON 格式的对象,包含以下几个字段:
character数组character数组用于描述这个作品中使用了哪些元素,以及相关配置。acts数组acts数组用于描述这个作品是如何编排的,什么元素在什么时刻做了什么行为。
interface IStoryDSL { acts: IActSpec[]; // 作品的章节,描述这个作品是如何编排的,什么元素在什么时刻做了什么行为。 characters: ICharacterConfig[]; // 作品中的元素,描述这个作品中使用了哪些元素,以及相关配置。 }
character 数组
character 数组用于描述这个作品中使用了哪些类型的元素,以及相关配置。其中包含位置大小(position),层级(layout)。
type ICharacterConfig = IChartCharacterConfig | IComponentCharacterConfig;
// position的定义,描述元素的位置和大小,以及旋转锚点等信息
type IWidgetData = {
left?: number;
top?: number;
x?: number;
y?: number;
angle?: number;
anchor?: [number, number];
} & (
| {
bottom?: number;
right?: number;
}
| {
width?: number;
height?: number;
}
);
interface ICharacterConfigBase {
id: string;
type: string; // character的类型
position: IWidgetData; // 定位描述
zIndex: number; // 层级描述
extra?: any; // 带着的额外信息,可不填
}
目前character有三大类型,分别是图表、组件、表格。主要是因为这三大类型的配置有较大差异,然后每个类型下面还有无数的子类型,比如组件类型,你可以自定义任意的组件,然后注册到 VStory 中在 DSL 中使用。
图表类型
图表类型支持 VChart 图表,可以直接配置 VChart 的 spec,然后支持一些额外属性列举如下:
interface IChartCharacterConfig extends ICharacterConfigBase { options: { // 图表spec spec?: any; // 初始化参数 initOption?: IInitOption; // 边距 padding?: { left: number; top: number; right: number; bottom: number }; // 图表容器 panel?: any; // 数据源 data?: any; // 标题 title?: { [key in ModelSelector]: Partial<ElementType<ISpec['title']>>; }; // 图例 legends?: { [key in ModelSelector]: Partial<ElementType<ISpec['legends']>>; }; // axes axes?: { [key in ModelSelector]: Partial<ElementType<ISpec['axes']>>; }; // 色板 color?: any; // mark 单元素样式 markStyle?: { [key: string]: IMarkStyle; }; // label 单元素样式 与 mark 区分开,runtime逻辑完全不同 labelStyle?: { [key: string]: IMarkStyle; }; // 组样式配置 dataGroupStyle?: { [StroyAllDataGroup]: IDataGroupStyle; // 全部分组的样式 [key: string]: IDataGroupStyle; // 某一组 }; // 直接合并的配置,使用VChart的spec rootConfig?: Record<string, any>; }; }
组件类型
文字、图片等都属于组件类型,如果需要在 VStory 中使用自定义组件,需要先注册到 VStory 中,然后在 DSL 中使用。这个在自定义组件中会详细介绍。
注意的是,组件可以携带一个额外的文本,这个文本通过text属性配置,而graphic属性则是组件本身的配置。
interface IComponentCharacterConfig extends ICharacterConfigBase { options: { // 主图元的配置 graphic: any; // 面板配置 panel?: any; // 文字配置 text?: any; // 边距 padding?: { left: number; top: number; right: number; bottom: number }; }; }
表格类型
正在开发中
Acts 数组
通过characters数组,我们可以在画布中放置多个元素,接下来我们需要通过acts数组来描述这个作品是如何编排的,什么元素在什么时刻做了什么行为。acts由幕、场景、动作组成。
acts数组中可以包含多个幕,幕与幕之间是有先后顺序的串联结构。每一个幕中可以包含多个场景,场景与场景默认是有先后顺序的串联结构。但是场景和场景的时间线是可以重叠的,通过配置场景的delay字段,可以控制该场景与上一个场景时间线的偏移。每一个场景中可以包含多个动作,动作中描述了一个或多个character的具体行为,一个场景中可以包含多个character和多个动作,动作之间是并行执行的,通过配置startTime来控制该动作的开始时间。
幕
幕是作品中最大的章节,一个作品可以包含多个幕,幕与幕之间是有先后顺序的串联结构。
interface IActSpec { id: string; // 幕的id scenes: ISceneSpec[]; // 场景数组 }