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