Example #1
0
function _round(area) {
  return d3.geo.transform({
    point: function(x, y, z) {
      this.stream.point(Math.round(x), Math.round(y));
    },
    sphere: function() {
      this.stream.sphere();
    }
  });
}
Example #2
0
function _simplify(area) {
  return d3.geo.transform({
    point: function(x, y, z) {
      if (!z) {
        this.stream.point(x, y);
      }
      else if (z >= area) {
        this.stream.point(x, y);
      }
    },
    sphere: function() {
      this.stream.sphere();
    }
  });
}
Example #3
0
  _redraw() {
    const pixelRatio = window.devicePixelRatio;
    const canvas = this.refs.overlay;
    const ctx = canvas.getContext('2d');
    const mercator = ViewportMercator(this.props);

    ctx.save();
    ctx.scale(pixelRatio, pixelRatio);
    ctx.clearRect(0, 0, this.props.width, this.props.height);

    function projectPoint(lon, lat) {
      const point = mercator.project([lon, lat]);
      /* eslint-disable no-invalid-this */
      this.stream.point(point[0], point[1]);
      /* eslint-enable no-invalid-this */
    }

    if (this.props.renderWhileDragging || !this.props.isDragging) {
      const transform = d3.geo.transform({point: projectPoint});
      const path = d3.geo.path().projection(transform).context(ctx);
      this._drawFeatures(ctx, path);
    }
    ctx.restore();
  }
