UPDATE 2/2: add graph
This commit is contained in:
parent
ffca9a8a74
commit
b29ffd0605
@ -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) {
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<div #tree></div>
|
@ -0,0 +1,5 @@
|
|||||||
|
::ng-deep .link {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user