用ArcGIS API for JavaScript制作三维可视化图

前段时间接了一个项目,涉及到了空间信息三维可视化的工作。之前在网上查找无意中看到ArcGIS API for JavaScript(以下简称“ArcGIS API”或“该API”)可以在网页上制作三维可视化图。好在有友人在国外帮我把整个文档和API下载下来了,于是就着手学习了一下这个API。

简介

做GIS的肯定清楚ArcGIS是什么,包括一系列的ArcMap、ArcScence、ArcEngine等。ArcGIS推出了这套JavaScript API,现在有4.2版本,该版本可以创建二维、三维的网页应用程序。

下面是官网给出的一些三维可视化的示例。

显示卫星位置  使用三维符号可视化

使用三维实体符号可视化  根据房屋高度伸出房屋脚印

ArcGIS制作可视化图的大体结构为:View 包含 Map 包含 Layer(s) 包含 Graphic(s)。带(s)表示是一个数组。其中

  • View(视图):对应HTML上的一个元素,在该元素中显示底图以及底图上的所有图层。
  • Map(底图):可以为多种类型:街道图、卫星图、大洋图、地表图等。
  • Layer(图层):有多种类型,如FeatureLayer、GraphicLayer、PointCloudLayer,甚至有CSVLayer等。对于图层的解释,ArcGIS官方文档指出:
    图层是 ArcMap、ArcGlobe 和 ArcScene 中地理数据集的显示机制。一个图层引用一个数据集,并指定如何利用符号和文本标注绘制该数据集。向地图添加图层时,要指定它的引用数据集并设定地图符号和标注属性。
  • Graphic(图形):图形在官方文档中的解释是:“图形是一个矢量图,代表了真实世界的地理事物或地理现象。它可以包含geometry(几何)、symbol(符号)、attributes(特性)。”

    A Graphic is a vector representation of real world geographic phenomena. It can contain geometry, a symbol, and attributes.A  Graphic is displayed in the GraphicsLayer.

    当我们拿到带有空间信息的数据,就可以对每个数据设计可视化的图形,将同类的数据显示的图形添加到同一个图层中,就可以显示了。官方指出Graphic是显示在GraphicLayer中的,但是FeatureLayer中有一个source属性,可以将Grapchic自动转换(autocast),从而在Layer中显示。

制作可视化图

使用ArcGIS API,需要引用各个组件(Map, SenceView, FeatureLayer ...),各个组件引用的路径在官网文档上会标注。引用时使用require()函数(这里使用TypeScript语法表示变量的类型)

require(modules: Array<String>, callback: function) => void

 

即可将各个组件引用到应用程序中。其中

  • modules:是一个字符串数组,每一项代表了一个组件的引用路径。例如,组件Map的地址是 “esri/Map” 。
  • callback:是一个回调函数,表示各个组件加载完成后执行的函数操作。这个函数的的参数比较特别,参数个数与modules中引用的组件的个数相同,每个参数与modules中的组件路径一一对应,表示引用的各个组件的一个对象。

于是,脚本整体上类似于:

require([
  "esri/Map",
  "esri/views/SceneView",
  "dojo/domReady!"
], function(Map, SceneView) {
  // Code to create the map and view will go here
});

 当然这些脚本要写在一对script标签里。

添加底图

 在ArcGIS API中,所有地图要素都是以对象的形式存在的。要在地图上添加地理地图,就需要创建地理地图对象。Map类的对象就表示一个地理地图。当引用了MA类组件之后,就可以创建其一个Map类的对象了。

var map = new Map({
  basemap: "streets",
  ground: "world-elevation"
});

Map类的属性有这些:

  • basemap:地理底图的类型。ArcGIS提供了多种类型的地理底图,包括了OpenStreetMap(osm)。
  • layers:包含了地图上展示的要素所在的图层,这个图层是“可操作的”,包括FeatureLayers、WebTileLayers和GraphicsLayers,其中不包含basemaps,也就是无法通过访问layers属性访问basemap。
  • allLayers:与layers属性不同的是,这个属性包含了basemap图层、ground图层以及“可操作图层”。
  • ground:这个属性只在使用三维视角的时候有用。ground属性是一个Ground类的对象,它将真实世界的地形或地势渲染到底图上。它包含了一组图层来显示地图。在创建地理底图的时候,ground属性可以包含一组layer,也可以仅仅赋予一个字符串 world-elevation ,通过操作ground中的layer属性来对底图进行操作。示例见Toggle ground elevation

 通过调节这些属性,就可以实现我们想要的地图。

