UPDATE 2/2: add graph

This commit is contained in:
Michał Romaszkin 2020-06-24 13:21:25 +02:00
parent ffca9a8a74
commit b29ffd0605
4 changed files with 109 additions and 6 deletions

View File

@ -4,12 +4,10 @@ import { Post } from '../_interfaces/post';
* Returns hierearchy-like array specified for D3 graph * Returns hierearchy-like array specified for D3 graph
*/ */
export default function makeHierarchy(data: Post[]) { export default function makeHierarchy(data: Post[]) {
console.log('In function!');
const tree: Post[] = []; const tree: Post[] = [];
const childOf: any = {}; const childOf: any = {};
data.forEach((element) => { data.forEach((element) => {
const { id, parent } = element; const { id, parent } = element;
console.log(parent);
childOf[id] = childOf[id] || []; childOf[id] = childOf[id] || [];
element.children = childOf[id]; element.children = childOf[id];
if (parent !== 0) { if (parent !== 0) {

View File

@ -0,0 +1,5 @@
::ng-deep .link {
fill: none;
stroke: #000;
stroke-width: 2px;
}

View File

@ -1,9 +1,16 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import {
Component,
OnInit,
OnDestroy,
ViewChild,
ElementRef,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { GetVisualizationDataService } from '../../_services/get-visualization-data.service'; import { GetVisualizationDataService } from '../../_services/get-visualization-data.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { concatMap } from 'rxjs/operators'; import { concatMap, finalize } from 'rxjs/operators';
import { Post } from 'src/app/_interfaces/post'; import { Post } from 'src/app/_interfaces/post';
import * as d3 from 'd3';
import maked3hierarchy from '../../_functions/maked3hierarchy'; import maked3hierarchy from '../../_functions/maked3hierarchy';
@Component({ @Component({
@ -14,6 +21,9 @@ import maked3hierarchy from '../../_functions/maked3hierarchy';
export class VisualizeForumComponent implements OnInit, OnDestroy { export class VisualizeForumComponent implements OnInit, OnDestroy {
private subscription: Subscription; private subscription: Subscription;
private data: Post[]; private data: Post[];
private hierarchizedData: Post[];
@ViewChild('tree', { read: ElementRef })
private treeContainer: ElementRef;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@ -24,12 +34,101 @@ export class VisualizeForumComponent implements OnInit, OnDestroy {
this.subscription = this.route.params this.subscription = this.route.params
.pipe(concatMap((params) => this.getDataService.getDiscussion(params.id))) .pipe(concatMap((params) => this.getDataService.getDiscussion(params.id)))
.subscribe((result) => { .subscribe((result) => {
this.data = maked3hierarchy(result.posts); this.initializeData(result.posts);
console.log(this.data); this.generateGraph();
}); });
} }
ngOnDestroy(): void { ngOnDestroy(): void {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
private initializeData(data: Post[]): void {
this.data = data;
this.hierarchizedData = maked3hierarchy(data);
}
private generateGraph(): void {
/* ToDo: Add option to change sizes */
const margin = { top: 50, right: 90, bottom: 30, left: 90 };
const width = 660 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
const hierarchizedNodes = d3.hierarchy<Post>(this.hierarchizedData[0]);
d3.tree().size([width, height])(hierarchizedNodes);
const element = this.treeContainer.nativeElement;
/* Clear previous graph */
d3.select(element).select('svg').remove();
/* Create SVG */
const svg = d3
.select(element)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
const group = svg
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
const gLink = group.append('g').attr('class', 'links');
const gNode = group.append('g').attr('class', 'nodes');
/* Custom tooltip */
const tooltip = d3
.select(element)
.append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('opacity', 0);
/* Select all nodes and pass data into them */
const node = gNode
.selectAll('g.nodes')
.data(hierarchizedNodes.descendants());
/* Select all links and pass data into them */
const link = gLink.selectAll('g.links').data(hierarchizedNodes.links());
/* 'Enter' into node, style it properly and create tooltip on hover */
const nodeEnter = node.enter().append('g').classed('node', true);
nodeEnter
.append('circle')
.attr('cx', (d: any) => d.x)
.attr('cy', (d: any) => d.y)
.attr('r', 25)
.style('fill', '#fff')
.style('stroke', '#ccc');
nodeEnter
.append('text')
.attr('x', (d: any) => d.x)
.attr('y', (d: any) => d.y)
.attr('text-anchor', 'middle')
.text((d: any) => d.data.id);
nodeEnter
.on('mouseover', (d) => {
tooltip.transition().duration(400).style('opacity', 1);
tooltip
.html(`Wiadomość:<br> ${d.data.message}`)
.style('width', '15rem')
.style('background-color', '#fff')
.style('border', '1px solid black')
.style('left', `${d3.event.pageX + 40}px`)
.style('top', `${d3.event.pageY - 10}px`);
})
.on('mouseout', function (d) {
tooltip.transition().duration(400).style('opacity', 0);
});
/* 'Enter' into links and style them properly */
const linkEnter = link.enter().append('line').classed('link', true);
linkEnter
.attr('x1', (d: any) => d.source.x)
.attr('y1', (d: any) => d.source.y)
.attr('x2', (d: any) => d.target.x)
.attr('y2', (d: any) => d.target.y);
}
} }