Как рисовать собственные динамические рекламные щиты в Cesium.js

В настоящее время я использую Cesium для картографического приложения, и у меня есть требование иметь индикаторы состояния для каждого элемента, который я рисую (например, если предмет, который я рисую, — это самолет, тогда мне нужно иметь индикатор состояния топлива). индикатор). Я не могу использовать инструменты рисования Cesium для этого, потому что они рисуются с использованием географических местоположений, но мне нужно, чтобы мои индикаторы состояния просто располагались рядом с рекламным щитом и не удалялись от рекламного щита, когда пользователи увеличивают и уменьшают масштаб.

В документации Cesium CZML указано, что свойство «изображение» рекламного щита может принимать URI данных, поэтому я решил, что самым простым способом справиться с этим будет создание пути SVG на лету и встраивание его в свойство изображения, но когда я это сделаю это в цезии, он не проявляется. Например, я попробовал такой простой тест:

"data:image/svg+xml,<svg viewBox='0 0 40 40' height='25' width='25'
xmlns='http://www.w3.org/2000/svg'><path fill='rgb(91, 183, 91)' d='M2.379,
14.729L5.208,11.899L12.958,19.648L25.877,6.733L28.707,9.561L12.958,25.308Z'
/></svg>"

Когда это не появилось, я попробовал просто HTML и текстовые значения, например:

"data:,Hello%2C%20World!"

и:

"data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E"

но и они не появляются. Я могу получить png для отображения, если я помещу строку base64 в URI данных, а также путь к изображению, хранящемуся на сервере, но мне действительно нужно иметь возможность рисовать пользовательские изображения на лету. Я не могу использовать фиксированный набор предварительно сгенерированных изображений с различными статусами в качестве хака (я могу объяснить, почему, если кому-то нужны эти подробности :)).

Кто-нибудь знает, есть ли что-то, что я делаю неправильно, или есть ли другой способ выполнить то, что мне нужно сделать?

Изменить Просто хотел добавить, что я использую Firefox версии 29, и у него обычно нет проблем с отображением таких незакодированных встроенных SVG. На всякий случай, это одна из причин, по которой я также пытался использовать простой HTML или текст.

Edit2 Я использую потоковую передачу CZML из серверной части для отображения своих элементов. Вот простой тестовый пример, показывающий, куда я пытаюсь поместить информацию об изображении:

{
"id":"test",
"billboard" : {
"image" : "data:image/svg+xml,<svg viewBox='0 0 40 40' height='25' width='25' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(91, 183, 91)' d='M2.379,
14.729L5.208,11.899L12.958,19.648L25.877,6.733L28.707,9.561L12.958,25.308Z'
/></svg>",
"show" : [ {"boolean" : true} ]
},
"position":{
  "cartographicDegrees":[0.0, 0.0, 0.0]
},
"label":{"text":"TEST"},   
}

Если я помещу туда строку base64 png или путь к файлу статического изображения, все будет работать нормально.

Благодарю вас!


person user990522    schedule 21.07.2014    source источник
comment
Что вы называете свойством изображения рекламного щита? Как вы загружаете свое изображение? С TextureAtlas?   -  person dgiugg    schedule 22.07.2014
comment
dgiugg — я только что отредактировал выше, чтобы показать образец CZML со свойством изображения, к которому я пытаюсь добавить данные SVG. Я транслирую CZML из серверной части, поэтому я не создаю рекламные щиты и не добавляю их в коллекцию рекламных щитов вручную.   -  person user990522    schedule 23.07.2014
comment
user990522 ты когда-нибудь это понял? Я нашел решение, используя Canvas и requestAnimationFrame, но анимация SVG была бы предпочтительнее.   -  person Minh Nguyen    schedule 14.11.2014
comment
В конце концов я понял это, мне нужно обновить этот пост :) На самом деле он работает так, как я изначально думал, но я думаю, что я делал неправильно, устанавливая viewBox за пределами правильных границ изображения или что-то в этом роде. глупо так. Однако я использую только статические SVG, которые обновляются каждый раз, когда обновляются данные моего рекламного щита, а не действительно анимированный SVG.   -  person user990522    schedule 15.11.2014