添加视图

我们需要一个视图来对我们所制作的地图进行观察,包括对底图的观察以及其他所有要素的观察。在ArcGIS软件中,如果制作二维地图或进行二维分析,就使用ArcMap软件;如果制作三维地图或进行三维分析,就使用ArcScene软件。在ArcGIS API中也是一样的。我们如果制作二维地图,就使用MapView类的对象创建视图;如果制作三维地图,就使用SceneView类的对象创建视图。

创建一个视图可以的方法与创建底图类似,如

var view = new SceneView({
    container: "viewDiv",
    map: map
});

这个SceneView的属性非常多,日后有空一一列举,与我们制作的三维地图关系较大的有:

  • container:是一个DOM元素的id,地图将渲染在该DOM元素内。ArcGIS API制作的地图可以自适应。
  • map:显示的底图。制作好底图后,在这里引用制作的底图实例,即可在地图上显示。
  • camera:视图摄像机。摄像机代表了三位观察的位置和方向。该属性是一个Camera类的实例,使用三个参数确定了摄像机的位置和方向:
    • position:摄像机的位置。是一个Point类的对象,可以使用经(longitude)纬(latitude)度作为平面位置的参数,也可以使用大地坐标(x, y)作为平面位置的参数。高程都是用z属性来指定的。还有一个spatialReference的属性,用于指定参考系。
    • heading:摄像机朝向的方位角。
    • tilt:摄像机的“垂直角”,这个定义与测量学中的垂直角(天顶距)定义不同,当摄像机竖直向下时,该角度为0°。

一旦创建了视图对象,就会在选定的DOM元素中进行渲染。

添加图层

ArcGIS API提供了丰富的图层可以使用,但是不同的图层代表了不同的含义。这里只分析一下FeatureLayer和GraphicLayer的区别:当图层与某一地理实体相对应时,最好使用FeatureLayer,表示是地理要素的图层,具有实体含义;否则使用GraphicLayer,表示仅仅是一些几何元素,没有地理含义。

我所拿到的项目要可视化的内容具有地理实体含义,所以使用FeatureLayer。一个FeatureLayer对象包含很多属性,可以通过REST服务创建,也可以本地创建。使用REST服务创建需要发布REST服务,然后在url属性上填入REST服务的地址。这里介绍从本地创建FeatureLayer中的要素,官网示例见Sample - Create a FeatureLayer with GeoJSON data

如果要从本地创建要素,需要同时设置FeatureLayer的五个属性:fields、objectIdField、spatialReference、geometryType和source。

  • fields:是一个对象数组,相当于ArcMap中的属性表各个字段的配置,每一个对象表示了属性表中的一个字段。每个对象有以下几个常用属性
    • name:字段名。
    • type:字段的数据类型,与ArcMap中一样,有small-integer、integer、single、double、string、date、oid、geometry、blob、raster、guid、global-id、xml等。
    • alias:字段替用名。
    • length:字段长度。
    • nullable:字段是否可空。
    • editable:字段时候可编辑。
  • objectIdField:指定fields中那个字段代表了要素的ObjectId。ObjectId是每个要素的唯一标识符。
  • spatialReference:指定地理参考系。
  • geometryType:表示要素的几何类型,有point、mulitpoint、polyline、polygon等类型。
  • source:是一个Graphic对象的集合。每个Graphic对象包括三个部分:geometry、symbol和attribute。
    • geometry:是一个Geometry类的对象,定义了Graphic对象的地理位置。Geometry类的派生类有Point(点)、MultiPoint(多点)、Polyline(折线)、Polygon(折线)等。
    • symbol:该要素显示时的符号,代表了可视化方式。在创建Graphic对象的时候直接指定其symbol属性不是一个比较好的做法。比较好的做法是使用Renderer(渲染器)来对图层中的所有要素进行统一渲染。
    • attribute:是一个对象数组,每个对象要包含fields中声明的所有不可空字段。

