From 6843f58f0b4abd495dd4936308fdfe16e473e232 Mon Sep 17 00:00:00 2001 From: Umut Tas Date: Tue, 9 Feb 2021 14:52:43 +0100 Subject: [PATCH 1/4] wordcloud first example --- package-lock.json | 274 +++++++++- package.json | 1 + .../pages/portfolio/portfolio.component.html | 3 + .../pages/portfolio/portfolio.component.scss | 6 + .../pages/portfolio/portfolio.component.ts | 69 +++ src/assets/js/d3.layout.cloud.js | 500 ++++++++++++++++++ 6 files changed, 850 insertions(+), 3 deletions(-) create mode 100644 src/assets/js/d3.layout.cloud.js diff --git a/package-lock.json b/package-lock.json index 81bf371..e54e53e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4103,6 +4103,266 @@ "type": "^1.0.1" } }, + "d3": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-6.5.0.tgz", + "integrity": "sha512-gr7FoRecKtBkBxelTeGVYERRTPgjPFLh2rOBisHdbXe3RIrVLjCo7COZYMSeFeiwVPOHDtxAGJlvN7XssNAIcg==", + "requires": { + "d3-array": "2", + "d3-axis": "2", + "d3-brush": "2", + "d3-chord": "2", + "d3-color": "2", + "d3-contour": "2", + "d3-delaunay": "5", + "d3-dispatch": "2", + "d3-drag": "2", + "d3-dsv": "2", + "d3-ease": "2", + "d3-fetch": "2", + "d3-force": "2", + "d3-format": "2", + "d3-geo": "2", + "d3-hierarchy": "2", + "d3-interpolate": "2", + "d3-path": "2", + "d3-polygon": "2", + "d3-quadtree": "2", + "d3-random": "2", + "d3-scale": "3", + "d3-scale-chromatic": "2", + "d3-selection": "2", + "d3-shape": "2", + "d3-time": "2", + "d3-time-format": "3", + "d3-timer": "2", + "d3-transition": "2", + "d3-zoom": "2" + } + }, + "d3-array": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz", + "integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==", + "requires": { + "internmap": "^1.0.0" + } + }, + "d3-axis": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-2.0.0.tgz", + "integrity": "sha512-9nzB0uePtb+u9+dWir+HTuEAKJOEUYJoEwbJPsZ1B4K3iZUgzJcSENQ05Nj7S4CIfbZZ8/jQGoUzGKFznBhiiQ==" + }, + "d3-brush": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-2.1.0.tgz", + "integrity": "sha512-cHLLAFatBATyIKqZOkk/mDHUbzne2B3ZwxkzMHvFTCZCmLaXDpZRihQSn8UNXTkGD/3lb/W2sQz0etAftmHMJQ==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + }, + "d3-chord": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-2.0.0.tgz", + "integrity": "sha512-D5PZb7EDsRNdGU4SsjQyKhja8Zgu+SHZfUSO5Ls8Wsn+jsAKUUGkcshLxMg9HDFxG3KqavGWaWkJ8EpU8ojuig==", + "requires": { + "d3-path": "1 - 2" + } + }, + "d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "d3-contour": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-2.0.0.tgz", + "integrity": "sha512-9unAtvIaNk06UwqBmvsdHX7CZ+NPDZnn8TtNH1myW93pWJkhsV25JcgnYAu0Ck5Veb1DHiCv++Ic5uvJ+h50JA==", + "requires": { + "d3-array": "2" + } + }, + "d3-delaunay": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-5.3.0.tgz", + "integrity": "sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==", + "requires": { + "delaunator": "4" + } + }, + "d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" + }, + "d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "d3-dsv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-2.0.0.tgz", + "integrity": "sha512-E+Pn8UJYx9mViuIUkoc93gJGGYut6mSDKy2+XaPwccwkRGlR+LO97L2VCCRjQivTwLHkSnAJG7yo00BWY6QM+w==", + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" + }, + "d3-fetch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-2.0.0.tgz", + "integrity": "sha512-TkYv/hjXgCryBeNKiclrwqZH7Nb+GaOwo3Neg24ZVWA3MKB+Rd+BY84Nh6tmNEMcjUik1CSUWjXYndmeO6F7sw==", + "requires": { + "d3-dsv": "1 - 2" + } + }, + "d3-force": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-2.1.1.tgz", + "integrity": "sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-quadtree": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + }, + "d3-geo": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-2.0.1.tgz", + "integrity": "sha512-M6yzGbFRfxzNrVhxDJXzJqSLQ90q1cCyb3EWFZ1LF4eWOBYxFypw7I/NFVBNXKNqxv1bqLathhYvdJ6DC+th3A==", + "requires": { + "d3-array": ">=2.5" + } + }, + "d3-hierarchy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz", + "integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==" + }, + "d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "requires": { + "d3-color": "1 - 2" + } + }, + "d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + }, + "d3-polygon": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-2.0.0.tgz", + "integrity": "sha512-MsexrCK38cTGermELs0cO1d79DcTsQRN7IWMJKczD/2kBjzNXxLUWP33qRF6VDpiLV/4EI4r6Gs0DAWQkE8pSQ==" + }, + "d3-quadtree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-2.0.0.tgz", + "integrity": "sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==" + }, + "d3-random": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-2.2.2.tgz", + "integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw==" + }, + "d3-scale": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz", + "integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==", + "requires": { + "d3-array": "^2.3.0", + "d3-format": "1 - 2", + "d3-interpolate": "1.2.0 - 2", + "d3-time": "1 - 2", + "d3-time-format": "2 - 3" + } + }, + "d3-scale-chromatic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz", + "integrity": "sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==", + "requires": { + "d3-color": "1 - 2", + "d3-interpolate": "1 - 2" + } + }, + "d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "d3-shape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.0.0.tgz", + "integrity": "sha512-djpGlA779ua+rImicYyyjnOjeubyhql1Jyn1HK0bTyawuH76UQRWXd+pftr67H6Fa8hSwetkgb/0id3agKWykw==", + "requires": { + "d3-path": "1 - 2" + } + }, + "d3-time": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.0.0.tgz", + "integrity": "sha512-2mvhstTFcMvwStWd9Tj3e6CEqtOivtD8AUiHT8ido/xmzrI9ijrUUihZ6nHuf/vsScRBonagOdj0Vv+SEL5G3Q==" + }, + "d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "requires": { + "d3-time": "1 - 2" + } + }, + "d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, + "d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "requires": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + }, "damerau-levenshtein": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", @@ -4312,6 +4572,11 @@ } } }, + "delaunator": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-4.0.1.tgz", + "integrity": "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6180,7 +6445,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -6385,6 +6649,11 @@ "ipaddr.js": "^1.9.0" } }, + "internmap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.0.tgz", + "integrity": "sha512-SdoDWwNOTE2n4JWUsLn4KXZGuZPjPF9yyOGc8bnfWnBQh7BD/l80rzSznKc/r4Y0aQ7z3RTk9X+tV4tHBpu+dA==" + }, "into-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", @@ -11118,8 +11387,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { "version": "1.27.0", diff --git a/package.json b/package.json index 4f83408..fbe7fb8 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@ngx-translate/http-loader": "^6.0.0", "angular-typing-animation": "^0.5.4", "bulma": "^0.9.1", + "d3": "^6.5.0", "mapbox-gl": "1.13.0", "ngx-mapbox-gl": "5.0.0", "ngx-markdown": "^11.0.1", diff --git a/src/app/components/pages/portfolio/portfolio.component.html b/src/app/components/pages/portfolio/portfolio.component.html index 45fa792..3f17bee 100644 --- a/src/app/components/pages/portfolio/portfolio.component.html +++ b/src/app/components/pages/portfolio/portfolio.component.html @@ -2,6 +2,9 @@

{{ "UNSERE_PROJEKTE" | translate }}

+
+ +
diff --git a/src/app/components/pages/portfolio/portfolio.component.scss b/src/app/components/pages/portfolio/portfolio.component.scss index 38757a9..a293cf4 100644 --- a/src/app/components/pages/portfolio/portfolio.component.scss +++ b/src/app/components/pages/portfolio/portfolio.component.scss @@ -89,3 +89,9 @@ } } } + +#wordcloud-container { + position: absolute; + top: 10px; + right: 10px; +} diff --git a/src/app/components/pages/portfolio/portfolio.component.ts b/src/app/components/pages/portfolio/portfolio.component.ts index b2c06be..7364613 100644 --- a/src/app/components/pages/portfolio/portfolio.component.ts +++ b/src/app/components/pages/portfolio/portfolio.component.ts @@ -4,6 +4,15 @@ import reProjectsEN from '../../../../assets/collections/projects/projects-en.js import rePartner from '../../../../assets/collections/partner/partner.json'; import { TranslateService } from '@ngx-translate/core'; import { ActivatedRoute, Router } from '@angular/router'; + + +import * as d3 from 'd3'; +import * as d3Scale from 'd3'; +import * as d3Shape from 'd3'; +import * as d3Array from 'd3'; +import * as d3Axis from 'd3'; +import * as cloud from '../../../../assets/js/d3.layout.cloud.js'; + @Component({ selector: 're-portfolio', templateUrl: './portfolio.component.html', @@ -22,6 +31,8 @@ export class PortfolioComponent implements OnInit { partners = rePartner; + cloud; + filter = { customer: null, topic: null, @@ -43,6 +54,8 @@ export class PortfolioComponent implements OnInit { ngOnInit(): void { + let that = this; + this.route.queryParamMap.subscribe((queryParams:any) => { let params = queryParams.params; for( let param in params){ @@ -85,6 +98,61 @@ export class PortfolioComponent implements OnInit { }) this.topics = [...new Set(this.topics)] this.targets = [...new Set(this.targets)] + + } + + drawWordCloud(words){ + words = words.flat() + console.log(words); + + var countedWords = {}; + words.forEach(function(word){ + if(countedWords[word]){ + countedWords[word]++; + } else { + countedWords[word]= 1; + } + }) + console.log(countedWords) + var finalWords = []; + for (var word in countedWords){ + finalWords.push({text: word, count: countedWords[word]}) + } + console.log(finalWords) + + d3.select("#wordCloud").select('g').remove(); + + var layout = cloud() + .size([500, 500]) + .words(finalWords.map(function(d) { + return {text: d.text, size: d.count*7, test: "haha"}; + })) + .padding(5) + .rotate(function() { return ~~(Math.random() * 2) * 90; }) + .font("Impact") + .fontSize(function(d) { return d.size; }) + .on("end", draw); + + layout.start(); + + function draw(words) { + d3.select("#wordCloud") + .attr("width", layout.size()[0]) + .attr("height", layout.size()[1]) + .append("g") + .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") + .selectAll("text") + .data(words) + .enter().append("text") + .style("font-size", function(d) { return d.size + "px"; }) + .style("font-family", "Impact") + .attr("text-anchor", "middle") + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + }) + .text(function(d) { return d.text; }); + } + } changeCustomer(event){ @@ -155,6 +223,7 @@ export class PortfolioComponent implements OnInit { }) this.filterOpen = false; + this.drawWordCloud(this.filteredProjects.map(item => item.topics)); } removeFilter(key){ diff --git a/src/assets/js/d3.layout.cloud.js b/src/assets/js/d3.layout.cloud.js new file mode 100644 index 0000000..14b01e2 --- /dev/null +++ b/src/assets/js/d3.layout.cloud.js @@ -0,0 +1,500 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.d3||(g.d3 = {}));g=(g.layout||(g.layout = {}));g.cloud = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> 5, + ch = 1 << 11; + +module.exports = function() { + var size = [256, 256], + text = cloudText, + font = cloudFont, + fontSize = cloudFontSize, + fontStyle = cloudFontNormal, + fontWeight = cloudFontNormal, + rotate = cloudRotate, + padding = cloudPadding, + spiral = archimedeanSpiral, + words = [], + timeInterval = Infinity, + event = dispatch("word", "end"), + timer = null, + random = Math.random, + cloud = {}, + canvas = cloudCanvas; + + cloud.canvas = function(_) { + return arguments.length ? (canvas = functor(_), cloud) : canvas; + }; + + cloud.start = function() { + var contextAndRatio = getContext(canvas()), + board = zeroArray((size[0] >> 5) * size[1]), + bounds = null, + n = words.length, + i = -1, + tags = [], + data = words.map(function(d, i) { + d.text = text.call(this, d, i); + d.font = font.call(this, d, i); + d.style = fontStyle.call(this, d, i); + d.weight = fontWeight.call(this, d, i); + d.rotate = rotate.call(this, d, i); + d.size = ~~fontSize.call(this, d, i); + d.padding = padding.call(this, d, i); + return d; + }).sort(function(a, b) { return b.size - a.size; }); + + if (timer) clearInterval(timer); + timer = setInterval(step, 0); + step(); + + return cloud; + + function step() { + var start = Date.now(); + while (Date.now() - start < timeInterval && ++i < n && timer) { + var d = data[i]; + d.x = (size[0] * (random() + .5)) >> 1; + d.y = (size[1] * (random() + .5)) >> 1; + cloudSprite(contextAndRatio, d, data, i); + if (d.hasText && place(board, d, bounds)) { + tags.push(d); + event.call("word", cloud, d); + if (bounds) cloudBounds(bounds, d); + else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}]; + // Temporary hack + d.x -= size[0] >> 1; + d.y -= size[1] >> 1; + } + } + if (i >= n) { + cloud.stop(); + event.call("end", cloud, tags, bounds); + } + } + } + + cloud.stop = function() { + if (timer) { + clearInterval(timer); + timer = null; + } + return cloud; + }; + + function getContext(canvas) { + canvas.width = canvas.height = 1; + var ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2); + canvas.width = (cw << 5) / ratio; + canvas.height = ch / ratio; + + var context = canvas.getContext("2d"); + context.fillStyle = context.strokeStyle = "red"; + context.textAlign = "center"; + + return {context: context, ratio: ratio}; + } + + function place(board, tag, bounds) { + var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}], + startX = tag.x, + startY = tag.y, + maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), + s = spiral(size), + dt = random() < .5 ? 1 : -1, + t = -dt, + dxdy, + dx, + dy; + + while (dxdy = s(t += dt)) { + dx = ~~dxdy[0]; + dy = ~~dxdy[1]; + + if (Math.min(Math.abs(dx), Math.abs(dy)) >= maxDelta) break; + + tag.x = startX + dx; + tag.y = startY + dy; + + if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || + tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; + // TODO only check for collisions within current bounds. + if (!bounds || !cloudCollide(tag, board, size[0])) { + if (!bounds || collideRects(tag, bounds)) { + var sprite = tag.sprite, + w = tag.width >> 5, + sw = size[0] >> 5, + lx = tag.x - (w << 4), + sx = lx & 0x7f, + msx = 32 - sx, + h = tag.y1 - tag.y0, + x = (tag.y + tag.y0) * sw + (lx >> 5), + last; + for (var j = 0; j < h; j++) { + last = 0; + for (var i = 0; i <= w; i++) { + board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); + } + x += sw; + } + delete tag.sprite; + return true; + } + } + } + return false; + } + + cloud.timeInterval = function(_) { + return arguments.length ? (timeInterval = _ == null ? Infinity : _, cloud) : timeInterval; + }; + + cloud.words = function(_) { + return arguments.length ? (words = _, cloud) : words; + }; + + cloud.size = function(_) { + return arguments.length ? (size = [+_[0], +_[1]], cloud) : size; + }; + + cloud.font = function(_) { + return arguments.length ? (font = functor(_), cloud) : font; + }; + + cloud.fontStyle = function(_) { + return arguments.length ? (fontStyle = functor(_), cloud) : fontStyle; + }; + + cloud.fontWeight = function(_) { + return arguments.length ? (fontWeight = functor(_), cloud) : fontWeight; + }; + + cloud.rotate = function(_) { + return arguments.length ? (rotate = functor(_), cloud) : rotate; + }; + + cloud.text = function(_) { + return arguments.length ? (text = functor(_), cloud) : text; + }; + + cloud.spiral = function(_) { + return arguments.length ? (spiral = spirals[_] || _, cloud) : spiral; + }; + + cloud.fontSize = function(_) { + return arguments.length ? (fontSize = functor(_), cloud) : fontSize; + }; + + cloud.padding = function(_) { + return arguments.length ? (padding = functor(_), cloud) : padding; + }; + + cloud.random = function(_) { + return arguments.length ? (random = _, cloud) : random; + }; + + cloud.on = function() { + var value = event.on.apply(event, arguments); + return value === event ? cloud : value; + }; + + return cloud; +}; + +function cloudText(d) { + return d.text; +} + +function cloudFont() { + return "serif"; +} + +function cloudFontNormal() { + return "normal"; +} + +function cloudFontSize(d) { + return Math.sqrt(d.value); +} + +function cloudRotate() { + return (~~(Math.random() * 6) - 3) * 30; +} + +function cloudPadding() { + return 1; +} + +// Fetches a monochrome sprite bitmap for the specified text. +// Load in batches for speed. +function cloudSprite(contextAndRatio, d, data, di) { + if (d.sprite) return; + var c = contextAndRatio.context, + ratio = contextAndRatio.ratio; + + c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); + var x = 0, + y = 0, + maxh = 0, + n = data.length; + --di; + while (++di < n) { + d = data[di]; + c.save(); + c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font; + var w = c.measureText(d.text + "m").width * ratio, + h = d.size << 1; + if (d.rotate) { + var sr = Math.sin(d.rotate * cloudRadians), + cr = Math.cos(d.rotate * cloudRadians), + wcr = w * cr, + wsr = w * sr, + hcr = h * cr, + hsr = h * sr; + w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5; + h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); + } else { + w = (w + 0x1f) >> 5 << 5; + } + if (h > maxh) maxh = h; + if (x + w >= (cw << 5)) { + x = 0; + y += maxh; + maxh = 0; + } + if (y + h >= ch) break; + c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); + if (d.rotate) c.rotate(d.rotate * cloudRadians); + c.fillText(d.text, 0, 0); + if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0); + c.restore(); + d.width = w; + d.height = h; + d.xoff = x; + d.yoff = y; + d.x1 = w >> 1; + d.y1 = h >> 1; + d.x0 = -d.x1; + d.y0 = -d.y1; + d.hasText = true; + x += w; + } + var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, + sprite = []; + while (--di >= 0) { + d = data[di]; + if (!d.hasText) continue; + var w = d.width, + w32 = w >> 5, + h = d.y1 - d.y0; + // Zero the buffer + for (var i = 0; i < h * w32; i++) sprite[i] = 0; + x = d.xoff; + if (x == null) return; + y = d.yoff; + var seen = 0, + seenRow = -1; + for (var j = 0; j < h; j++) { + for (var i = 0; i < w; i++) { + var k = w32 * j + (i >> 5), + m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0; + sprite[k] |= m; + seen |= m; + } + if (seen) seenRow = j; + else { + d.y0++; + h--; + j--; + y++; + } + } + d.y1 = d.y0 + seenRow; + d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); + } +} + +// Use mask-based collision detection. +function cloudCollide(tag, board, sw) { + sw >>= 5; + var sprite = tag.sprite, + w = tag.width >> 5, + lx = tag.x - (w << 4), + sx = lx & 0x7f, + msx = 32 - sx, + h = tag.y1 - tag.y0, + x = (tag.y + tag.y0) * sw + (lx >> 5), + last; + for (var j = 0; j < h; j++) { + last = 0; + for (var i = 0; i <= w; i++) { + if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) + & board[x + i]) return true; + } + x += sw; + } + return false; +} + +function cloudBounds(bounds, d) { + var b0 = bounds[0], + b1 = bounds[1]; + if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; + if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; + if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1; + if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1; +} + +function collideRects(a, b) { + return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; +} + +function archimedeanSpiral(size) { + var e = size[0] / size[1]; + return function(t) { + return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)]; + }; +} + +function rectangularSpiral(size) { + var dy = 4, + dx = dy * size[0] / size[1], + x = 0, + y = 0; + return function(t) { + var sign = t < 0 ? -1 : 1; + // See triangular numbers: T_n = n * (n + 1) / 2. + switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) { + case 0: x += dx; break; + case 1: y += dy; break; + case 2: x -= dx; break; + default: y -= dy; break; + } + return [x, y]; + }; +} + +// TODO reuse arrays? +function zeroArray(n) { + var a = [], + i = -1; + while (++i < n) a[i] = 0; + return a; +} + +function cloudCanvas() { + return document.createElement("canvas"); +} + +function functor(d) { + return typeof d === "function" ? d : function() { return d; }; +} + +var spirals = { + archimedean: archimedeanSpiral, + rectangular: rectangularSpiral +}; + +},{"d3-dispatch":2}],2:[function(require,module,exports){ +// https://d3js.org/d3-dispatch/ Version 1.0.3. Copyright 2017 Mike Bostock. +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.d3 = global.d3 || {}))); +}(this, (function (exports) { 'use strict'; + +var noop = {value: function() {}}; + +function dispatch() { + for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { + if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t); + _[t] = []; + } + return new Dispatch(_); +} + +function Dispatch(_) { + this._ = _; +} + +function parseTypenames(typenames, types) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); + return {type: t, name: name}; + }); +} + +Dispatch.prototype = dispatch.prototype = { + constructor: Dispatch, + on: function(typename, callback) { + var _ = this._, + T = parseTypenames(typename + "", _), + t, + i = -1, + n = T.length; + + // If no callback was specified, return the callback of the given type and name. + if (arguments.length < 2) { + while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t; + return; + } + + // If a type was specified, set the callback for the given type and name. + // Otherwise, if a null callback was specified, remove callbacks of the given name. + if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); + while (++i < n) { + if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback); + else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null); + } + + return this; + }, + copy: function() { + var copy = {}, _ = this._; + for (var t in _) copy[t] = _[t].slice(); + return new Dispatch(copy); + }, + call: function(type, that) { + if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + }, + apply: function(type, that, args) { + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + } +}; + +function get(type, name) { + for (var i = 0, n = type.length, c; i < n; ++i) { + if ((c = type[i]).name === name) { + return c.value; + } + } +} + +function set(type, name, callback) { + for (var i = 0, n = type.length; i < n; ++i) { + if (type[i].name === name) { + type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1)); + break; + } + } + if (callback != null) type.push({name: name, value: callback}); + return type; +} + +exports.dispatch = dispatch; + +Object.defineProperty(exports, '__esModule', { value: true }); + +}))); + +},{}]},{},[1])(1) +}); \ No newline at end of file From 60fbb2a490823971c840ff1793e37a982a4a3d63 Mon Sep 17 00:00:00 2001 From: Umut Tas Date: Tue, 9 Feb 2021 15:11:35 +0100 Subject: [PATCH 2/4] wordcloud update --- .../components/pages/portfolio/portfolio.component.html | 2 +- src/app/components/pages/portfolio/portfolio.component.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/components/pages/portfolio/portfolio.component.html b/src/app/components/pages/portfolio/portfolio.component.html index 3f17bee..69d808c 100644 --- a/src/app/components/pages/portfolio/portfolio.component.html +++ b/src/app/components/pages/portfolio/portfolio.component.html @@ -3,7 +3,7 @@

