|
@@ -0,0 +1,85 @@
|
|
|
+<template>
|
|
|
+ <div :id="id" class="map-zoom">
|
|
|
+ <svg :view-box.camel="viewBox">
|
|
|
+ <g :transform="transform">
|
|
|
+ <slot name="default" />
|
|
|
+ </g>
|
|
|
+ </svg>
|
|
|
+
|
|
|
+ <button-zoom
|
|
|
+ v-bind="{ minZoom, maxZoom, value: scale }"
|
|
|
+ @zoom="onZoom"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { select, zoom } from 'd3'
|
|
|
+
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'MapZoom',
|
|
|
+
|
|
|
+ props: {
|
|
|
+ id: { type: String, required: true },
|
|
|
+ minZoom: { type: Number, default: 0.3 },
|
|
|
+ maxZoom: { type: Number, default: 1 }
|
|
|
+ },
|
|
|
+
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ zoom: zoom().scaleExtent([this.minZoom, this.maxZoom]),
|
|
|
+ svg: undefined, // d3 select(svg)
|
|
|
+ width: undefined,
|
|
|
+ height: undefined,
|
|
|
+ scale: 1,
|
|
|
+ transform: 'translate(0, 0) scale(1)'
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ computed: {
|
|
|
+ viewBox () {
|
|
|
+ const { width, height } = this
|
|
|
+ if (width === undefined) return
|
|
|
+ return `-${width / 2} -${height / 2} ${width} ${height}`
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ updateSize () {
|
|
|
+ const { width, height } = this.$el.getBoundingClientRect()
|
|
|
+ Object.assign(this.$data, { width, height })
|
|
|
+ },
|
|
|
+
|
|
|
+ onZoom (direction) {
|
|
|
+ this.zoom.scaleBy(this.svg, direction === 1 ? 1.3 : 1 / 1.3, [0, 0])
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted () {
|
|
|
+ window.addEventListener('resize', () => this.updateSize())
|
|
|
+
|
|
|
+ this.zoom.on('zoom', ({ transform }) => {
|
|
|
+ this.transform = transform
|
|
|
+ this.scale = transform.k
|
|
|
+ })
|
|
|
+
|
|
|
+ this.updateSize()
|
|
|
+ this.svg = select('#' + this.id + ' svg')
|
|
|
+ this.svg.call(this.zoom)
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.map-zoom {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|