Flex纯as写的等待控件

本文介绍了一个名为Spinner的Flash加载器组件实现细节,该组件能够显示一个旋转的加载动画,并可通过参数配置外观与行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spinner.as

import flash.events.TimerEvent;

    import flash.utils.Timer;
    
    import mx.core.UIComponent;
    import mx.events.FlexEvent;
    import mx.styles.CSSStyleDeclaration;
    import mx.styles.StyleManager;
    
    //[ExcludeClass]
    
    [Style(name="tickColor", type="uint", format="Color", inherit="no")]
    
    /**
     * Creates a spinning "loader" component that is sort of an indeterminate progress bar.
     * @author Qiang JiShen
     */
    public class Spinner extends UIComponent {
        
        private static var STYLE_TICK_COLOR:String = "tickColor";
        
        private var tickColorChanged:Boolean;
        
        private static var classConstructed:Boolean = classConstruct();
        
        // Make sure we create the ticks the first time updateDisplayList is called
        private var creation:Boolean = true;
        
        
        private var fadeTimer:Timer;
        
        private var _isPlaying:Boolean;
        
        private var _numTicks:int = 24;
        
        private var numTicksChanged:Boolean;
        
        private var _size:Number = 76;
        
        private var sizeChanged:Boolean;
        
        private var _tickWidth:Number = 3;
        
        private var tickWidthChanged:Boolean;
        
        private var _speed:int = 1000;
        
        [Bindable]
        public var fadeSpeed:int = 600;
        
        public var autoPlay:Boolean = true;
        
        
        public function Spinner() {
            super();
            
            //addEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
        }
        
        private function handleCreationComplete(e:FlexEvent):void {
            removeEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
            if (autoPlay) {
                play();
            }
        }
        
        
        /**
         * Set the height and width based on the size of the spinner. This should be more robust, but oh well.
         */
        override protected function measure():void {
            super.measure();
            
            width = _size;
            height = _size;
        }
        
        
        /**
         * Override the updateDisplayList method
         */
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
            if (tickColorChanged || numTicksChanged || sizeChanged || tickWidthChanged || creation) {
                creation = false;
                // Find out whether it's playing so we can restart it later if we need to
                var wasPlaying:Boolean = _isPlaying;
                
                // stop the spinning
                stop();
                
                // Remove all children
                for (var i:int = numChildren - 1; i >= 0; i--) {
                    removeChildAt(i);
                }
                
                // Re-create the children
                var radius:Number = size / 2;
                var angle:Number = 2 * Math.PI / _numTicks; // The angle between each tick
                var tickWidth:Number = (_tickWidth != -1) ? _tickWidth : size / 10;
                var tickColor:uint = getStyle(STYLE_TICK_COLOR);
                
                var currentAngle:Number = 0;
                for (var j:int = 0; j < _numTicks; j++) {
                    
                    var xStart:Number = radius + Math.sin(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
                    var yStart:Number = radius - Math.cos(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
                    var xEnd:Number = radius + Math.sin(currentAngle) * (radius - tickWidth);
                    var yEnd:Number = radius - Math.cos(currentAngle) * (radius - tickWidth);
                    
                    var t:Tick = new Tick(xStart, yStart, xEnd, yEnd, tickWidth, tickColor);
                    t.alpha = 0.1;
                    
                    this.addChild(t);
                    
                    currentAngle += angle;
                }
                
                // Start the spinning again if it was playing when this function was called.
                if (wasPlaying) {
                    play();
                }
                
                tickColorChanged = false;
                numTicksChanged = false;
                sizeChanged = false;
                tickWidthChanged = false;
            }
        }
        
        
        private static function classConstruct():Boolean {
            if (!StyleManager.getStyleDeclaration("Spinner")) {
                // If there is no CSS definition for StyledRectangle,
                // then create one and set the default value.
                var newStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
                newStyleDeclaration.setStyle(STYLE_TICK_COLOR, 0x000000);
                StyleManager.setStyleDeclaration("Spinner", newStyleDeclaration, true);
            }
            return true;
        }
        
        override public function styleChanged(styleProp:String):void {
            if (styleProp == STYLE_TICK_COLOR) {
                tickColorChanged = true;
                invalidateDisplayList();
            }
        }
        
        /**
         * Begin the circular fading of the ticks.
         */
        public function play():void {
            if (!_isPlaying) {
                visible = true;
                fadeTimer = new Timer(speed / _numTicks, 0);
                // Anonymous functions are especially useful as simple event handlers
                fadeTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
                    var tickNum:int = int(fadeTimer.currentCount % _numTicks);
                    
                    if (numChildren > tickNum) {
                        var tick:Tick = getChildAt(tickNum) as Tick;
                        tick.fade(fadeSpeed != 1 ? fadeSpeed : speed * 6 / 10);
                    }
                });
                fadeTimer.start();
                _isPlaying = true;
            }
        }
        
        /**
         * Stop the spinning.
         */
        public function stop():void {
            if (fadeTimer != null && fadeTimer.running) {
                _isPlaying = false;
                visible = false;
                fadeTimer.stop();
            }
        }
        
        /**
         * The overall diameter of the spinner; also the height and width.
         */
        [Bindable]
        public function set size(value:Number):void {
            if (value != _size) {
                _size = value;
                sizeChanged = true;
                invalidateDisplayList();
                invalidateSize();
            }
        }
        
        public function get size():Number {
            return _size;
        }
        
        /**
         * The number of 'spokes' on the spinner.
         */
        [Bindable]
        public function set numTicks(value:int):void {
            if (value != _numTicks) {
                _numTicks = value;
                numTicksChanged = true;
                invalidateDisplayList();
            }
        }
        
        public function get numTicks():int {
            return _numTicks;
        }
        
        /**
         * The width of the 'spokes' on the spinner.
         */
        [Bindable]
        public function set tickWidth(value:int):void {
            if (value != _tickWidth) {
                _tickWidth = value;
                tickWidthChanged = true;
                invalidateDisplayList();
            }
        }
        
        public function get tickWidth():int {
            return _tickWidth;
        }
        
        /**
         * The duration (in milliseconds) that it takes for the spinner to make one revolution.
         */
        [Bindable]
        public function set speed(value:int):void {
            if (value != _speed) {
                _speed = value;
                if (fadeTimer) {
                    fadeTimer.stop();
                    fadeTimer.delay = value / _numTicks;
                    fadeTimer.start();
                }
            }
        }
        
        public function get speed():int {
            return _speed;
        }
        
        
        public function get isPlaying():Boolean {
            return _isPlaying;
        }

    }


