ArcGIS JSAPI 高级教程 - 创建渐变色材质的自定义几何体

ArcGIS JSAPI 高级教程 - 创建渐变色材质的自定义几何体

工作中遇到一个比较复杂的功能,其中用到渐变色,于是研究了一下,发现虽然 JS API 不直接支持渐变色,但是也可以自定义创建渐变色,通过 Mesh 自定义顶点、索引来实现。

这里简单介绍一下原理,并且提供在线渐变色示例。

本文包括 核心代码、完整代码以及在线示例。


核心代码

介绍一下原理:首先通过 canvas 创建渐变色,可以选择两个颜色或者多个颜色。

根据想要创建的几何体,构建顶点和索引数据,简单图形的话,根据经验即可,如果是复杂几何体,

可以通过一些工具来获取,然后通过 Mesh 创建几何体对象即可,最终添加到地图中。

javascript 复制代码
// 创建渐变色
function createLinearGradient() {

    const canvas = document.createElement("canvas");
    const width = 32 * 32;
    const height = 32 * 32;
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext("2d");
    ctx.globalAlpha = globalAlpha;

    // Create the linear gradient with which to fill the canvas
    const gradient = ctx.createLinearGradient(0, 0, width, 0);

    // 这里创建三个渐变色,可随意调整
    gradient.addColorStop(0, "#0000ff");
    gradient.addColorStop(0.5, "#ff0000");
    gradient.addColorStop(1, "#ffffff");
    // Fill the canvas with the gradient pattern
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, width, height);

    return canvas;
}

const uv = 1;

// 材质
const material = {
    colorTexture: {
        data: createLinearGradient(),
        wrap: 'clamp'
    },
};

// 创建 box
const mesh = new Mesh({
    // 顶点属性
    vertexAttributes: {
        position: cameraPositionGeographic,
        uv: [
            0, 0,
            uv, 0,
            uv, 0,
            uv, 0,
            uv, 0,
        ]
    },
    // 三角面材质纹理
    components: [
        {
            faces: [0, 2, 1],
            material
        },
        {
            faces: [0, 2, 3],
            material
        },
        {
            faces: [0, 3, 4],
            material
        },
        {
            faces: [0, 4, 1],
            material
        },
        {
            faces: [1, 2, 4],
            material: {
                color: "transparent"
            }
        },
        {
            faces: [2, 3, 4],
            material: {
                color: "transparent"
            }
        }],
    spatialReference,
})

完整代码

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>ArcGIS JS API mesh 自定义几何渐变色示例</title>
    <style>
        html, body, #viewDiv {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }
    </style>

    <!-- 引入ArcGIS JS API样式和脚本 -->
    <link rel="stylesheet" href="https://js.arcgis.com/4.28/esri/themes/light/main.css">
    <script src="https://js.arcgis.com/4.28/"></script>

    <script>
        require([
            "esri/Map",
            "esri/views/SceneView",
            "esri/WebScene",
            "esri/geometry/Mesh",
            "esri/geometry/Point",
            "esri/geometry/SpatialReference",
            "esri/Graphic",
        ], function (Map, SceneView, WebScene, Mesh, Point, SpatialReference, Graphic,
        ) {

            const view = new SceneView({
                container: "viewDiv",
                map: new Map({
                    basemap: "hybrid",
                }),
            });

            const spatialReference = SpatialReference.WebMercator;
            // 视椎体顶点
            const cameraPositionGeographic = [12121597.211481025, 4060392.3041098495, 673.0166350845248, 12121688.817691227, 4060067.135944337, 825.3678379664198, 12121265.251479909, 4060329.6045611626, 825.3678379654884, 12121245.121950569, 4060297.137362419, 571.5452030794695, 12121668.70426917, 4060034.659804911, 571.5452030794695]

            // 透明度
            const globalAlpha = 0.7;

            // 创建渐变色
            function createLinearGradient() {

                const canvas = document.createElement("canvas");
                const width = 32 * 32;
                const height = 32 * 32;
                canvas.width = width;
                canvas.height = height;

                const ctx = canvas.getContext("2d");
                ctx.globalAlpha = globalAlpha;

                // Create the linear gradient with which to fill the canvas
                const gradient = ctx.createLinearGradient(0, 0, width, 0);

                // 这里创建三个渐变色,可随意调整
                gradient.addColorStop(0, "#0000ff");
                gradient.addColorStop(0.5, "#ff0000");
                gradient.addColorStop(1, "#ffffff");
                // Fill the canvas with the gradient pattern
                ctx.fillStyle = gradient;
                ctx.fillRect(0, 0, width, height);

                return canvas;
            }

            const uv = 1;

            // 材质
            const material = {
                colorTexture: {
                    data: createLinearGradient(),
                    wrap: 'clamp'
                },
            };

            // 创建 box
            const mesh = new Mesh({
                // 顶点属性
                vertexAttributes: {
                    position: cameraPositionGeographic,
                    uv: [
                        0, 0,
                        uv, 0,
                        uv, 0,
                        uv, 0,
                        uv, 0,
                    ]
                },
                // 三角面材质纹理
                components: [
                    {
                        faces: [0, 2, 1],
                        material
                    },
                    {
                        faces: [0, 2, 3],
                        material
                    },
                    {
                        faces: [0, 3, 4],
                        material
                    },
                    {
                        faces: [0, 4, 1],
                        material
                    },
                    {
                        faces: [1, 2, 4],
                        material: {
                            color: "transparent"
                        }
                    },
                    {
                        faces: [2, 3, 4],
                        material: {
                            color: "transparent"
                        }
                    }],
                spatialReference,
            })

            const conusGraphic = new Graphic({
                // 缩放至矩阵范围
                geometry: mesh,
                symbol: {
                    type: "mesh-3d",
                    symbolLayers: [
                        {
                            type: "fill",
                        },
                    ],
                },
            });

            // 将圆柱体添加到视图
            view.graphics.add(conusGraphic);

            // 当视图加载完成后执行
            view.when(() => {
                // 将视图缩放到圆柱体范围
                view.goTo({
                    target: mesh,
                    tilt: 90,
                    heading: 150
                }, {duration: 1500});
            });
        });
    </script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

在线示例

ArcGIS Maps SDK for JavaScript 在线示例:创建渐变色材质的自定义几何体