npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

map-sdk-leaflet

v0.1.3

Published

A Component Library for Vue 3

Readme

  • 💪 Vue 3 Composition API
  • 🔥 Written in TypeScript

使用示例

<template>
  <div class="home" style="width: 100%; height: 100%">
    <BaseMapComponent
      ref="baseMap"
      :right-menu="status.rightMenuList"
      @initMap="initMap"
      @selectShipItem="selectShipItem"
      @selectedShipUpdate="selectedShipUpdate"
      @rightMenuShip="rightMenuShip"
      @aiDetectionClick="aiDetectionClick"
    >
      <!-- 提供默认插槽 -->
      <section
        v-show="status.isShowTools"
        class="toolbar"
        @dblclick.stop
        @click.stop
      >
        <el-button @click="shipShow">显示船舶</el-button>
        <el-button :disabled="isDisabled" @click="local">定位船舶</el-button>
        <el-button :disabled="isDisabled" @click="cancelLocate"
          >取消定位船舶</el-button
        >
        <el-button @click="closeRightMenu">关闭右键菜单</el-button>
        <el-button @click="drawLine">绘制航线</el-button>
        <el-button @click="drawLineEdit">编辑航线</el-button>
        <el-button @click="cancleDrawLineEdit">取消编辑</el-button>
        <el-button @click="showTrack">显示历史轨迹</el-button>
        <el-button :disabled="!status.trackId" @click="appendTrack"
          >追加历史轨迹</el-button
        >
        <el-button :disabled="!status.trackId" @click="hideOrShowTrack"
          >隐藏历史轨迹</el-button
        >
        <el-button :disabled="isDisabled" @click="showTrackForecast"
          >显示气象预测轨迹</el-button
        >
        <el-button :disabled="isDisabled" @click="hideTrackForeacast"
          >隐藏气象预测轨迹</el-button
        >
        <el-button @click="showNavigationalWarning">显示航行警告</el-button>
        <el-button @click="hideNavigationalWarning"
          >隐藏第一条航行警告</el-button
        >

        <el-button @click="localPirate">定位海盗</el-button>
        <el-button @click="cancelLocalPirate">取消定位海盗</el-button>
        <el-button @click="showNavigation">显示ais航标</el-button>
        <el-button @click="hideNavigation">隐藏ais航标</el-button>
        <el-button @click="aisNavLocation">定位ais航标</el-button>
        <el-button @click="showShipSj">显示船舶三角</el-button>
        <el-button @click="hideShipSj">隐藏船舶三角</el-button>

        <el-form label-width="auto" class="demo-ruleForm" label-position="top">
          <el-form-item label="图层显示">
            <section style="display: flex; padding: 0 5px; flex-wrap: wrap">
              <section
                v-for="(item, index) in getLayer"
                :key="index"
                style="display: flex"
                flex
                items-center
              >
                <label style="flex: 1" flex-1>{{ item.label }}</label>
                <section>
                  <el-switch
                    v-model="item.value"
                    @change="
                      (val) => handleChange(item.typeName, val, item.typeCode)
                    "
                  />
                </section>
              </section>
            </section>
          </el-form-item>
          <el-form-item label="水文气象">
            <section style="display: flex; padding: 0 5px; flex-wrap: wrap">
              <section
                v-for="(item, index) in getWeather"
                :key="index"
                style="display: flex"
                items-center
              >
                <label style="flex: 1">{{ item.label }}</label>
                <section>
                  <el-switch
                    v-model="item.value"
                    @change="
                      (val) => handleChange(item.typeName, val, item.typeCode)
                    "
                  />
                </section>
              </section>
            </section>
          </el-form-item>
        </el-form>

        <el-button @click="() => drawPoline('clear')">清空绘制</el-button>
        <el-button @click="() => drawPoline('Rectange')"
          >长方形/ 正方形</el-button
        >
        <el-button @click="() => drawPoline('Polygon')">多边形</el-button>
        <el-button @click="() => drawPoline('Circle')">圆形</el-button>
        <el-button @click="() => drawPoline('Sector')">扇形</el-button>
        <el-button @click="() => drawPoline('Ellipse')">椭圆</el-button>
        <el-button @click="() => drawPoline('FreeDraw')"
          >自由绘制按住鼠标左键开始绘制</el-button
        >

        <el-button @click="() => showArea('areas')">回显区域数据</el-button>
        <el-button @click="() => showArea('lines')">回显航线</el-button>
        <el-button @click="() => showArea('markers')">回显marker点</el-button>
      </section>
      <!-- <template #rightMenu>
        <div>测试插槽</div>
      </template> -->
    </BaseMapComponent>
    <ElAffix position="bottom" :offset="160" :z-index="10000">
      <ElButton type="primary" @click="handleShowTools">工具箱</ElButton>
    </ElAffix>
  </div>
