vue3实现模拟地图上,站点名称按需显示的功能
很久很久没有更新博客了,因为实在是太忙了,每天都有公司的事情忙不完.......
最近在做车辆模拟地图,在实现控制站点名称按需显示时,折腾了好一段时间,特此记录一下。最终界面如下图所示:

站点显示需求:首末站必须显示,从第一个站开始,如果站点名称能显示下,则显示,如果站点名称会重叠则隐藏,以此类推。当界面宽度变化时,车辆模拟地图自动变化,保证站点名称能够最大限度的显示。
最开始我用的比例换算法,算法复杂度是O,结果总是不准。尽管一开始我就觉得算法的复杂度应该是O2。我之前一直想着只遍历一次就算出来,
需要注意的地方:由于站点的名称内容是千奇百怪的,可以有空格,各种特殊图标,所以站点文字的长度计算是一个问题,这里是通过canvas来计算的。还有,这里我添加了一个限制,站点文字内容我最大显示120px,超出隐藏并显示省略号,站点名称上添加了title显示全称。
/**
* 获取站点名称
* @param item
* @param showFullName 是否总是显示站点全名
*/
/** */
export const getSiteName = (item: any,showFullName?:boolean=false) => {
const { siteSign } = simulatedMapConf.value;
let name = '';
if (siteSign == 'firstWord') {
name = getSubStrByPreNum(item.stationName);
} else if (siteSign == 'order') {
name = item.stationSeq + '';
} else {
if(showFullName){
name=item.stationName;
}else{
name =item.show? item.stationName:''; //show控制站点名称是否显示
}
}
return name || '';
}
/**
* 获取站点名称宽度
* @param item 站点对象
* @param showFullName 是否总是显示站点全名
* @returns
*/
export const getSiteNameWidth = (item: any,showFullName?:boolean=false) => {
const name =showFullName?item.stationName: getSiteName(item,showFullName);
const width= calculateStringWidth(name);
return width>siteMaxWidth?siteMaxWidth:width;
}
/**
* 根据字符串计算出界面渲染的宽度
* @param str
* @returns
*/
function calculateStringWidth(str:string) {
// 创建一个虚拟的 <canvas> 元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置字体样式
ctx.font = '12px sans-serif';
// 使用 canvas 的 measureText 方法测量字符串的宽度
const width = ctx.measureText(str).width;
// 返回计算出的宽度
return width;
}
最核心的算法:
//计算上行站点,控制站点是否显示在模拟地图上
function calcSite(station: any, lineWidth: number) {
if (station.length < 1) return [];
station.forEach((f: any, index) => {
f.show=false;
});
let lastSiteLength = getSiteNameWidth(station[station.length - 1], true) / 2;//站点文字宽度
let lastLeft = getSiteCx(station[station.length - 1], station.length - 1);//最后一个站点left
lastLeft = toDecimal(lastLeft - lastSiteLength);
station.forEach((f: any, index) => {
let siteLength = getSiteNameWidth(f, true);//站点文字宽度
let bigHalf = siteLength / 2;//获取当前的半宽
f.left = getSiteCx(f, index);
if (index == 0 || index == station.length - 1) { //第一项和最后一项必须显示
f.show = true;
} else {
const preShowIndex = getLastTrueIndex(station); //获取前面最近一个显示站点的索引
const preEndLeft = toDecimal(station[preShowIndex].left + getSiteNameWidth(station[preShowIndex], true) / 2);//上一项显示的站点名称结束left位置
f.show = toDecimal(f.left - bigHalf) >=preEndLeft && preEndLeft < lastLeft; //如果上一个显示站点文字的结尾位置 小于等于 当前站点文字的开始位置 并且小于最后一个站点文字的开始位置
if (f.show && toDecimal(f.left + bigHalf) > lastLeft) {
f.show = false;
}
}
})
}
下行站点的计算有些差别,因为left基本上是反着的:
//计算下行站点,控制站点是否显示在模拟地图上 getDownSiteCx
function calcDownSite(station: any, lineWidth: number) {
if (station.length < 1) return [];
station.forEach((f: any, index) => {
f.show=false;
});
let lastSiteLength = getSiteNameWidth(station[station.length - 1], true) / 2;//站点文字宽度
let lastLeft = getDownSiteCx(station[station.length - 1], station.length - 1);//最后一个站点left
lastLeft = toDecimal(lastLeft + lastSiteLength);
station.forEach((f: any, index) => {
let siteLength = getSiteNameWidth(f, true);//站点文字宽度
let bigHalf = siteLength / 2;//获取当前的半宽
f.left = getDownSiteCx(f, index);
if (index == 0 || index == station.length - 1) { //第一项和最后一项必须显示
f.show = true;
} else {
const preShowIndex = getLastTrueIndex(station); //获取前面最近一个显示站点的索引
const preEndLeft = toDecimal(station[preShowIndex].left - getSiteNameWidth(station[preShowIndex], true) / 2);//上一项显示站的的结束left位置
f.show = toDecimal(f.left + bigHalf) <=preEndLeft && preEndLeft > lastLeft;
if (f.show && toDecimal(f.left - bigHalf) < lastLeft) {
f.show = false;
}
}
})
}
另外获取站点中心点位置的方法
//获取上行站点水平x位置
const getSiteCx = (item: any, index: number) => {
return startleft.value + dLayout.lineWidth * index;
}
//获取下行站点水平x位置
const getDownSiteCx = (item: any, index: number) => {
return downStartleft.value - layout.endLine - dLayout.downLineWidth * index;
}
说明:站点的布局采用css绝对定位。第一个版本这块我是采用的svg画的,后来发现扩展起来越来越麻烦,周末就在家花了半天时间全部改造为html实现了。
vue3实现模拟地图上,站点名称按需显示的功能的更多相关文章
- MeteoInfo-Java解析与绘图教程(七)_图层添加站点名称或区域名称
MeteoInfo-Java解析与绘图教程(七)_图层添加站点名称或区域名称 在上文说了用自动站的数据经过插值绘制色斑图,这种一般是在geoserver上叠加图片呈现,但遇到后端导出图片,我们又想添加 ...
- WordPress获取首页网站链接和站点名称
利用bloginfo 获取WordPress网站名称和主页链接 用法一: $blog_title = get_bloginfo('name'); //获取站点名称 $linkzmki = get_bl ...
- 罗列Linux发行版的基础目录名称,命令法则和功能
罗列Linux发行版的基础目录名称命名法则及功用规定 目录描述 /主层次 的根,也是整个文件系统层次结构的根目录 /bin存放在单用户模式可用的必要命令二进制文件,所有用户都可用,如 cat.ls.c ...
- SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...
- python测试开发django-21.admin后台表名称和字段显示中文
前言 admin后台页面表名称(默认会多加一个s)和字段名称是直接显示在后台的,如果我们想设置成中文显示需加verbose_name和verbose_name_plural属性 verbose_nam ...
- 为axure生成的html站点添加关闭所有节点的功能
上一篇随笔:将Axure用于需求分析工具中,我分享了我做了一个axure部件,方便用axure中制作各种uml图. 用axure的朋友可能会发现一个问题,如下图,axure生成的html站点中所有的文 ...
- NuGetTools:批量上传、删除和显示NuGet包
快照 前言 NuGet是.NET开发必不可少的包管理工具,在日常更新版本过程中,可能需要批量发布 NuGet 包,也不可避免需要发布一些测试的包,后期想将这些测试或者过期的包删除掉.nuget.org ...
- 上传媒体文件--添加显示进度条 layui的upload控件
上传媒体文件--添加显示进度条 layui的upload控件 详细上传功能请参考博客:上传文件--媒体文件+获取上传文件的属性信息 layui的upload控件 - じ逐梦 - 博客园 (cnbl ...
- [django]Django站点admin支持中文显示和输入设置
正文: Django站点admin支持中文输入设置,操作如下: 1 需要确定的你的数据库的client客户端和服务端的编码设置为utf-8,如果不是,请将其设置成utf-8编码,我采用mysql,详情 ...
- iOS:实现MKAnnotation协议,在地图上设置大头针,点击显示具体的位置信息
如何添加大头针(地标): 通过MapView的addAnnotation方法可以添加一个大头针到地图上 通过MapView的addAnnotations方法可以添加多个大头针到地图上 –(void)a ...
随机推荐
- [FE] G2Plot 在 Vue 中使用 CDN 方式避免构建时增大 js 体积
使用 npm.yarn 方式安装的包,虽方便使用,但是会极大增加 vendor.xx.js 体积,拖慢网站运行速度. 以 G2Plot 为例,实际在 build 构建时,会下载一些额外字体到 vend ...
- SemanticFunction 自然语言函数
本文将和大家介绍 LLM 的魔法,通过自然语言编程的方式开发 SemanticFunction 函数 大家都知道,编程里面的函数可以是一个完成某个功能的逻辑片段,绝大部分的函数都需要使用人类不友好的编 ...
- WPF 开源二维绘画小工具 GeometryToolDemo 项目
这是一个演示 WPF 进行二维绘画的小工具 Demo 项目,基于 MIT 协议在 GitHub 上完全开源 源作者是 YuWeiCong 我只是帮助开源的工具人 软件运行界面效果: 开源地址: htt ...
- dotnet Roslyn 通过读取 suo 文件获取解决方案的启动项目
本文来告诉大家一个黑科技,通过 .suo 文件读取 VisualStudio 的启动项目.在 sln 项目里面,都会生成对应的 suo 文件,这个文件是 OLE 格式的文件,文件的格式没有公开,本文的 ...
- PageOffice6最简集成代码(Asp.Net)
本文描述了PageOffice产品在普通的Asp.Net项目中如何集成调用. 新建Asp.Net项目:PageOffice6-Net-Simple 在您的web项目的"依赖项-包-管理NuG ...
- npm创建项目
创建项目 创建项目目录 首先新建一个文件夹,这里存放着我们的项目. 创建项目文件 这里不使用任何项目模板,相当于使用空模板. 进入这个文件夹,再cmd中运行npm init. 然后按照提示输入pack ...
- 文件系统(四):FAT32文件系统实现原理
FAT32是从FAT12.FAT16发展而来,目前主要应用在移动存储设备中,比如SD卡.TF卡.隐藏的FAT文件系统现在也有被大量使用在UEFI启动分区中. 为使文章简单易读,下面内容特意隐藏了很多实 ...
- containerd 源码分析:kubelet 和 containerd 交互
0. 前言 Kubernetes:kubelet 源码分析之创建 pod 流程 介绍了 kubelet 创建 pod 的流程,其中介绍了 kubelet 调用 runtime cri 接口创建 pod ...
- Istio(十二):Istio问题排查
目录 一.模块概览 二.Envoy基础 2.1 Envoy 基础 三.Envoy示例 四.调试备忘录 4.1 配置 4.2 运行时 4.3 检查 Envoy 日志 4.4 配置 istiod 日志 一 ...
- GeminiDB PITR,让游戏回档“进退自如”!
本文分享自华为云社区<GeminiDB PITR,让游戏回档"进退自如"!>,作者:GaussDB 数据库. 在实际业务场景中,客户数据库难免会出现数据损毁.数据丢失. ...