上个月底,ArcGIS Online发布了一款全新风格的底图服务,Light Gray Basemap。该底图服务尽可能少地使用了色彩,标注和要素内容,目的是突出地图的主题内容,把重点展示给最终用户。美化的底图固然好看,但有时我们不能为了使用地图而去使用地图,忽略了我们真正想要表达的意思,很多时候,都会回归到以简为美的原点。使用这种底图服务,我们可以很轻松的将注意力集中在业务数据上。
可以看到,只有在右上角的Light Gray Canvas底图上,四个要素点才清晰可见。
其实Google Maps API中就一直能够设置显示风格,以适应我们的需求。虽然ArcGIS Online已经推出了灰度底图服务,但对于自己的底图服务(尤其是国内数据用户)来说,如何能够风格化显示呢?以ArcGIS API for Silverlight为例来说明。
缓存地图服务所对应的ArcGISTiledMapServiceLayer类中,暴露出了TileLoaded事件(继承自TiledLayer)。这个事件会在每一个切片加载完成时触发,并且事件参数中可以获得ImageSource属性,它就是切片本身,随后地图控件会对这些切片进行拼接,从而形成完整的地图。我们的工作,就是在这个事件中,对切片上的每个像素做色彩处理,从而达到风格化地图服务的效果。在Silverlight中,我们可以利用WritableBitmap来完成这项工作,代码如下,具体原理可自己参详:
1: private void ArcGISTiledMapServiceLayer_TileLoaded(object sender, TiledLayer.TileLoadEventArgs e)
2: {
3: WriteableBitmap wb = new WriteableBitmap(e.ImageSource as BitmapSource);
4: for (int y = 0; y < wb.PixelHeight; y++)
5: {
6: for (int x = 0; x < wb.PixelWidth; x++)
7: {
8: int pixel = wb.Pixels[y * wb.PixelWidth + x];
9: byte[] dd = BitConverter.GetBytes(pixel);
10: double R = dd[2];
11: double G = dd[1];
12: double B = dd[0];
13: byte gray = (byte)(0.333 * R + 0.333 * G + 0.333 * B);
14: dd[0] = dd[1] = dd[2] = gray;
15:
16: wb.Pixels[y * wb.PixelWidth + x] = BitConverter.ToInt32(dd, 0);
17: }
18: }
19: e.ImageSource = wb;
20: }
下图是加载ArcGIS Online上StreetMap时的效果:
细心的朋友可能会发现,这个Silverlight程序并没有运行在浏览器中。这的确是一个OOB的程序,因为TileLoaded事件要求Silverlight程序必须获得提升权限才行。但是WPF和Windows Phone程序可以直接使用上述代码。
那么在Silverlight应用中还能否显示风格化的地图服务呢?答案是肯定的。Map控件有一个Effect属性(继承自UIElement),系统提供了 BlurEffect,DropShadowEffect两个现成的效果。我们可以通过HLSL(High Level Shading Language)语言来自定义一些效果,比如灰度,通过PixelShader类应用到UIElement上,从而达到显示灰度地图的目的(此时Map控件中的所有图层都将变为灰色)。有兴趣的朋友可以动手实践一下,Windows Presentation Foundation Pixel Shader Effects Library这个项目中可以找到很多现成的效果。
再来看看ArcGIS API for Javascript/Flex,两个API甚至都没有类似的TileLoaded事件可用。即使有,在Javascript中处理图片的颜色也是一项有难度的工作。不过不用担心,Portable Basemap Server从1.0.6版本开始,提供了风格化地图服务的功能,有灰度图和反色图两个选项,无需任何代码,即可在所有的ArcGIS REST客户端程序中,使用风格化的地图了:)