现实生活中的SVG。 Yandex报告

嗨,我叫Artyom,我是Yandex界面开发小组的负责人。 一周前,在Ya。Subbotnik上,我告诉了我们如何使用SVG创建内部日历。 这是我的报告的抄本,其中包括日历小部件实现的一些故事:缩放,图案填充,蒙版,符号和格式功能。



-Yandex中有很多人在不同城市,不同时区工作,您需要了解同事什么时候忙,什么时候可以见面和交谈。 我们决定设计一个日历,以帮助查找。

当然,我们从布局开始。 他看起来像这样:



它显示填充不同的偶数和奇数事件。 与其他事件重叠的事件位于第二层-另一个填充。 一整天都在忙碌的事件。 当前时间如下所示。 那是目标。



我们开始选择要做的事情。 制作了几种不同的原型。 我们从画布开始,但是有很多代码,需要手动缩放才能编写。 我们的想法是,日历会根据需要占用尽可能多的空间,在不同的布局中,日历的形状和大小会有所不同。 对于画布来说,这很复杂。

当我们生成具有线性渐变的整个图片时,有一个很酷的原型,但是当缩放和切换到视网膜时,它会移出。 因此,最后,我们来到了SVG。 怎么了 首先,有一个完全独立于文档的坐标系,因此您可以将所有内容完全放置在内部,并且无论任何情况都不会中断。 缩放也可以正常进行。 即使放大浏览器,如果您打开视网膜或以某种方式拉伸日历,日历也会像图片一样调整大小,无论如何看起来都是正常的。 我们在版式上填充了一个单元格,并且SVG填充了图案非常好。



要绘制日历,您需要一些数据。 要在布局上绘制一个日期,您需要知道它的开始日期(通常是当前日期),以知道水平的天数,垂直显示的小时数以及日历中一天的开始时间。 我们需要以某种方式获取事件。

由于我们在不同时区设有许多办事处,因此我们决定将事件始终在UTC进行,并且我们已经将它们显示在客户端上,以供用户使用,因为需要查看我们所在时区和该人所在时区的日历,您正在查看日历的人-要了解现在是晚上,最好不要预约。 以红色突出显示的内容将在以后使用。



让我们从基础开始。 SVG是一个巨型坐标平面,可以在其上任意放置矢量图形。 同时,我们看到的区域部分由viewBox决定,其边界背后是隐藏在类固醇上的溢出。 无论是什么,它都不可见。 为了简化计算,我们决定将日历中的一个像素等于一分钟。 因此,一小时将恰好占据60像素。 为了使其更简单,我们决定一天的宽度也应为60像素-以便一切都像军队一样是正方形的。 然后他们开始排版。

Viewbox由四个参数设置。 前两个是坐标系中的左上点,从该点开始考虑viewBox,对于我们来说,它是0.0。 宽度为60 *天数,高度为60 *小时数。

将其他SVG文档插入SVG内是有效的,这些文档内部将具有自己的坐标系。 为了使当天的事件只能沿垂直轴定位,我们决定每天有一个单独的SVG,然后将它们水平移动60 *到日历中当天的位置。 然后所有事件都可以简单地垂直设置在Y中,这将非常方便。 然后在每个SVG(一天)中放置一个矩形,以显示当天的填充情况。

由于未指定填充颜色,因此此矩形将继承SVG的fill属性。 在这种情况下,这一天正在工作,并且每周休息两天,因此它们充满了阳光。 这仅由类决定。



有一个空白。 现在,您需要添加网格。 由于我们要调整日历的大小,并且网格线应始终为单个像素,因此我们使用了vector-effect = non-scaling-stroke属性。 这导致这样一个事实,无论我们如何调整大小或缩放,总会有一个单像素网格。 仅添加适当数量的水平和垂直线就足够了,并且将会有这样的网格。



我们已经弄清了基础,让我们继续进行全天活动。 这是一件棘手的事情。 您注意到日历上有活动,并且有“全天”复选标记。 这些事件全天不同,无论您在哪个时区都可以看到。 因此,如果该事件在阿拉斯加时区的最开始部分在清晨开始,则在地球另一端48小时内的某个地方仍将继续。 听起来很复杂,但是最容易实现:只需将日期与显示的日期进行比较即可。 如果成功,则表示当天发生了事件。 如果一天中有两个事件属于当天,则显示稍后开始的事件。 因此,填充显示整天的事件。



对于其他事件,则要困难一些。 假设有一个会议。 它是蓝色的,一切都很简单。 但是,如果连续召开两次会议,根据我们的布局,我们将用不同的颜色填充它们,它们是偶数和奇数。

如果一个会议与另一个会议相交,位于较高位置,则需要以某种方式显示它。 如果有会议交叉口,则将它们完全分别倒入单元格中。 为了使我们变得更加有趣,我们不仅有会议,还有缺席,会议等等。 我不想在布局中对所有这些进行硬编码,因此我们决定弄清楚它在CSS中是如何或多或少的跨浏览器和方便的配置。