除此之外,还有一些属性是非常有用的:

  • renderer:渲染器。是一个Renderer类的对象,表示对要素的geometry和attribute如何进行渲染。
  • popupTemplate:弹出框的模板,是一个PopupTemplate对象,可以用来显示要素的数据。

当我们获取到了可视化的数据,首先创建一个Graphic数组,在官网示例中,是这样的

return arrayUtils.map(geoJson.features, function(feature, i) {
    return {
    geometry: new Point({
        x: feature.geometry.coordinates[0],
        y: feature.geometry.coordinates[1]
    }),
    // select only the attributes you care about
    attributes: {
        ObjectID: i,
        title: feature.properties.title,
        type: feature.properties.type,
        place: feature.properties.place,
        depth: feature.geometry.coordinates[2] + " km",
        time: feature.properties.time,
        mag: feature.properties.mag,
        mmi: feature.properties.mmi,
        felt: feature.properties.felt,
        sig: feature.properties.sig,
        url: feature.properties.url
    }
    };
});

这里使用了arrayUtils的方法将一个数组映射为另一个数组。也可以使用foreach循环来完成这件事。将Griphic数组用一个变量保存起来。

fields也需要我们进行创建,官网的示例中创建了如下的属性表:

var fields = [
    {name: "ObjectID",alias: "ObjectID",type: "oid"},
    {name: "title",alias: "title",type: "string"},
    {name: "type",alias: "type",type: "string"},
    {name: "place",alias: "place",type: "string"},
    {name: "depth",alias: "depth",type: "string"},
    {name: "time",alias: "time",type: "date"},
    {name: "mag",alias: "Magnitude",type: "double"},
    {name: "url",alias: "url",type: "string"},
    {name: "mmi",alias: "intensity",type: "double"},
    {name: "felt",alias: "Number of felt reports",type: "double"},
    {name: "sig",alias: "significance",type: "double"}
];

我们现在就可以创建FeatureLayer了,示例代码如下:

var lyr = new FeatureLayer({
    source: graphics, // autocast as an array of esri/Graphic
    // create an instance of esri/layers/support/Field for each field object
    fields: fields, // This is required when creating a layer from Graphics
    objectIdField: "ObjectID", // This must be defined when creating a layer from Graphics
    renderer: quakesRenderer, // set the visualization on the layer
    spatialReference: {
    wkid: 4326
    },
    geometryType: "point", // Must be set when creating a layer from Graphics
    popupTemplate: pTemplate
});

map.add(lyr);

最后一行通过map类对象的add()方法,将该要素图层添加到地图上。其中,quakesRenderer是创建的渲染器,下小节中会详细讲解。

设计渲染器

渲染器是地图显示符号的方法,相当于Echarts中的VisualMap配置项。ArcGIS API中有很多渲染器,我们这里对点符号的渲染可以使用SimpleRenderer,有几个属性

  • label:渲染器标签。
  • symbol:渲染用的符号。是Symbol类的一个对象。Symbol的派生类包含了丰富的可视化类型,有二维的和三维的。如果使用三维的可视化符号,使用Symbol3D类,包括二维可视化符号的三维版本和一些三维可视化特有的符号,如MeshSymbol3D。
  • visualVariables:视觉变量,是一个对象数组。效果类似于Echarts中的VisualMap配置项,可以根据某一属性值对颜色、尺寸、透明度、旋转角度进行映射调整。每一个元素都是以下几种类型:ColorVisualVariableSizeVisualVariableOpacityVisualVariableRotationVisualVariable

官网设计的渲染器如下所示:

var quakesRenderer = new SimpleRenderer({
symbol: new SimpleMarkerSymbol({
    style: "circle",
    size: 20,
    color: [211, 255, 0, 0],
    outline: {
    width: 1,
    color: "#FF0055",
    style: "solid"
    }
}),
visualVariables: [
{
    type: "size",
    field: "mag", // earthquake magnitude
    valueUnit: "unknown",
    minDataValue: 2,
    maxDataValue: 7,
    // Define size of mag 2 quakes based on scale
    minSize: {
        type: "size",
        expression: "view.scale",
        stops: [
        {value: 1128,size: 12},
        {value: 36111,size: 12},
        {value: 9244649,size: 6},
        {value: 73957191,size: 4},
        {value: 591657528,size: 2}]
    },
    // Define size of mag 7 quakes based on scale
    maxSize: {
        type: "size",
        expression: "view.scale",
        stops: [
        {value: 1128,size: 80},
        {value: 36111,size: 60},
        {value: 9244649,size: 50},
        {value: 73957191,size: 50},
        {value: 591657528,size: 25}]
    }
}]
});

 这个渲染器的效果如下所示

 

