【ArcGis API For JS】

<html lang="en">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <!-- 引入boostrap Css框架 -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
  <link href="https://getbootstrap.com/docs/5.3/assets/css/docs.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
  <!-- 引入ArcGis API -->
  <link rel="stylesheet" href="https://js.arcgis.com/4.25/esri/themes/dark/main.css" />
  <script src="https://js.arcgis.com/4.25/"></script>
  <title>  2029432 2029518 全球海盗事件可视化页面  </title>

  <script>
    require([
      "esri/Map",
      "esri/layers/FeatureLayer",
      "esri/views/MapView",
      "esri/core/promiseUtils",
      "esri/widgets/Legend",
      "esri/widgets/Home",
      "esri/widgets/Slider",
      "esri/widgets/Fullscreen",
      "esri/renderers/HeatmapRenderer"
    ], (
      Map,
      FeatureLayer,
      MapView,
      promiseUtils,
      Legend,
      Home,
      Slider,
      Fullscreen,
      HeatmapRenderer
    ) => {
      
      //--------------------------------------------------------------------------
      //  1 显示要素
      //--------------------------------------------------------------------------
      const layer = new FeatureLayer({
        url: "https://services3.arcgis.com/XDzy9VWpT2sZyZqz/arcgis/rest/services/seapoint/FeatureServer"
        // url: "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/ASAM_events_V1/FeatureServer"
      });

      //--------------------------------------------------------------------------
      //  2 设置点击弹框
      //--------------------------------------------------------------------------
      popupTemplate = {
        title: "{dateofocc}",             //以时间为title
        content: [
          {
            type: "fields",
            fieldInfos: [
              {
                fieldName: "expression/type-of-hostility",    //敌意类型
              }
            ]
          },
          {
            type: "fields",
            fieldInfos: [
              {
                fieldName: "expression/type-of-victim",       //受害者类型
              }
            ]
          },
          {
            type: "fields",
            fieldInfos: [
              {
                fieldName: "victim_d",
                label: "【  Name Of Victim Vessel 】"        //受害者船只名称
              }
            ]
          },
          {
            type: "fields",
            fieldInfos: [
              {
                fieldName: "descriptio",
                label: "【 Details Of The Event 】"         //详细描述

              }
            ]
          },
        ],
        expressionInfos: [{                                 // Arcade表达式,将代号转化为类型名
          name: "type-of-victim",
          title: "【 Type Of victim 】",
          expression: `Decode( $feature.victim_l,
                        0, 'Anchored Ship',
                        1,'Barge',
                        2, 'Cargo Ship',
                        3, "Fishing Vessel",
                        4, "Merchant Vessel",
                        5,"Offshore Vessel",
                        6,"Passenger Ship",
                        7,"Sailing Vessel",
                        8,"Tanker",
                        9,"Tugboat",
                        10,"Vessel",
                        11,"Unknown",
                        'Other'
                      )`
        },
        { name: "type-of-hostility",
          title: "【 Type Of Hostility 】",
          expression: `Decode( $feature.hostilityt,
                        0, "Attempted Boarding",
                        1,"Hijacking",
                        2,  "Kidnapping",
                        3, "Naval Engagement",
                        4, "Other",
                        5,"Pirate Assault",
                        6,"Suspicious Approach",
                        7,"Unknown",
                        'Other'
                      )`
        }
      ]}
      layer.popupTemplate = popupTemplate;                  
      //--------------------------------------------------------------------------
      //  3 创建 Map&MapView
      //--------------------------------------------------------------------------
      const map = new Map({
        basemap: {
          portalItem: {
            id: "4f2e99ba65e34bb8af49733d9778fb8e"
          }
        },
        layers: [layer]
      });
      const view = new MapView({
        map: map,
        container: "viewDiv",
        center: [25, 20],
        zoom: 2,
        constraints:{
          snapToZoom: false,
          minScale: 120000000
        },
        resizeAlign: "top-left",
      });

      //--------------------------------------------------------------------------
      //  4 UI设置
      //--------------------------------------------------------------------------
      //  定义UI
      const applicationDiv = document.getElementById("applicationDiv");
      const sliderValue = document.getElementById("sliderValue");
      const playButton = document.getElementById("playButton");
      const playButton2 = document.getElementById("openHeat");
      const titleDiv = document.getElementById("titleDiv");
      let animation = null;                                           //初始化动画变量
      //  定义进度条
      const slider = new Slider({
        container: "slider",
        min: 1975,
        max: 2010,
        values: [1975],
        step: 1,
        visibleElements: {
          rangeLabels: true
        }
      });
      var currentYear = 1975;
      // 拖动滑块时停止动画并设置展示事件为滑块时间
      function inputHandler(event) {
        stopAnimation();
        setYear(event.value);
      }
      slider.on("thumb-drag", inputHandler);
      // 点击播放按钮时切换动画
      playButton.addEventListener("click", () => {
        if (playButton.classList.contains("toggled")) {
          stopAnimation();
        } else {
          startAnimation();
        }
      });
      playButton2.addEventListener("click", () => {
        if (playButton.classList.contains("toggled")) {
          stopAnimation();
        } 
      });
      // 控件位置
      view.ui.empty("top-left");
      view.ui.add(titleDiv, "top-left");
      view.ui.add(        //返回初始位置
        new Home({
          view: view
        }),
        "top-left"
      );
      view.ui.add(         //图例
        new Legend({
          view: view
        }),
        "bottom-left"
      );
      // 
      view.ui.add(         //全屏
        new Fullscreen({
          view: view,
          element: applicationDiv
        }),
        "top-right"
      );
      // 悬停交互
      view.whenLayerView(layer).then(setupHoverTooltip);
      // 以1978为动画初始时间
      setYear(1975);

      //--------------------------------------------------------------------------
      //  5 功能实现
      //--------------------------------------------------------------------------
      // 5.1 设置可视化的构建年份
      function setYear(value) {
        currentYear = value;
        sliderValue.innerHTML = Math.floor(value);
        slider.viewModel.setValue(0, value);
        layer.renderer = createRenderer(value);
      }
      // 透明度变化
      function createRenderer(year) {
        const opacityStops = [
          {
            opacity: 0.99,
            value: year
          },
          {
            opacity: 0,
            value: year + 1
          }
        ];
        return {
          type: "simple",
          symbol: {
            type: "simple-marker",
            color: "rgb(0, 0, 0)",
            outline: null
          },
          visualVariables: [
            {
              type: "opacity",
              field: "year",
              stops: opacityStops,
              legendOptions: {
                showLegend: false
              }
            },
            {
              type: "color",
              field: "year",
              legendOptions: {
                title: "Happen:"
              },
              // 颜色变化
              stops: [
                {
                  value: year,
                  color: "#d8e3e7",
                  label: "in " + Math.floor(year)
                },
                {
                  value: year - 10,
                  color: "#1a94bc",
                  label: "in " + (Math.floor(year) - 10)
                },
                {
                  value: year - 20,
                  color: "#132c33",
                  label: "in " + (Math.floor(year) - 20)
                }
              ]
            }
          ]
        };
      }
      // 5.3 设置悬浮交互弹窗
      function setupHoverTooltip(layerview) {
        let highlight;

        const tooltip = createTooltip();

        const hitTest = promiseUtils.debounce((event) => {
          return view.hitTest(event).then((hit) => {
            const results = hit.results.filter((result) => {
              return result.graphic.layer === layer;
            });

            if (!results.length) {
              return null;
            }

            return {
              graphic: results[0].graphic,
              screenPoint: hit.screenPoint
            };
          });
        });

        view.on("pointer-move", (event) => {
          return hitTest(event).then(
            (hit) => {
              // 鼠标移开 移除高亮
              if (highlight) {
                highlight.remove();
                highlight = null;
              }
              // 鼠标选中 添加高亮,显示悬浮交互窗
              if (hit) {
                const graphic = hit.graphic;
                const screenPoint = hit.screenPoint;

                highlight = layerview.highlight(graphic);
                tooltip.show(
                  screenPoint,
                  "Happen in " + graphic.getAttribute("year")
                );
              } else {
                tooltip.hide();
              }
            },
            () => { }
          );
        });
      }
      // 5.4 开始动画并循环
      function startAnimation() {
        stopAnimation();
        animation = animate(slider.values[0]);
        playButton.classList.add("toggled");
      }
      // 5.5 停止动画
      function stopAnimation() {
        if (!animation) {
          return;
        }
        animation.remove();
        animation = null;
        playButton.classList.remove("toggled");
      }
      // 5.6进度条动画
      function animate(startValue) {
        let animating = true;
        let value = startValue;

        const frame = (timestamp) => {
          if (!animating) {
            return;
          }
          // 设置进度条移动间隔
          value += 0.01;
          if (value > 2010) {
            value = 1975;
          }
          setYear(value);
          // 以1000帧播放进度条
          setTimeout(() => {
            requestAnimationFrame(frame);
          }, 1000 / 1200);
        };
        frame();
        return {
          remove: () => {
            animating = false;
          }
        };
      }
     // 5.7 设置热力图渲染器
      let hrender = new HeatmapRenderer({
        colorStops: [
        { ratio: 0, color: "rgba(255, 255, 255, 1)" },
        { ratio: 0.2, color: "rgba(255, 255, 255, 1)" },
        { ratio: 0.5, color: "rgba(255, 140, 0, 1)" },
        { ratio: 0.8, color: "rgba(255, 140, 0, 1)" },
        { ratio: 1, color: "rgba(255, 0, 0, 1)" }
        ],
        blurRadius: 8,
        maxPixelIntensity: 0.01,
        minPixelIntensity: 0.0,
        radius: 20
      });
      
      document.getElementById('openHeat').onclick = () => {
        console.log(layer);
        layer.renderer = hrender;
      }

      document.getElementById('closeHeat').onclick = () => {
        setYear(currentYear);
      }
      // 5.8 筛选功能
      let type = 1;
      var v_l = ['Anchored Ship', "Barge", "Cargo Ship", "Fishing Vessel", "Merchant Vessel", "Offshore Vessel", "Passenger Ship", "Sailing Vessel", "Tanker", "Tugboat", "Vessel", "Unknown", "Other"];
      var h_l = ["Attempted Boarding", "Hijacking", "Kidnapping", "Naval Engagement", "Other", "Pirate Assault", "Suspicious Approach", "Unknown"]
      var current_l = h_l;
      function changeOptions(type) {
        document.getElementById('aselect');
        aselect.innerHTML = '';
        var tl = [];
        if (type == 1) {
          tl = h_l;
        } else {
          tl = v_l;
        }
        for (var i = 0; i < tl.length; i++) {
          var option = document.createElement('option');
          option.innerHTML = tl[i];
          option.value = i;
          aselect.appendChild(option);
        }
      }  
      changeOptions(type);
      // 切换筛选字段
      document.getElementById("input1").onclick = () => {
        type = 1;
        document.getElementById("input2").checked = false;
        current_l = h_l
        doCheck(1);
      }
      document.getElementById("input2").onclick = () => {
        type = 2;
        current_l = v_l;
        document.getElementById("input1").checked = false;
        doCheck(2);
      }
      // 筛选下拉框
      function doCheck(index) {
        changeOptions(index);
      }
      document.getElementById("aselect").onchange = () => {
        var selectVal = $("#aselect option:selected").val();
        var where = '';
        if(type == 1){
          where = 'hostilityt='+selectVal;
        }else if(type == 2){
          where = 'victim_l='+selectVal;
        }
        layer.definitionExpression = where;
      }
      // 取消筛选
      document.getElementById("cancel").onclick = ()=>{
        layer.definitionExpression='';
      }
    });
  </script>

  <style>
    html,
    body {
      width: 100%;
      height: 100%;
      padding: 0;
      margin: 0;
    }

    #applicationDiv {
      position: absolute;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }

    #viewDiv {
      width: 100%;
      height: 100%;
      flex: 1 1 auto;
      order: 1;
    }
    /* 标题 */
    #titleDiv {
      font-weight: 400;
      font-style: normal;
      font-size: 1.2019rem;
      padding: 10px;
    }
    /* 进度条 */
    #sliderContainer {
      flex: 0 0 80px;
      order: 2;

      display: flex;
      flex-flow: row;

      padding: 0 12px;
    }
    #sliderValue {
      flex: 0 0 100px;
      order: 1;

      display: flex;
      justify-content: center;
      flex-direction: column;
      text-align: center;

      font-size: 300%;
    }
    #sliderInnerContainer {
      flex: 1 1 auto;
      order: 2;

      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: 0 20px;
    }
    #slider {
      width: 100%;
    }

    /* 播放按钮 */
    #playButton {
      flex: 0 0 100px;
      order: 3;
      margin: 20px 0;
    }
    .toggle-button {
      display: flex;
    }
    .toggle-button.toggled .toggle-button-icon {
      color: #cc1b1b;
    }
    .toggle-button .toggle-button-icon {
      color: #1bcc1b;
    }
    .toggle-button> :nth-child(2) {
      display: none;
    }
    .toggle-button.toggled> :nth-child(1) {
      display: none;
    }
    .toggle-button.toggled> :nth-child(2) {
      display: block;
    }

    #openHeat,
    #closeHeat{
      background-color:rgb(36, 36, 36); 
      padding: 10px;
      border-color:rgb(36, 36, 36);
      color:rgb(207,207,207); 
      font-family:'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif
    }
    #input1,
    #input2,
    #cancel,#aselect{
      background-color:rgb(36, 36, 36); 
      padding: 8px; 
      border-color:rgb(36, 36, 36);
      color:rgb(207,207,207);
      font-family:'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif
    }
    .heatCon {
      position: absolute;
      right: 10px;
      top: 8vh;
    }
    .selectCon {
      position: absolute;
      right: 10px;
      top: 15vh;
    }
  </style>
