I'm creating a app with Angular 4
and D3
. When I create a svg
component from inside of a component by injecting the component to another component, it shows the component, but resizing and moving functions aren't working (Even resize and move cursors aren't show on hovering).
If I use the same component and navigate to the component with routing, resizing and moving functions work. Any idea why.
Following is the component I use.
import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'app-function-box',
templateUrl: './function-box.component.html',
styleUrls: ['./function-box.component.css']
})
export class FunctionBoxComponent implements OnInit {
constructor() { }
ngOnInit() {
}
w = 500;
h = 350;
r = 120;
width = 200;
height = 100;
dragbarw = 10;
svg = d3.select("body").append("svg")
.attr("width", this.w)
.attr("height", this.h);
newg = this.svg.append("g")
.data([{x: 400, y: 100}]); //position
dragrect = this.newg.append("rect")
.attr("id", "active")
.attr("x", (d) => { return d.x; })
.attr("y", (d) => { return d.y; })
.attr("height", this.height)
.attr("width", this.width)
.attr("fill-opacity", .5)
.attr("cursor", "move")
.call(d3.drag()
.on("drag", this.dragmove.bind(this)));
dragbarleft = this.newg.append("rect")
.attr("x", (d) => { return d.x - (this.dragbarw/2); })
.attr("y", (d) => { return d.y + (this.dragbarw/2); })
.attr("height", this.height - this.dragbarw)
.attr("id", "dragleft")
.attr("width", this.dragbarw)
.attr("fill", "lightblue")
.attr("fill-opacity", .5)
.attr("cursor", "ew-resize")
.call(d3.drag()
.on("drag", this.ldragresize.bind(this)));
dragbarright = this.newg.append("rect")
.attr("x", (d) => { return d.x + this.width - (this.dragbarw/2); })
.attr("y", (d) => { return d.y + (this.dragbarw/2); })
.attr("id", "dragright")
.attr("height", this.height - this.dragbarw)
.attr("width", this.dragbarw)
.attr("fill", "lightblue")
.attr("fill-opacity", .5)
.attr("cursor", "ew-resize")
.call(d3.drag()
.on("drag", this.rdragresize.bind(this)));
dragbartop = this.newg.append("rect")
.attr("x", (d) => { return d.x + (this.dragbarw/2);})
.attr("y", (d) => { return d.y - (this.dragbarw/2); })
.attr("height", this.dragbarw)
.attr("id", "dragleft")
.attr("width", this.width - this.dragbarw)
.attr("fill", "lightgreen")
.attr("fill-opacity", .5)
.attr("cursor", "ns-resize")
.call(d3.drag()
.on("drag", this.tdragresize));
dragbarbottom = this.newg.append("rect")
.attr("x", (d) => { return d.x + (this.dragbarw/2); })
.attr("y", (d) => { return d.y + this.height - (this.dragbarw/2); })
.attr("id", "dragright")
.attr("height", this.dragbarw)
.attr("width", this.width - this.dragbarw)
.attr("fill", "lightgreen")
.attr("fill-opacity", .5)
.attr("cursor", "ns-resize")
.call(d3.drag()
.on("drag", this.bdragresize.bind(this)));
dragmove(d) {
this.dragrect
.attr("x", d.x = Math.max(0, Math.min(this.w - this.width, d3.event.x)));
this.dragbarleft
.attr("x", (d) => { return d.x - (this.dragbarw/2); });
this.dragbarright
.attr("x", (d) => { return d.x +this.width - (this.dragbarw/2); });
this.dragbartop
.attr("x", (d) => { return d.x + (this.dragbarw/2); });
this.dragbarbottom
.attr("x", (d) => { return d.x + (this.dragbarw/2); })
this.dragrect
.attr("y", d.y = Math.max(0, Math.min(this.h - this.height, d3.event.y)));
this.dragbarleft
.attr("y", (d) => { return d.y + (this.dragbarw/2); });
this.dragbarright
.attr("y", (d) => { return d.y + (this.dragbarw/2); });
this.dragbartop
.attr("y", (d) => { return d.y - (this.dragbarw/2); });
this.dragbarbottom
.attr("y", (d) => { return d.y + this.height - (this.dragbarw/2); });
}
ldragresize(d) {
let oldx = d.x;
//Max x on the right is x + width - dragbarw
//Max x on the left is 0 - (dragbarw/2)
d.x = Math.max(0, Math.min(d.x + this.width - (this.dragbarw / 2), d3.event.x));
this.width = this.width + (oldx - d.x);
this.dragbarleft
.attr("x", (d) => { return d.x - (this.dragbarw / 2); });
this.dragrect
.attr("x", (d) => { return d.x; })
.attr("width", this.width);
this.dragbartop
.attr("x", (d) => { return d.x + (this.dragbarw/2); })
.attr("width", this.width - this.dragbarw)
this.dragbarbottom
.attr("x", (d) => { return d.x + (this.dragbarw/2); })
.attr("width", this.width - this.dragbarw)
};
rdragresize(d) {
//Max x on the left is x - width
//Max x on the right is width of screen + (dragbarw/2)
let dragx = Math.max(d.x + (this.dragbarw/2), Math.min(this.w, d.x + this.width + d3.event.dx));
//recalculate width
this.width = dragx - d.x;
//move the right drag handle
this.dragbarright
.attr("x", (d) => { return dragx - (this.dragbarw/2) });
//resize the drag rectangle
//as we are only resizing from the right, the x coordinate does not need to change
this.dragrect
.attr("width", this.width);
this.dragbartop
.attr("width", this.width - this.dragbarw)
this.dragbarbottom
.attr("width", this.width - this.dragbarw)
}
tdragresize(d) {
let oldy = d.y;
//Max x on the right is x + width - dragbarw
//Max x on the left is 0 - (dragbarw/2)
d.y = Math.max(0, Math.min(d.y + this.height - (this.dragbarw / 2), d3.event.y));
this.height = this.height + (oldy - d.y);
this.dragbartop
.attr("y", (d) => { return d.y - (this.dragbarw / 2); });
this.dragrect
.attr("y", (d) => { return d.y; })
.attr("height", this.height);
this.dragbarleft
.attr("y", (d) => { return d.y + (this.dragbarw/2); })
.attr("height", this.height - this.dragbarw);
this.dragbarright
.attr("y", (d) => { return d.y + (this.dragbarw/2); })
.attr("height", this.height - this.dragbarw);
}
bdragresize(d) {
//Max x on the left is x - width
//Max x on the right is width of screen + (dragbarw/2)
let dragy = Math.max(d.y + (this.dragbarw/2), Math.min(this.h, d.y + this.height + d3.event.dy));
//recalculate width
this.height = dragy - d.y;
//move the right drag handle
this.dragbarbottom
.attr("y", (d) => { return dragy - (this.dragbarw/2) });
//resize the drag rectangle
//as we are only resizing from the right, the x coordinate does not need to change
this.dragrect
.attr("height", this.height);
this.dragbarleft
.attr("height", this.height - this.dragbarw);
this.dragbarright
.attr("height", this.height - this.dragbarw);
}
}
And since SVG sits in the DOM, we can use attr () and append () just like we did for HTML elements. Let's learn about some of the most used SVG elements in visualizations and how to create and apply styling to them using D3 library. An SVG line element is represented by <line> tag.
The SVG is resized, but not the bars. To solve the previous problem, one solution is to calculate the properties of each element acording to the parent width and height: It works, but it is not the best solution. D3.js provides dedicated tools for resizing charts.
The question was about having an svg element that keeps covering the full window on resize, which in most cases means a different aspect ratio. Just a note regarding UX: For some use cases, treating your SVG-based d3 chart like an asset with a fixed aspect ratio isn't ideal.
It is good to have them in variables so that you can change them at one place without having to go through the entire code in case you decide to change your SVG's dimensions. Next, we select the body element and append our SVG element to it and set SVG's width and height.
Answer to your question can be achieved using ViewChild in Angular to access a Child Component, Directive or DOM Element.
If given component is your child component then you can add some reference variable to your html code something like this (here #chartbar)
<div #chartbar class="someclass"></div>
Now you need to use ViewChild in your Child Component
import { Component, OnInit, ViewChild, ElementRef} from '@angular/core'; //Imported ViewChild, ElementRef
import * as d3 from 'd3';
@Component({
selector: 'app-function-box',
templateUrl: './function-box.component.html',
styleUrls: ['./function-box.component.css']
})
export class FunctionBoxComponent implements OnInit {
@ViewChild('chartbar') private chartContainer: ElementRef; //Provider defined here
constructor() { }
ngOnInit() {
}
w = 500;
h = 350;
r = 120;
const element = that.chartContainer.nativeElement; //To use DOM element of html
width = 200;
height = 100;
dragbarw = 10;
svg = d3.select(element).append("svg") //select DOM element instead of body
.attr("width", this.w)
.attr("height", this.h);
For resize You will get good options here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With