如何在 vue 中正确设置 d3-zoom?

问题描述

我有 svg 来渲染场地的座位。所有席位均按部门分组。我需要座位点击事件,放大该扇区中的那些座位,当我点击另一个扇区时,它应该缩小并再次放大新扇区。这是我想要的示例:https://observablehq.com/@d3/zoom-to-bounding-box?collection=@d3/d3-zoom

目前我使用 svgPanZoom.js 库来操作 svg(我知道它使用矩阵而不是 viewBox)。 D3 似乎有点难,你能给我建议一个 d3 的替代方案,我可以做一些类似上面例子的事情吗?

这是我的代码

<svg width="100%"
     xmlns="http://www.w3.org/2000/svg"
     ref="venueMap" id="venue-map"
     opacity="1"
     class="seat-map"
     @mousedown.prevent="startDrag"
     @touchstart="startDrag"
     @mousemove="updateEndDragPoint"
     @mouseup="stopDrag"
     @touchend="stopDrag"
     @touchcancel="stopDrag">

  <image :href="layoutimage.url"
         :width="layoutimage.width - (+layoutimage.width * 0.01 * 60)"
         :height="layoutimage.height - (+layoutimage.height * 0.01 * 60)">
  </image>

  <rect
    class="selectArea"
    v-show="shoulddisplaySelectRect"
    :x="dragData.start.x < dragData.end.x ? dragData.start.x : dragData.end.x"
    :y="dragData.start.y < dragData.end.y ? dragData.start.y : dragData.end.y"
    :width="Math.abs(dragData.start.x - dragData.end.x)"
    :height="Math.abs(dragData.start.y - dragData.end.y)">
  </rect>

  <g v-for="(sector,sectorIndex) in placements">
    <g v-for="(row,rowIndex) in sector">
      <rect v-for="(seat,seatIndex) in row"
            :key="seatIndex + 'A'"
            :x="seat.x"
            :y="seat.y"
            :class="seatStyle(seat)"
            class="seat-rect"
            height="9"
            width="9"
            @mouSEOver="mouSEOverSeat(seat,$event)"
            @mouSEOut="mouSEOutFromSeat($event)"
            @click="selectSeat(seat,{sectorIndex,rowIndex},$event)">
      </rect>
    </g>
  </g>


  <polygonComponent v-for="(sector,index) in sectors"
                    :key="index"
                    :sector-index="index"
                    :sector="sector"
                    :sector-text-positions="sectorTextPosition">
  </polygonComponent>

</svg>

解决方法

这是一个简单的缩放示例(Vue + D3 V6

我建议明确传递 SVG 宽度和高度,而不是使用 viewBox:

  const onZoom = (container,event) => container.attr('transform',event.transform);
    
const initView = (ref,width,height) => {    
      // Init SVG container
      const svg = d3.select(ref);
      const container = svg.append('g')
        .classed('container',true);
            
      // Draw something under your container  
      container.append('circle')
        .attr('r',50)
        .style('fill','#aaa')
        .style('cursor','pointer');
          
      // Init D3 zoom
      const zoom = d3.zoom()
        .scaleExtent([0.5,10])
        .on('zoom',e => onZoom(container,e));
      svg.call(zoom);
            
      // Center container within SVG    
      const centered = d3.zoomIdentity
        .translate(width/2,height/2);
      svg.call(zoom.transform,centered);  
    }
    
    Vue.component('d3-component',{
      props: ['width','height'],mounted() {
        initView(this.$refs.svg,this.width,this.height);
      },template: '<svg ref="svg" :width="width" :height="height"></svg>'
    })
    
    new Vue({ el: '#d3-zoom-demo' })
    svg {
      background-color: #ccc;
    }
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.2/d3.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="d3-zoom-demo">
  <d3-component width="200" height="150"/>
</div>