Реализация D3: изображение собственной топологии за картой D3 - PullRequest
0 голосов
/ 31 мая 2018

Мне нужно отобразить карту D3 с топологическим / затененным рельефным фоном.Все пользовательские функции должны быть реализованы (например, масштабирование и панорамирование)

Пока что я наложил карту на PNG с топологией.Затем я немного поработал с проекцией, чтобы выровнять границу PNG с границами карты.Затем я разрешаю пользователю масштабировать PNG (например: http://bl.ocks.org/pbogden/7363519). Результат на самом деле очень хороший. Когда я панорамирую и масштабирую, карта перемещается с великолепным PNG (изображение ниже):

enter image description here

Проблема в том, что PNG очень тяжелый (20 МБ), и весь полученный опыт серьезно глючит до такой степени, что его невозможно использовать. Результаты, очевидно, используют меньшееразрешение изображения, но тогда топология выглядит дерьмово, когда пользователь увеличивает масштаб. Я пытался преобразовать PNG в JPG ... что на самом деле было хуже!

Какое было бы лучшее решение для достижения моей цели в D3?мысли заключаются в следующем:

(1) Плагин d3.geo.tile (http://bl.ocks.org/mbostock/4132797).) Сложность заключается в том, что мне нужно будет создавать свои собственные плитки из моего изображения PNG. Является ли это многообещающимПроспект? Могу ли я наложить слой D3 поверх этого? Я не могу найти пример с пользовательскими плитками.

(2) Я видел эту успешную реализацию OpenSeaDragon и D3 (http://bl.ocks.org/zloysmiertniy/0ab009ca832e7e0518e585bfa9a7ad59). Проблема здесь в том, чтоЯ не уверен, что удастся ли реализовать желаемые функции D3 (масштабирование, панорамирование, переходы) так, чтобы карта D3 и нижележащее изображение перемещались одновременно.

(3) Какие-нибудь другие мысли или идеи?

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Вы, конечно, можете использовать OpenSeadragon для этого.Вы хотели бы превратить изображение в плитки;вам не нужен специализированный сервер для этого ... есть несколько автономных скриптов, которые вы можете использовать:

http://openseadragon.github.io/examples/creating-zooming-images/

Как только вы это сделаете, OpenSeadragon обрабатывает масштабирование и панорамированиедля тебя.

Чтобы наложить SVG так, чтобы он соответствовал масштабированию и панорамированию, используйте плагин SVG:

https://github.com/openseadragon/svg-overlay

Он отлично работает с SVG, созданным D3.

Следует помнить, что OpenSeadragon не имеет каких-либо гео-специфических функций, поэтому вы будете размещать наложение в пикселях изображения, а не в широте / долготе.

Кстати, OpenSeadragon можеттакже работайте с изображениями без мозаики, так что если вы хотите протестировать их перед созданием мозаики, это не проблема.Вы просто захотите поместить изображение перед производством, чтобы не отправлять пользователям 20 Мб.

0 голосов
/ 01 июня 2018

Чтобы превратить изображение в плитки, вам нужно иметь изображение с географической привязкой или иметь возможность привязать изображение к себе.Поскольку я полагаю, что вы используете набор данных естественной земли для создания этого изображения, вы можете использовать исходный tif-файл и работать с ним.Я обычно использую плитку для своих плиток (с некоторым питоном), и это довольно просто.Вы не сможете использовать свой png как есть для плиток.

Тем не менее, создание в наборе плиток не требуется, если вы ищете склон или вид текстуры местности.Используя пример листовки здесь , вы можете найти довольно много провайдеров плиток, ESRI.WorldShadedRelieve выглядит так, как будто он отвечает всем требованиям.Вот демоверсия, в которую встроен d3 с топографическим элементом, нарисованным поверх:

var pi = Math.PI,
        tau = 2 * pi;

    var width = 960;
        height = 500;

    // Initialize the projection to fit the world in a 1×1 square centered at the origin.
    var projection = d3.geoMercator()
        .scale(1 / tau)
        .translate([0, 0]);

    var path = d3.geoPath()
        .projection(projection);

    var tile = d3.tile()
        .size([width, height]);

    var zoom = d3.zoom()
        .scaleExtent([1 << 11, 1 << 14])
        .on("zoom", zoomed);

    var svg = d3.select("svg")
        .attr("width", width)
        .attr("height", height);

    var raster = svg.append("g");
    var vector = svg.append("g");

    // Compute the projected initial center.
    var center = projection([-98.5, 39.5]);

    d3.json("https://unpkg.com/world-atlas@1/world/110m.json",function(error,data) {
    
     vector.append("path")
       .datum(topojson.feature(data,data.objects.land))
       .attr("stroke","black")
       .attr("stroke-width",2)
       .attr("fill","none")
       .attr("d",path)

    // Apply a zoom transform equivalent to projection.{scale,translate,center}.
    svg
        .call(zoom)
        .call(zoom.transform, d3.zoomIdentity
            .translate(width / 2, height / 2)
            .scale(1 << 12)
            .translate(-center[0], -center[1]));
     
    })

    function zoomed() {
        var transform = d3.event.transform;

        var tiles = tile
            .scale(transform.k)
            .translate([transform.x, transform.y])
            ();

        projection
            .scale(transform.k / tau)
            .translate([transform.x, transform.y]);

        var image = raster
            .attr("transform", stringify(tiles.scale, tiles.translate))
            .selectAll("image")
            .data(tiles, function(d) {
                return d;
            });

        image.exit().remove();
        // enter:
        var entered = image.enter().append("image");
        // update:
        image = entered.merge(image)
            .attr('xlink:href', function(d) {
                return 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/' + d.z + '/' + d.y + '/' + d.x + '.png';
            })
            .attr('x', function(d) {
                return d.x * 256;
            })
            .attr('y', function(d) {
                return d.y * 256;
            })
            .attr("width", 256)
            .attr("height", 256);
            
      vector.selectAll("path")
        .attr("transform", "translate(" + [transform.x, transform.y] + ")scale(" + transform.k + ")")
        .style("stroke-width", 1 / transform.k);
    }

    function stringify(scale, translate) {
        var k = scale / 256,
            r = scale % 1 ? Number : Math.round;
        return "translate(" + r(translate[0] * scale) + "," + r(translate[1] * scale) + ") scale(" + k + ")";
    }
body {    margin: 0;  }
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/d3-tile@0.0.4/build/d3-tile.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
...