Tick.as:


import mx.effects.Fade;
    
    [ExcludeClass]

    /**
     * @author Qiang JiShen
     */
    public class Tick extends Sprite {
        
        private var tickFade:Fade = new Fade(this);

        public function Tick(fromX:Number, fromY:Number, toX:Number, toY:Number, tickWidth:int, tickColor:uint) {
            this.graphics.lineStyle(tickWidth, tickColor, 1.0, false, "normal", "rounded");
            this.graphics.moveTo(fromX, fromY);
            this.graphics.lineTo(toX, toY);
        }

        public function fade(duration:Number):void {
            tickFade.alphaFrom = 1.0;
            tickFade.alphaTo = 0.1;
            tickFade.duration = duration;
            tickFade.play();
        }
    }


<template> <div class="viewport"> <div class="map-container"> <div id="cesiumContainer" class="main-map"></div> <div id="overviewMap" class="overview-map"></div> </div> </div> </template> <script setup lang="ts"> import { onMounted, onUnmounted, ref, watch } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 株洲市范围常量 const ZHUZHOU_EXTENT = Cesium.Rectangle.fromDegrees( 112.5, // west 26.0, // south 114.5, // east 28.0 // north ); // 地图实例引用 const mainViewer = ref<Cesium.Viewer | null>(null); const overviewViewer = ref<Cesium.Viewer | null>(null); const rectangleEntity = ref<Cesium.Entity | null>(null); // 初始化主地图 const initMainMap = async () => { try { // 设置Cesium访问令牌 Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE"; // 创建主地图实例 mainViewer.value = new Cesium.Viewer('cesiumContainer', { sceneMode: Cesium.SceneMode.SCENE3D, animation: false, baseLayerPicker: false, fullscreenButton: true, geocoder: false, homeButton: true, infoBox: false, sceneModePicker: true, selectionIndicator: true, timeline: false, navigationHelpButton: false, shouldAnimate: true, // 使用可靠的影像服务 imageryProvider: new Cesium.UrlTemplateImageryProvider({ url: "https://t{s}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=9e8b46c0d7b9278af7053b7b593d7390", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], minimumLevel: 1, maximumLevel: 18 }), // 使用默认地形(避免加载失败) terrain: Cesium.Terrain.fromWorldTerrain({ requestVertexNormals: true, requestWaterMask: true }) }); // 设置初始视图到株洲市范围 mainViewer.value.camera.flyTo({ destination: ZHUZHOU_EXTENT, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-30), roll: 0.0 }, duration: 2.0 }); // 添加错误处理(确保对象存在) if (mainViewer.value.scene.globe) { mainViewer.value.scene.globe.tileLoadProgress.addEventListener((pending) => { if (pending === 0) console.log('所有瓦片加载完成'); }); } mainViewer.value.scene.error.addEventListener((error) => { console.error('Cesium错误:', error); }); } catch (error) { console.error('初始化主地图失败:', error); } }; // 初始化鹰眼地图 const initOverviewMap = () => { if (!mainViewer.value) return; try { // 创建鹰眼地图 overviewViewer.value = new Cesium.Viewer('overviewMap', { sceneMode: Cesium.SceneMode.SCENE2D, animation: false, baseLayerPicker: false, fullscreenButton: false, geocoder: false, homeButton: false, infoBox: false, sceneModePicker: false, selectionIndicator: false, timeline: false, navigationHelpButton: false, shouldAnimate: false, // 简化版底图 imageryProvider: new Cesium.UrlTemplateImageryProvider({ url: "https://t{s}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=9e8b46c0d7b9278af7053b7b593d7390", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], minimumLevel: 1, maximumLevel: 13, rectangle: ZHUZHOU_EXTENT }), // 不使用地形 terrainProvider: new Cesium.EllipsoidTerrainProvider() }); // 禁用鹰眼地图的用户交互 const controller = overviewViewer.value.scene.screenSpaceCameraController; controller.enableRotate = false; controller.enableTranslate = false; controller.enableZoom = false; controller.enableTilt = false; controller.enableLook = false; // 添加矩形指示器 rectangleEntity.value = overviewViewer.value.entities.add({ rectangle: { coordinates: ZHUZHOU_EXTENT, material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.RED } }); // 设置鹰眼地图初始视图 overviewViewer.value.camera.setView({ destination: ZHUZHOU_EXTENT }); } catch (error) { console.error('初始化鹰眼地图失败:', error); } }; // 同步地图视图 const syncMaps = () => { if (!mainViewer.value || !overviewViewer.value || !rectangleEntity.value) return; // 监听主地图相机变化 const handler = mainViewer.value.camera.changed.addEventListener(() => { const rectangle = mainViewer.value!.camera.computeViewRectangle(); if (rectangle) { // 更新鹰眼地图中的矩形 rectangleEntity.value!.rectangle!.coordinates = rectangle; } }); return handler; }; // 组件挂载时初始化地图 onMounted(() => { if (!Cesium.Ion.defaultAccessToken) { console.error('Cesium访问令牌未设置!'); return; } initMainMap(); // 等待主地图初始化完成后初始化鹰眼地图 const unwatch = watch(mainViewer, (viewer) => { if (viewer) { // 添加延迟确保主地图完全加载 setTimeout(() => { initOverviewMap(); // 等待鹰眼地图初始化完成后同步地图 const unwatchOverview = watch(overviewViewer, (overview) => { if (overview && rectangleEntity.value) { const cleanup = syncMaps(); onUnmounted(() => { if (typeof cleanup === 'function') cleanup(); }); unwatchOverview(); } }, { immediate: true }); }, 1000); unwatch(); } }, { immediate: true }); }); // 组件卸载时销毁地图实例 onUnmounted(() => { mainViewer.value?.destroy(); overviewViewer.value?.destroy(); }); </script> <style> /* 全局重置样式 */ * { margin: 0; padding: 0; box-sizing: border-box; } html, body, #app { width: 100%; height: 100%; overflow: hidden; font-family: sans-serif; } #app { position: relative; } </style> <style scoped> .viewport { display: flex; flex-direction: column; height: 100vh; width: 100vw; overflow: hidden; } .map-container { flex: 1; position: relative; background-color: #1e1e1e; } .main-map { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; } .overview-map { position: absolute; bottom: 20px; right: 20px; width: 300px; height: 200px; border: 2px solid #fff; box-shadow: 0 0 15px rgba(0, 0, 0, 0.7); z-index: 100; background-color: #000; border-radius: 4px; overflow: hidden; } @media (max-width: 768px) { .overview-map { width: 150px; height: 100px; bottom: 10px; right: 10px; } } </style> 修改代码,还是有问题,所以先弄简单点,先不加载株洲市,就正常加载一个初始地球,采用cesium默认的就行,基于此修改点
07-09
<think>根据要求,我们简化代码,只加载默认地球,去除株洲市范围设置,并确保使用Cesium默认的影像和地形服务。 主要修改点: 1. 移除ZHUZHOU_EXTENT相关的代码,包括初始视图的flyTo和鹰眼地图的矩形指示器。 2. 初始化主地图时,使用Cesium默认的影像和地形(即不指定imageryProvider和terrainProvider,让Cesium自动使用默认的Bing地图和世界地形)。 3. 鹰眼地图也使用默认的影像,并设置为2D模式,同时禁用交互。 4. 由于移除了株洲范围,同步地图视图的逻辑需要调整:我们不再显示矩形指示器,而是将主地图的当前视域在鹰眼地图中高亮(如果需要,可以添加一个矩形来表示,但这里先不添加)。 5. 简化错误处理,只保留基本的错误打印。 注意:由于Cesium默认使用Bing地图,需要设置有效的Bing地图密钥或者使用其他默认底图。但Cesium也提供了无令牌的默认底图(OpenStreetMap等),但为了确保显示,我们使用Cesium自带的ArcGIS底图作为备用。 修改后的代码将做如下调整: - 主地图:不指定imageryProvider和terrainProvider,使用默认值。 - 鹰眼地图:使用简单的单张图片作为底图(或者也使用默认的ArcGIS底图),并设置为2D模式。 由于问题中已经提到先不加载株洲市,我们直接使用默认地球视图。 具体修改如下:</think>### 简化版 Cesium 地图组件(使用默认地球视图) 以下是修改后的代码,移除了株洲市特定范围设置,使用 Cesium 默认地球视图,并简化了初始化逻辑: ```vue <template> <div class="viewport"> <div class="map-container"> <div id="cesiumContainer" class="main-map"></div> <div id="overviewMap" class="overview-map"></div> </div> </div> </template> <script setup lang="ts"> import { onMounted, onUnmounted, ref, watch } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; // 地图实例引用 const mainViewer = ref<Cesium.Viewer | null>(null); const overviewViewer = ref<Cesium.Viewer | null>(null); // 初始化主地图(简化版) const initMainMap = async () => { try { // 设置Cesium访问令牌(使用您的有效令牌) Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE"; // 创建主地图实例(使用默认配置) mainViewer.value = new Cesium.Viewer('cesiumContainer', { // 使用Cesium默认的Bing地图影像 imageryProvider: new Cesium.IonImageryProvider({ assetId: 2 }), // 使用Cesium默认的世界地形 terrainProvider: Cesium.Terrain.fromWorldTerrain(), // 简化UI配置 animation: false, baseLayerPicker: true, // 允许用户切换底图 fullscreenButton: true, homeButton: true, sceneModePicker: true, timeline: false, navigationHelpButton: false, infoBox: false }); // 添加基本错误处理 mainViewer.value.scene.error.addEventListener((error) => { console.error('Cesium错误:', error); }); console.log('主地图初始化完成'); } catch (error) { console.error('初始化主地图失败:', error); } }; // 初始化鹰眼地图(简化版) const initOverviewMap = () => { if (!mainViewer.value) return; try { // 创建鹰眼地图 overviewViewer.value = new Cesium.Viewer('overviewMap', { // 使用简化的影像服务 imageryProvider: new Cesium.SingleTileImageryProvider({ url: 'https://cesium.com/docs/tutorials/creating-application/thumbnail.jpg' }), // 设置为2D模式 sceneMode: Cesium.SceneMode.SCENE2D, // 禁用所有UI控件 animation: false, baseLayerPicker: false, fullscreenButton: false, geocoder: false, homeButton: false, infoBox: false, sceneModePicker: false, selectionIndicator: false, timeline: false, navigationHelpButton: false, shouldAnimate: false, // 不使用地形 terrainProvider: new Cesium.EllipsoidTerrainProvider() }); // 禁用用户交互 const controller = overviewViewer.value.scene.screenSpaceCameraController; controller.enableRotate = false; controller.enableTranslate = false; controller.enableZoom = false; controller.enableTilt = false; controller.enableLook = false; // 设置初始视图为全球视图 overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90) }); console.log('鹰眼地图初始化完成'); } catch (error) { console.error('初始化鹰眼地图失败:', error); } }; // 组件挂载时初始化地图 onMounted(() => { // 检查Cesium可用性 if (!window.Cesium) { console.error('Cesium库未加载!'); return; } // 初始化主地图 initMainMap(); // 等待主地图初始化完成后初始化鹰眼地图 watch(mainViewer, (viewer) => { if (viewer) { // 添加延迟确保主地图完全加载 setTimeout(() => { initOverviewMap(); }, 1000); } }, { immediate: true }); }); // 组件卸载时销毁地图实例 onUnmounted(() => { mainViewer.value?.destroy(); overviewViewer.value?.destroy(); }); </script> <style> /* 全局重置样式 */ * { margin: 0; padding: 0; box-sizing: border-box; } html, body, #app { width: 100%; height: 100%; overflow: hidden; font-family: sans-serif; } #app { position: relative; } </style> <style scoped> .viewport { display: flex; flex-direction: column; height: 100vh; width: 100vw; overflow: hidden; } .map-container { flex: 1; position: relative; background-color: #1e1e1e; } .main-map { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; } .overview-map { position: absolute; bottom: 20px; right: 20px; width: 300px; height: 200px; border: 2px solid #fff; box-shadow: 0 0 15px rgba(0, 0, 0, 0.7); z-index: 100; background-color: #000; border-radius: 4px; overflow: hidden; } @media (max-width: 768px) { .overview-map { width: 150px; height: 100px; bottom: 10px; right: 10px; } } </style> ``` ### 主要修改点说明 #### 1. 移除了复杂的地图配置 ```javascript // 旧版复杂配置 terrain: Cesium.Terrain.fromWorldTerrain({ requestVertexNormals: true, requestWaterMask: true }) // 新版简化配置 terrainProvider: Cesium.Terrain.fromWorldTerrain() // 使用默认配置 ``` #### 2. 使用 Cesium 内置的默认服务 ```javascript // 使用Cesium官方推荐的默认影像 imageryProvider: new Cesium.IonImageryProvider({ assetId: 2 }) // 使用Cesium默认的世界地形 terrainProvider: Cesium.Terrain.fromWorldTerrain() ``` #### 3. 简化了鹰眼地图实现 ```javascript // 鹰眼地图使用单张静态图片 imageryProvider: new Cesium.SingleTileImageryProvider({ url: 'https://cesium.com/docs/tutorials/creating-application/thumbnail.jpg' }) // 设置全球视图 overviewViewer.value.camera.setView({ destination: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90) }) ``` #### 4. 移除了不必要的同步逻辑 ```javascript // 移除了视图同步代码 // 移除了矩形指示器代码 ``` #### 5. 增强了错误处理 ```javascript // 检查Cesium库是否加载 if (!window.Cesium) { console.error('Cesium库未加载!'); return; } // 基本错误处理 mainViewer.value.scene.error.addEventListener((error) => { console.error('Cesium错误:', error); }); ``` ### 备选方案:完全使用默认配置 如果仍然遇到问题,可以使用最简化的配置: ```javascript const initMainMap = () => { try { Cesium.Ion.defaultAccessToken = "您的令牌"; // 完全使用默认配置 mainViewer.value = new Cesium.Viewer('cesiumContainer', { // 不提供任何自定义配置 }); console.log('主地图初始化完成'); } catch (error) { console.error('初始化主地图失败:', error); } }; ``` ### 故障排除建议 如果问题仍然存在,请尝试以下步骤: 1. **检查 Cesium 版本**: ```javascript console.log('Cesium版本:', Cesium.VERSION); ``` 2. **验证令牌有效性**: ```javascript // 临时使用公共令牌测试 Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE"; ``` 3. **创建最简测试用例**: ```vue <template> <div id="cesiumContainer" style="width:100%; height:100vh;"></div> </template> <script setup> import { onMounted } from 'vue'; import * as Cesium from 'cesium'; import 'cesium/Build/Cesium/Widgets/widgets.css'; onMounted(() => { Cesium.Ion.defaultAccessToken = "您的令牌"; new Cesium.Viewer('cesiumContainer'); }); </script> ``` 4. **检查网络请求**: - 在浏览器开发者工具中查看网络请求是否成功 - 确保没有跨域问题(CORS) ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值