3

I have svg where I render seats of venue. All seats are grouped by sectors. I need on seat click event, zoom in those seats which are in that sector, when I click another sector it should zoom out and zoom in again on new sector. Here is an example what I want: https://observablehq.com/@d3/zoom-to-bounding-box?collection=@d3/d3-zoom.

Currently I use svgPanZoom.js library to manipulate svg (as I know it uses matrix instead of viewBox). D3 seemed a little hard, can you advice me an alternative for d3 with what I can do something like in example above?

Here is my code:

<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>
andre1ka
  • 33
  • 4

1 Answers1

1

Here is a simple zoom example (Vue + D3 V6)

I suggest to pass SVG width and height explicitly instead of using 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>
Michael Rovinsky
  • 6,807
  • 7
  • 15
  • 30