{{ "UNSERE_PROJEKTE" | translate }}

- +
diff --git a/src/app/components/pages/portfolio/portfolio.component.ts b/src/app/components/pages/portfolio/portfolio.component.ts index 7364613..95fd4d9 100644 --- a/src/app/components/pages/portfolio/portfolio.component.ts +++ b/src/app/components/pages/portfolio/portfolio.component.ts @@ -123,12 +123,14 @@ export class PortfolioComponent implements OnInit { d3.select("#wordCloud").select('g').remove(); var layout = cloud() - .size([500, 500]) + .size([1000, 500]) .words(finalWords.map(function(d) { - return {text: d.text, size: d.count*7, test: "haha"}; + console.log(Math.log(d.count)) + return {text: d.text, size: Math.log(d.count+1)*20, test: "haha"}; })) .padding(5) - .rotate(function() { return ~~(Math.random() * 2) * 90; }) + // .rotate(function() { return ~~(Math.random() * 2) * 90; }) + .rotate(function() { return 0; }) .font("Impact") .fontSize(function(d) { return d.size; }) .on("end", draw); From 4d6e22905b95d6672f5763f3158ed7eb75935102 Mon Sep 17 00:00:00 2001 From: Umut Tas Date: Tue, 9 Feb 2021 15:33:59 +0100 Subject: [PATCH 3/4] use brixslab --- src/app/components/pages/portfolio/portfolio.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/pages/portfolio/portfolio.component.ts b/src/app/components/pages/portfolio/portfolio.component.ts index 95fd4d9..e141155 100644 --- a/src/app/components/pages/portfolio/portfolio.component.ts +++ b/src/app/components/pages/portfolio/portfolio.component.ts @@ -131,7 +131,7 @@ export class PortfolioComponent implements OnInit { .padding(5) // .rotate(function() { return ~~(Math.random() * 2) * 90; }) .rotate(function() { return 0; }) - .font("Impact") + .font("Brixslab-Regular") .fontSize(function(d) { return d.size; }) .on("end", draw); @@ -147,7 +147,7 @@ export class PortfolioComponent implements OnInit { .data(words) .enter().append("text") .style("font-size", function(d) { return d.size + "px"; }) - .style("font-family", "Impact") + .style("font-family", "Brixslab-Regular") .attr("text-anchor", "middle") .attr("transform", function(d) { return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; From 5d325d3b4e270deb21314ebe88f571a3c3c5f9f0 Mon Sep 17 00:00:00 2001 From: Umut Tas Date: Fri, 12 Feb 2021 10:47:50 +0100 Subject: [PATCH 4/4] try wordcloud stuff --- .../pages/portfolio/portfolio.component.html | 2 +- .../pages/portfolio/portfolio.component.ts | 269 ++++++++++++++++-- tsconfig.json | 2 +- 3 files changed, 240 insertions(+), 33 deletions(-) diff --git a/src/app/components/pages/portfolio/portfolio.component.html b/src/app/components/pages/portfolio/portfolio.component.html index 69d808c..55fa298 100644 --- a/src/app/components/pages/portfolio/portfolio.component.html +++ b/src/app/components/pages/portfolio/portfolio.component.html @@ -3,7 +3,7 @@

{{ "UNSERE_PROJEKTE" | translate }}

- +
diff --git a/src/app/components/pages/portfolio/portfolio.component.ts b/src/app/components/pages/portfolio/portfolio.component.ts index e141155..cbb1199 100644 --- a/src/app/components/pages/portfolio/portfolio.component.ts +++ b/src/app/components/pages/portfolio/portfolio.component.ts @@ -54,6 +54,108 @@ export class PortfolioComponent implements OnInit { ngOnInit(): void { + function wordCloud(selector) { + + var fill = d3.scaleOrdinal(d3Scale.schemeCategory10); + + //Construct the word cloud's SVG element + var svg = d3.select(selector).append("svg") + .attr("width", 500) + .attr("height", 500) + .append("g") + .attr("transform", "translate(250,250)"); + + + //Draw the word cloud + function draw(words) { + var cloud = svg.selectAll("g text") + .data(words, function(d) { return d.text; }) + + //Entering words + cloud.enter() + .append("text") + .style("font-family", "Impact") + .style("fill", function(d, i) { return fill(i); }) + .attr("text-anchor", "middle") + .attr('font-size', 1) + .text(function(d) { return d.text; }); + + //Entering and existing words + cloud + .transition() + .duration(600) + .style("font-size", function(d) { return d.size + "px"; }) + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + }) + .style("fill-opacity", 1); + + //Exiting words + cloud.exit() + .transition() + .duration(200) + .style('fill-opacity', 1e-6) + .attr('font-size', 1) + .remove(); + } + + + //Use the module pattern to encapsulate the visualisation code. We'll + // expose only the parts that need to be public. + return { + + //Recompute the word cloud for a new set of words. This method will + // asycnhronously call draw when the layout has been computed. + //The outside world will need to call this function, so make it part + // of the wordCloud return value. + update: function(words) { + cloud().size([500, 500]) + .words(words) + .padding(5) + .rotate(function() { return ~~(Math.random() * 2) * 90; }) + .font("Impact") + .fontSize(function(d) { return d.size; }) + .on("end", draw) + .start(); + } + } + + } + + //Some sample data - http://en.wikiquote.org/wiki/Opening_lines + var words = [ + "You don't know about me without you have read a book called The Adventures of Tom Sawyer but that ain't no matter.", + "The boy with fair hair lowered himself down the last few feet of rock and began to pick his way toward the lagoon.", + "When Mr. Bilbo Baggins of Bag End announced that he would shortly be celebrating his eleventy-first birthday with a party of special magnificence, there was much talk and excitement in Hobbiton.", + "It was inevitable: the scent of bitter almonds always reminded him of the fate of unrequited love." + ] + + //Prepare one of the sample sentences by removing punctuation, + // creating an array of words and computing a random size attribute. + function getWords(i) { + return words[i] + .replace(/[!\.,:;\?]/g, '') + .split(' ') + .map(function(d) { + return {text: d, size: 10 + Math.random() * 10}; + }) + } + + //This method tells the word cloud to redraw with a new set of words. + //In reality the new words would probably come from a server request, + // user input or some other source. + function showNewWords(vis, i) { + i = i || 0; + console.log(words) + vis.update(getWords(i ++ % words.length)) + setTimeout(function() { showNewWords(vis, i + 1)}, 2000) + } + + //Create a new instance of the word cloud visualisation. + var myWordCloud = wordCloud('body'); + + //Start cycling through the demo data + showNewWords(myWordCloud,0); let that = this; this.route.queryParamMap.subscribe((queryParams:any) => { @@ -101,10 +203,79 @@ export class PortfolioComponent implements OnInit { } + wordCloud(selector) { + + var fill = d3.scaleOrdinal(d3Scale.schemeCategory10); + + //Construct the word cloud's SVG element + var svg = d3.select(selector).append("svg") + .attr("width", 500) + .attr("height", 500) + .append("g") + .attr("transform", "translate(250,250)"); + + + //Draw the word cloud + function draw(words) { + var cloud = svg.selectAll("g text") + .data(words, function(d) { return d.text; }) + + //Entering words + cloud.enter() + .append("text") + .style("font-family", "Impact") + .style("fill", function(d, i) { return fill(i); }) + .attr("text-anchor", "middle") + .attr('font-size', 1) + .text(function(d) { return d.text; }); + + //Entering and existing words + cloud + .transition() + .duration(600) + .style("font-size", function(d) { return d.size + "px"; }) + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + }) + .style("fill-opacity", 1); + + //Exiting words + cloud.exit() + .transition() + .duration(200) + .style('fill-opacity', 1e-6) + .attr('font-size', 1) + .remove(); + } + + + //Use the module pattern to encapsulate the visualisation code. We'll + // expose only the parts that need to be public. + return { + + //Recompute the word cloud for a new set of words. This method will + // asycnhronously call draw when the layout has been computed. + //The outside world will need to call this function, so make it part + // of the wordCloud return value. + update: function(words) { + cloud().size([500, 500]) + .words(words) + .padding(5) + .rotate(function() { return ~~(Math.random() * 2) * 90; }) + .font("Impact") + .fontSize(function(d) { return d.size; }) + .on("end", draw) + .start(); + } + } + +} + drawWordCloud(words){ words = words.flat() console.log(words); - + // console.log(d3Scale) + var fill = d3.scaleOrdinal(d3Scale.schemeCategory10); var countedWords = {}; words.forEach(function(word){ if(countedWords[word]){ @@ -122,37 +293,73 @@ export class PortfolioComponent implements OnInit { d3.select("#wordCloud").select('g').remove(); - var layout = cloud() - .size([1000, 500]) - .words(finalWords.map(function(d) { - console.log(Math.log(d.count)) - return {text: d.text, size: Math.log(d.count+1)*20, test: "haha"}; - })) - .padding(5) - // .rotate(function() { return ~~(Math.random() * 2) * 90; }) - .rotate(function() { return 0; }) - .font("Brixslab-Regular") - .fontSize(function(d) { return d.size; }) - .on("end", draw); - - layout.start(); + // var layout = cloud() + // .size([1000, 500]) + // .words(finalWords.map(function(d) { + // console.log(Math.log(d.count)) + // return {text: d.text, size: Math.log(d.count+1)*20, test: "haha"}; + // })) + // .padding(5) + // // .rotate(function() { return ~~(Math.random() * 2) * 90; }) + // .rotate(function() { return 0; }) + // .font("Brixslab-Regular") + // .fontSize(function(d) { return d.size; }) + // .on("end", draw); + + var svg = d3.select('#wordcloud-container').append("svg") + .attr("width", 1000) + .attr("height", 500) + .append("g") + .attr("transform", "translate(500,250)"); + + // layout.start(); function draw(words) { - d3.select("#wordCloud") - .attr("width", layout.size()[0]) - .attr("height", layout.size()[1]) - .append("g") - .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") - .selectAll("text") - .data(words) - .enter().append("text") - .style("font-size", function(d) { return d.size + "px"; }) - .style("font-family", "Brixslab-Regular") - .attr("text-anchor", "middle") - .attr("transform", function(d) { - return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; - }) - .text(function(d) { return d.text; }); + var cloud = d3.select("#wordcloud-container").selectAll("g text") + .data(words, function(d) { return d.text; }) + //Entering words + cloud.enter() + .append("text") + .style("font-family", "Impact") + .style("fill", function(d, i) { return fill(i); }) + .attr("text-anchor", "middle") + .attr('font-size', 1) + .text(function(d) { return d.text; }); + + //Entering and existing words + cloud + .transition() + .duration(600) + .style("font-size", function(d) { return d.size + "px"; }) + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + }) + .style("fill-opacity", 1); + + //Exiting words + cloud.exit() + .transition() + .duration(200) + .style('fill-opacity', 1e-6) + .attr('font-size', 1) + .remove(); + + + // d3.select("#wordCloud") + // .attr("width", layout.size()[0]) + // .attr("height", layout.size()[1]) + // .append("g") + // .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") + // .selectAll("text") + // .data(words) + // .enter().append("text") + // .style("font-size", function(d) { return d.size + "px"; }) + // .style("font-family", "Brixslab-Regular") + // .attr("text-anchor", "middle") + // .attr("transform", function(d) { + // return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + // }) + // .text(function(d) { return d.text; }); } } @@ -225,9 +432,9 @@ export class PortfolioComponent implements OnInit { }) this.filterOpen = false; - this.drawWordCloud(this.filteredProjects.map(item => item.topics)); } + removeFilter(key){ this.filter[key] = null; this.filterToUrl(); diff --git a/tsconfig.json b/tsconfig.json index 9a93747..2d7e110 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "importHelpers": true, "target": "es2015", "module": "es2020", - "lib": ["es2018", "dom"], + "lib": ["es2018", "dom", "es2019"], "resolveJsonModule": true, "esModuleInterop": true }