</head>

<body>
  <div id="applicationDiv">
    <div id="viewDiv">
      <div id="titleDiv" class="esri-widget">《 Global Piracy Showcase 》</div>
    </div>
    <!-- 进度条 -->
    <div id="sliderContainer" class="esri-widget">
      <span id="sliderValue"></span>
      <div id="sliderInnerContainer">
        <div id="slider"></div>
      </div>
      <div id="playButton" class="esri-widget esri-widget--button toggle-button">
        <div>
          <span class="toggle-button-icon esri-icon-play" aria-label="play icon"></span>
          Play
        </div>
        <div>
          <span class="toggle-button-icon esri-icon-pause" aria-label="pause icon"></span>
          Pause
        </div>
      </div>
    </div>
    <!-- 热力图 -->
    <div class="heatCon">
      <a class="btn btn-primary" id="openHeat" href="#" role="button" >Thermodynamic chart</a>
      <a class="btn btn-primary" id="closeHeat" href="#" role="button" >Close </a>
    </div>
    <!-- 筛选 -->
    <div class="selectCon">
      <br>
      <a class="btn btn-primary" id="input1" href="#" role="button" >hostility</a>
      <a class="btn btn-primary" id="input2" href="#" role="button" >victim</a>
      <a class="btn btn-primary" id="cancel" href="#" role="button">Unfilter</a>
      <div>
        <br>
        <select id="aselect" class="form-select" ></select></select>
      </div>
      
    </div>

  </div>
</body>

</html>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值