Example #4
0
    function ZoomableCanvasMap(parameters) {
        var map = new CanvasMap(parameters),
            simplify = d3.geo.transform({
                point: function(x, y, z) {
                    if (!z || z >= area) this.stream.point(x, y)
                }
            }),
            area = 0,
            canvas = null,
            context = null,
            settings = map.settings(),
            dataPath = d3.geo.path().projection({
                stream: function(s) {
                    if (settings.projection)
                        return simplify.stream(settings.projection.stream(s))
                    return simplify.stream(s)
                }
            }),
            imageCache = new ImageCache({
                width: settings.width,
                height: settings.height
            }),
            busy = false

        settings.map = this
        settings.zoomScale = settings.zoomScale || 0.5

        this.init = function() {
            map.init()

            canvas = d3.select(settings.element).append("canvas")
            context = canvas.node().getContext("2d")
            area = 1 / settings.ratio
            if (settings.projection)
                area = area / settings.projection.scale() / 25

            canvas.attr("width", settings.width * settings.ratio / settings.projectedScale)
            canvas.attr("height", settings.height * settings.ratio / settings.projectedScale)
            canvas.style("width", settings.width + "px")
            canvas.style("height", settings.height + "px")
            canvas.style("display", "none")
            context.lineJoin = "round"
            context.lineCap = "round"

            dataPath.context(context)

            imageCache.addImage({
                image: settings.background,
                scale: settings.scale,
                translate: settings.translate
            })

            createRTrees(settings.data, dataPath)
        }
        this.paint = function() {
            map.paint()
        }
        function scaleZoom(scale, translate) {
            // We can just mutex with a standard variable, because JS is single threaded, yay!
            // The mutex is needed not to start multiple d3 transitions.
            if (busy) {
                return
            }
            busy = true
            if (nearEqual(scale, settings.scale) &&
                nearEqual(translate[0], settings.translate[0]) &&
                nearEqual(translate[1], settings.translate[1])) {
                scale = 1
                translate = [0, 0]
            }
            if (scale == 1 && settings.scale == 1 &&
                !translate[0] && !translate[1] &&
                !settings.translate[0] && !settings.translate[1]) {
                busy = false
                return
            }
            area = 1 / scale / settings.ratio
            if (settings.projection)
                area = area / settings.projection.scale() / 25

            context.save()
            context.scale(scale * settings.ratio, scale * settings.ratio)
            context.translate(translate[0], translate[1])
            context.clearRect(- translate[0], - translate[1],
                settings.width * settings.ratio / settings.projectedScale,
                settings.height * settings.ratio / settings.projectedScale)
            var parameters = {
                path: dataPath,
                context: context,
                scale: scale,
                projectedScale: settings.projectedScale,
                translate: translate,
                width: settings.width,
                height: settings.height,
                map: settings.map,
                projection: settings.projection,
                projectedScale: settings.projectedScale
            }

            var image = imageCache.getImage({
                scale: scale,
                translate: translate
            })
            if (!image) {
                var partialPainter = new PartialPainter(settings.data, parameters)
            }

            var translatedOne = translatePoint([settings.width, settings.height], scale, translate),
                translatedTwo = translatePoint([settings.width, settings.height], settings.scale, settings.translate)
            var bbox = [
                Math.min(- translate[0], - settings.translate[0]),
                Math.min(- translate[1], - settings.translate[1]),
                Math.max(translatedOne[0], translatedTwo[0]),
                Math.max(translatedOne[1], translatedTwo[1])
            ]
            var zoomImage = imageCache.getFittingImage(bbox)
            if (zoomImage) {
                settings.background = zoomImage.image
                settings.backgroundScale = zoomImage.scale
                settings.backgroundTranslate = zoomImage.translate
            }
            d3.transition()
                .duration(300)
                .ease("linear")
                .tween("zoom", function() {
                    var i = d3.interpolateNumber(settings.scale, scale),
                        oldTranslate = settings.translate,
                        oldScale = settings.scale
                    return function(t) {
                        settings.scale = i(t)
                        settings.translate = [
                            oldTranslate[0] + (translate[0] - oldTranslate[0]) / (scale - oldScale) * (i(t) - oldScale) * scale / i(t),
                            oldTranslate[1] + (translate[1] - oldTranslate[1]) / (scale - oldScale) * (i(t) - oldScale) * scale / i(t),
                        ]
                        map.paint()
                        !image && partialPainter.renderNext()
                    }
                })
                .each("end", function() {
                    settings.scale = scale
                    settings.translate = translate

                    if (image) {
                        context.restore()
                        settings.background = image.image
                        settings.backgroundScale = image.scale
                        settings.backgroundTranslate = image.translate
                        map.paint()
                    } else {
                        map.paint()
                        partialPainter.finish()

                        var background = new Image()
                        background.onload = function() {
                            context.restore()
                            imageCache.addImage({
                                image: background,
                                scale: scale,
                                translate: translate
                            })
                            settings.background = background
                            settings.backgroundScale = scale
                            settings.backgroundTranslate = translate
                            map.paint()
                        }
                        // TODO there is a function to get the image data from the context, is that faster?
                        // TODO use getImageData/putImageData, because it's faster?
                        background.src = canvas.node().toDataURL()
                    }
                    busy = false
                })
        }
        this.zoom = function(d) {
            if (!d) {
                scaleZoom.call(this, 1, [0, 0])
                return
            }
            var bounds = dataPath.bounds(d),
                dx = bounds[1][0] - bounds[0][0],
                dy = bounds[1][1] - bounds[0][1],
                bx = (bounds[0][0] + bounds[1][0]) / 2,
                by = (bounds[0][1] + bounds[1][1]) / 2,
                scale = settings.zoomScale / settings.projectedScale *
                    Math.min(settings.width / dx, settings.height / dy),
                translate = [-bx + settings.width / settings.projectedScale / scale / 2,
                             -by + settings.height / settings.projectedScale / scale / 2]

            scaleZoom.call(this, scale, translate)
        }
    }
