我在手撕 SVG 条形图时踩过的定位坑

本文讲的是我在手撕 SVG 条形图时踩过的定位坑,


让我们来看看这周早些时候我在做一个(看似)简单的条形图的时候学到的用在 SVG 里定位元素的方法吧。

SVG 里并没有多少定位元素的方法。SVG 是一个声明式图形格式,但做一个图表它(实际上)是用绘图命令来进行定位的。所以它有很多潜在的陷阱和令人沮丧的地方,我们来慢慢分析。

我们要构建一个像下面这样的条形图表:

我可以选择用制图软件导出这张图片,再用 <img> 标签引入(甚至可以直接存储为 .svg 文件),但是这样做又有什么意义呢?比起直接用 Sketch 或 Illustrator 文件,我觉得手工制作这张图我能学到到更多的(SVG)语法。

开工,先创建一个 svg 标签来容纳子元素。

<svg width='100%' height='65px'>

</svg>

然后开始做两个长方形。第一个在后面作为背景,第二个在前面代表图表的具体数据:

<svg width='100%' height='65px'>
  <g class='bars'>
    <rect fill='#3d5599' width='100%' height='25'></rect>;
    <rect fill='#cb4d3e' width='45%' height='25'></rect>
  </g>
</svg>

(当没有给 <rect> 元素提供 x 和 y 属性的时候,它们默认是0)

在上面的样例中,我给它们添加一点动画,你可以看到第二个长方形被放在第一个长方形的上面(这像在 Sketch 中绘制了两个长方形,一个叠在另一个上方):

查看 Robin Rendle 在 CodePen 创建的样例示例代码 1

接下来,我们添加一个标记以更容易地读取 0%,25%,50%,75% 和 100% 这样的数据。所以需要做的是建个新的组,并为每个标记添加一个 rect 标签,看起来是这样的吧?肯定没错,但是下一秒我就遇到了一点小问题。

在 SVG 中,用 <g> 标签来绘制图表数据的样式,像下面这样:

<g class='markers'>
    <rect fill='red' x='50%' y='0' width='2' height='35'></rect>
</g>

看起来应该像这样:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 2

很好!让我们添加剩下的全部标记,并更改一下它的颜色:

<g class='markers'>
    <rect fill='#001f3f' x='0%' y='0' width='2' height='35'></rect>
    <rect fill='#001f3f' x='25%' y='0' width='2' height='35'></rect>
    <rect fill='#001f3f' x='50%' y='0' width='2' height='35'></rect>
    <rect fill='#001f3f' x='75%' y='0' width='2' height='35'></rect>
    <rect fill='#001f3f' x='100%' y='0' width='2' height='35'></rect>
</g>

为每一个标记点添加一个 rect 标签,并添加了 fill 标签来改变它的颜色,再用 x 属性来定位。让我们看看他在浏览器渲染成怎样子了:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 3

最后一个去哪了呢? 嗯,我们确实告诉它应该被定位在 100% 的地方,所以它实际上位于屏幕右边。 我们需要考虑它的宽度,并将它向左移动两个单位长度。有很多方法可以解决这个问题。

1.我们可以应用一个内联的变换(transform)样式将它扭转回来:

<rect fill='#001f3f' x='100%' y='0' width='2' height='35' transform="translate(-2, 0)"></rect>

2.我们可以用 CSS 来表示同样的变换:

    rect:last-of-type {
      transform: translateX(-2px); /* Remember this isn't really "pixels", it's a length of 2 in the SVG coordinate system */
    }

3.或者不用百分比,我们可以沿着 X 轴将其标记放在一个精确的地方。由于有 viewBox 属性的存在我们就可以知道 SVG 确切的坐标系了。在 SVG 应用的第六章有提到:

viewBox 是 svg 的一个属性,它决定了坐标系和纵横比。它有四个属性分别为 x,y,宽度和高度。

这么说来我们加上 viewBox 之后应该是这样的:

<svg viewBox='0 0 1000 65'>
  <!-- the rest of our svg code goes here -->
</svg>

