cax-svg - update readme & sync lib from mps

This commit is contained in:
dntzhang 2019-04-17 07:18:55 +08:00
parent f3dbfcbb18
commit 2424493588
15 changed files with 127 additions and 52 deletions

BIN
assets/cax-svg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,23 +1,70 @@
http://tutorials.jenkov.com/svg/index.html
# 今天,小程序正式支持 SVG
todo:
经过腾讯 Omi 团队的努力,今天你可以在小程序中使用 SVG!
* 自动轮播支持 http://tavmjong.free.fr/blog/wp-content/uploads/BATMAN/batman_logos.svg (间隔时间支持)
* debug bounds box
* pasition easing function
SVG 是可缩放矢量图形(Scalable Vector Graphics)基于可扩展标记语言用于描述二维矢量图形的一种图形格式。它由万维网联盟制定是一个开放标准。SVG 的优势有很多:
* Transformation + tojs
* Transformation
* boundsX 和 boundsY
* text
* image
* SVG Viewport and View Box
* event handler
* jsx support(extend omip)
* SVG 使用 XML 格式定义图形,可通过文本编辑器来创建和修改
* SVG 图像可被搜索、索引、脚本化或压缩
* SVG 是可伸缩的,且放大图片质量不下降
* SVG 图像可在任何的分辨率下被高质量地打印
* SVG 可被非常多的工具读取和修改(比如记事本)
* SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性、可编程星更强
* SVG 完全支持 DOM 编程,具有交互性和动态性
vscode 安装 lit-html 使 html`内容` 高亮
而支持上面这些优秀特性的前提是 - **需要支持 SVG 标签**。比如在小程序中直接写:
```html
<svg width="300" height="150">
<rect
bindtap="tapHandler" height="100" width="100"
style="stroke:#ff0000; fill: #0000ff">
</rect>
</svg>
```
上面定义了 SVG 的结构、样式和点击行为。但是小程序目前不支持 SVG 标签,仅仅支持加载 SVG 之后 作为 background-image 进行展示,如 `background-image: url("data:image/svg+xml.......)`,或者 base64 后作为 background-image 的 url。
那么怎么办呢?有没有办法让小程序支持 SVG? 答案是有的!需要下面这些东西(站在巨人的肩膀上):
* JSX史上最强 UI 表达式,支持书写 XML-Hyperscript 互转的 JS 语言
* 小程序内置 Canvas 渲染器
* [Cax 最新渲染引擎](https://github.com/Tencent/omi/tree/master/packages/cax-svg/cax)
* HTMHyperscript Tagged Markup可能是 JSX 的替代品或者另一种选择使用ES标准的模板语法实现的 Hyperscript 运行时/编译时生成preact 作者(也是google工程师)打造
一句话总结:
> 使用小程序内置的 Canvas 渲染器, 在 Cax 中实现 SVG 标准的子集,使用 JSX 或者 HTM 描述 SVG 结构行为表现
直接看在小程序种使用案例:
```js
import { html, renderSVG } from '../../cax/svg'
Page({
onLoad: function () {
renderSVG(html`
<svg width="300" height="220">
<rect bindtap="tapHandler"
height="110" width="110"
style="stroke:#ff0000; fill: #ccccff"
transform="translate(30) rotate(45 50 50)">
</rect>
</svg>`, 'svg-a', this)
},
tapHandler: function () {
console.log('你点击了 rect')
}
})
```
小程序种显示效果:
import testSVG from 'svg/test'
renderSVG(testSVG, 'canvas-id', this)
在来一个复杂的例子,用 SVG 绘制 Omi 的 logo:

View File

@ -9,7 +9,7 @@ function renderSVG(vdom, canvas, scope) {
canvas,
scope
)
const svg = new SVG(vdom)
const svg = new SVG(vdom, scope)
stage.add(svg)
stage.update()
triggerAddedStage(svg)

View File

@ -3,7 +3,7 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function circle(props) {
export function circle(props, scope) {
const options = Object.assign(
{
r: 0,
@ -18,6 +18,6 @@ export function circle(props) {
// circle.y = Number(options.cy)
transform(props, circle, Number(options.cx), Number(options.cy))
parseEvent(props, circle)
parseEvent(props, circle, scope)
return circle
}

View File

@ -3,7 +3,7 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function ellipse(props) {
export function ellipse(props, scope) {
const options = Object.assign(
{
rx: 0,
@ -22,6 +22,6 @@ export function ellipse(props) {
// ellipse.x = Number(options.cx)
// ellipse.y = Number(options.cy)
transform(props, ellipse, Number(options.cx), Number(options.cy))
parseEvent(props, ellipse)
parseEvent(props, ellipse, scope)
return ellipse
}

View File

@ -2,7 +2,7 @@ import Group from '../render/display/group'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function group(props) {
export function group(props, scope) {
const options = Object.assign(
{
width: 0,
@ -18,7 +18,7 @@ export function group(props) {
// obj.y = Number(options.y)
transform(props, obj, Number(options.x), Number(options.y))
parseEvent(props, obj)
parseEvent(props, obj, scope)
return obj
}

View File

@ -9,12 +9,13 @@ import { path } from './path'
import { pasition } from './pasition'
import { group } from './group'
import { animate } from './animate'
import { parseEvent } from './parse-event'
class SVG extends Group {
constructor(vdom) {
constructor(vdom, scope) {
super()
this.vdom = vdom
this.scope = scope
if (Object.prototype.toString.call(this.vdom) === '[object Array]') {
this.vdom = this.vdom.filter(item => typeof item !== 'string')[0]
}
@ -29,43 +30,43 @@ class SVG extends Group {
)
this.vdom.children && this.vdom.children.forEach(vdomChild => {
this.generate(root, vdomChild)
this.generate(root, vdomChild, scope)
})
root.x = Number(options.x)
root.y = Number(options.y)
parseEvent(vdom.props, root, scope)
this.add(root)
}
generate(parent, vdomChild) {
generate(parent, vdomChild, scope) {
switch (vdomChild.type) {
case 'rect':
parent.add(rect(vdomChild.props))
parent.add(rect(vdomChild.props, scope))
break
case 'circle':
parent.add(circle(vdomChild.props))
parent.add(circle(vdomChild.props, scope))
break
case 'ellipse':
parent.add(ellipse(vdomChild.props))
parent.add(ellipse(vdomChild.props, scope))
break
case 'line':
parent.add(line(vdomChild.props))
parent.add(line(vdomChild.props, scope))
break
case 'polyline':
parent.add(polyline(vdomChild.props))
parent.add(polyline(vdomChild.props, scope))
break
case 'polygon':
parent.add(polygon(vdomChild.props))
parent.add(polygon(vdomChild.props, scope))
break
case 'path':
const obj = path(vdomChild.props)
const obj = path(vdomChild.props, scope)
parent.add(obj)
if (
vdomChild.children &&
@ -77,14 +78,14 @@ class SVG extends Group {
break
case 'pasition':
parent.add(pasition(vdomChild.props))
parent.add(pasition(vdomChild.props, scope))
break
case 'g':
const p = group(vdomChild.props)
const p = group(vdomChild.props, scope)
parent.add(p)
vdomChild.children.forEach(child => {
this.generate(p, child)
this.generate(p, child, scope)
})
break
}

View File

@ -3,7 +3,7 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function line(props) {
export function line(props, scope) {
const obj = new Line(
Number(props.x1),
Number(props.y1),
@ -12,6 +12,6 @@ export function line(props) {
parseStyle(props)
)
transform(props, obj)
parseEvent(props, obj)
parseEvent(props, obj, scope)
return obj
}

View File

@ -1,4 +1,4 @@
export function parseEvent(props, obj) {
export function parseEvent(props, obj, scope) {
if (!props) return
const tapHandler =
@ -22,7 +22,11 @@ export function parseEvent(props, obj) {
obj.on('touchend', evt => {
if (_x !== null) {
if (Math.abs(evt.stageX - _x) < 20 && Math.abs(evt.stageY - _y) < 20) {
tapHandler(evt)
if (typeof tapHandler === 'string') {
scope[tapHandler]()
} else {
tapHandler(evt)
}
_x = null
_y = null
}

View File

@ -6,7 +6,7 @@ import pathTransition from '../pasition/index'
import color from '../common/color'
import { toSVGString } from '../common/util'
export function pasition(props) {
export function pasition(props, scope) {
const lerp = color.lerp
const obj = new Path(props.from, parseStyle(props))
const fs = props['from-stroke']
@ -22,7 +22,7 @@ export function pasition(props) {
obj.pasitionTo = props.to
obj.pasitionFrom = props.from
transform(props, obj)
parseEvent(props, obj)
parseEvent(props, obj, scope)
let stage,
isFrom = true,

View File

@ -3,9 +3,9 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function path(props) {
export function path(props, scope) {
const obj = new Path(props.d, parseStyle(props))
transform(props, obj)
parseEvent(props, obj)
parseEvent(props, obj, scope)
return obj
}

View File

@ -3,13 +3,13 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function polygon(props) {
export function polygon(props, scope) {
const points = props.points
.split(/\s+|,/)
.filter(item => item !== '')
.map(item => Number(item))
const obj = new Polygon(points, parseStyle(props))
transform(props, obj)
parseEvent(props, obj)
parseEvent(props, obj, scope)
return obj
}

View File

@ -3,10 +3,10 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function polyline(props) {
export function polyline(props, scope) {
const points = props.points.split(/\s+|,/).map(item => Number(item))
const obj = new Polyline(points, parseStyle(props))
transform(props, obj)
parseEvent(props, obj)
parseEvent(props, obj, scope)
return obj
}

View File

@ -3,7 +3,7 @@ import { parseStyle } from './parse-style'
import { transform } from './parse-transform'
import { parseEvent } from './parse-event'
export function rect(props) {
export function rect(props, scope) {
const options = Object.assign(
{
width: 0,
@ -26,7 +26,7 @@ export function rect(props) {
transform(props, rect, Number(options.x), Number(options.y))
parseEvent(props, rect)
parseEvent(props, rect, scope)
return rect
}

23
packages/cax-svg/list.md Normal file
View File

@ -0,0 +1,23 @@
http://tutorials.jenkov.com/svg/index.html
todo:
* 自动轮播支持 http://tavmjong.free.fr/blog/wp-content/uploads/BATMAN/batman_logos.svg (间隔时间支持)
* debug bounds box
* pasition easing function
* Transformation + tojs
* Transformation
* boundsX 和 boundsY
* text
* image
* SVG Viewport and View Box
* event handler
* jsx support(extend omip)
vscode 安装 lit-html 使 html`内容` 高亮
import testSVG from 'svg/test'
renderSVG(testSVG, 'canvas-id', this)