Example #5
0
    function CanvasMap(parameters) {
        var settings = extend({
                width: d3.select(parameters.element).node().getBoundingClientRect().width,
                ratio: 1,
                area: 0,
                scale: 1,
                projectedScale: 1,
                translate: [0, 0],
                background: null,
                backgroundScale: 1,
                backgroundTranslate: [0, 0],
                map: this
            }, parameters),
            simplify = d3.geo.transform({
                point: function(x, y, z) {
                    if (!z || z >= settings.area) {
                        this.stream.point(x, y)
                    }
                }
            }),
            canvas = null,
            context = null

        if (!parameters.hasOwnProperty("projection")) {
            var b = [[Infinity, Infinity],
                     [-Infinity, -Infinity]]
            for (var i in settings.data) {
                b = maxBounds(b, d3.geo.bounds(settings.data[i].features))
            }
            settings.projection = d3.geo.mercator()
                .scale(1)
                .center([(b[1][0] + b[0][0]) / 2, (b[1][1] + b[0][1]) / 2])
        }
        var dataPath = d3.geo.path().projection({
            stream: function(s) {
                if (settings.projection)
                    return simplify.stream(settings.projection.stream(s))
                return simplify.stream(s)
            }
        })
        var b = [[Infinity, Infinity],
                 [-Infinity, -Infinity]]
        for (var i in settings.data) {
            b = maxBounds(b, dataPath.bounds(settings.data[i].features))
        }

        var dx = b[1][0] - b[0][0],
            dy = b[1][1] - b[0][1]

        if (!settings.projection) {
            settings.projectedScale = settings.width / b[1][0]
        }

        if (!parameters.hasOwnProperty("projection")) {
            settings.height = settings.height || Math.ceil(dy * settings.width / dx)
            settings.projection.scale(0.9 * (settings.width / dx))
                .translate([settings.width / 2, settings.height / 2])
        } else if (!settings.projected) {
            settings.height = Math.ceil(b[1][1] * settings.projectedScale)
        } else if (!settings.height) {
            settings.height = Math.ceil(dy / 0.9)
        }
        d3.select(settings.parameters).attr("height", settings.height)

        function init() {
            canvas = d3.select(settings.element)
                .append("canvas")
            context = canvas.node().getContext("2d")

            var devicePixelRatio = window.devicePixelRatio || 1,
                backingStoreRatio = context.webkitBackingStorePixelRatio ||
                                    context.mozBackingStorePixelRatio ||
                                    context.msBackingStorePixelRatio ||
                                    context.oBackingStorePixelRatio ||
                                    context.backingStorePixelRatio || 1

            settings.ratio = devicePixelRatio / backingStoreRatio * settings.projectedScale
            settings.area = 1 / settings.ratio
            if (settings.projection)
                settings.area = settings.area / settings.projection.scale() / 25

            canvas.attr("width", settings.width / settings.projectedScale * settings.ratio)
            canvas.attr("height", settings.height / settings.projectedScale * settings.ratio)
            canvas.style("width", settings.width + "px")
            canvas.style("height", settings.height + "px")
            context.lineJoin = "round"
            context.lineCap = "round"

            dataPath.context(context)
            context.clearRect(0, 0, settings.width * settings.ratio, settings.height * settings.ratio)
            context.save()
            context.scale(settings.ratio, settings.ratio)

            var hasHover = false,
                hasClick = false
            for (var i in settings.data) {
                var element = settings.data[i]

                hasHover = hasHover || (element.events && element.events.hover)
                hasClick = hasClick || (element.events && element.events.click)
            }

            // Only compute rtrees if we need it for event handling
            if (hasHover || hasClick) {
                createRTrees(settings.data, dataPath)
            }

            settings.background = new Image()
            settings.backgroundScale = settings.scale
            settings.backgroundTranslate = settings.translate
            var parameters = {
                path: dataPath,
                context: context,
                scale: settings.scale,
                translate: settings.translate,
                width: settings.width,
                height: settings.height,
                map: settings.map,
                projection: settings.projection,
                projectedScale: settings.projectedScale
            }
            var callback = function() {
                context.restore()

                hasClick && canvas.on("click", click)
                hasHover && canvas.on("mousemove", hover)
                                  .on("mouseleave", hoverLeave)

                paint() // For dynamic paints
            }

            for (var i in settings.data) {
                var element = settings.data[i]
                paintBackgroundElement(element, parameters)
            }
            settings.background.onload = callback
            settings.background.src = canvas.node().toDataURL()

            //Prevent another call to the init method
            this.init = function() {}
        }

        function paint() {
            context.save()
            context.scale(settings.scale * settings.ratio, settings.scale * settings.ratio)
            context.translate(settings.translate[0], settings.translate[1])

            context.clearRect(- settings.translate[0], - settings.translate[1],
                settings.width * settings.ratio / settings.projectedScale,
                settings.height * settings.ratio / settings.projectedScale)

            context.rect(- settings.translate[0], - settings.translate[1],
                settings.width / settings.scale / settings.projectedScale,
                settings.height / settings.scale / settings.projectedScale)
            context.clip()

            // FIXME this needs a way for the callback to use the lookupTree?
            var parameters = {
                path: dataPath,
                context: dataPath.context(),
                scale: settings.scale,
                translate: settings.translate,
                width: settings.width,
                height: settings.height,
                map: settings.map,
                projection: settings.projection,
                projectedScale: settings.projectedScale
            }

            settings.area = 1 / settings.scale / settings.ratio
            if (settings.projection)
                settings.area = settings.area / settings.projection.scale() / 25

            for (var i in settings.data) {
                var element = settings.data[i]
                if (element.dynamic && element.dynamic.prepaint)
                    element.dynamic.prepaint(parameters, element.hoverElement)
            }

            context.drawImage(settings.background, 0, 0,
                settings.width * settings.ratio / settings.projectedScale,
                settings.height * settings.ratio / settings.projectedScale,
                - settings.backgroundTranslate[0],
                - settings.backgroundTranslate[1],
                settings.width / settings.backgroundScale / settings.projectedScale,
                settings.height / settings.backgroundScale / settings.projectedScale)

            for (var i in settings.data) {
                var element = settings.data[i]
                if (element.dynamic && element.dynamic.postpaint)
                    element.dynamic.postpaint(parameters, element.hoverElement)
            }

            context.restore()
        }

        function click() {
            var point = translatePoint(d3.mouse(this), settings.scale * settings.projectedScale, settings.translate),
                topojsonPoint = settings.projection ? settings.projection.invert(point) : point

            var parameters = {
                scale: settings.scale,
                translate: settings.translate,
                width: settings.width,
                height: settings.height,
                map: settings.map,
                projection: settings.projection,
                projectedScale: settings.projectedScale
            }
            for (var i in settings.data) {
                var element = settings.data[i]
                if (!element.events || !element.events.click)
                    continue

                var lookup = element.lookupTree.search({
                    minX: point[0],
                    minY: point[1],
                    maxX: point[0],
                    maxY: point[1]
                })
                var isInside = false
                for (var j in lookup) {
                    var feature = lookup[j].polygon
                    if (inside(topojsonPoint, feature)) {
                        element.events.click(parameters, feature)
                        isInside = true
                    }
                }
                isInside || element.events.click(parameters, null)
            }
        }

        function hoverLeave() {
            var parameters = {
                scale: settings.scale,
                translate: settings.translate,
                width: settings.width,
                height: settings.height,
                map: settings.map,
                projection: settings.projection,
                projectedScale: settings.projectedScale
            }
            for (var i in settings.data) {
                var element = settings.data[i]
                if (!element.events || !element.events.hover)
                    continue
                element.hoverElement = false
                element.events.hover(parameters, null)
            }
        }

        function hover() {
            var point = translatePoint(d3.mouse(this), settings.scale * settings.projectedScale, settings.translate),
                parameters = {
                    scale: settings.scale,
                    translate: settings.translate,
                    width: settings.width,
                    height: settings.height,
                    map: settings.map,
                    projection: settings.projection,
                    projectedScale: settings.projectedScale
                },
                topojsonPoint = settings.projection ? settings.projection.invert(point) : point
            //console.log(topojsonPoint)
            for (var i in settings.data) {
                var element = settings.data[i]
                if (!element.events || !element.events.hover ||
                    (element.hoverElement && inside(topojsonPoint, element.hoverElement))) {
                    continue
                }
                element.hoverElement = false
                var lookup = element.lookupTree.search({
                    minX: point[0],
                    minY: point[1],
                    maxX: point[0],
                    maxY: point[1]
                })
                for (var j in lookup) {
                    var feature = lookup[j].polygon
                    if (inside(topojsonPoint, feature)) {
                        element.hoverElement = feature
                        break
                    }
                }
                element.events.hover(parameters, element.hoverElement)
            }
        }

        this.init = init
        this.paint = paint
        this.settings = function() {
            return settings
        }
    }
				zoom = _layer._undef(zoom) ? _layer._zoom : zoom
				let projectedPoint = L.point(point).add(_layer._pixelOrigin)
				return _layer.map.unproject(projectedPoint, zoom)
			},
			unitsPerMeter: 256 * Math.pow(2, _layer._zoom) / 40075017,
			map: _layer.map,
			layer: _layer,
			scale: 1
		}
		this.projection._projectPoint = function (x, y) {
			let point = _layer.projection.latLngToLayerPoint(new L.LatLng(y, x))
			this.stream.point(point.x, point.y)
		}

		this.projection.pathFromGeojson =
				d3.geo.path().projection(d3.geo.transform({point: this.projection._projectPoint}))

		// Compatibility with v.1
		this.projection.latLngToLayerFloatPoint = this.projection.latLngToLayerPoint
		this.projection.getZoom = this.map.getZoom.bind(this.map)
		this.projection.getBounds = this.map.getBounds.bind(this.map)
		this.selection = this._rootGroup // ???

		// Initial draw
		this.draw()
	},

	onRemove (map) {
		if (this._container != null)
			this._container.remove()
Example #7
0
 function matrix(a, b, c, d, tx, ty) {
         return d3.geo.transform({
             point: function(x, y) { 
                 this.stream.point(scaleX(x)+offsetW, scaleY(y)+offsetH); 
             }});
 }
Example #8
0
    onAdd: function (map) {
        this.map = map;
        var _layer = this;

        // SVG element
        if (L.version < "1.0") {
            map._initPathRoot();
            this._svg = d3.select(map._panes.overlayPane)
                .select("svg");
            this._rootGroup = this._svg.append("g");
        } else {
            this._svg = L.svg();
            map.addLayer(this._svg);
            this._rootGroup = d3.select(this._svg._rootGroup).classed("d3-overlay", true);
        }
        this._rootGroup.classed("leaflet-zoom-hide", this.options.zoomHide);
        this.selection = this._rootGroup;

        // Init shift/scale invariance helper values
        this._pixelOrigin = map.getPixelOrigin();
        this._wgsOrigin = L.latLng([0, 0]);
        this._wgsInitialShift = this.map.latLngToLayerPoint(this._wgsOrigin);
        this._zoom = this.map.getZoom();
        this._shift = L.point(0, 0);
        this._scale = 1;

        // Create projection object
        this.projection = {
            latLngToLayerPoint: function (latLng, zoom) {
                zoom = _layer._undef(zoom) ? _layer._zoom : zoom;
                var projectedPoint = _layer.map.project(L.latLng(latLng), zoom)._round();
                return projectedPoint._subtract(_layer._pixelOrigin);
            },
            layerPointToLatLng: function (point, zoom) {
                zoom = _layer._undef(zoom) ? _layer._zoom : zoom;
                var projectedPoint = L.point(point).add(_layer._pixelOrigin);
                return _layer.map.unproject(projectedPoint, zoom);
            },
            unitsPerMeter: 256 * Math.pow(2, _layer._zoom) / 40075017,
            map: _layer.map,
            layer: _layer,
            scale: 1
        };
        this.projection._projectPoint = function(x, y) {
            var point = _layer.projection.latLngToLayerPoint(new L.LatLng(y, x));
            this.stream.point(point.x, point.y);
        };
        this.projection.pathFromGeojson =
            d3.geo.path().projection(d3.geo.transform({point: this.projection._projectPoint}));

        // Compatibility with v.1
        this.projection.latLngToLayerFloatPoint = this.projection.latLngToLayerPoint;
        this.projection.getZoom = this.map.getZoom.bind(this.map);
        this.projection.getBounds = this.map.getBounds.bind(this.map);
        this.selection = this._rootGroup;

        if (L.version < "1.0") map.on("viewreset", this._zoomChange, this);

        // Initial draw
        this.draw();
    },