How to draw custom dynamic billboards in Cesium.js

大城市里の小女人 提交于 2020-01-02 10:21:50

问题


I'm currently using Cesium for a mapping application, and I have a requirement to have status indicators for each item I'm plotting (for example, if the item I'm plotting is an airplane, then I need to have a fuel status indicator). I can't use Cesium's drawing tools to do this because they are drawn using geographic locations, but I need my status indicators to simply be located near the billboard and not get farther away from the billboard as users zoom in and out.

Cesium's CZML documentation states that the billboard's "image" property can take a data URI, so I figured the easiest way to handle this would be for me to create an SVG path on the fly and embed it in the image property, but when I do this in Cesium, it does not show up. For example, I tried a simple test like this:

"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>"

When that didn't show up, I tried just simple HTML and text values, like this:

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

and:

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

but those don't show up either. I am able to get a png to show up if I put the base64 string in the data URI, as well as a path to an image stored on the server, but I really need to be able to draw custom images on the fly. I can't use a fixed set of pre-generated images set with various statuses as a hack (I can explain why if anyone wants those details :) ).

Does anyone know if there's something I'm doing wrong here, or if there is another way to accomplish what I need to do?

Edit Just wanted to add that I am using Firefox version 29 and it normally has no problem displaying the non-encoded embedded SVGs like that. Just in case, that's one of the reasons I was also trying simple HTML or text.

Edit2 I am using CZML streaming from the back end to plot my items, here is a simple test example showing where I am trying to put the image information:

{
"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"},   
}

If I put a base64 png string in there, or a path to a static image file, it works fine.

Thank you!


回答1:


Simple JS code to insert SVG into cesium

          // 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"}
             });



回答2:


My method to accomplish this is to create a canvas element, add text to it, crop it and convert that result into a data URL. It works great and it's quick.

I'm not using CZML, but this is how I did it:

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();
}   

These are two methods of a MooTools class, but can be easily rewritten into whatever framework (or no framework) you need.




回答3:


Drawing an SVG does work as I expected it to, but I believe I may have just been getting one of the size elements wrong (height/width or x, y). Whenever those values don't match up just right, the image isn't shown because it's outside of the view area I've defined for it.

Note that I never did get the simple html example work, but that's not what I needed anyway, so I didn't pursue it further.



来源:https://stackoverflow.com/questions/24869733/how-to-draw-custom-dynamic-billboards-in-cesium-js

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!