【问题标题】:How to draw custom dynamic billboards in Cesium.js如何在 Cesium.js 中绘制自定义动态广告牌
【发布时间】:2014-07-21 16:12:58
【问题描述】:

我目前正在将 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"

但那些也没有出现。如果我将 base64 字符串放在数据 URI 中,以及存储在服务器上的图像的路径,我就能显示一个 png,但我确实需要能够动态绘制自定义图像。我不能使用一组具有各种状态的固定预生成图像作为破解(如果有人想要这些细节,我可以解释为什么:))。

有谁知道我在这里做错了什么,或者是否有其他方法可以完成我需要做的事情?

编辑 只是想补充一点,我使用的是 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 字符串,或者一个静态图像文件的路径,它就可以正常工作。

谢谢!

【问题讨论】:

  • 你怎么称呼“广告牌的图像属性”?你如何加载你的图像? TextureAtlas?
  • dgiugg - 我刚刚在上面进行了编辑,以显示一个示例 CZML,其中包含我试图添加 SVG 数据的图像属性。我从后端流式传输 CZML,所以我没有创建广告牌并将它们手动添加到广告牌集合中。
  • user990522 你有想过这个吗?我找到了一个使用 Canvas 和 requestAnimationFrame 的解决方案,但 SVG 动画会更好
  • 我最终明白了这一点,我需要更新这篇文章 :) 它确实像我最初认为的那样工作,但我认为我做错的是将 viewBox 设置在图像的正确边界或类似的愚蠢的东西。但是,我只使用了每次我的广告牌数据更新时都会更新的静态 SVG,而不是真正的动画 SVG。

标签: svg cesium czml


【解决方案1】:

将 SVG 插入 cesium 的简单 JS 代码

// 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】:

    我的方法是创建一个画布元素,向其中添加文本,裁剪它并将结果转换为数据 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 类的两种方法,但可以轻松地重写为您需要的任何框架(或无框架)。

    【讨论】:

      【解决方案3】:

      绘制 SVG 确实可以按我的预期工作,但我相信我可能只是弄错了其中一个尺寸元素(高度/宽度或 x、y)。每当这些值不匹配时,图像就不会显示,因为它位于我为其定义的视图区域之外。

      请注意,我从来没有得到简单的 html 示例工作,但这不是我需要的,所以我没有进一步研究它。

      【讨论】:

      • 这不应该被接受,这不是答案。
      • 这不是回答问题。
      猜你喜欢
      • 1970-01-01
      • 2018-01-03
      • 2012-09-09
      • 2023-04-02
      • 1970-01-01
      • 2021-02-18
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多