category
D2是一种现代的从文本到图表的语言。它的构建考虑到了可扩展性。
…D2有一个内置的API,用于在高级操作AST(比AST节点上的CRUD更智能)。这允许任何人以编程方式构建和编辑图表。目标不是启用特定的用例,而是为无限的工作流启用不可预见的用例。
- https://d2lang.com/tour/future#developer-工具
这篇博客文章将展示一个具体的例子,通过使用D2的语言API来构建一个图表,在SQL语句的每一行之后可视化模式。
我们将把这组语句。。。
CREATE TABLE movie;
ALTER TABLE movie ADD COLUMN id integer;
ALTER TABLE movie ADD COLUMN star integer;
ALTER TABLE movie ADD COLUMN budget integer;
ALTER TABLE movie ADD COLUMN profit integer;
ALTER TABLE movie ADD COLUMN producer integer;
ALTER TABLE movie ADD COLUMN dialogue integer;
CREATE TABLE actor;
ALTER TABLE actor ADD COLUMN id integer;
ALTER TABLE actor ADD COLUMN name text;
ALTER TABLE actor ADD COLUMN native_lang integer;
CREATE TABLE producer;
ALTER TABLE producer ADD COLUMN id integer;
ALTER TABLE producer ADD COLUMN name text;
ALTER TABLE producer ADD COLUMN native_lang integer;
CREATE TABLE language;
ALTER TABLE language ADD COLUMN id integer;
ALTER TABLE language ADD COLUMN name text;
ALTER TABLE movie ADD CONSTRAINT fk_movie_actor FOREIGN KEY (star) REFERENCES actor (id)
ALTER TABLE movie ADD CONSTRAINT fk_movie_producer FOREIGN KEY (producer) REFERENCES producer (id)
ALTER TABLE movie ADD CONSTRAINT fk_movie_language FOREIGN KEY (dialogue) REFERENCES language (id)
ALTER TABLE producer ADD CONSTRAINT fk_producer_language FOREIGN KEY (native_lang) REFERENCES language (id)
ALTER TABLE actor ADD CONSTRAINT fk_actor_language FOREIGN KEY (native_lang) REFERENCES language (id)
注意每个步骤如何与上面的SQL查询相对应,从而创建正在构建的模式的可视化。
步骤1:设置
下面的代码将调用D2库来创建一个具有单个形状的新图表,并呈现SVG文件。我将隐藏导入并跳过错误检查以避免样板文件。您可以在GitHub存储库中找到此演示的可运行代码。
func main() {
ctx := context.Background()
// Start with a new, empty graph
_, graph, _ := d2lib.Compile(ctx, "", nil)
// Create a shape, "meow"
graph, _, _ = d2oracle.Create(graph, "meow")
// Turn the graph into a script (which would just be "meow")
script := d2format.Format(graph.AST)
// Initialize a ruler to measure font glyphs
ruler, _ := textmeasure.NewRuler()
// Compile the script into a diagram
diagram, _, _ := d2lib.Compile(context.Background(), script, &d2lib.CompileOptions{
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
})
// Render to SVG
out, _ := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
})
// Write to disk
_ = ioutil.WriteFile(filepath.Join("out.svg"), out, 0600)
}
这为我们提供了以下SVG:
步骤2:解析SQL语句
下面的代码遍历SQL语句,并为我们提供结构化数据,比如命令调用的命令和表。一堆假设,例如语句必须是一行。不重要/演示要点。
type Query struct {
Command string
Table string
Column string
Type string
ForeignTable string
ForeignColumn string
}
func parseSQL(plan string) (out []Query) {
lines := strings.Split(plan, "\n")
for _, line := range lines {
if len(strings.TrimSpace(line)) == 0 {
continue
}
out = append(out, parseSQLCommand(strings.Trim(line, ";")))
}
return out
}
func parseSQLCommand(command string) Query {
q := Query{}
words := strings.Split(command, " ")
if strings.HasPrefix(command, "CREATE") {
q.Command = "create_table"
q.Table = words[2]
} else if strings.Contains(command, "ADD COLUMN") {
q.Command = "add_column"
q.Table = words[2]
q.Column = words[5]
q.Type = words[6]
} else if strings.Contains(command, "ADD CONSTRAINT") {
q.Command = "add_foreign_key"
q.Table = words[2]
q.Column = strings.Trim(strings.Trim(words[8], "("), ")")
q.ForeignTable = words[10]
q.ForeignColumn = strings.Trim(strings.Trim(words[11], "("), ")")
}
return q
}
步骤3:调用d2oracle
d2oracle是D2中的API包。它可以用于创建和删除对象和连接、设置属性以及将对象移动到不同的容器。例如,给定这个D2脚本:
netflix: {
movie
}
hulu
let's watch -> netflix.movie
你可以调用d2oracle。Move(graph,“netflix.movie”,“hulu.moire”)将电影对象从一个容器移动到另一个容器,生成的脚本将是:
netflix
hulu: {
movie
}
let's watch -> hulu.movie
回到我们的演示,然后可以将每条SQL语句转换为d2oracle调用。
func (q Query) transformGraph(g *d2graph.Graph) *d2graph.Graph {
switch q.Command {
case "create_table":
// Create an object with the ID set to the table name
newG, newKey, _ := d2oracle.Create(g, q.Table)
// Set the shape of the newly created object to be D2 shape type "sql_table"
shape := "sql_table"
newG, _ = d2oracle.Set(g, fmt.Sprintf("%s.shape", newKey), nil, &shape)
return newG
case "add_column":
newG, _ := d2oracle.Set(g, fmt.Sprintf("%s.%s", q.Table, q.Column), nil, &q.Type)
return newG
case "add_foreign_key":
newG, _, _ := d2oracle.Create(g, fmt.Sprintf("%s.%s -> %s.%s", q.Table, q.Column, q.ForeignTable, q.ForeignColumn))
return newG
}
return nil
}
第4步:把所有的东西放在一起
读取.sql文件。
将每个原始字符串语句转换为结构化命令(使用步骤2中的函数)。
将每个命令传递到步骤3的函数中,以编程方式编辑图表。
在每行之后渲染一个SVG文件。
ctx := context.Background()
_, graph, _ := d2lib.Compile(ctx, "", nil)
ruler, _ := textmeasure.NewRuler()
// 1----
f, _ := ioutil.ReadFile(filepath.Join("plan.sql"))
// 2----
queries := parseSQL(string(f))
for i, q := range queries {
// 3----
graph = q.transformGraph(graph)
script := d2format.Format(graph.AST)
diagram, _, _ := d2lib.Compile(context.Background(), script, &d2lib.CompileOptions{
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
})
// 4----
out, _ := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
})
_ = ioutil.WriteFile(filepath.Join("svgs", fmt.Sprintf("step%d.svg", i)), out, 0600)
}
有文本支持的图表
如果您使用图形库来完成此操作,那么生成的SVG就会僵化。但是,使用D2,对于它生成的任何图表,您都可以获得支持它的文本。在我们的程序末尾插入这一行。。。
_ = ioutil.WriteFile("out.d2", []byte(d2format.Format(graph.AST)), 0600)
…为您获取这个D2脚本:
movie: {
id: integer
star: integer
budget: integer
profit: integer
producer: integer
dialogue: integer
}
movie.shape: sql_table
actor: {
id: integer
name: text
native_lang: integer
}
actor.shape: sql_table
producer: {
id: integer
name: text
native_lang: integer
}
producer.shape: sql_table
language: {
id: integer
name: text
}
language.shape: sql_table
movie.star -> actor.id
movie.producer -> producer.id
movie.dialogue -> language.id
producer.native_lang -> language.id
actor.native_lang -> language.id
想为受众自定义此图表吗?给你的产品经理或设计师花呢,然后在其他地方重复使用?根据你的喜好设计风格,还是通过互动来丰富?没有必要修改分支的源代码。将支持文本添加到图表中意味着您可以以简单、可访问的格式进行存储、版本控制和进一步修改。也许你的同事会拿下图表并做一些笔记:
在开源的两个月里,可扩展性和可组合性是D2流行的关键。它使我们能够快速集成技术,如用于Latex的MathJax,或用于上面手绘外观的RoughJS。它还使社区能够轻松地在D2之上进行构建。重要的是,它为用户提供了可选性,比如交换布局引擎的能力,或者主题的选择(或者自己制作!)。
- 登录 发表评论
- 6 次浏览
最新内容
- 1 day 18 hours ago
- 1 day 18 hours ago
- 1 day 18 hours ago
- 1 day 18 hours ago
- 2 days 19 hours ago
- 2 days 19 hours ago
- 2 days 19 hours ago
- 2 days 19 hours ago
- 2 days 19 hours ago
- 2 days 19 hours ago