带摩擦因子的加速度距离计算公式
因为要写一个库,用以模拟现实世界的运动逻辑。在经典力学里,我们常常用匀速运动来说事,但现实中哪有那么好的事情,摩擦力等阻力会让速度慢下来,重力加速度会让速度越来越快等等。
已知:某物体以 v1 的初始速度被加速前进,t1 秒后,速度达到了 v2(v2 > v1)。
求:t2(t2 > t1)时停止加速,物体滑行多长距离之后停下来?
当看到这个题目,作为文科生,我完全懵逼,把毕生学到当物理学知识翻出来也找不到快速解决的办法。所以,只能通过自己的推演慢慢解决这道题目。
分析
这道题的特别之处在于受到了阻力影响,且运动过程分为两段。那么接下来我们来进行受力分析。
第 1 阶段由于受到比 f 大的 F 力的助推,所以呈实际受力为 F - f 的推力,匀加速运动。第 2 阶段由于只受 f 阻力,所以呈匀减速运动。
关于加速运动用到的公式有如下:
- 求加速度公式 a = (v2 - v1) / t
- 求距离公式 s = v1t + at2/2
且公式中如果 v1 为 0,那么更加简单。
由于第 2 阶段物体停下来,只受 f 阻力影响,因此,我们只需要知道 f 所带来的减速度,以及 t2 时的即时速度即可算出滑行需要的时间,进而算出滑行距离。
开始解题
1.计算第一阶段加速度
a1 = (v2 - v1) / t
2.计算到达 t2 时的速度
vx = a1 * t2 = (v2 - v1) * t2 / t
3.计算计算阻力减速度
即时速度比较好算,但是 f 所带来的减速度是多少呢?
根据牛顿第二定律 F = ma。因为质量固定,所以摩擦力 f 所产生的减速度 ax 是固定的。同时根据动摩擦力公式 f = µFn = µG = µmg(µ 为动摩擦因子)。质量和重力加速度都是固定的,所以最终 ax 的大小仅仅和动摩擦因子有关,也就是物质表面的粗糙程度,ax = ƒ(µ)。
现在,我们假设在没有阻力的情况下所产生的加速度为 a0:
kµ = ax / a0
即损失加速度与理想状态(无阻力)加速度之比,k 为一个常量系数,表示摩擦因子与加速度损失之间的某种特定关系,那么
ax = ƒ(µ) ≈ µa0
而对于同一个事物,µ 是固定不变的。又因为
ax = a0 - a1
所以
ax = µa0 = a0 - a1
=> a0 = a1 / (1 - µ)
=> ax = a0 - a1 = a1 / (1 - µ) - a1
=> ax = µa1 / (1 - µ) = µ(v2 - v1) / t(1 - µ)
现在我们得到了摩擦力带来的减速度。
4. 计算停下来要花的时间
我们就可以得到从 t2 开始减速到停止所需要花费的时间:
tx = vx / ax
5. 计算停下来之前滑行的路程
在该时间内物体前进的距离是多少呢?
sx = ax * tx2 / 2
经过上面这些步骤我们就算出了物体滑行的距离。
多端统一开发
这段时间关注了一些利用 react 实现跨平台开发的方案,几乎无一例外,都不能很好的满足我的需要。我的理想是,特别针对移动端开发,写一份代码,然后编译到不同平台,直接运行,除了修改编译工具配置和少量的全局覆盖以外,不对应用本身的代码做任何修改。
我写 Nautil 的目的也是这样。
目前我接触到的跨端开发方案有:
- taro 京东出品,相对比较成熟,需要理解其工作原理,在写法上需要开发者自己遵循一些规则
- kbone 微信小程序团队自己成员开发的针对微信小程序方案,理念上提供虚拟 DOM 挂载节点,从而让整个应用像运行在 web 内部一样,不需要考虑兼容性问题
- remax 理念上和 kbone 很像,同时提供自己的一整套构建、框架,不足在于需要根据不同的小程序引入不同的库,当然,这个可以用构建工具来 alias
目前我自己使用了 kbone 希望能出现更好的方案来解决我的需求。
Great minds discuss ideas;
Average minds discuss events;
Small minds discuss people——埃莉诺·罗斯福(Eleanor Roosevelt)
webpack umd library only for root, replace exports
webpack 导出的 umd 模块在传入了 output.library 的情况下,会输出四个条件语句,大概如下:
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("a"), require("b"));
else if(typeof define === 'function' && define.amd)
define(["a", "b"], factory);
else if(typeof exports === 'object')
exports["o"] = factory(require("a"), require("b"));
else
root["o"] = factory(root["a"], root["b"]);
这样的 umd 模式。其中,关于依赖、导出接口名都可以定制,其中依赖部分通过 externals 配置来定制,导出接口名通过 library 来定制。
但是,现在的一个情况是,在第三个条件句,即红色部分,这个部分会在标准的 commonjs 中被引用。所谓标准的 commonjs 是由 commonjs 官方定义的,只有 exports 和 require 两个关键字的模块方案。而 nodejs 虽然遵循 commonjs,但是在其基础上实现了 module 关键字,将 exports 作为 module.exports 的引用,因此被成为 commonjs2。
我们现在去看这个部分,倘若一个模块在遵循标准 commonjs 的情况下,导出如下:
// a.js exports.a = function a() {}
// b.js exports.b = function b() {}
// main.js export.a = require('./a.js') export.b = require('./b.js')
外部使用这个包,实际上应该是:
const { a, b } = require('./main.js')
但是在 webpack 的 umd 模块下使用时变成了:
// bundle.js exports.o = factory()
那么在外面的其他程序去用这个包时就需要变成下面这种方式才可以:
const { o } = require('./bundle.js') const { a, b } = o
这显然不符合我们的期望,我们希望即使 webpack 打包之后,仍然保持原有的使用方式。所以,我写了一个方法来修改这个部分的输出,经过处理之后,webpack 这个部分的输出将会是:
else if(typeof exports === 'object') { var a = factory(require("a"), require("b")); for (var i in a) exports[i] = a[i]; }
即替换掉原来的输出形式,将原本的输出接口直接赋值到 exports 上,这样就保持了原本的逻辑。
具体做法如下:
// webpack.config.js const { bufferify } = require('webpack-bufferify') const plugins = [ bufferify(function(content, file, assets, compilation, compiler) { if (file.split('.').pop() !== 'js') { return } const { optimization } = compiler.options content = content.toString() content = optimization.minimize === true ? content.replace(/exports\[.*?\]=(.*?):/, `function(e,a){for(var i in a)e[i]=a[i]}(exports,$1):`) : content.replace(/exports\[.*?\](.*?);/, `{ var a$1; for (var i in a) exports[i] = a[i]; }`) return content }), ] module.exports = { ..., plugins, }
webpack-bufferify 是我写的一个组件,用以替换 webpack 输出的结果内容。通过上面的处理,就可以实现我们的目的。
收集 scroll 事件
scroll 事件是不支持冒泡的,那么怎么收集呢?当然是在捕获阶段进行收集了。
document.addEventListener('scroll', (e) => { const target = e.target const isTop = Object.getPrototypeOf(target).constructor.name === 'HTMLDocument' const scrollLeft = isTop ? window.scrollX : target.scrollLeft const scrollTop = isTop ? window.scrollY : target.scrollTop console.log({ target, scrollLeft, scrollTop }) }, true)
这样就可以通过兼容方式收集到滚动事件的信息了。
文字旅行者:一种文本加载(类似打字机)效果
我的博客首页会在一段时间后加上一个作品区域,每个区域都会点缀一点点动效。在 Nautil 的部分,我想实现一个效果,就是在 Nautil 这个单词后面,不断切换 Nautilidae, Nautilus, Nautil.js 这几个单词,效果就像用键盘输入、删除再输入的效果。
在谷歌搜索了一段时间后,我确信没有一个库能够完完整整的实现这个效果。它们都实现了输入效果,但是没有回删效果。于是,我只能自己写一个 js 库来实现这个效果。最终的效果你可以在我的博客首页看到。但是,后来我觉得,这是一个非常不错的效果,虽然在我的博客上看到的是一个输入的效果,但是实际上,对它重新思考,会发现它比这个效果的想象空间大很多。你可以用它来断句、给视频打字幕、利用文字翻语音接口朗读小说。它像一个具有生命的灵活工具,因此,我称它为“文字旅行者”(github:TextTraveler)。
遍历文本怎么才能做到对开发者友好呢?我们以“视频字幕”来举例,如果你想写一个视频字幕,你会怎样?对于我来说,我想象中的写字幕的方式,就是在剧本中打断点。那么什么样的方式可以让我们打断点呢?我想到了 ES6 的字符串模板标签。于是,一个字幕效果就出来了:
`你話三年。${[0,100,1]}三年之後又三年,${[0,100,1]}三年之後又三年!${[0,100,1]}十年都嚟緊頭啦老細!${[0,1000]}`
通过在字符串模板中加入占位符,就可以给字符串打断点了。每个断点的地方加入参数,用以控制该断点前面的文字,将会以怎样的时间或行为出现在字幕中。
如何利用这些参数呢?
使用标签函数即可。我写了 travelText
这个标签函数,它可以生成一个 text traveler 用以处理每个段落。
const traveler = travelText`你話三年。${[0,100,1]}三年之後又三年,${[0,100,1]}三年之後又三年!${[0,100,1]}十年都嚟緊頭啦老細!${[0,1000]}`
接下来所有的事情就交给 traveler 去做。但他实际上只是一个记录者,你可以通过 on
方法监听他记录的内容,并作出相应的界面修改。
而为了更方便的实现我想要的那个效果,我又写了 createTextWriter
函数,它直接在一个 DOM 元素中不断的根据 traveler 的记录情况重写 html 中的文本,从而达到我想要的效果。
一切的一切都在 github 上。
利用 Ps 获得文字或路径的 svg
今天有个需求,电脑上有一些特殊的字体(免费的),想把它们用到网页中,但是因为兼容性问题,所以想转化为 svg 来使用,做到最轻便。本来以为可以通过 Photoshop 直接导出文字的 svg,结果 ps 导出的 svg 是将图片 base64 后的 png 作为 svg 内嵌的图片,也是醉了。于是开始 google,很多文献都指向一条路,就是先在 ps 中抽离出路径,然后用 Illustrator 来导出 svg,但我没有装 illustrator,然后想装一个吧,结果 2g 的安装包,要下 1 天多。。。试了网上各种办法之后,最终找到了自己的办法。现在记录一下。
1.创建路径
如果直接在 ps 里面用路径相关的工具画路径,那就无所谓,随便画。如果是文字转路径,很简单,在图层上右键,选择 convert to shape 即可。这个时候,切换到路径面板,可以看到已有的路径。然后回到图层面板,把所有的图层删除干净,这样,就只保留了路径。如果路径和图层绑定,可以在路径面板复制一下该路径。
2.导出为 .ai
新版的 ps 可以直接导出为 .ai 文件。file -> export -> paths to illustrator
3.在线工具
这一招真的很神,在 google 里搜索 ai to svg,一大堆在线工具可以用,我用了这个可以成功转化。
另,由于 ai 实际上是 pdf,文档尺寸必须按照 pdf 的尺寸来,把要转化的元素放在左上角上,才能最好的控制路径的结果。
4.处理 svg
下载下来 svg 之后,你可以得到所有的路径,但是这些路径是分开的。我的文字,一个字就是一个 path,当然,对于字来说,这是好事,但是对于其他画来说就不是了,你要一个一个的去调试,找到哪一个 path 代表哪一个部分。
经过整理之后,我得到了:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <path style="stroke:#000; fill:none" d="M 4.4891 43.676L 6.2891 43.676L 13.8491 5.75598L 26.2091 5.75598L 26.5691 4.07605L 0.0491 4.07605L -0.3109 5.75598L 12.0491 5.75598L 4.4891 43.676z"/> <path style="stroke:#000; fill:none" d="M 18.4089 56.996C 23.5689 56.996 26.8089 52.076 29.0889 47.636L 47.0889 14.996L 45.2889 14.996L 35.0889 33.7161C 33.5289 36.5961 31.9689 39.4761 30.5289 42.2361L 30.2889 42.2361C 29.9289 39.5961 29.4489 36.4761 28.9689 33.7161L 25.9689 14.996L 24.2889 14.996L 29.0889 44.276L 27.7689 46.916C 25.2489 52.076 22.1289 55.436 18.5289 55.436C 17.8089 55.436 17.2089 55.316 16.4889 54.9561L 15.7689 56.396C 16.8489 56.876 17.8089 56.996 18.4089 56.996z"/> <path style="stroke:#000; fill:none" d="M 58.8483 44.396C 66.0483 44.396 71.5683 39.8361 71.5683 32.876C 71.5683 28.556 69.0483 25.796 65.3283 23.636L 60.1683 20.636C 57.4083 19.076 54.8883 16.916 54.8883 13.076C 54.8883 9.11609 58.3683 4.91595 63.7683 4.91595C 68.0883 4.91595 71.3283 7.07605 73.3683 9.71606L 74.6883 8.63599C 72.6483 5.75598 68.9283 3.35608 64.1283 3.35608C 57.5283 3.35608 53.0883 8.03595 53.0883 13.316C 53.0883 17.516 56.0883 20.276 59.3283 22.196L 64.6083 25.316C 67.7283 27.1161 69.7683 29.516 69.7683 33.1161C 69.7683 38.996 65.0883 42.8361 59.0883 42.8361C 53.9283 42.8361 50.3283 40.676 47.8083 36.8361L 46.3683 37.796C 49.0083 41.996 53.2083 44.396 58.8483 44.396z"/> <path style="stroke:#000; fill:none" d="M 77.2077 43.676L 78.8877 43.676L 83.2077 22.196C 87.7677 17.756 91.3677 15.8361 94.0077 15.8361C 97.8477 15.8361 99.4077 17.756 99.4077 21.4761C 99.4077 22.676 99.2877 23.516 98.9277 25.316L 95.2077 43.676L 96.8877 43.676L 100.608 25.076C 100.968 23.396 101.088 22.676 101.088 21.2361C 101.088 17.1559 99.1677 14.276 94.2477 14.276C 90.7677 14.276 87.5277 16.556 83.6877 19.796L 83.4477 19.796L 84.1677 17.0359L 87.5277 0.355957L 85.8477 0.355957L 77.2077 43.676z"/> <path style="stroke:#000; fill:none" d="M 107.087 32.636C 107.087 40.316 111.287 44.396 117.887 44.396C 121.007 44.396 124.007 42.9561 126.287 41.276L 125.447 39.9561C 123.287 41.516 120.647 42.8361 118.007 42.8361C 112.007 42.8361 107.387 38.756 109.127 29.1559L 129.647 29.1559C 130.007 27.9561 130.367 26.276 130.367 24.3561C 130.367 18.4761 127.967 14.276 121.847 14.276C 114.527 14.276 107.087 21.7161 107.087 32.636zM 109.487 27.5961C 111.047 20.756 116.327 15.8361 121.727 15.8361C 126.887 15.8361 128.687 19.916 128.687 23.996C 128.687 25.316 128.567 26.396 128.327 27.5961L 109.487 27.5961z"/> <path style="stroke:#000; fill:none" d="M 134.926 43.676L 136.726 43.676L 142.246 16.076C 142.846 12.8361 143.446 8.99597 144.046 5.75598L 144.286 5.75598L 145.726 14.276L 150.046 39.1161L 152.086 39.1161L 165.646 14.276L 170.326 5.75598L 170.566 5.75598C 169.846 8.87598 169.006 12.8361 168.286 16.076L 162.766 43.676L 164.566 43.676L 172.486 4.07605L 169.486 4.07605L 156.286 27.9561L 151.606 36.9561L 151.366 36.9561L 149.806 27.9561L 145.846 4.07605L 142.846 4.07605L 134.926 43.676z"/> <path style="stroke:#000; fill:none" d="M 185.326 44.396C 193.126 44.396 200.326 36.2361 200.326 25.556C 200.326 18.3561 196.606 14.276 190.846 14.276C 183.046 14.276 175.846 22.436 175.846 33.1161C 175.846 40.316 179.566 44.396 185.326 44.396zM 185.446 42.8361C 180.406 42.8361 177.526 39.3561 177.526 32.756C 177.526 23.636 184.246 15.8361 190.726 15.8361C 195.766 15.8361 198.646 19.316 198.646 25.916C 198.646 35.0359 191.926 42.8361 185.446 42.8361z"/> </svg>