使用 JavaScript 创建图表
方法
可视化数据
图是由一系列带有边的节点组成的数据结构。图可以是有向的,也可以是无向的。
有向图包含的边的功能类似于单行道。边从一个节点流向另一个节点。
例如,您可能有一个人物和电影的图表,其中每个人可以有几部喜欢的电影,但电影没有喜欢的人。
无向图包含双向流动的边,类似于双向通行的双车道道路。
例如,你可能有一张宠物图,其中每只宠物都有一个主人,每个主人也拥有一只宠物。注意:双向箭头代表一条边,但为了清晰起见,我画了两条箭头。
图表中没有清晰的信息层次。
方法
我们将构建一个关于人和冰淇淋口味的图。它将是一个有向图,因为人们可能喜欢某些口味,但口味并不喜欢人。
我们将创建三个类:
PersonNode
IceCreamFlavorNode
Graph
人员节点
该类PersonNode
将接受一个参数:一个人的名字。这将作为其标识符。
构造函数PersonNode
将包含两个属性:
name
:唯一标识符favoriteFlavors
:IceCreamFlavorNodes 数组
此外,该类PersonNode
将包含一个方法:addFlavor
。它将接受一个参数,IceCreamFlavorNode
并将其添加到favoriteFlavors
数组中。
类定义如下:
class PersonNode {
constructor(name) {
this.name = name;
this.favoriteFlavors = [];
}
addFlavor(flavor) {
this.favoriteFlavors.push(flavor);
}
}
冰淇淋口味节点
该类IceCreamFlavorNode
将接受一个参数:冰淇淋口味。这将作为其标识符。
这个类不需要包含任何方法,因为这是一个无向图,数据从人流向口味,但不能向后流。
类定义如下:
class IceCreamFlavorNode {
constructor(flavor) {
this.flavor = flavor;
}
}
图形
该类Graph
不会接受任何参数,但其构造函数将包含三个属性:
peopleNodes
:PersonNode 数组。iceCreamFlavorNodes
:IceCreamFlavorNodes 数组edges
:包含 PersonNodes 和 IceCreamFlavorNodes 之间的边的数组。
Graph 类包含六种方法:
addPersonNode(name)
:接受一个参数,即一个人的名字,PersonNode
用这个名字创建一个新名字,然后将其推送到peopleNodes
数组中。addIceCreamFlavorNode(flavor)
:接受一个参数,一种冰淇淋口味,创建一个IceCreamFlavorNode
具有这种口味的新冰淇淋,并将其推送到iceCreamFlavorNodes
数组中。getPerson(name)
:接受一个参数,即一个人的名字,并返回该人的节点。getFlavor(flavor)
:接受一个参数,一种冰淇淋口味,并返回该口味的节点。addEdge(personName, flavorName)
:接受两个参数,一个人的名字和冰淇淋口味,检索两个节点,将口味添加到人的favoriteFlavors
数组中,并将边推送到边缘数组。print()
:只需打印出数组中的每个人peopleNodes
及其最喜欢的冰淇淋口味。
类定义如下:
class Graph {
constructor() {
this.peopleNodes = [];
this.iceCreamFlavorNodes = [];
this.edges = [];
}
addPersonNode(name) {
this.peopleNodes.push(new PersonNode(name));
}
addIceCreamFlavorNode(flavor) {
this.iceCreamFlavorNodes.push(new IceCreamFlavorNode(flavor));
}
getPerson(name) {
return this.peopleNodes.find(person => person.name === name);
}
getFlavor(flavor) {
return this.iceCreamFlavorNodes.find(flavor => flavor === flavor);
}
addEdge(personName, flavorName) {
const person = this.getPerson(personName);
const flavor = this.getFlavor(flavorName);
person.addFlavor(flavor);
this.edges.push(`${personName} - ${flavorName}`);
}
print() {
return this.peopleNodes.map(({ name, favoriteFlavors }) => {
return `${name} => ${favoriteFlavors.map(flavor => `${flavor.flavor},`).join(' ')}`;
}).join('\n')
}
}
可视化数据
现在我们有了三个类,我们可以添加一些数据并进行测试:
const graph = new Graph(true);
graph.addPersonNode('Emma');
graph.addPersonNode('Kai');
graph.addPersonNode('Sarah');
graph.addPersonNode('Maranda');
graph.addIceCreamFlavorNode('Chocolate Chip');
graph.addIceCreamFlavorNode('Strawberry');
graph.addIceCreamFlavorNode('Cookie Dough');
graph.addIceCreamFlavorNode('Vanilla');
graph.addIceCreamFlavorNode('Pistachio');
graph.addEdge('Emma', 'Chocolate Chip');
graph.addEdge('Emma', 'Cookie Dough');
graph.addEdge('Emma', 'Vanilla');
graph.addEdge('Kai', 'Vanilla');
graph.addEdge('Kai', 'Strawberry');
graph.addEdge('Kai', 'Cookie Dough');
graph.addEdge('Kai', 'Chocolate Chip');
graph.addEdge('Kai', 'Pistachio');
graph.addEdge('Maranda', 'Vanilla');
graph.addEdge('Maranda', 'Cookie Dough');
graph.addEdge('Sarah', 'Strawberry');
console.log(graph.print());
我们的有向图如下所示:
如果您想查看完整的代码,请查看我的CodePen。
文章来源:https://dev.to/emmabostian/creating-graphs-with-javascript-4efm