条形图的宽度为 1000 个单位。我们的标记宽度是 2 单位。为了能在最右边缘放置最后一个标记,所以我们将它放在 998! (1000 - 2)。 这也是我们的 x 属性:

<svg viewBox='0 0 1000 65'>
  ...
  <rect fill='#001f3f' x='998' y='0' width='2' height='35'></rect>
  ...
</svg>

这样即使我们改变它的大小,标记也还是会位于 SVG 的最右边了:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 4

好极了! 我们不必在这里添加 % 或像素值了,因为这里使用由 viewBox 设置的坐标系。

排序完成后我们接着看下一个问题:在每个标记下面添加 % 的文本,以表示 25%,50% 等。为了做到这一点,我们在 <svg>里面创建一个新的 <g> 标签并添加 <text> 元素。

<g>
    <text fill='#0074d9' x='0' y='60'>0%</text>
    <text fill='#0074d9' x='25%' y='60'>25%</text>
    <text fill='#0074d9' x='50%' y='60'>50%</text>
    <text fill='#0074d9' x='75%' y='60'>75%</text>
    <text fill='#0074d9' x='100%' y='60'>100%</text>
</g>

我们手工在操作这些并且打算用 % 来表示 x 的数值,但是不幸的是最后看起来是这样:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 5

于是我们再次遇到了这个问题,最后一个元素并没有在我们预期的位置。中间标签的位置是错误的,在理想的情况下他们会在标志下面居中。在 Chris 告诉我可以用一个我没有听说过的属性 text-ancho 之前,我本想将每个元素都放置在它正确的 x 坐标上。

有了这个属性我们可以像使用 CSS 中的 text-align 属性一样操纵文本。这个属性是可继承的,所以我们对 g 标签设置一次再指向第一个和最后一个元素就好了。

<g text-anchor='middle'>
  <text text-anchor='start' fill='#0074d9' x='0' y='60'>0%</text>
  <text fill='#0074d9' x='25%' y='60'>25%</text>
  <text fill='#0074d9' x='50%' y='60'>50%</text>
  <text fill='#0074d9' x='75%' y='60'>75%</text>
  <text text-anchor='end' fill='#0074d9' x='100%' y='60'>100%</text>
</g>

就像这样:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 6

就是这样!稍微知道 viewBox 是如何工作的,以及 xy 坐标和像 text-anchor 这样的属性,我们就几乎可以用 SVG 做任何事了。

通过亲手实现这些图表,使得我们能够更好的去控制它们了。不难想象我们如何使用 JavaScript ,就能实现更多的设计,控制更多的数据。

再做一点点额外的工作,我们可以加上动画让这些图表真正的脱颖而出。请尝试将鼠标悬停在此版本的图表上,例如:

查看 Robin Rendle 在 CodePen 创建的样例示例代码 7

看起来非常棒,对吧?只使用 SVG 和 CSS 也可以创造出无限可能。如果你想了解更多可以看我前阵子写的如何使用 SVG 来做图表,来对此进行更深入的理解。

现在让我们开始做一些很帅的图表吧~





原文发布时间为:2016年11月22日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-12-30 09:43:57

我在手撕 SVG 条形图时踩过的定位坑的相关文章

web service-网页上使用SVG文件时出现问题

问题描述 网页上使用SVG文件时出现问题 在自适应网页上使用svg显示地图,设置了方法和缩小按钮,用jqurey控制svg文件的尺寸.现在问题是在svg文件放大以后,图片无法向右拖动,页面的横向偏移量一拖动就会改变,但是一松开鼠标(或者手机上放开手指)就会变成0,造成无法横向浏览放大的svg地图文件.请教各位大神如何解决这个问题?

安装python爬虫scrapy踩过的那些坑和编程外的思考

这些天应朋友的要求抓取某个论坛帖子的信息,网上搜索了一下开源的爬虫资料,看了许多对于开源爬虫的比较发现开源爬虫scrapy比较好用.但是以前一直用的java和php,对python不熟悉,于是花一天时间粗略了解了一遍python的基础知识.然后就开干了,没想到的配置一个运行环境就花了我一天时间.下面记录下安装和配置scrapy踩过的那些坑吧. 运行环境:CentOS 6.0 虚拟机 开始上来先得安装python运行环境.然而我运行了一下python命令,发现已经自带了,窃(大)喜(坑).于是go

