vue3-yuanma/packages/vue/examples/composition/svg.html

171 lines
3.3 KiB
HTML
Raw Normal View History

2019-12-02 12:54:32 +08:00
<script src="../../dist/vue.global.js"></script>
<script>
// math helper...
function valueToPoint (value, index, total) {
var x = 0
var y = -value * 0.8
var angle = Math.PI * 2 / total * index
var cos = Math.cos(angle)
var sin = Math.sin(angle)
var tx = x * cos - y * sin + 100
var ty = x * sin + y * cos + 100
return {
x: tx,
y: ty
}
}
const AxisLabel = {
template: '<text :x="point.x" :y="point.y">{{stat.label}}</text>',
props: {
stat: Object,
index: Number,
total: Number
},
setup(props) {
return {
point: Vue.computed(() => valueToPoint(
+props.stat.value + 10,
props.index,
props.total
))
}
}
}
</script>
<!-- template for the polygraph component. -->
<script type="text/x-template" id="polygraph-template">
<g>
<polygon :points="points"></polygon>
<circle cx="100" cy="100" r="80"></circle>
<axis-label
v-for="(stat, index) in stats"
:stat="stat"
:index="index"
:total="stats.length">
</axis-label>
</g>
</script>
<script>
const Polygraph = {
props: ['stats'],
template: '#polygraph-template',
setup(props) {
return {
points: Vue.computed(() => {
const total = props.stats.length
return props.stats.map((stat, i) => {
const point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
})
}
},
components: {
AxisLabel
}
}
</script>
<!-- demo root element -->
<div id="demo">
<!-- Use the polygraph component -->
<svg width="200" height="200">
<polygraph :stats="stats"></polygraph>
</svg>
<!-- controls -->
<div v-for="stat in stats">
<label>{{stat.label}}</label>
<input type="range" v-model="stat.value" min="0" max="100">
<span>{{stat.value}}</span>
<button @click="remove(stat)" class="remove">X</button>
</div>
<form id="add">
<input name="newlabel" v-model="newLabel">
<button @click="add">Add a Stat</button>
</form>
<pre id="raw">{{ stats }}</pre>
</div>
<script>
const App = {
components: {
Polygraph
},
setup() {
const newLabel = Vue.ref('')
const stats = Vue.reactive([
{ label: 'A', value: 100 },
{ label: 'B', value: 100 },
{ label: 'C', value: 100 },
{ label: 'D', value: 100 },
{ label: 'E', value: 100 },
{ label: 'F', value: 100 }
])
function add(e) {
e.preventDefault()
if (!newLabel.value) return
stats.push({
label: newLabel.value,
value: 100
})
newLabel.value = ''
}
function remove(stat) {
if (stats.length > 3) {
stats.splice(stats.indexOf(stat), 1)
} else {
alert('Can\'t delete more!')
}
}
return {
newLabel,
stats,
add,
remove
}
}
}
Vue.createApp().mount(App, '#demo')
</script>
<style>
body {
font-family: Helvetica Neue, Arial, sans-serif;
}
polygon {
fill: #42b983;
opacity: .75;
}
circle {
fill: transparent;
stroke: #999;
}
text {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 10px;
fill: #666;
}
label {
display: inline-block;
margin-left: 10px;
width: 20px;
}
#raw {
position: absolute;
top: 0;
left: 300px;
}
</style>