d3.js使用不同的缩放比例和地图缩放在圆圈下定位

时间:2016-11-07 22:47:06

标签: javascript d3.js svg css-transforms

我有一个svg元素,其中包含此图像上的地图和标记等图像。标记有圆圈和下降。使用d3.zoom我可以缩放地图,并且在悬停在标记上时,它们必须按x缩放到1.1并且按y缩放到1,但是保持圆形。我的问题是在圆圈下方定位标记,它们总是在圆圈上方左/右移动。

使用d3.js我在此代码中添加了新标记(this.map.layout是svg上的g元素,在缩放后移动和缩放):

let map = {
  element: null,
  layout: null,
  currentZoomLevel: 1.0
};

const consts = {
  markersScales: {
    small: {
      x: 1,
      y: 1
    },
    hovered: {
      x: 1,
      y: 1.1
    },
    extended: {
      x: 7,
      y: 7
    }
  }
};


const markers = [
  {x: 1, y: 10, color: 'red'},
  {x: 5, y: 16, color: 'green'},
  {x: 45, y: 30, color: 'blue'},
  {x: 20, y: 50, color: 'yellow'},
  {x: 0, y: 0, color: 'black'},
]


map.element = d3.select("#map");
let mapWidth = map.element.node().parentNode.getBoundingClientRect().width;
let mapHeight = mapWidth * 2/3;

map.layout = map.element.append('g');

map.layout
  .append('svg:image')
  .attr('xlink:href', 'http://filipinofreethinkers.org/wp-content/uploads/2009/03/map-to-ateneo.png')
  .attr('width', 400)
  .attr('height', 202);

map.element.call(d3.zoom().on('zoom', _zoomed));

function _zoomed() {

        let {x, y, k} = d3.event.transform;
        map.layout.attr("transform", `translate(${x}, ${y}) scale(${k})`);

        map.currentZoomLevel = k;


        map.layout.selectAll('.marker')
            .each(function(d) {
                _setScale(d3.select(this));
            });

    }

function _setScale(element, scale = null) {

        let markerData = element.datum();

        if (!scale) {
            scale = markerData.scale;
        }

        const yOffset = scale.x == consts.markersScales.extended.x ? -45 :  0;
        const strokeWidth = scale.x == consts.markersScales.extended.x ? 0.2 : 1;

        const duration = scale.x == consts.markersScales.extended.x ? 500 : 200;

        const currentZoom = map.currentZoomLevel;

        const totScale = scale.x / currentZoom;

        const xOffset = 25.5/totScale;

        element.select("use.drop").transition()
            .attr('stroke-width', strokeWidth)
            .attr('transform', `translate(${25.5*(1-totScale) + 3/currentZoom} ) scale(${ scale.x / currentZoom} ${scale.y / currentZoom}) `)
            .duration(duration);
          
    }  


function _renderMarker(x, y, color, data, type, scale = {x: 1, y: 1}) {

        const offset = 25;
        const yOffset = 0;

        let g = map.layout.append('g');
        g
            .datum({
                color: color,
                x: x,
                y: y,
                type: type,
                scale: scale,
                data: data,
                open: false

            })
            .attr('class', 'marker')
            .attr('style', `transform: translate(${x-offset}px, ${y-yOffset}px)`);


        const currentZoom = map.currentZoomLevel;

        const totScale = scale.x / currentZoom;

        g.append("use")
            .attr('xlink:href', '#path-1')
            .attr('fill', color)
            .attr('class', 'drop')
            .attr('transform', `translate(${25.5*(1-totScale) + 3/currentZoom}) scale(${ scale.x * currentZoom} ${scale.y * currentZoom})`)
            .attr('stroke', 'white')
            .attr('stroke-width', 1)
            .attr('fill-rule', 'evenodd');

        g.append('circle')
            .attr('cx', offset)
            .attr('cy', yOffset)
            .attr('r', 3)
            .attr('stroke', 'white')
            .attr('stroke-width', 1)
            .attr('fill', color);

        g.on('mouseenter', function(d) {
            d3.select(this).raise();
            _setScale(d3.select(this), consts.markersScales.hovered);
        });

        g.on('mouseleave', function(d) {
            _setScale(d3.select(this), consts.markersScales.small);
        });

        g.on('click', function(d) {
            _setScale(d3.select(this), consts.markersScales.extended);
        });

        return g;

    }

markers.forEach(marker => _renderMarker(marker.x, marker.y, marker.color, null, null, consts.markersScales.small));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
<svg id="map" width=400 height=300>
  <defs>
   <path d="
     M  43,   39
     C  37,   25  25.5,  21  24, 8
     C  24,   21  11.35, 25  5,  39
     C  -1.5, 52  8,     68  24, 68
     C  39,   68  49.5,  52  43, 39
     Z" id="path-1"></path>
  </defs>
</svg>

0 个答案:

没有答案