I want to use d3-cloud to generate a word cloud in my Angular2 app. However, I'm not able to find the right typings to install. I tried this but when I tried to import it in my component, it did not work. I kept getting the error, "Property layout could not be found in type". Can someone help me out on this?
Asked
Active
Viewed 3,554 times
6
-
Did you ever solve this? have exactly the same issue at the minute – Simon McLoughlin Feb 02 '17 at 09:53
-
@SimonMcLoughlin I did get it to work. Posted an answer below. Comment if you need more clarifications. – Rajshri Mohan K S Feb 02 '17 at 11:56
-
check [https://stackoverflow.com/questions/36355842/importing-d3-and-d3-cloud-with-webpack/50975582#50975582](https://stackoverflow.com/questions/36355842/importing-d3-and-d3-cloud-with-webpack/50975582#50975582) – mQuiroz Jun 21 '18 at 18:56
2 Answers
9
I figured out how to do this. Not the correct Typescript way, but using the fallback JS way. Here's how you'd go about it:
import
the d3 library like usual, but give it an alias:import * as D3 from 'd3';
(Notice: Capital D for D3)declare
d3 again so you can use it for WordCloud:declare let d3: any;
- Use
D3
for everything concerning the parent d3 library andd3
for word cloud generation alone.
The typings for d3-cloud doesn't seem to work. So declare
ing seems to be the only way for now.
Full Code:
word-cloud.component.ts:
import { Component, Input, ElementRef, DoCheck, KeyValueDiffers } from '@angular/core';
import { WordCloudConfig } from '../../../models/charts/word-cloud-config';
import * as D3 from 'd3';
declare let d3: any;
@Component({
selector : 'word-cloud',
templateUrl: './word-cloud.component.html',
styleUrls : ['./word-cloud.component.scss']
})
export class WordCloudComponent implements DoCheck {
@Input() config: WordCloudConfig;
private _host; // D3 object referencing host DOM object
private _svg; // SVG in which we will print our chart
private _margin: { // Space between the svg borders and the actual chart graphic
top: number,
right: number,
bottom: number,
left: number
};
private _width: number; // Component width
private _height: number; // Component height
private _htmlElement: HTMLElement; // Host HTMLElement
private _minCount: number; // Minimum word count
private _maxCount: number; // Maximum word count
private _fontScale; // D3 scale for font size
private _fillScale; // D3 scale for text color
private _objDiffer;
constructor(private _element: ElementRef, private _keyValueDiffers: KeyValueDiffers) {
this._htmlElement = this._element.nativeElement;
this._host = D3.select(this._element.nativeElement);
this._objDiffer = this._keyValueDiffers.find([]).create(null);
}
ngDoCheck() {
let changes = this._objDiffer.diff(this.config);
if (changes) {
if (!this.config) {
return;
}
this._setup();
this._buildSVG();
this._populate();
}
}
private _setup() {
this._margin = {
top : 10,
right : 10,
bottom: 10,
left : 10
};
this._width = ((this._htmlElement.parentElement.clientWidth == 0)
? 300
: this._htmlElement.parentElement.clientWidth) - this._margin.left - this._margin.right;
if (this._width < 100) {
this._width = 100;
}
this._height = this._width * 0.75 - this._margin.top - this._margin.bottom;
this._minCount = D3.min(this.config.dataset, d => d.count);
this._maxCount = D3.max(this.config.dataset, d => d.count);
let minFontSize: number = (this.config.settings.minFontSize == null) ? 18 : this.config.settings.minFontSize;
let maxFontSize: number = (this.config.settings.maxFontSize == null) ? 96 : this.config.settings.maxFontSize;
this._fontScale = D3.scaleLinear()
.domain([this._minCount, this._maxCount])
.range([minFontSize, maxFontSize]);
this._fillScale = D3.scaleOrdinal(D3.schemeCategory20);
}
private _buildSVG() {
this._host.html('');
this._svg = this._host
.append('svg')
.attr('width', this._width + this._margin.left + this._margin.right)
.attr('height', this._height + this._margin.top + this._margin.bottom)
.append('g')
.attr('transform', 'translate(' + ~~(this._width / 2) + ',' + ~~(this._height / 2) + ')');
}
private _populate() {
let fontFace: string = (this.config.settings.fontFace == null) ? 'Roboto' : this.config.settings.fontFace;
let fontWeight: string = (this.config.settings.fontWeight == null) ? 'normal' : this.config.settings.fontWeight;
let spiralType: string = (this.config.settings.spiral == null) ? 'rectangular' : this.config.settings.spiral;
d3.layout.cloud()
.size([this._width, this._height])
.words(this.config.dataset)
.rotate(() => 0)
.font(fontFace)
.fontWeight(fontWeight)
.fontSize(d => this._fontScale(d.count))
.spiral(spiralType)
.on('end', () => {
this._drawWordCloud(this.config.dataset);
})
.start();
}
private _drawWordCloud(words) {
this._svg
.selectAll('text')
.data(words)
.enter()
.append('text')
.style('font-size', d => d.size + 'px')
.style('fill', (d, i) => {
return this._fillScale(i);
})
.attr('text-anchor', 'middle')
.attr('transform', d => 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')')
.attr('class', 'word-cloud')
.text(d => {
return d.word;
});
}
}
word-cloud.component.html:
<ng-content></ng-content>
word-cloud.component.scss:
.word-cloud {
cursor : default;
-webkit-touch-callout : none;
-webkit-user-select : none;
-khtml-user-select : none;
-moz-user-select : none;
-ms-user-select : none;
user-select : none;
}

Rajshri Mohan K S
- 1,557
- 17
- 30
-
thanks man, thats working for me now. Just need to play around with the library to get the look I want. – Simon McLoughlin Feb 02 '17 at 14:47
-
how did you include d3-cloud in your application? I'm using the angular-cli with webpack, which chokes because the d3-cloud NPM module uses 'require.' – ansorensen Jul 18 '17 at 08:49
-
@ansorensen You need not have to "include" d3-cloud. I simply added `` into `index.html` and accessed it using the method mentioned in the answer. – Rajshri Mohan K S Jul 18 '17 at 10:11
-
Thanks! That link is broken, but the current package does have a build folder. I had been using the index.js (which requires node or browserify) and hadn't realized the build version is standalone. Just added the build version to my list of compiled scripts, and voila! (Well, plus a lot of massaging the example code from the package). – ansorensen Jul 20 '17 at 05:08
-
Cool! I didn't realize the link was broken all this time. Thanks to you, I fixed it. :D – Rajshri Mohan K S Jul 20 '17 at 11:23
-
-
-
-
@mohammad Just `d3`. You can add `d3-cloud` as described in this comment: https://stackoverflow.com/questions/41763075/typings-for-d3-cloud/42001600?noredirect=1#comment77295431_42001600 – Rajshri Mohan K S Mar 19 '18 at 10:58
-
@mohammad I do not understand. Do you mean the `dataset`? If yes, it should be `{ word: string, count: number }` – Rajshri Mohan K S Mar 19 '18 at 11:08
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167085/discussion-between-mohammad-and-rajshri-mohan-k-s). – mohammad Mar 19 '18 at 11:09
-
@RajshriMohanKS Thanks for this, but where is **"WordCloudConfig"**? Or setting? – Mohammad Hossein Ganjyar Nov 13 '18 at 15:15
-
What happend? I got this error: **"d3 is not defined"**, although I using **declare let d3** – Mohammad Hossein Ganjyar Nov 13 '18 at 15:37
-
@MohammadHosseinGanjyar`WordCloudConfig` is my custom class which provides some properties for the example I provided. You should be able to do the same with any class/property of your own. – Rajshri Mohan K S Nov 15 '18 at 10:50
3
I worked it out by following below steps -
- Import d3-cloud npm package --> npm i d3-cloud
- Import typings of d3-cloud --> npm i @types/d3-cloud --save-dev
- Now below in the sample component.ts imports and code -
import * as d3 from "d3";
import * as d3Cloud from "d3-cloud";
wordCloud(): void {
let svg: any = d3.select("svg")
.attr("width", 850)
.attr("height", 350);
d3Cloud().size([800, 300])
.words(wordList)
}

Nitesh Sharma
- 73
- 5