Canvas绘制折线图时,线条总是超出容器边界怎么办?
在用Canvas画折线图时遇到了怪问题,设置好容器宽高后,线条总会从右边和底边溢出。我试过给canvas加了max-width:100%,还用flex布局包裹容器,但效果没变化。
这是我的CSS代码:
.canvas-container {
width: 80%;
margin: 20px auto;
border: 1px solid #ccc;
overflow: hidden;
}
canvas {
display: block;
width: 100%;
height: 100%;
background: #f5f5f5;
}
画布初始化用了const ctx = canvas.getContext('2d'),然后用path绘制了多段线。明明计算坐标时预留了边距,但最后一个点总会超出容器右边框。是不是哪里没考虑像素比?或者CSS设置冲突了?
你用CSS设置了width: 100%,这只是把Canvas显示区域拉伸了,但Canvas内部的绘图分辨率还是默认的300x150。所以你画图时的坐标系统和实际显示尺寸根本对不上,线条超出边界太正常了。
正确的做法是直接设置Canvas元素的width和height属性,而且要在JS里动态设置,顺便处理一下设备像素比:
另外你提到的坐标计算问题,这里要做校验。画图之前先确认一下几个关键参数:
还有几点要注意:
第一,
getBoundingClientRect()返回的值可能是小数,要取整,不然在某些浏览器里会有1像素的偏差。第二,数据范围计算时要防一手除零错误,尤其是
maxVal === minVal的情况,我就被这个坑过,线上报错找了半天。第三,如果图表容器后面会resize,记得监听窗口变化重新初始化Canvas尺寸,不然拉伸一下就全乱套了。
你先改一下Canvas的初始化方式,应该就能解决超出边界的问题。
你虽然给canvas设置了100%宽高,但canvas元素本身有默认的width和height属性,比如
300x150,这是绘图上下文的实际分辨率。当你用CSS拉伸它时,浏览器会缩放这个画布,导致绘制失真、坐标偏移,看起来就像线条溢出。解决办法分两步:
第一,让canvas的绘制宽高和显示宽高一致。假设你的容器实际尺寸是800x400,那你得设置:
或者动态获取:
第二,考虑设备像素比,不然高清屏会模糊:
这时候你再用原来的坐标逻辑绘图,就不会超出边界了。记得重算坐标时别忘了dpr的影响,尤其是留边距的地方。
还有个小建议:画折线前先清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height),避免旧图形叠加造成视觉误差。这个问题表面看是前端布局,其实跟我们服务端生成图片时遇到的渲染偏差是一类问题,根本都是像素对不上。