script(type="text/x-template" id="little-car")
g
mt-shortcut(shortcode="left", @trigger="moveLeft")
mt-shortcut(shortcode="right", @trigger="moveRight")
mt-shortcut(shortcode="up", @trigger="moveUp")
mt-shortcut(shortcode="down", @trigger="moveDown")
v-timer(time="0.05", @buzz="updatePosition")
path(:d="trace", stroke="red", fill="none")
rect(:x="x", :y="y", width="20" height="20" fill="black")
svg#app
little-car
View Compiled
svg
margin: 5vh 0 0 5vw
width: 90vw
height: 90vh
border: solid 1px black
box-sizing: border-box
html, body
margin: 0
padding: 0
View Compiled
// Composant Mousetrap, je ne reviens pas dessus
var mtShortcut = {
props: ['shortcode', 'modifier'],
// S'execute lors de l'apparition de l'element
beforeMount () {
Mousetrap.bind(this.shortcode, evt => this.$emit('trigger', evt), this.modifier)
},
// Se supprime lors de la disparition de l'element
beforeDestroy () {
Mousetrap.unbind(this.shortcode, this.modifier)
}
}
// Un timer permettant d'executer une method à interval régulier
// La propriété 'time' est à donner en secondes.
var vTimer = {
props: ['time'],
data () {
return { timer: undefined }
},
// S'execute lors de l'apparition de l'element
beforeMount () {
this.timer = setInterval(e => this.$emit("buzz"), parseFloat(this.time)*1000)
},
// Se supprime lors de la disparition de l'element
beforeDestroy () {
this.clearInterval(this.timer)
},
reset () {
this.clearInterval(this.timer)
this.timer = setInterval(e => this.$emit("buzz"), parseFloat(this.time)*1000)
}
}
// Enfin, notre composant.
let littleCar = {
// la liste des composants dont nous allons avoir besoin
components: { mtShortcut, vTimer },
template: '#little-car',
data() {
// Ce petit paragraphe permet de récupérer le centre de notre SVG
// qui nous servira de point de départ
let boundingBox = document.querySelector('svg').getBoundingClientRect(),
screenWidth = boundingBox.width,
screenHeight = boundingBox.height,
startingPosX = (screenWidth / 2) - 10,
startingPosY = (screenHeight / 2) - 10
// Trace est cette trace rouge qui suit notre bolide
return {
x: startingPosX,
y: startingPosY,
vx: 0,
vy: 0,
trace: `M${startingPosX + 10} ${startingPosY + 10}`
}
},
methods: {
updatePosition () {
// On récupère les dimmensions de l'écran
let boundingBox = document.querySelector('svg').getBoundingClientRect(),
screenWidth = boundingBox.width - 20,
screenHeight = boundingBox.height - 20,
// On détermine l'éventuelle nouvelle position (position actuelle + vitesse)
newX = this.x + this.vx,
newY = this.y + this.vy
// On vérifie que la nouvelle position est bien à l'interieur du SVG, sinon on la contraint
if (newX > screenWidth) {
newX = screenWidth
// On inverse la vitesse pour un effet 'rebond'
this.vx = - this.vx
} else if (newX < 0) {
newX = 0
this.vx = - this.vx
}
// comme au dessus, mais pour l'axe Y
if (newY > screenHeight) {
newY = screenHeight
this.vy = - this.vy
} else if (newY < 0) {
newY = 0
this.vy = - this.vy
}
// On applique la nouvelle position
this.x = newX
this.y = newY
// on trace
this.trace += `L${newX + 10} ${newY + 10}`
// On réduit la vitesse, pour ajouter des 'frictions'
this.vx = this.vx * 0.95
this.vy = this.vy * 0.95
},
moveUp () {
this.vy -= 5
},
moveDown () {
this.vy += 5
},
moveRight () {
this.vx += 5
},
moveLeft () {
this.vx -= 5
}
}
}
//---------------------------------------------
new Vue({
el: "#app",
components: { littleCar },
})
View Compiled
This Pen doesn't use any external CSS resources.