lbp的blog

纸上得来终觉浅,绝知此事要躬行

0%

工作笔记

记录了日常工作中值得记录的内容
移动端如果使用vConsole进行调试有发送post请求有可能失败 - 20210113
玉溪项目遇到的一些bug - 20201223
chrome 网络请求错误以及排查 - 20200908
d3.js 树图的实现 - 20200805
mapbox 异常点的处理 - 20200805

vConsole 引起的请求错误

https://github.com/Tencent/vConsole/issues/223

玉溪项目bug

  • 后端在人数,数量一些问题上使用了 int,前端使用了 el-input。 自定义指令 v-number 解决

    • int 超出最大值报错,前端校验
    • el-input 输入非数字,前端校验
  • 在测试阶段会有频繁的部署需求,虽然 webpackcss js 打包做了 hash 后缀。但是 spa 项目的入口 index。html 并没有处理缓存

  • 直接通过cookie查询用户信息,而不是id

    • 不安全,随便换一个id就可以看到别人信息
  • mixin 抽取

    chrome 网络请求错误以及排查 - 20200908

    在实际项目中,遇到的一个chrome bug,具有一定的误导性。bug的复现的必要条件如下:

  • chrome -> network -> disable cache 取消勾选

  • 使用 img 标签和 XMLHttpRequest 请求同一个图片(保证这个图片之前没有请求过)
    简化代码如下:

    1
    2
    3
    4
    5
    6
    <p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="html,result" data-user="sdlbp" data-slug-hash="qBZxmOQ" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="chrome bug demo">
    <span>See the Pen <a href="https://codepen.io/sdlbp/pen/qBZxmOQ">
    chrome bug demo</a> by liubaopeng (<a href="https://codepen.io/sdlbp">@sdlbp</a>)
    on <a href="https://codepen.io">CodePen</a>.</span>
    </p>
    <script async src="https://static.codepen.io/assets/embed/ei.js"></script>

在这种情况下, chrome 会提示一个关于 cors 的错误信息。如下所示(截图来自实际项目中截图,上面代码提示错误类似):
chrome 中的错误提示

细心的读者可能这个时候就会疑问了,为什么明明两个请求,一个成功,另外错误,提示跨域。

这个问题在我们当时开发的场景下比较诡异:

  • 有些同学的浏览器是两个请求都可以正常加载
  • 不能正常加载的同学,是一个提示了跨域,但是另外一个可以正常展示。而且在oss上已经针对跨域进行了配置

基本情况就是这样,那么是什么原因造成的呢?你有答案吗。

针对这个问题,最后借助的 chrome://net-export/# 进行了分析,发现原来是 XMLHttpRequest 的请求走了缓存,但是这个时候其实是没有缓存数据的。所以报错了,比较诡异的是报 cors , 个人认为是 chrome的bug。
chrome 网络请求分析

所以,针对这个问题解决方案就很明了了。
只要区分两个相同的请求就可以,我们是在第二次请求中挂了 query 参数

mapbox 异常点的处理 - 20200805

背景: 服务返回的gis点有异常数据, 比如查询山东-青岛的商家gis点, 返回的数据中会有零星的其它城市坐标. 如果对这些异常坐标点不处理, 会导致用户视角体验不好

处理前后效果对比

gis点处理前
gis点处理后
以上两个图片可以看出, 在 gis点处理前 视角没有聚焦到点较密集的区域, 在 gis点处理后 的视角, 较符合心里预期
视角的确定使用了函数 envelope 确定区域, 在区域确定之后调用 fitBounds 漫游到指定区域

如何剔除异常点?

