首页 文章 精选 留言 我的

精选列表

搜索[智博会],共10000篇文章
优秀的个人博客,低调大师

每日一博 | 揭开链表的真面目

链表是一种常见的数据结构,链表是由一连串的结点组成,这个节点就是链结点,每个链结点都由数据域和指针域两部分组成。 使用链表结构可以克服数组结构需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。 链表比较好的一种理解是:将链表看成一个火车,每个车厢之间都是相互连接的,只要找到火车头,就可以找到具体的车身。链表也是,我们只关心它的头。 一 单向链表 1.1 单向链表原理图 单向链表的一个链结点包含数据域和下一个链结点的指针。头结点也包含数据域和指针域,但是一般为了方便查找,头节点不写数据,最后一个结点的指针指向空。 1.2 实现单向链表的存储等操作 创建一个链结点的实体类 publicclassNode{//数据域publiclongdata;//指针域publicNodenext;publicNode(longvalue){this.data=value;}} 1.2.1 插入一个节点 在头节点后插入一个结点,第一步需要将新插入的结点指向头结点指向的结点,第二步将头结点指向新插入的结点。插入结点只需要改变一个引用,所以复杂度为O(1)。 i publicclassLinkList{privateNodehead;/***在头节点之后插入一个节点*/publicvoidinsertFirst(longvalue){Nodenode=newNode(value);node.next=head;head=node;}} 1.2.2 头结点后删除一个结点 在头结点后删除一个结点,就是让头结点指向这个结点的下一个结点。复杂度也是O(1)。 publicNodedeleteFirst(){Nodetmp=head;head=tmp.next;returntmp;} 1.2.3 根据数据域查找结点 查找需要比对每个结点的数据,理论上查找一个结点平均需要N/2次,所以复杂度为O(N)。 publicNodefind(longvalue){Nodecurrent=head;while(current.data!=value){if(current.next==null){returnnull;}current=current.next;}returncurrent;} 1.2.4 根据数据与删除结点 查找需要比对每个结点的数据,理论上删除一个结点平均需要N/2次,所以复杂度为O(N)。 publicNodedelete(intvalue){Nodecurrent=head;//当前结点的前一个结点Nodepre=head;while(current.data!=value){if(current.next==null){returnnull;}pre=current;current=current.next;}if(current==head){head=head.next;}else{pre.next=current.next;}returncurrent;} 二 双端链表 2.1 双端链表原理图 双端链表是在单向链表的基础上,头结点增加了一个尾结点的引用。 2.2 实现双端链表的存储等操作 2.2.1 从头部插入结点 如果链表为空,则设置尾结点就是新添加的结点。复杂度为O(1)。 publicclassFirstLastLinkList{privateNodefirst;privateNodelast;/***在头结点之后插入一个节点*/publicvoidinsertFirst(longvalue){Nodenode=newNode(value);if(first==null){last=node;}node.next=first;first=node;}} 2.2.2 从尾部插入结点 如果链表为空,则设置头结点为新添加的结点,否则设置尾结点的后一个结点为新添加的结点。复杂度为O(1)。 publicvoidinsertLast(longvalue){Nodenode=newNode(value);if(first==null){first=node;}else{last.next=node;}last=node;} 2.2.3 从头部进行删除 判断头结点是否有下一个结点,如果没有则设置尾结点为null,复杂度为O(1)。 publicNodedeleteFirst(){Nodetmp=first;if(first.next==null){last=null;}first=tmp.next;returntmp;} 三 双向链表 3.1 双向链表原理图 每个结点除了保存对后一个结点的引用外,还保存着对前一个结点的引用。 3.2 实现双向链表的存储等操作 链结点实体类 publicclassNode{//数据域publiclongdata;//后一个结点指针域publicNodenext;//前一个结点指针域publicNodeprev;publicNode(longvalue){this.data=value;}} 3.2.1 从头部插入结点 如果链表为空,则设置尾结点为新添加的结点,如果不为空,还需要设置头结点的前一个结点为新添加的结点。插入结点只需要改变两个结点的引用,所以复杂度为O(1)。 publicclassDoubleLinkList{privateNodefirst;privateNodelast;/***在头结点之后插入一个节点*/publicvoidinsertFirst(longvalue){Nodenode=newNode(value);if(first==null){last=node;}else{first.prev=node;}node.next=first;first=node;}} 3.2.2 从尾部插入结点 如果链表为空,则设置头结点为新添加的结点,否则设置尾结点的后一个结点为新添加的结点。同时设置新添加的结点的前一个结点为尾结点。插入结点只需要改变1个结点的引用,所以复杂度为O(1)。 publicvoidinsertLast(longvalue){Nodenode=newNode(value);if(first==null){first=node;}else{last.next=node;node.prev=last;}last=node;} 3.2.3 从头部删除结点 判断头结点是否有下一个结点,如果没有则设置尾结点为null,否则设置头结点的下一个结点的prev为null。复杂度也为O(1)。 publicNodedeleteFirst(){Nodetmp=first;if(first.next==null){last=null;}else{first.next.prev=null;}first=tmp.next;returntmp;} 3.2.4 从尾部删除结点 如果头结点后没有其他结点,则设置头结点为null,否则设置尾结点的前一个结点的next为null,设置尾结点为前一个结点。复杂度为O(1)。 publicNodedeleteLast(){Nodetmp=last;if(first.next==null){first=null;}else{last.prev.next=null;}last=last.prev;returnlast;} 四 总结 链表包含一个头结点和多个结点,头结点包含一个引用,这个引用通常叫做first,它指向链表的第一个链结点。结点的next为null,则意味着这个结点是尾结点。与数组相比,链表更适合做插入、删除操作,而查找操作的复杂度更高。还有一个优势就是链表不需要初始化内存大小,不会造成内存溢出(数组中插入元素个数超过数组长度)或内存浪费(声明的数组长度比实际放的元素长)。 < END > 往期精选 ☞ 揭开数组的真面目 ☞ 聊聊Mysql中的int(1) ☞ 如何有效防止SQL注入攻击 ☞ 《RabbitMQ》什么是死信队列 ☞ 《RabbitMQ》如何保证消息不被重复消费 ☞ 《RabbitMQ》如何保证消息的可靠性 本文分享自微信公众号 - Java旅途(Javatrip)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

每日一博 | 滴滴数据分析实践

↑ 点击上方 “凹凸数据”关注 + 星标 ~ 每天更新,干货&福利不断 hi,我是 Rilke Yang 这是一篇我关于滴滴的数据实战,之前首发在和鲸,这次投稿到凹凸数据,希望能够帮助到大家~ 原文链接:https://www.kesci.com/home/project/5f06b0193af6a6002d0fa357 随着企业日常经营活动的进行,企业内部必然产生了各式各样的数据,如何利用这些数据得出有益的见解,并支持我们下一步的产品迭代以及领导决策就显得尤为重要。 A/B测试是互联网企业常用的一种基于数据的产品迭代方法,它的主要思想是在控制其他条件不变的前提下对不同(或同一、同质)样本设计不同实验水平(方案),并根据最终的数据变现来判断自变量对因变量的影响;A/B测试的理论基础主要源于数理统计中的假设检验部分,此部分统计学知识读者可自行探索。 长话短说,本次实战用到的数据集分为两个Excel文件,其中test.xlsx为滴滴出行某次A/B测试结果数据,city.xlsx为某城市运营数据。 数据说明 test.xlsx city.xlsx date:日期 date:日期 group:组别(控制组/实验组) hour:时点 requests:订单请求数 requests:请求数 gmv:成交总额 trips:订单数 coupon per trip:每单优惠券金额 supply hours:可服务时长 trips:订单数 average minutes of trips:平均订单时长(分钟) canceled requests:取消请求数 pETA:顾客预计等待时长 aETA:顾客实际等待时长 utiliz:司机在忙率 test.xlsx 数据可以用来判断实验条件对此次A/B测试的结果影响是否显著;city.xlsx 数据可以用来探索该城市运营中出现的问题,根据关键结论辅助决策。 在本文中,我们将使用该数据来做A/B测试效果分析与城市运营分析。 一、A/B测试效果分析 1、数据导入 #A/B测试结果数据导入importpandasaspdtest=pd.read_excel('/home/kesci/input/didi4010/test.xlsx')test.head() 2、计算ROI #计算优惠券投入相对gmv的ROItest['ROI']=test['gmv']/(test['couponpertrip']*test['trips'])test.head() 3、requests检验 数据共58条,对照组与实验组各29条,样本量<30。 3.1 requests方差检验 记两组requests方差分别为从c1,c2 零假设H0:c1=c2;备选假设:H1:c1≠c2 显著性水平取0.05 #levene检验requests是否齐方差requests_A=test[test.group=='control'].requestsrequests_B=test[test.group=='experiment'].requestsimportscipy.statsasstst.levene(requests_A,requests_B) p值大于0.05,不拒绝原假设,因此可认为两组实验requests齐方差。 3.2 requests均值检验 该数据为同一样本实验前后的不同水平,因此选用配对样本t检验。 记两组requests均值分别为从u1,u2 零假设H0:u1=u2;备选假设:H1:u1≠u2 显著性水平取0.05 #配对样本t检验(两独立样本t检验之前需检验是否齐方差,此处不需要)st.ttest_rel(requests_A,requests_B) p值大于0.05,不拒绝原假设,因此可认为实验条件对requests影响不显著。 4、gmv检验 4.1 gmv方差检验 #levene检验gmv是否齐方差gmv_A=test[test.group=='control'].gmvgmv_B=test[test.group=='experiment'].gmvst.levene(gmv_A,gmv_B) p值大于0.05,不拒绝原假设,因此可认为两组实验gmv齐方差。 4.2 gmv均值检验 #配对样本t检验(两独立样本t检验之前需检验是否齐方差,此处不需要)st.ttest_rel(gmv_A,gmv_B) p值小于0.05,拒绝原假设,因此可认为实验条件对gmv有显著影响。 5、ROI检验 5.1 ROI方差检验 #levene检验ROI是否齐方差ROI_A=test[test.group=='control'].ROIROI_B=test[test.group=='experiment'].ROIst.levene(ROI_A,ROI_B) p值大于0.05,不拒绝原假设,因此可认为两组实验ROI齐方差。 5.2 ROI均值检验 #配对样本t检验(两独立样本t检验之前需检验是否齐方差,此处不需要)st.ttest_rel(ROI_A,ROI_B) p值小于0.05,拒绝原假设,因此可认为实验条件对ROI有显著影响。 二、城市运营分析 1、数据导入 #导入该城市运营相关数据city=pd.read_excel('/home/kesci/input/didi4010/city.xlsx')city.head() #查看数据有无缺失值city.info() 2、数据探索 2.1 单量最多的时间点 req_hour=city.groupby(['hour'],as_index=True).agg({'requests':sum},inplace=True)req_hour #绘制各时点订单请求柱状图importmatplotlib.pyplotaspltreq_hour.plot(kind='bar')plt.xticks(rotation=0)plt.show() 可见,在11、12、13这三个时间点内,12点用户发起订单的需求是最大的,其次是13点,11点。 司机运营平台应考虑加大该时点车辆供应。 2.2 单量最多的日期 req_date=city.groupby(['date'],as_index=True).agg({'requests':sum},inplace=True)req_date.sort_values('date').head() #绘制订单请求数随日期变化的折线图req_date.plot(kind='line')plt.show() 单月订单请求数随日期的变化呈周期性变化,我们猜测4个峰值分别对应4个周末,周末用户出行需求较大。 经验证发现猜想与数据吻合,因此司机运营平台应考虑加大周末、节假日的车辆供给。 2.3 各时段订单完成率 com_hour=city.groupby(['hour'],as_index=False).agg({'requests':sum,'trips':sum},inplace=True)com_hour['rate']=com_hour['trips']/com_hour['requests']com_hour 13点订单需求较多,但订单完成率仅47%,说明较多订单没有得到及时相应。 客运部应重点关注13点订单相应时长,排查具体原因。 2.4 单月每日订单完成率 com_date=city.groupby(['date'],as_index=True).agg({'requests':sum,'trips':sum},inplace=True)com_date['rate']=com_date['trips']/com_date['requests']com_date.sort_values('date').head() #绘制订单完成率随日期变化的折线图com_date.rate.plot(kind='line')plt.show() 单月每日订单完成率规律不太明显,但几个谷值基本都出现在周末附近,说明客户出行需求的提升可能导致响应率的降低。 2.5 顾客等待时间 importnumpyasnpeta_hour=city.groupby(['hour'],as_index=True).agg({'pETA':np.mean,'aETA':np.mean},inplace=True)eta_hour #绘制顾客等待时长复合柱状图eta_hour.plot(kind='bar') 以上可见,无论哪个时点,用户实际等待时长均明显大于用户预计等待时长。 各时点用户等待时长差异不明显,但13点最高。 客运部一方面应提升用户预计等待时长的准确性,另一方面优化平台派单逻辑等。 2.6 司机在忙率 city['busy']=city['supplyhours']*city['utiliz']city.head() busy_hour=city.groupby(['hour'],as_index=False).agg({'supplyhours':sum,'busy':sum})busy_hour['utiliz']=busy_hour['busy']/busy_hour['supplyhours']busy_hour 12点司机在忙总时长最长,在忙率也最高,用户订单请求也最多,说明车辆总数偏少。 2.7 订单时长 trip_min=city.groupby(['hour'],as_index=False).agg({'averageminutesoftrips':np.mean})trip_min 12点用户订单需求较多,同时订单时长最长,说明这个时间点是一个非常重要的时间点。 supply_hour=city.groupby(['hour'],as_index=False).agg({'supplyhours':np.mean})supply_hour 13点订单量也较大,此时点司机服务时长较短。 为优化用户出行体验,司机运营平台可联合客运部可考虑此时段尽量分配总服务时长较长的司机来接单(经验较为丰富)。 3、后续思考方向: 提升顾客预计等待时长预测准确度(需要历史数据进行预测) 加大车辆投入(分车辆不同等级来看,因此可能需要车辆相关信息表) 优化用户体验(需要客诉相关数据) 优化平台派单逻辑(需要订单的位置相关数据) 个性化需求(需要用户属性、及其他行为数据) 本文相关代码下载: https://alltodata.cowtransfer.com/s/9bb9acdc15ae40 推荐一本书,本周末统一上架 感谢北京大学出版社的大力支持 PS 当当新用户优惠码:DPC3CX 满60-20,亲测可以换手机号使用 本文分享自微信公众号 - 凹凸数据(alltodata)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

每日一博 | 向强大的 SVG 迈进

作者:凹凸曼 - 暖暖 SVG 即 Scalable Vector Graphics 可缩放矢量图形,使用XML格式定义图形。 一、SVG印象 SVG 的应用十分广泛,得益于 SVG 强大的各种特性。 1.1、 矢量 可利用 SVG 矢量的特点,描出深圳地铁的轮廓: 1.2、iconfont SVG 可依据一定的规则,转成 iconfont 使用: 1.3、 foreignObject 利用 SVG 的 foreignObject 标签实现截图功能,原理:foreignObject 内部嵌入 HTML 元素: <svg xmlns="http://www.w3.org/2000/svg"> <foreignObject width="120" height="60"> <p style="font-size:20px;margin:0;">凹凸实验室 欢迎您</p> </foreignObject> </svg> 截图实现流程: 首先声明一个基础的 svg 模版,这个模版需要一些基础的描述信息,最重要的,它要有 <foreignObject></foreignObject> 这对标签; 将要渲染的 DOM 模版模版嵌入 foreignObject 即可; 利用 Blob 构建 svg 对象; 利用 URL.createObjectURL(svg) 取出 URL。 1.4、SVG SMIL 由于微信编辑器不允许嵌入 <style><script><a> 标签,利用SVG SMIL 可进行微信公众号极具创意的图文排版设计,包括动画与交互。 但是也要注意,标签里不允许有id,否则会被过滤或替换掉。 点击 "凹凸实验室" 后,围绕 "凹凸实验室" 中心旋转 360度,点击0.5秒后 出现 https://aotu.io/ ,动画只运行一次。 下图为 GIF循环演示: 代码如下: <svg width="360" height="300" xmlns="http://www.w3.org/2000/svg"> <g> <!-- 点击后 运行transform旋转动画,restart="never"表示只运行一次 --> <animateTransform attributeName="transform" type="rotate" begin="click" dur="0.5s" from="0 100 80" to="360 100 80" fill="freeze" restart="never" /> <g> <text font-family="microsoft yahei" font-size="20" x="50" y="80"> 凹凸实验室 </text> </g> <g style="opacity: 0;"> <!-- 同一个初始位置以及大致的宽高,触发点击事件 --> <text font-family="microsoft yahei" font-size="20" x="50" y="80">https://aotu.io/</text> <!-- 点击后 运行transform移动动画,改变文本的位置 --> <animateTransform attributeName="transform" type="translate" begin="click" dur="0.1s" to="0 40" fill="freeze" restart="never" /> <!-- 点击0.5秒后 运行opacity显示动画 --> <animate attributeName="opacity" begin="click+0.5s" from="0" to="1" dur="0.5s" fill="freeze" restart="never" /> </g> </g> </svg> 以上是鄙人对SVG的大致印象,最近的需求开发再次刷新了我的认知,那就是 SVG实现非比例缩放 以及 小程序不支持SVG标签的处理,下面容我来讲述一番。 二、SVG 实现非比例缩放 我们熟知的 iconfont,可通过改变字体大小缩放,但是这是 比例缩放,那如何实现 SVG 的非比例缩放呢? 如下图所示,如何将 一只兔子 非比例缩放? 划重点:实现非比例缩放主要涉及三个知识点:viewport、viewBox和preserveAspectRatio,viewport 与viewBox 结合可实现缩放的功能,viewBox 与 preserveAspectRatio 结合可实现非比例的功能。 2.1、viewport viewport 表示SVG可见区域的大小。 viewport 就像是我们的显示器屏幕大小,超出区域则隐藏,原点位于左上角,x 轴水平向右,y 轴垂直向下。 通过类似CSS的属性 width、height 指定视图大小: <svg width="400" height="200"></svg> 2.2、viewBox viewBox值有4个数字:x, y, width, height 。 其中 x:左上角横坐标,y:左上角纵坐标,width:宽度,height:高度。 原点默认位于左上角,x 轴水平向右,y 轴垂直向下。 <svg width="400" height="200" viewBox="0 0 200 100"></svg> 显示器屏幕的画面,可以特写,可以全景,这就是 viewBox。 viewBox 可以想象成截屏工具选中的那个框框,和 viewport 作用的结果就是 把框框中的截屏内容再次在 显示器 中全屏显示。 (图片来源:SVG 研究之路 (23) - 理解 viewport 與 viewbox) 2.3、preserveAspectRatio 上图的红色框框和蓝色框框,恰好和显示器的比例相同,如果是下图的绿色框框,怎样在显示器屏幕中显示呢? 2.3.1、 定义 preserveAspectRatio 作用的对象是 viewBox,使用方法如下: preserveAspectRatio="[defer] <align> [<meetOrSlice>]" // 例如 preserveAspectRatio="xMidYMid meet" 其中 defer 此时不是重点,暂且忽略,主要了解 align 和 meetOrSlice 的 用法: align:由两个名词组成,分别代表 viewbox 与 viewport 的 x 方向、y方向的对齐方式。 值 含义 xMin viewport 和 viewBox 左边对齐 xMid viewport 和 viewBox x轴中心对齐 xMax viewport 和 viewBox 右边对齐 YMin viewport 和 viewBox 上边缘对齐。注意Y是大写。 YMid viewport 和 viewBox y轴中心点对齐。注意Y是大写。 YMax viewport 和 viewBox 下边缘对齐。注意Y是大写。 meetOrSlice:表示如何维持高宽的比例,有三个值 meet、slice、none。 meet - 默认值,保持纵横比缩放 viewBox 适应 viewport,可能会有余留的空白。 slice - 保持纵横比同时比例小的方向放大填满 viewport,超出的部分被剪裁掉。 none - 扭曲纵横比以充分适应 viewport。 2.3.2、 例子 例子1:preserveAspectRatio="xMidYMid meet" 表示 绿色框框 与 显示器的 x 方向、y方向的 中心点 对齐; 例子2:preserveAspectRatio="xMidYMin slice" 表示 绿色框框 与 显示器的 x 方向 中心点 对齐,Y 方向 上边缘对齐,保持比例放大填满 显示屏 后超出部分隐藏; 例子3:preserveAspectRatio="xMidYMid slice" 表示 绿色框框 与 显示器的 x 方向、y方向的 中心点 对齐,保持比例放大填满显示屏 后超出部分隐藏; 例子4:preserveAspectRatio="none" 不管三七二十一,随意缩放绿色框框,填满 显示屏即可;这就是非比例缩放的答案了。 三、小程序不支持svg标签怎么办 微信小程序官方不支持 SVG 标签的,但是决定曲线救国,相当于自己实现了一个SVG标签:使用小程序内置的 Canvas 渲染器, 在 Cax 中实现 SVG 标准的子集,使用 JSX 或者 HTM(Hyperscript Tagged Markup) 描述 SVG 结构行为表现。 但是今天我想讲讲其他的。 我们知道,小程序虽然不支持 SVG 标签,但是支持 svg 转成 base64 后作为 background-image 的 url,如 background-image: url("data:image/svg+xml.......) 。 但是我这边还有个需求,随时更改 SVG 每个路径的颜色,即 颜色可配置: 来回转 Base64 肯定是比较麻烦的,有没有更好的方式呢? 直接贴答案:对于SVG图形,还有更好的实现方式,就是直接使用SVG XML格式代码,无需进行base64转换。 3.1、URL 编码 直接使用 SVG XML 格式代码,首先要了解 Data URI的格式。 划重点:base64非必选项,不指定的时候,后面的 <data> 将使用 URL编码。 3.1.1、入门 百分号编码(Percent-encoding), 也称作URL编码(URL encoding),是特定上下文的统一资源定位符 (URL)的编码机制。 原理:ASCII 字符 = % + 两位 ASCII 码(十六进制)。 例如,字符 a 对应的 ASCII 码为 0x61,那么 URL 编码后得到 %61 。 3.1.2、URL 编码压缩 前言: Data URI 的格式中的 <data> 完全使用URL 编码也是可以的,如 encodeURIComponent('<svg version="1.1" viewBox= …</svg>')。 但是和转义前原始SVG相比,可读性差了很多,而且占用体积也变大了。 如果深入了解URL 编码的话,<data> 没必要全部编码的。 正文: RFC3986文档规定,URL中只允许包含 未保留字符 以及 所有保留字符。 未保留字符:包含英文字母(a-zA-Z)、数字(0-9)、-_.~ 4个特殊字符。对于未保留字符,不需要百分号编码。 保留字符:具有特殊含义的字符 :/?#[]@ (分隔Url的协议、主机、路径等组件) 和 !$&'()*+,;= (用于在每个组件中起到分隔作用的,如&符号用于分隔查询多个键值对)。 受限字符或不安全字符:直接放在Url中的时候,可能会引起解析程序的歧义,因此这部分需要百分号编码,如%、空格、双引号"、尖号 <>等等。 综上所述,只需要对 受限字符或不安全字符 进行编码即可。 JS 处理比较简单,利用 replace 将 需要编码的字符 替换掉 即可,基本替换 以下的符号 就够用了: svgToUrl (svgData) { encoded = encoded .replace(/<!--(.*)-->/g, '') // 亲测必须去掉注释 .replace(/[\r\n]/g, ' ') // 亲测最好去掉换行 .replace(/"/g, `'`) // 单引号是保留字符,双引号改成单引号减少编码 .replace(/%/g, '%25') .replace(/&/g, '%26') .replace(/#/g, '%23') .replace(/{/g, '%7B') .replace(/}/g, '%7D') .replace(/</g, '%3C') .replace(/>/g, '%3E') return `data:image/svg+xml,${encoded}` } 如果使用在 CSS 中,可利用 SASS版本3.3以上 的 三个API 对 SVG字符串做替换处理。 str_insert(string, insert, index): 从 $string 第 $index 插入字符 $insert; str_index(string, substring): 返回 $substring 在 $string 中第一个位置; str_slice(string, start_at, end_at = nil): 返回从字符 $string 中第 $start_at 开始到 $end_at 结束的一个新字符串。 前人已有总结,可前往 https://github.com/leeenx/sass-svg/blob/master/sass-encodeuri.scss 查看完整代码。 3.2、SVG 压缩 一般从 Sketch 导出 SVG ,冗余代码比较多,有条件的话建议使用 SVGO 压缩SVG的原本体积,比如清除换行、重复空格;删除文档声明;删除注释;删除desc描述等等。 四、总结 SVG强大的地方在于,出其不意,炫酷,与众不同。 无论是微信公众号花式排版,foreignObject 标签实现截图,实现非比例缩放,或者 背景图直接使用 SVG XML 格式代码,还是上文没有提及的路径动画、描边动画、图形裁剪、滤镜等等,都可以玩出新的花样。 SVG 一个属性可成就一篇文章,学习 SVG 可以说是在挑战自己,欢迎加入 SVG 的学习队列。 五、参考内容 · 推荐阅读 三看 SVG Web 动效 URL编码的奥秘 学习了,CSS中内联SVG图片有比Base64更好的形式 超级强大的SVG SMIL animation动画详解 详细教你微信公众号正文页SVG交互开发 SVG <foreignObject>简介与截图等应用 欢迎关注凹凸实验室博客:aotu.io 或者关注凹凸实验室公众号(AOTULabs),不定时推送文章:

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册