现在,将有整个报告中最困难的示例,请耐心等待,然后进行三个步骤,然后变得更加容易。

让我们按顺序开始。 SVG具有<defs>标记,它允许您在其中声明未显示的元素,但是您可以通过引用引用它们来使用它们。 我们要做的第一件事是声明<defs>并在其中创建一个模式。 <pattern>是一个标签,允许您声明一个模式,可用于用特定模式填充特定元素。

我们需要以这种模式制作单元格。 我们有60 x 60像素,像元应该是6 x 6,因此我们声明了12 x 12的图案,并在其中绘制了<path>,如左图所示。 它具有属性d,该属性准确指示线的移动方式。 它从点0,0开始,然后坐标显示箭头如何绘制。 如果将其填充为白色,则会得到以下模式:未填充白色的是黑色。



转到下一步,现在声明掩码。 <mask>是SVG中的此类元素,允许您向其他元素添加Alpha通道。 在蒙版中应用蒙版的元素中,蒙版中用黑色绘制的内容是不可见的,透明的。 涂成白色的是不透明的。 灰色是半透明的。 我们有一个黑白图案,我们将在遮罩内添加一个矩形,并用该图案填充它。 现在我们有一个面具。

下一步是<symbol>。 SVG中的标签就是这样,您可以声明可重用的图形。 大多数情况下,符号用于例如图标。 在这里我们声明一个符号,在其中放置两个矩形。 一个没有填充任何东西,因此它继承了父SVG的fill属性,另一个则填充了currentColor并对其应用了蒙版。 现在,我们将有两个矩形:一个带有孔并填充有currentColor的矩形,另一个没有孔并填充有填充的矩形。 他们躺在彼此的顶部。 如果我们将这些颜色设置为相同,则将填充为纯色。 如果不同的话-细胞。 这一切都过去了。 现在,您可以使用CSS并通过类为所有事件设置两种颜色的任意填充。



现在,您需要确定在给定日期应在日历中包括哪些事件。 我们的时区为+3,我们所有人都坐在那里,时区从9到20个小时。 还有一个人坐在有条件的Orenburg中,他的时区为+5,相对于我们,他的天平偏移了两个小时。 我们将在UTC上进行投影,然后看到在UTC上需要在底部显示从上到下的间隔,以便用户可以在时区之间切换,既可以查看属于他的日历的事件,也可以查看正在查看的人的日历。

请记住这些数字,它们是有偏移的,因为最容易将到达UTC的事件定位在同一UTC中。 为此,我们使用<g>标记(在SVG中表示一个组),然后将所有事件绝对通过UTC定位在该位置,然后将<g>移位需要显示一个或另一个时区的像素数。



总结这项研究,我们得到一个我们要参考的符号,其中有一个事件类型,级别,奇偶性,从UTC开始到今天有-120分钟,持续时间为30分钟。 通过添加所有事件,我们得到了这样的画面。



当前时间也可以简单地完成,它将是一条具有相同非缩放描边效果的行,因此它始终是单个像素。 这样显示。

时间不会停滞不前,箭头必须移动。 我们想到的最酷的方法是动画。 我们决定制作一个动画,将一天中的箭头移动分钟数,然后在一天中完成。 为了使它不会一直缓慢移动,即每分钟滴答一次,我们使用了步骤()。 一旦我们添加了它,时间就开始移动。 同时,实际上,由于动画不能保证它会不断移动,因此它要么滞后,要么其他。 但是我们的日历中的事件会不时更新,每两到三分钟的某个地方或当用户离开标签页并返回时,整个日历将被重绘并更新时间。 因此,只有当您坐着并专心观看动画是否在滴答作响时,动画才可见。



有一个问题。 在这里,我将日历制作得更宽,使它看起来更像生产中的日历。 显然,这些单元不再是正方形的。 这是因为未保留比例,并且如果我们物理上拉伸或更改纵横比,则它会像图片中那样改变。 为了避免这种情况,您需要编写一些JS。 我们的原始SVG中有长宽比viewBox,而在我们的布局中有实际的长宽比。 如果找到这些比率的比率,然后将其放入图案的变换中,则单元将变为正方形。 如果我们想了解用户点击的位置,也可以使用此处获得的系数。 由于我们在原始SVG中有1分钟等于一个像素,因此,通过点击坐标乘以该系数,我们可以了解用户几点钟了。



仍然需要添加HTML,以便在顶部带有字母和数字。 获取日历。



因此,这是通过位于+5时区的用户的眼睛在生产中看到的。 下面是同事按下的一个拨动开关,日历在时区中移动。 然后,他单击该事件,然后看到星期六在+5时区,也就是现在,我的报告打开了。



还有更多的例子。 这是开发人员的日历,他有站立式演讲,几次例会,仅此而已。 这是经理的日历。 这是设计师。

使用CSS,使用SVG。 谢谢你

Source: https://habr.com/ru/post/zh-CN461571/


All Articles