</template>

<script setup>
  import { computed, reactive, ref } from 'vue'
  import { ElAffix, ElButton } from 'element-plus'
  import { BaseMapComponent } from '@map-sdk/components'
  import { trackAi, trackList, trackList3 } from './trackList'
  import { haifeng } from './haifeng'
  import { hl } from './hl'
  import { yangliu } from './yangliu'

  const baseMap = ref(null)
  const isShowShip = ref(false)
  const status = reactive({
    isShowTools: false,
    map: null,
    trackId: null,
    settingList: {
      layer: [
        {
          label: '全球排放控制区',
          typeName: 'showGlobalEmissionControlArea',
        },
        {
          label: '中国领海基线',
          typeName: 'showBaselineOfChinaTerritorialSea',
        },
        {
          label: '全球重要海峡',
          typeName: 'showStraitsOfGlobalImportance',
        },
        {
          label: '全球海区',
          typeName: 'showGlobalMarineArea',
        },
        {
          label: '全球时区',
          typeName: 'showGlobalTimeZone',
        },
        {
          label: '经纬网格',
          typeName: 'showWarpAndLatitudeGrid',
        },
        {
          label: '中国沿海航路',
          typeName: 'showSeaRoute',
        },
        {
          label: '渔区边界',
          typeName: 'showFisheryManager',
        },
        {
          label: 'AIS图层显示',
          typeName: 'showAisManager',
        },

        {
          label: '海洋地震',
          typeName: 'showEarthQuakeAreaSymbol',
        },
        {
          label: '海盗事件',
          typeName: 'showPiratesSymbol',
        },
        {
          label: '碰撞高风险区',
          typeName: 'showCollisionRiskSymbol',
        },
        {
          label: '碍航网具',
          typeName: 'showObstacleareaSymbol',
        },
        {
          label: '渔业协定水域',
          typeName: 'showFinshAreaSymbol',
        },
        {
          label: '🌓全球晨昏线',
          typeName: 'showTerminatorSymbol',
        },
      ],
      weather: [
        {
          label: '海区预报',
          typeName: 'showSeaAreaForecast',
        },
        {
          label: '潮汐',
          typeName: 'showTide',
        },
        {
          label: '台风',
          typeName: 'showTyphoon',
        },
        {
          label: '风场',
          typeName: 'showSeaBreeze',
        },
        {
          label: '海风',
          typeName: 'showWind',
        },
        {
          label: '海流',
          typeName: 'showHL',
        },

        {
          label: '洋流',
          typeName: 'showYangliu',
        },
        {
          label: '水温',
          typeName: 'showWaterTemperature',
          typeCode: '0',
        },
        {
          label: '冰情',
          typeName: 'showIceCondition',
          typeCode: '1',
        },
        {
          label: '海冰',
          typeName: 'showSeaIce',
          typeCode: '2',
        },
        {
          label: '海风',
          typeName: 'showSeaBreezeLayer',
          typeCode: '3',
        },
        {
          label: '海风箭头',
          typeName: 'showSeaBreezeArrow',
          typeCode: '4',
        },
        {
          label: '海风+箭头',
          typeName: 'showSeaBreezeArrow',
          typeCode: '3,4',
        },
        {
          label: '降雨量',
          typeName: 'showRainfall',
          typeCode: '5',
        },
        {
          label: '气压',
          typeName: 'showAtmosphericPressure',
          typeCode: '6',
        },
        {
          label: '能见度',
          typeName: 'showVisibility',
          typeCode: '7',
        },
        {
          label: '气温',
          typeName: 'showAirTemperature',
          typeCode: '8',
        },
        {
          label: '海浪',
          typeName: 'showSeaWave',
          typeCode: '9',
        },
        {
          label: '海浪箭头',
          typeName: 'showWaveArrow',
          typeCode: '10',
        },
        {
          label: '海浪+箭头',
          typeName: 'showHaiLang',
          typeCode: '9,10',
        },
      ],
    },
    rightMenuList: [
      {
        label: '传入菜单',
        clickCallback: (e, data) => {
          console.log('点击了click', e, data)
        },
      },
    ],
  })
  const getLayer = computed(() => status.settingList.layer)
  const getWeather = computed(() => status.settingList.weather)
  const isDisabled = computed(() => !isShowShip.value)
  const handleShowTools = () => {
    status.isShowTools = !status.isShowTools
    console.log('isShowTools', status.isShowTools)
  }
  const initMap = (map) => {
    console.log(`地图:${map}`)
    status.map = map
  }
  const selectShipItem = (item) => {
    console.log('selectShipItem', item)
  }
  const selectedShipUpdate = (item) => {
    console.log('selectedShipUpdate', item)
  }
  const local = () => {
    if (baseMap.value) {
      // 通过 ref 访问子组件的方法
      baseMap.value.locate('14554a117d5c4e98bf34d1a8e05babe8')
    }
  }

  const shipShow = () => {
    baseMap.value.shipShow([
      {
        source: 0,
        mmsi: 229402000,
        shipid: 'EDC78302A978E5B5',
        lng: 113.925383,
        lat: 22.364165,
        hdg: 128,
        cog: 155.1,
        sog: 0.09,
        rot: 0,
        name: 'CEPOLIS',
        length: 180,
        width: 32,
        left: 10,
        trail: 33,
        // tracks: [],
      },
      {
        source: 0,
        mmsi: 477887901,
        shipid: '7F1B356A294C6D13',
        tradetype: 2,
        name: 'SITC HENGDE 11',
        cnname: '',
        callsign: 'VRVG3',
        draught: 9100,
        dest: 'SHEKOU,CN',
        eta: '07-02 12:00',
        laststa: 1719904688,
        lng: 113.868147,
        lat: 22.484455,
        sog: 0,
        cog: 6.64,
        hdg: 34.2,
        rot: 0,
        navistatus: 5,
        lastdyn: 1720060310,
        satelliteutc: 0,
        lastdyn_active: true,
        type: 100,
        imo: 0,
        length: 180,
        width: 32,
        left: 10,
        trail: 33,
      },
      {
        name: 'SITC HENGDE',
        shipid: '14554a117d5c4e98bf34d1a8e05babe8',
        orgId: '91cf0b2216e74f688e86f19213139423',
        lng: 114.0297,
        lat: 22.3498,
        cog: 13.776,
        rot: 1.1,
        sog: 0,
        mmsi: '477887900',
        hdg: 128,
        // 按比例缩放值
        length: 180,
        width: 32,
        left: 10,
        trail: 33,
      },
      {
        name: '测试船舶定位船舶',
        source: 0,
        mmsi: 412321605,
        shipid: 'BF29CDE29F45D02E',
        lng: 121.121472,
        lat: 38.722985,
        cog: 163.1,
        sog: 6.2,
        rot: 327.67,
        is_radar: false,
        navistatus: 255,
        lastdyn: 1711503635,
        type: 30,
        length: 26,
        tracks: [],
        istop: false,
        state: 0,
        lineWidth: 1,
        rotate: 0,
        shiptype: 1,
        lineColor: '#00BCD4',
        heightLineColor: '#00BCD4',
        color: '#00BCD4',
      },
      {
        name: '测试预测轨迹船舶',
        source: 0,
        mmsi: '4131101',
        shipid: '6138CF3E5B032BD2',
        lng: 121.13555,
        lat: 38.727367,
        sog: 65.535,
        cog: 65.535,
        hdg: 65.535,
        rot: 32.767,
        tradetype: 99,
        type: 60,
        imo: '524288000',
        matchtype: 0,
        cnname: '',
        callsign: 'BAPO',
        length: 1300,
        width: 200,
        left: 150,
        trail: 1130,
        draught: 5000,
        dest: 'LANSHAN,CN',
        eta: '08-01 04:10',
        laststa: 1439241968,
        navistatus: 255,
        lastdyn: 1718602690,
        satelliteutc: 0,
      },
    ])
    isShowShip.value = true
  }
  const closeRightMenu = () => {
    baseMap.value.closeRightMenu()
  }
  const drawLine = () => {
    baseMap.value.drawLine()
  }
  const drawLineEdit = () => {
    baseMap.value.drawLineEdit()
  }
  const cancleDrawLineEdit = () => {
    baseMap.value.cancleDrawLineEdit()
  }
  const getTrack = (start) => {
    return trackList.slice(start * 20, 20 * start + 20)
  }
  // 测试多次追加  "rollup-plugin-javascript-obfuscator": "^1.0.4",
  const testLoad = () => {
    let i = 0
    const interval = setInterval(() => {
      if (trackList.length <= i * 20) {
        interval && clearInterval(interval)
        baseMap.value.appendFinish(status.trackId)
        return
      }
      const list = getTrack(i)
      baseMap.value.appendTrack(status.trackId, list)
      i++
    }, 1000)
  }
  const showTrack = () => {
    status.trackId = baseMap.value.showTrack(
      '123123trackId',
      { name: '船舶名称', mmsi: '0000000' },
      trackList3.init, // trackAi.track1.list, //getTrack(0),
      {
        isEnablePlayer: true, //是否需要播放轨迹,默认值:false
        lineColor: '#00BCD4',
        // ai 检测
        aiDetection: {
          show: true,
          activityColor: '#06c84a',
          datas: [],
          event: {
            clickCallback: (item) => {
              console.log('点击回调函数', item)
              emit('AiDetectionClick', item)
            },
          },
        },
      }
    )
  }

  const emit = defineEmits(['AiDetectionClick'])

  const appendTrack = () => {
    baseMap.value.appendTrack(status.trackId, trackList3.track, trackList3.ai)
    // testLoad()
  }
  const hideOrShowTrack = () => {
    // trackId isHide 是否隐藏 true:隐藏  false:显示 默认true
    baseMap.value.hideOrShowTrack(status.trackId)
    status.trackId = null
  }
  const showTrackForecast = () => {
    baseMap.value.showTrackForecast()
  }
  const hideTrackForeacast = () => {
    baseMap.value.hideTrackForeacast()
  }
  const showNavigationalWarning = () => {
    baseMap.value.showNavigationalWarning()
  }
  const hideNavigationalWarning = () => {
    baseMap.value.hideNavigationalWarning('1')
  }
  const handleChange = (layerType, isShow, item) => {
    let data
    if (layerType === 'showSeaBreeze') {
      data = haifeng.data
    }
    if (layerType === 'showYangliu') {
      data = yangliu.data
    }
    if (layerType === 'showHL') {
      data = hailiu.data
    }
    if (layerType === 'showWind') {
      data = haifeng.data
    }
    baseMap.value.showLayer(layerType, isShow, item, data)
  }

  /**
   * 右键菜单回调函数
   * @param {*} param0
   */
  const rightMenuShip = ({ ship, style }) => {
    console.log(ship, style)
  }
  /**
   * ai 检测回调函数
   * @param {*} item
   */
  const aiDetectionClick = (item) => {
    console.log(item)
  }

  const drawPoline = (type) => {
    baseMap.value.drawPoline(type)
  }
  const showArea = (type) => {
    baseMap.value.showArea(type)
  }
  const cancelLocate = () => {
    baseMap.value.cancelLocate()
  }
  const localPirate = () => {
    baseMap.value.localPirate()
  }
  const cancelLocalPirate = () => {
    baseMap.value.cancelLocalPirate()
  }
  const showNavigation = () => {
    baseMap.value.showNavigation()
  }
  const hideNavigation = () => {
    baseMap.value.hideNavigation()
  }
  const aisNavLocation = () => {
    baseMap.value.aisNavLocation()
  }
  const showShipSj = () => {
    baseMap.value.showShipSj(
      '/ship-tiles/tileserver/mvt/cache?z={z}&x={x}&y={y}&shipNaviStat=0,1,2,3,4,5,6,7,8,15,255&srid=3395',
      {
        elaneOptions: {
          shipDetailURL: '/Ship/GetVector?k={k}',
          drawType: 'solid',
          radius: 3,
          enableMousemove: true,
          enableElaneClick: true,
        },
      }
    )
  }
  const hideShipSj = () => {
    baseMap.value.hideShipSj()
  }
</script>

<style lang="scss" scoped>
  .toolbar {
    position: absolute;
    z-index: 1000;
    background-color: rgb(153 240 255 / 50%);
    backdrop-filter: blur(5px);
    padding: 10px 53px;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    flex-direction: row;
    align-items: stretch;
  }
  .toolbar button {
    margin: 2.5px 5px;
  }
  ul,
  li {
    list-style: none;
  }
</style>

效果图

总览 绘制船舶 选中船舶 历史轨迹 气象轨迹 航行警告 晨昏线