整体代码

  1 var arcgis_groupLayer;
  2 
  3 function ArcGIS_Map_Init() {
  4     require([
  5         "esri/layers/GroupLayer",
  6         "esri/layers/FeatureLayer",
  7         "esri/Map", 
  8         "esri/views/SceneView",
  9         "esri/widgets/LayerList",
 10         "esri/layers/support/Field",
 11         "esri/geometry/Point",
 12         "esri/renderers/SimpleRenderer",
 13         "esri/symbols/PointSymbol3D",
 14         "esri/symbols/ObjectSymbol3DLayer",
 15         "esri/request",
 16         "dojo/_base/array",
 17         "dojo/dom",
 18         "dojo/on",
 19         "dojo/domReady!"
 20     ], function (GroupLayer, FeatureLayer, Map, SceneView, LayerList, Field, Point, SimpleRenderer, PointSymbol3D, ObjectSymbol3DLayer, esriRequest, 
 21     arrayUtils, dom, on) {
 22         
 23         var arcgis_fields = [
 24             {name: "ObjectID", alias: "ObjectID", type: "oid"},
 25             {name: "title", alias: "title", type: "string"},
 26             {name: "num", alias: "num", type: "integer"}
 27         ];
 28 
 29         arcgis_groupLayer = new GroupLayer({
 30             title: "消防数据",
 31             visibility: true,
 32             visibilityMode: "exclusive"
 33         })
 34 
 35         var arcgis_arcgismap = new Map({
 36             basemap: "osm",
 37             layers: [arcgis_groupLayer]
 38         });
 39 
 40         var arcgis_initCam = {
 41             position: {
 42                 x: 120.61,
 43                 y: 30.50,
 44                 z: 100000,
 45                 spatialReference: {
 46                     wkid: 4326
 47                 }
 48             },
 49             heading: 15,
 50             tilt: 60
 51         };
 52 
 53         var arcgis_view = new SceneView({
 54             map: arcgis_arcgismap,
 55             container: "arcgismap",
 56             camera: arcgis_initCam
 57         });
 58 
 59         arcgis_view.then(function () {
 60             arcgis_layerList = new LayerList({
 61                 view: arcgis_view
 62             })
 63 
 64             arcgis_view.ui.add(arcgis_layerList, "top-right");
 65         })
 66 
 67         $.getJSON("js/json/fire.json", function (data) {
 68             var graphics = [];
 69 
 70             data.forEach(function(iSender, i) {
 71                 graphics.push({
 72                     geometry: new Point({
 73                         longitude: iSender.longitude,
 74                         latitude: iSender.latitude
 75                     }),
 76                     attributes: {
 77                         ObjectID: iSender.senderId,
 78                         title: iSender.senderName,
 79                         num: iSender.num
 80                     }
 81                 })
 82             }, this);
 83 
 84             var arcgis_fireRenderer = new SimpleRenderer({
 85                 symbol: new PointSymbol3D({
 86                     symbolLayers: [new ObjectSymbol3DLayer({
 87                         resource: {
 88                             primitive: "cube"
 89                         },
 90                         width: 500,
 91                         depth: 500,
 92                         material: {color: "#e6b600"}
 93                     })]
 94                 }),
 95                 label: "火警数",
 96                 visualVariables: [{
 97                     type: "size",
 98                     field: "num",
 99                     axis: "height"
100                 },{
101                     type: "size",
102                     axis: "width-and-depth",
103                     useSymbolValue: true,
104                 }]
105             });
106 
107             var arcgis_fireLayer = new FeatureLayer({
108                 source: graphics,
109                 fields: arcgis_fields,
110                 objectIdField: "ObjectID",
111                 renderer: arcgis_fireRenderer,
112                 spatialReference: {
113                     wkid: 4326
114                 },
115                 geometryType: "point",
116                 popupTemplate: {
117                     title: "{title}",
118                     content: [{
119                         type: "fields",
120                         fieldInfos: [{
121                             fieldName: "num",
122                             label: "火警数",
123                             visible: true
124                         }]
125                     }]
126                 },
127                 title: "火警数",
128                 id: "fireLayer"
129             })
130 
131             arcgis_groupLayer.add(arcgis_fireLayer, 0);
132         })
133 
134         $.getJSON("js/json/fault.json", function (data) {
135             var graphics = [];
136 
137             data.forEach(function(iSender, i) {
138                 graphics.push({
139                     geometry: new Point({
140                         longitude: iSender.longitude,
141                         latitude: iSender.latitude
142                     }),
143                     attributes: {
144                         ObjectID: iSender.senderId,
145                         title: iSender.senderName,
146                         num: iSender.num
147                     }
148                 })
149             }, this);
150 
151             var arcgis_faultRenderer = new SimpleRenderer({
152                 symbol: new PointSymbol3D({
153                     symbolLayers: [new ObjectSymbol3DLayer({
154                         resource: {
155                             primitive: "cube"
156                         },
157                         width: 500,
158                         depth: 500,
159                         material: {color: "#0098d9"}
160                     })]
161                 }),
162                 label: "故障数",
163                 visualVariables: [{
164                     type: "size",
165                     field: "num",
166                     axis: "height"
167                 },{
168                     type: "size",
169                     axis: "width-and-depth",
170                     useSymbolValue: true,
171                 }]
172             });
173 
174             var arcgis_faultLayer = new FeatureLayer({
175                 source: graphics,
176                 fields: arcgis_fields,
177                 objectIdField: "ObjectID",
178                 renderer: arcgis_faultRenderer,
179                 spatialReference: {
180                     wkid: 4326
181                 },
182                 geometryType: "point",
183                 popupTemplate: {
184                     title: "{title}",
185                     content: [{
186                         type: "fields",
187                         fieldInfos: [{
188                             fieldName: "num",
189                             label: "故障数",
190                             visible: true
191                         }]
192                     }]
193                 },
194                 title: "故障数",
195                 id: "faultLayer",
196                 visible: false                
197             })
198 
199             arcgis_groupLayer.add(arcgis_faultLayer, 1);
200         })
201 
202         $.getJSON("js/json/linkage.json", function (data) {
203             var graphics = [];
204 
205             data.forEach(function(iSender, i) {
206                 graphics.push({
207                     geometry: new Point({
208                         longitude: iSender.longitude,
209                         latitude: iSender.latitude
210                     }),
211                     attributes: {
212                         ObjectID: iSender.senderId,
213                         title: iSender.senderName,
214                         num: iSender.num
215                     }
216                 })
217             }, this);
218 
219             var arcgis_linkageRenderer = new SimpleRenderer({
220                 symbol: new PointSymbol3D({
221                     symbolLayers: [new ObjectSymbol3DLayer({
222                         resource: {
223                             primitive: "cube"
224                         },
225                         width: 500,
226                         depth: 500,
227                         material: {color: "#2b821d"}
228                     })]
229                 }),
230                 label: "联动数",
231                 visualVariables: [{
232                     type: "size",
233                     field: "num",
234                     axis: "height"
235                 },{
236                     type: "size",
237                     axis: "width-and-depth",
238                     useSymbolValue: true,
239                 }]
240             });
241 
242             var arcgis_linkageLayer = new FeatureLayer({
243                 source: graphics,
244                 fields: arcgis_fields,
245                 objectIdField: "ObjectID",
246                 renderer: arcgis_linkageRenderer,
247                 spatialReference: {
248                     wkid: 4326
249                 },
250                 geometryType: "point",
251                 popupTemplate: {
252                     title: "{title}",
253                     content: [{
254                         type: "fields",
255                         fieldInfos: [{
256                             fieldName: "num",
257                             label: "联动数",
258                             visible: true
259                         }]
260                     }]
261                 },
262                 title: "联动数",
263                 id: "linkageLayer",
264                 visible: false
265             })
266 
267             arcgis_groupLayer.add(arcgis_linkageLayer, 2);
268         })
269     })
270 }
271 
272 spatial_echarts_instant.arcgismap = {
273     init: function () {
274         ArcGIS_Map_Init();
275     },
276     clear: function (params) {
277         arcgis_view = {};
278     },
279     resize: function (params) {
280         
281     },
282     setOption: function (params) {
283         require([
284             "esri/views/SceneView"
285         ], function (SceneView) {
286             arcgis_view = new SceneView({
287                 map: arcgis_arcgismap,
288                 container: "arcgismap",
289                 camera: arcgis_initCam
290             });
291         })
292     },
293     changeLayer: function (layerIndex) {
294         var layerId = null;
295         switch (layerIndex) {
296             case 1:
297                 layerId = "fireLayer";
298                 break;
299             case 2:
300                 layerId = "faultLayer";
301                 break;
302             case 3:
303                 layerId = "linkageLayer";
304                 break;
305             default:
306                 break;
307         }
308         if (layerId) {
309             var layer = arcgis_groupLayer.findLayerById(layerId);
310             layer.visible = true;
311         }
312     }
313 }
314 
315 $(function () {
316     ArcGIS_Map_Init();
317 })

 