观察 gis点处理前 图片可以发现: 大多gis都是汇聚在一起, 只有零星的散落. 换句话说大多数点的距离都是差不多的, 异常点距离较远, 最终订下如下方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 伪代码
* 1. 寻找gis点中位数参考点A
* 2. 计算gis点距离A点距离,排序
* 3. 截取排序后gis点
*/
function formatGeojson(geojson, k = 0.9) {
const features = Array.from(geojson.features)
if (features.length <= 10) return geojson
// 欧式距离
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0)
// 寻找中位数
const lngList = features.map(v => v.geometry.coordinates[0]).sort()
const latList = features.map(v => v.geometry.coordinates[1]).sort()
const lngIndex = Math.max(0, Math.floor(lngList.length / 2))
const latIndex = Math.max(0, Math.floor(latList.length / 2))
const lngM = lngList[lngIndex]
const latM = latList[latIndex]
// 距离排序
features.sort((a, b) => {
return distance(lngM, latM, a.geometry.coordinates[0], a.geometry.coordinates[1]) - distance(lngM, latM, b.geometry.coordinates[0], b.geometry.coordinates[1])
})
// 截取一定范围坐标点
return {
type: 'FeatureCollection',
features: features.slice(0, Math.floor(features.length * k))
}
}

其实对于这个问题也可以使用电子围栏, 判断某个 gis 点是否在指定区域内.
就我们问题来说, 因为支持市/县 这种级别, 电子围栏对于数据的采集有一定的要求, 不如以上方式来的便捷

d3.js 树图的实现 - 20200805

背景: UI设计出来的树图效果定制化程度很高, echarts g6 等可视化工具满足不了需求, 最终使用 d3 基本完成

设计/实现

UI设计效果
最终实现效果

遇到的问题

最终的实现效果基本是在 Collapsible Tree 进行修改, 效果图如下
参考模板

连接线处理

参考模板 中可以看出, 连接线是首尾相接的, 但是UI图中的连接线是从一个节点的尾部开始, 连接到下一个节点的头部
其实对于这个问题, 经常使用 d3 的开发者, 在参考 Collapsible Tree 基础上应该可以很快的定位出来问题所在
连接线的绘制使用了函数

1
diagonal = d3.linkHorizontal().x(d => d.y).y(d => d.x)

直接对这个函数进行改造, 起始点位置偏移出节点的宽度就可以

1
2
3
4
5
6
7
8
9
10
11
// 线段生成
this.diagonal = d3.linkHorizontal().x(d => d.y).y(d => d.x)
.source(function (d) {
var s = d.source
let offset = 0
if (s.hasOwnProperty('depth')) {
offset = this.wh[`l${d.source.depth}`][1]
if (+d.source.depth === 0) offset -= 40
}
return {x: s.x, y: s.y + offset}
})

树图节点定制化程度很高

UI设计效果 中每个节点的定制化程度还是很高的, 每个节点都有背景图片, 一些定制化的字体等
如果在 svg 中实现这种效果基本不可能. 但是使用html + css 就很得心应手了
所以这个问题就转换为: 如果在 svg 中插入 html ?
答案是: 使用 svgforeignObject 标签
l0节点的结构

后端返回数据的加工

对于这个树图, 产品对于展示数据的需求是, 展示出来 字段说明 + 字段值
对外下属投资方 , 需要展示出来 字段说明: 被投资公司名称, 关系类型, 以及这两个字段的对应值.参考下图
不同字段展示效果
后端返回的数据结构如下:

1
2
3
4
5
6
7
8
9
10
{
"code": 200,
"message": "success",
"data": [
{
"companyName": "大鹏证券有限责任公司",
"investType": "投资进入"
}
]
}

每一个二级节点, 都对应一个独立的接口, 返回的结构都如上所示是一个 数组, 数组元素为对象.
我们知道对于树图, 他有自己的数据结构, 如下:

1
2
3
4
5
6
7
{
"children": [
{
"children": []
}
]
}

一层一层 children 嵌套
所以, 目前来看我们需要构造一个函数:

  1. 可以满足树图数据的使用, children的嵌套
  2. 对后端返回的字段进行映射, 10个接口中每个字段的映射
    最终实现如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function formatTreeChildren (data, map) {
    return data.map(v => {
    let item = null
    for (const key in map) {
    item = {
    name: v[key] || '暂无',
    relation: map[key],
    children: item ? [item] : null
    }
    }
    return item
    })
    }
    // 以对外下属投资方来说, 调用如下
    // this.formatTreeChildren(data, {investType: '关系类型', companyName: '被投资公司名称'})
    树图数据处理