123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- <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, zoomIdentity } from 'd3'
- export default {
- name: 'MapZoom',
- props: {
- id: { type: String, required: true },
- minZoom: { type: Number, default: 0.3 },
- maxZoom: { type: Number, default: 1 },
- initialZoom: { type: Number, default: 1 },
- center: { type: Object, default: null }
- },
- data () {
- return {
- zoom: zoom().scaleExtent([this.minZoom, this.maxZoom]),
- svg: undefined, // d3 select(svg)
- width: undefined,
- height: undefined,
- scale: this.initialZoom,
- transform: zoomIdentity.translate(0, 0).scale(this.initialZoom)
- }
- },
- computed: {
- viewBox () {
- const { width, height } = this
- if (width === undefined) return
- return `-${width / 2} -${height / 2} ${width} ${height}`
- }
- },
- watch: {
- center (val, prevVal) {
- this.transform = this.transform.translate(prevVal.x - val.x, prevVal.y - val.y)
- }
- },
- methods: {
- updateSize () {
- const { width, height } = this.$el.getBoundingClientRect()
- Object.assign(this.$data, { width, height })
- this.$emit('input', { width, height })
- },
- onZoom (direction) {
- this.zoom.scaleBy(this.svg, direction === 1 ? 1.3 : 1 / 1.3, [0, 0])
- },
- reset () {
- this.transform = zoomIdentity.translate(0, 0).scale(this.initialZoom)
- this.svg.call(this.zoom.transform, this.transform)
- }
- },
- mounted () {
- window.addEventListener('resize', () => this.updateSize())
- this.zoom.on('zoom', ({ transform }) => {
- this.transform = this.center ? transform.translate(-this.center.x, -this.center.y) : transform
- this.scale = transform.k
- })
- this.updateSize()
- this.svg = select('#' + this.id + ' svg')
- this.svg.call(this.zoom).call(this.zoom.transform, this.transform)
- }
- }
- </script>
- <style lang="scss" scoped>
- .map-zoom {
- position: relative;
- width: 100%;
- height: 100%;
- cursor: grab;
- svg {
- width: 100%;
- height: 100%;
- }
- }
- </style>
|