转载于:https://www.cnblogs.com/MSspblxh/p/6273998.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ArcGIS API for JavaScript 3.9是一种基于JavaScript的Web开发工具,可以使用它来构建交互性和可视化性很强的GIS应用程序。API提供了丰富的地显示和交互功能,使得用户可以轻松地在地上进行搜索、浏览、编辑和分析等操作。 该API还提供了许多基本和高级工具,包括底选择、例、搜索、还原操作、渲染和动画等。它还支持多种类型的数据,包括栅格、矢量等,并支持与其他ArcGIS平台数据的兼容性。 此外,API还提供了强大的开发工具,包括开发者文档、代码示例和应用程序模板等,这些工具可帮助开发人员更快速地构建应用程序并提高生产力。开发者可以通过使用API来打造卓越的GIS应用程序,实现更好的数据可视化、数据分析和空间查询等功能。 ### 回答2: ArcGIS API for JavaScript 3.9(以下简称JS API)是一个基于浏览器的GIS编程接口,它可以让Web 开发者快速构建地理信息应用程序。该文档提供了详细的使用说明和API参考文档,以帮助开发者快速上手。JS API 3.9 支持与ArcGIS Server、ArcGIS Online和Portal for ArcGIS等平台进行交互,支持多种数据源,如:Web Map Service (WMS)、Web Feature Service (WFS)、GeoRSS、CSV、KML等,用户可以通过地层、标注和样式等多种方式来创建交互式的地应用程序。同时,JS API 3.9 还提供了大量的工具和插件,包括编辑器、查询工具、测量工具等,可以快速搭建自己所需的应用程序。 总之,JS API 3.9 具备了很好的开发性能和易于使用性,可以迅速构建出高质量的地理信息应用程序,有助于用户更好地进行空间分析和地理数据可视化等操作。 ### 回答3: ArcGIS API for JavaScript 3.9是一个基于JavaScript的开发工具包,用于构建Web地应用程序和跨平台GIS应用程序。它提供了一组丰富的开发API和工具,能够访问和处理地理空间数据。API支持基本地理空间操作,如添加层、缩放和平移地,以及高级操作,如地理空间分析、三维可视化和协同编辑等。随着API的不断发展,它还支持移动设备和桌面应用程序开发,并提供跨平台的开发解决方案,满足不同开发需求。 ArcGIS API for JavaScript 3.9提供了一份详细而全面的文档,包含了所有API以及相关示例,能够帮助开发人员更轻松地学习和使用API。同时,该文档也提供了许多实践案例,涵盖了不同的应用场景和解决方案,帮助开发人员快速了解API的用法,并应用到实际项目中去。文档中还包含了详细的API文档和代码示例,这些示例不仅展示了如何使用API来解决实际问题,还详细介绍了API的各种使用方法和特性。对于开发人员来说,这是一个非常有用的参考资料,可以帮助他们快速了解和使用API。 总之,ArcGIS API for JavaScript 3.9是一个功能强大的GIS开发工具包,它提供了丰富的API和工具,能够访问和处理地理空间数据,满足不同的开发需求。而文档则提供了详细的API和示例,帮助开发人员更加轻松地学习和使用API,是一个非常有价值的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值