Ответы (3)


Простой код JS для вставки SVG в цезий

// create the svg image string
var svgDataDeclare = "data:image/svg+xml,";
var svgCircle = '<circle cx="10" cy="10" r="5" stroke="black" stroke-width="3" fill="red" /> ';
var svgPrefix = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="40px" height="40px" xml:space="preserve">';
var svgSuffix = "</svg>";
var svgString = svgPrefix + svgCircle + svgSuffix;

// create the cesium entity
var svgEntityImage = svgDataDeclare + svgString;
viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(-80.12, 25.46),
    billboard: {
        image: svgEntityImage
    }
});

// test the image in a dialog
$("#dialog").html(svgString );
$("#dialog").dialog({
    position: {my: "left top", at: "left bottom"}
});
person Sal    schedule 19.05.2015

Мой способ добиться этого — создать элемент холста, добавить к нему текст, обрезать его и преобразовать этот результат в URL-адрес данных. Это работает отлично, и это быстро.

Я не использую CZML, но вот как я это сделал:

buildImage:function(text,text2){
    var self = this;
    var canvas = new Element('canvas',{width:500,height:500});
    var ctx = canvas.getContext("2d");
    ctx.font = "bold 16px monospace";
    ctx.fillText(text, 60, 20);
    ctx.fillText(text2, 60, 50);
    imagedata = self.cropCanvas(canvas,ctx);
    return imagedata;
},
cropCanvas:function(canvas,ctx){        
    ww = canvas.width;
    wh = canvas.height;

    imageData = ctx.getImageData(0, 0, ww, wh);

    var topLeftCorner = {};
    topLeftCorner.x = 9999;
    topLeftCorner.y = 9999;

    var bottomRightCorner = {};
    bottomRightCorner.x = -1;
    bottomRightCorner.y = -1;                             

    for (y = 0; y < wh; y++) {
        for (x = 0; x < ww; x++) {
            var pixelPosition = (x * 4) + (y * wh * 4);
            a = imageData.data[pixelPosition+3]; //alpha
            if (a > 0) {
                if (x < topLeftCorner.x) {
                    topLeftCorner.x = x;
                }
                if (y < topLeftCorner.y) {
                    topLeftCorner.y = y;
                }
                if (x > bottomRightCorner.x) {
                    bottomRightCorner.x = x;
                }
                if (y > bottomRightCorner.y) {
                    bottomRightCorner.y = y;
                }
            }
        }
    }
    topLeftCorner.x -= 2;
    topLeftCorner.y -= 2;
    bottomRightCorner.x += 2;
    bottomRightCorner.y += 2;

    relevantData = ctx.getImageData(topLeftCorner.x, topLeftCorner.y, bottomRightCorner.x -topLeftCorner.x, bottomRightCorner.y - topLeftCorner.y);

    canvas.width = bottomRightCorner.x - topLeftCorner.x;
    canvas.height = bottomRightCorner.y - topLeftCorner.y;
    ww = canvas.width;
    wh = canvas.height;

    ctx.clearRect(0,0,ww,wh);

    ctx.putImageData(relevantData, 0, 0);
    return canvas.toDataURL();
}   

Это два метода класса MooTools, но их можно легко переписать в любой фреймворк (или без фреймворка), который вам нужен.

person Michael    schedule 15.09.2014

Рисование SVG действительно работает, как я и ожидал, но я полагаю, что, возможно, просто ошибся с одним из элементов размера (высота/ширина или x, y). Всякий раз, когда эти значения не совпадают, изображение не отображается, потому что оно находится за пределами области просмотра, которую я для него определил.

Обратите внимание, что я так и не получил работу с простым примером html, но это все равно не то, что мне было нужно, поэтому я не стал заниматься этим дальше.

person user990522    schedule 14.11.2014
comment
Это не должно быть принято, это не ответ. - person Zac; 16.07.2015
comment
Это не ответ на вопрос. - person Pegues; 02.11.2017