Skip to content

Commit

Permalink
feat(render): add d3 to ttree for #83
Browse files Browse the repository at this point in the history
  • Loading branch information
phodal committed May 9, 2020
1 parent 20e2b01 commit abc6361
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { LedgeListItem } from '../../components/model/ledge-chart.model';
import * as d3 from 'd3';

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<p>ledge-tree works!</p>
<div #chart class="ledge-tree">

</div>
181 changes: 181 additions & 0 deletions projects/ledge-render/src/lib/chart/ledge-tree/ledge-tree.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { LedgeListItem } from '../../components/model/ledge-chart.model';
import * as d3 from 'd3';

@Component({
selector: 'ledge-tree',
Expand Down Expand Up @@ -31,6 +32,186 @@ export class LedgeTreeComponent implements OnInit, OnChanges {
}

private render() {
const treeData = {
name: 'Top Level',
children: [
{
name: 'Level 2: A',
children: [
{name: 'Son of A'},
{name: 'Daughter of A'}
]
},
{name: 'Level 2: B'}
]
};

const chartElement = this.chartEl.nativeElement;
// Set the dimensions and margins of the diagram
const margin = {top: 20, right: 90, bottom: 30, left: 90};
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;

// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
const svg = d3.select(chartElement).append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate('
+ margin.left + ',' + margin.top + ')');

let i = 0;
const duration = 750;
let root;

// declares a tree layout and assigns the size
const treemap = d3.tree().size([height, width]);

// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, (d: any) => d.children);
root.x0 = height / 2;
root.y0 = 0;

// Collapse after the second level
root.children.forEach(collapse);

update(root);

// Collapse the node and all it's children
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}

function update(source) {
// Assigns the x and y position for the nodes
const treemapDatta = treemap(root);

// Compute the new tree layout.
const nodes = treemapDatta.descendants();
const links = treemapDatta.descendants().slice(1);

// Normalize for fixed-depth.
nodes.forEach(d => {
d.y = d.depth * 180;
});

// ****************** Nodes section ***************************

// Update the nodes...
const node = svg.selectAll('g.node')
.data(nodes, (d: any) => d.id || (d.id = ++i));

// Enter any new modes at the parent's previous position.
const nodeEnter = node.enter().append('g')
.attr('class', 'node')
.attr('transform', d => 'translate(' + source.y0 + ',' + source.x0 + ')')
.on('click', click);

// Add Circle for the nodes
nodeEnter.append('circle')
.attr('class', 'node')
.attr('r', 1e-6)
.style('fill', (d: any) => d._children ? 'lightsteelblue' : '#fff');

// Add labels for the nodes
nodeEnter.append('text')
.attr('dy', '.35em')
.attr('x', (d: any) => d.children || d._children ? -13 : 13)
.attr('text-anchor', (d: any) => d.children || d._children ? 'end' : 'start')
.text((d: any) => d.data.name);

// UPDATE
const nodeUpdate = nodeEnter.merge(node as any);

// Transition to the proper position for the node
nodeUpdate.transition()
.duration(duration)
.attr('transform', d => 'translate(' + d.y + ',' + d.x + ')');

// Update the node attributes and style
nodeUpdate.select('circle.node')
.attr('r', 10)
.style('fill', (d: any) => d._children ? 'lightsteelblue' : '#fff')
.attr('cursor', 'pointer');


// Remove any exiting nodes
const nodeExit = node.exit().transition()
.duration(duration)
.attr('transform', d => 'translate(' + source.y + ',' + source.x + ')')
.remove();

// On exit reduce the node circles size to 0
nodeExit.select('circle')
.attr('r', 1e-6);

// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);

// ****************** links section ***************************

// Update the links...
const link = svg.selectAll('path.link')
.data(links, (d: any) => d.id);

// Enter any new links at the parent's previous position.
const linkEnter = link.enter().insert('path', 'g')
.attr('class', 'link')
.attr('d', d => {
const o = {x: source.x0, y: source.y0};
return diagonal(o, o);
});

// UPDATE
const linkUpdate = linkEnter.merge(link as any);

// Transition back to the parent element position
linkUpdate.transition()
.duration(duration)
.attr('d', d => diagonal(d, d.parent));

// Remove any exiting links
const linkExit = link.exit().transition()
.duration(duration)
.attr('d', d => {
const o = {x: source.x, y: source.y};
return diagonal(o, o);
})
.remove();

// Store the old positions for transition.
nodes.forEach((d: any) => {
d.x0 = d.x;
d.y0 = d.y;
});

// Creates a curved (diagonal) path from parent to the child nodes
function diagonal(s, d) {
const path = `M ${s.y} ${s.x}
C ${(s.y + d.y) / 2} ${s.x},
${(s.y + d.y) / 2} ${d.x},
${d.y} ${d.x}`;
return path;
}

// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
}
}
}
4 changes: 4 additions & 0 deletions src/assets/docs/help.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Ledge 语法帮助

```tree
```

```maturity
- 敏捷成熟度模型
- 组织治理: 3
Expand Down
1 change: 1 addition & 0 deletions src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@import "styles/mdstyles/tech-radar";
@import "styles/mdstyles/fish-bone";
@import "styles/mdstyles/maturity";
@import "styles/mdstyles/tree";

html, body {
height: 100%;
Expand Down
17 changes: 17 additions & 0 deletions src/styles/mdstyles/_tree.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.ledge-tree {
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}

.node text {
font: 12px sans-serif;
}

.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
}

0 comments on commit abc6361

Please sign in to comment.