js页面滚动时层智能浮动定位实现

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-

7个产品经理/交互新人初入职场时踩过的坑

  前车之鉴后事之师,聪明的人可以从别人的错误中学到经验.这次特意邀请了七位迈入职场不久的产品经理.交互设计师同学,分享那些他们踩过的坑.话不多说,收获有多少,就看你有多聪明啦. 当从象牙塔走入职场,新人们除了兴奋和憧憬以外更多的还有紧张和迷茫:对庞大业务的不熟悉.对工作模式和规范的不了解.对同事和前辈的生疏,都是新人成长的必经之路.有些坑,需要我们亲自踩过才能有深刻的体会,但是前车之鉴后事之师,聪明的人一样可以从别人的错误中学到经验. 这次特意邀请了七位迈入职场不久的产品经理.交互设计师同学,

使用Bakit对SVG编程时,如何从svg文件里获得ellipse结点的位置

问题描述 刚刚接触svg,想编一个可以显示图像和定位元素的小程序.现在遇到的问题是,在svg显示后并经过一系列的坐标平移和缩放变换后,如何获得文件里定义的ellipse在viewport里的现在的cx和cy坐标.通过DOM读出来的只是文档里定义的原始坐标.有没有帮帮忙呀....不胜感激 解决方案 解决方案二:帮帮忙呀....解决方案三:该回复于2011-05-10 13:00:23被版主删除

《javascript模式》读书笔记:容易踩中的那些坑

<javascript模式>第2章 基本技巧 中,讲了一些在前段编程中的一些规范和建议,同时还有一些平常经常忽视且容易踩中的坑. 以下仅是部分内容的摘要和总结,以做备忘用,如有错漏,敬请指出.如需了解更多,可参阅原著,挺不错的书.   1 链式赋值的陷阱 function func(){ var innerVar = globalVar = 20; } func(); console.log(typeof globalVar); //输出结果为? 上面最后的输出结果是?相信不少人会毫不犹豫地说

unix环境高级编程 环境搭建踩过的那些坑~

在UBUNTU下进行APUE的代码编译的话,需要改动的地方很多,尤其是ubuntu12.04下,内核升级到3.0后. 一 首先进行一些改动,将工作区间改变,修改MAKE文件以为编译打基础 http://blog.csdn.net/dycwahaha/article/details/2300938 (一)作者提供的编译方法的实现      README文件中给出的编译方法如下:     To build the source, edit the Make.defines.* file for yo

细数阿里云在使用 Docker 过程中踩过的那些坑

昨天下午道哥在微信上丢给我一条新闻,看看,我们阿里云支持 Docker 企业版了.我打开一看,果然,阿里云发布了飞天敏捷版,开始支持企业级的 Docker 容器. 美国中部时间4月19日,阿里云在容器技术大会 DockerCon 2017上正式推出了 Apsara Stack Agility,也就是飞天的敏捷版.Docker 公司首席执行官 Ben Golub 在大会上宣布了 Apsara Stack Agility 的正式发布,这也是国内第一个支持 Docker 官方企业版(Enterpris

运维专家:我在大数据项目中踩过的那些坑

一.主要讨论人员 提问:陈超,七牛云技术总监 回答:朱冠胤,百度资深大数据专家,连续两次百度最高奖得主. 二.引言 "坐而论道"是一个轮流问答的玩法.本文是大数据主题周中,几位国内一线专家激情问答的一部分内容.期间,各位群友也积极参与. 三.问题集锦 1.MongoDB在百度的使用场景及规模? 2.假设现在让你完全主导一个类似Hadoop的项目,你会选择哪种语言? 3.分享你在百度各种大数据项目中踩过的坑? 4.你所在团队在自研和使用开源方案的主要考虑因素? 5.新一代分布式数据库(N