6 changed files with 214 additions and 30 deletions
@ -0,0 +1,92 @@
|
||||
<template> |
||||
<svg :width="width" :height="height"> |
||||
<g :transform="`translate(${width / 2}, ${height / 2})`"> |
||||
<text |
||||
v-for="word in words" |
||||
:key="word.text" |
||||
:style="{ |
||||
fontSize: word.size + 'px', |
||||
fontFamily: word.font, |
||||
}" |
||||
:transform="`translate(${word.x}, ${word.y})rotate(${word.rotate})`" |
||||
text-anchor="middle" |
||||
@click="highlightText(word.text)" |
||||
> |
||||
{{ word.text }} |
||||
</text> |
||||
</g> |
||||
</svg> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import cloud from "d3-cloud"; |
||||
import * as skills from "@/data/skills"; |
||||
import { defineComponent } from "vue"; |
||||
|
||||
export default defineComponent({ |
||||
props: { |
||||
width: Number, |
||||
height: Number, |
||||
}, |
||||
data() { |
||||
return { |
||||
loading: false, |
||||
words: [] as cloud.Word[], |
||||
minFontSize: 8, |
||||
maxFontSize: 40, |
||||
}; |
||||
}, |
||||
created() { |
||||
this.computeWords(); |
||||
}, |
||||
methods: { |
||||
highlightText(text: string) { |
||||
console.log(text); |
||||
}, |
||||
computeWords() { |
||||
this.loading = true; |
||||
const words = Object.keys(skills) |
||||
.map((p) => skills[p]) |
||||
.map((s) => ({ text: s.name, size: s.score })); |
||||
|
||||
const min = words |
||||
.map((s) => s.size) |
||||
.reduce((prev, current) => Math.min(prev, current)); |
||||
const max = words |
||||
.map((s) => s.size) |
||||
.reduce((prev, current) => Math.max(prev, current)); |
||||
const scaleFontSize = (size: number) => { |
||||
const number = |
||||
((size - min) / (max - min)) * (this.maxFontSize - this.minFontSize) + |
||||
this.minFontSize; |
||||
return number; |
||||
}; |
||||
const randomRotate = (s: number) => { |
||||
const range = 120 * (1 - ((s - min) / (max - min)) * 0.7); |
||||
return Math.random() * range - range / 2; |
||||
}; |
||||
cloud<{ size: number } & cloud.Word>() |
||||
.size([this.width!, this.height!]) |
||||
.words(words) |
||||
.padding(1) |
||||
.rotate((w) => randomRotate(w.size)) |
||||
.spiral("archimedean") |
||||
.fontSize((d) => scaleFontSize(d.size)) |
||||
.on("end", (d: cloud.Word[]) => { |
||||
console.log( |
||||
`d: ${d.length} - w: ${words.length} - f: ${this.maxFontSize}` |
||||
); |
||||
if (d.length < words.length) { |
||||
console.log("On recommence !"); |
||||
this.maxFontSize = this.maxFontSize - 2; |
||||
this.computeWords(); |
||||
} else { |
||||
this.words = d; |
||||
this.loading = false; |
||||
} |
||||
}) |
||||
.start(); |
||||
}, |
||||
}, |
||||
}); |
||||
</script> |
||||
@ -1,11 +0,0 @@
|
||||
<template> |
||||
<div>Words Cloud !</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: "WordsCloud", |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped></style> |
||||
Loading…
Reference in new issue