Arcgis Mapserver
Runnable Cesium example: Arcgis Mapserver. Open the live demo, read the complete source, and copy the file into your project. No build step or API key.
single HTML file · CDN dependencies onlyinterface may contain Chinese labels
Source
<!--
示例:自己实现一个逐瓦片生成的影像提供者
说明:不用远程地图服务,requestImage 里按切片号在 canvas 上画出经纬网与色带,直接交给 imageryLayers
核心逻辑:tilingScheme.tileXYToRectangle 算范围 → canvas 绘制 → 返回 Promise<canvas>
依赖:CesiumJS 1.121 · jsDelivr CDN,无外部图片与瓦片请求
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="robots" content="noindex,follow">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>自定义瓦片影像提供者</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cesium@1.121.0/Build/Cesium/Widgets/widgets.css">
<style>
html,body{height:100%;margin:0}
body{background:#0e1116;color:#e6e8ec;overflow:hidden;
font:13px/1.6 -apple-system,"Segoe UI","PingFang SC",sans-serif}
#c{height:100%}
.hud{position:absolute;left:12px;top:12px;z-index:5;background:rgba(23,28,35,.9);
border:1px solid #2a313b;border-radius:6px;padding:9px 12px;font-size:12px;
color:#a2a9b6;max-width:260px}
.hud b{color:#e6e8ec;font-weight:600}
.hud .row{margin-top:7px}
input[type=range]{width:100%}
.cesium-viewer-bottom .cesium-widget-credits,.cesium-viewer-animationContainer,
.cesium-viewer-timelineContainer{display:none!important}
</style>
</head>
<body>
<div id="c"></div>
<div class="hud">
<div><b>canvas 瓦片提供者</b></div>
<div class="row">每块瓦片都是现画的,最大层级 5</div>
<div class="row">图层透明度 <span id="alphaVal">1.00</span></div>
<div class="row"><input id="alpha" type="range" min="0" max="1" step="0.05" value="1"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/cesium@1.121.0/Build/Cesium/Cesium.js"></script>
<script>
(function () {
'use strict';
var viewer = new Cesium.Viewer('c', {
baseLayer: false,
baseLayerPicker: false, geocoder: false, homeButton: false,
sceneModePicker: false, navigationHelpButton: false,
animation: false, timeline: false, fullscreenButton: false,
infoBox: false, selectionIndicator: false
});
var scene = viewer.scene;
scene.globe.baseColor = Cesium.Color.fromCssColorString('#121820');
scene.backgroundColor = Cesium.Color.fromCssColorString('#0e1116');
scene.skyBox.show = false;
scene.sun.show = false;
scene.moon.show = false;
if (scene.skyAtmosphere) scene.skyAtmosphere.show = false;
var scheme = new Cesium.WebMercatorTilingScheme();
/* ---------- 单个瓦片:底色 + 地形斑块 + 经纬网 + 编号 ---------- */
function drawTile(x, y, level) {
var size = 256;
var canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
var g = canvas.getContext('2d');
var rect = scheme.tileXYToRectangle(x, y, level);
var west = Cesium.Math.toDegrees(rect.west);
var east = Cesium.Math.toDegrees(rect.east);
var south = Cesium.Math.toDegrees(rect.south);
var north = Cesium.Math.toDegrees(rect.north);
var midLat = (south + north) / 2;
var hue = 205 - Math.abs(midLat) * 1.1;
g.fillStyle = 'hsl(' + hue.toFixed(0) + ', 32%, 24%)';
g.fillRect(0, 0, size, size);
/* 用固定公式造几块明暗不同的斑块,保证同一瓦片每次画出来都一样 */
for (var k = 0; k < 12; k++) {
var seed = (x * 31 + y * 17 + level * 13 + k * 7) % 97;
var cx = ((seed * 37) % size);
var cy = ((seed * 53) % size);
var r = 26 + (seed % 40);
g.beginPath();
g.arc(cx, cy, r, 0, Math.PI * 2);
g.fillStyle = 'hsla(' + (hue + 12).toFixed(0) + ', 38%, ' +
(30 + (seed % 18)) + '%, .45)';
g.fill();
}
/* 经纬网:落在本瓦片里的每 10 度画一条 */
g.strokeStyle = 'rgba(180, 210, 255, .18)';
g.lineWidth = 1;
for (var lon = Math.ceil(west / 10) * 10; lon <= east; lon += 10) {
var px = (lon - west) / (east - west) * size;
g.beginPath(); g.moveTo(px, 0); g.lineTo(px, size); g.stroke();
}
for (var lat = Math.ceil(south / 10) * 10; lat <= north; lat += 10) {
var py = (north - lat) / (north - south) * size;
g.beginPath(); g.moveTo(0, py); g.lineTo(size, py); g.stroke();
}
g.strokeStyle = 'rgba(120, 170, 240, .35)';
g.strokeRect(0.5, 0.5, size - 1, size - 1);
g.fillStyle = 'rgba(214, 230, 255, .75)';
g.font = '11px Consolas, monospace';
g.fillText('L' + level + ' X' + x + ' Y' + y, 8, 18);
g.fillText(west.toFixed(1) + '°, ' + midLat.toFixed(1) + '°', 8, size - 10);
return canvas;
}
/* ---------- 只实现必需字段的影像提供者 ---------- */
var provider = {
tileWidth: 256,
tileHeight: 256,
maximumLevel: 5,
minimumLevel: 0,
tilingScheme: scheme,
rectangle: scheme.rectangle,
hasAlpha: true,
hasAlphaChannel: true,
defaultAlpha: 1,
defaultBrightness: 1,
ready: true,
readyPromise: Promise.resolve(true),
credit: '本地 canvas 瓦片',
getTileCredits: function () { return []; },
requestImage: function (x, y, level) {
return Promise.resolve(drawTile(x, y, level));
}
};
var layer = viewer.imageryLayers.addImageryProvider(provider);
document.getElementById('alpha').addEventListener('input', function () {
layer.alpha = parseFloat(this.value);
document.getElementById('alphaVal').textContent = layer.alpha.toFixed(2);
});
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(110, 31, 6200000),
orientation: {
heading: 0,
pitch: Cesium.Math.toRadians(-72),
roll: 0
},
duration: 0
});
})();
</script>
</body>
</html>
Language: the code and this page are in English; the full tutorial and API notes for this example are in Chinese. The demo itself is the authoritative version — it runs exactly as shown.