From 994cb7e01029e05ccf558c22e3c807717f463153 Mon Sep 17 00:00:00 2001 From: yutent Date: Thu, 14 Mar 2024 12:55:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B2=BE=E7=AE=80=E4=BC=98=E5=8C=96attr?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/attr.js | 2 + src/emitter.js | 55 ++++++++++++++++ src/svg.js | 173 +++++++++++++++++-------------------------------- src/utils.js | 69 +++++++++++++++----- 4 files changed, 169 insertions(+), 130 deletions(-) create mode 100644 src/emitter.js diff --git a/src/attr.js b/src/attr.js index 64910a6..97dc2e2 100644 --- a/src/attr.js +++ b/src/attr.js @@ -277,6 +277,7 @@ eve.on('snap.util.attr.textpath', function (value) { } } })(-1) + eve.on('snap.util.attr.text', function (value) { if (this.type == 'text') { let i = 0, @@ -303,6 +304,7 @@ eve.on('snap.util.attr.text', function (value) { } eve.stop() })(-1) + function setFontSize(value) { eve.stop() if (value == +value) { diff --git a/src/emitter.js b/src/emitter.js new file mode 100644 index 0000000..837137c --- /dev/null +++ b/src/emitter.js @@ -0,0 +1,55 @@ +/** + * + * @author yutent + * @date 2021/05/30 11:43:54 + */ + +export class EventEmitter { + // + __events__ = Object.create(null) + + $on(name, fn) { + if (this.__events__[name]) { + this.__events__[name].push(fn) + } else { + this.__events__[name] = [fn] + } + } + + $once(name, fn) { + function fn1(...args) { + fn(...args) + } + if (this.__events__[name]) { + this.__events__[name].push(fn) + } else { + this.__events__[name] = [fn] + } + } + + $off(name, fn) { + if (this.__events__[name]) { + if (fn) { + this.__events__[name] = this.__events__[name].filter(it => it !== fn) + } else { + this.__events__[name] = [] + } + } + } + + $emit(name, ...args) { + if (this.__events__[name]) { + for (let fn of this.__events__[name]) { + try { + fn.apply(this, args) + } catch (e) { + console.error(e) + } + } + } + } + + $destroy() { + this.__events__ = Object.create(null) + } +} diff --git a/src/svg.js b/src/svg.js index fad41c3..054338d 100644 --- a/src/svg.js +++ b/src/svg.js @@ -4,8 +4,6 @@ * @date 2024/03/08 10:59:09 */ -import eve from './eve.js' - import { doc, win, @@ -18,7 +16,7 @@ import { import { Matrix } from './matrix.js' import { - $, + h, is, uuid, clone, @@ -36,11 +34,10 @@ let has = 'hasOwnProperty', objectToString = Object.prototype.toString, hub = {} -export function make(name, parent) { - let res = $(name) - parent.appendChild(res) - let el = wrap(res) - return el +export function make(name, parent = doc.body, attr, children) { + let el = h(name, attr, children) + parent.appendChild(el) + return wrap(el) } export function wrap(dom) { @@ -96,7 +93,7 @@ export class Fragment { } export class Snap { - static _ = { $ } + static _ = {} /* ** @@ -294,7 +291,7 @@ export class Snap { } if (h == null) { try { - w = doc.querySelector(String(w)) + w = doc.querySelector(w) return wrap(w) } catch (e) { return null @@ -536,8 +533,7 @@ export function unit2px(el, name, value) { out = {}, mgr = svg.querySelector('.svg---mgr') if (!mgr) { - mgr = $('rect') - $(mgr, { + mgr = h('rect', { x: -9e9, y: -9e9, width: 10, @@ -554,7 +550,7 @@ export function unit2px(el, name, value) { if (val == +val) { return val } - $(mgr, { width: val }) + h(mgr, { width: val }) try { return mgr.getBBox().width } catch (e) { @@ -568,7 +564,7 @@ export function unit2px(el, name, value) { if (val == +val) { return val } - $(mgr, { height: val }) + h(mgr, { height: val }) try { return mgr.getBBox().height } catch (e) { @@ -672,23 +668,25 @@ setInterval(function () { }, 1e4) export class Paper { - constructor(w, h) { - let res, desc, defs - if (w && w.tagName && w.tagName.toLowerCase() == 'svg') { - if (w.snap in hub) { - return hub[w.snap] + constructor(width, height) { + let dom, res, desc, defs + if (width && width.nodeType) { + dom = width + } + if (dom) { + if (dom.snap in hub) { + return hub[dom.snap] } - let doc = w.ownerDocument - res = new SnapElement(w) - desc = w.getElementsByTagName('desc')[0] - defs = w.getElementsByTagName('defs')[0] + let doc = dom.ownerDocument + res = new SnapElement(dom) + desc = dom.querySelector('desc') + defs = dom.querySelector('defs') if (!desc) { - desc = $('desc') - desc.appendChild(doc.createTextNode('Created with Snap')) + desc = h('desc', null, 'Created with @bytedo/snapsvg') res.node.appendChild(desc) } if (!defs) { - defs = $('defs') + defs = h('defs') res.node.appendChild(defs) } res.defs = defs @@ -696,9 +694,9 @@ export class Paper { res.paper = res.root = res } else { res = make('svg', doc.body) - $(res.node, { - width: w, - height: h, + h(res.node, { + width, + height, version: 1.1, xmlns }) @@ -858,18 +856,8 @@ export class Paper { | let pth = paper.path("M10,10L100,100"); | t1.attr({textpath: pth}); \*/ - text(x, y, text) { - let attr = {} - if (is(x, 'object')) { - attr = x - } else if (x != null) { - attr = { - x: x, - y: y, - text: text || '' - } - } - return this.el('text', attr) + text(x = 0, y = 0, text = '') { + return this.el('text', { x, y }, text) } /*\ ** @@ -961,10 +949,8 @@ export class Paper { | r: 10 | }); */ - el(name, attr) { - let el = make(name, this.node) - attr && el.attr(attr) - return el + el(name, attr, children) { + return make(name, this.node, attr, children) } /* @@ -1067,13 +1053,13 @@ export class Paper { set.height = height } else { preload(src, function () { - $(el.node, { + h(el.node, { width: this.offsetWidth, height: this.offsetHeight }) }) } - $(el.node, set) + h(el.node, set) } return el } @@ -1145,15 +1131,14 @@ export class Paper { if (paper.type !== 'svg') { paper = paper.paper } - let f = Snap.parse(String(filstr)), + let f = Snap.parse(filstr), id = uuid((this.type || '') + 'S'), width = paper.node.offsetWidth, height = paper.node.offsetHeight, - filter = $('filter') - $(filter, { - id: id, - filterUnits: 'userSpaceOnUse' - }) + filter = h('filter', { + id, + filterUnits: 'userSpaceOnUse' + }) filter.appendChild(f.node) paper.defs.appendChild(filter) return new SnapElement(filter) @@ -1167,7 +1152,7 @@ export class Paper { res f.appendChild(d) d.appendChild(svg) - $(svg, { xmlns: 'http://www.w3.org/2000/svg' }) + h(svg, { xmlns: 'http://www.w3.org/2000/svg' }) res = d.innerHTML return res } @@ -1215,12 +1200,9 @@ export class SnapElement { if (svg) { this.paper = new Paper(svg) } - /*\ - * SnapElement.type - [ property (string) ] - ** + /** * SVG tag name of the given element. - \*/ + */ this.type = el.tagName || el.nodeName let id = (this.id = uuid((this.type || '') + 'S')) this.anims = {} @@ -1260,34 +1242,28 @@ export class SnapElement { * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` * and `-`: `"+=2em"`. */ - attr(params, value) { + attr(key, value) { let node = this.node + let out = {} - if (!params) { - if (node.nodeType != 1) { - return { - text: node.nodeValue + if (key) { + if (is(key, 'string')) { + if (value === void 0) { + return node.getAttribute(key) + } else { + key = { [key]: value } } } - let attr = node.attributes, - out = {} - for (let i = 0, ii = attr.length; i < ii; i++) { - out[attr[i].nodeName] = attr[i].nodeValue - } + h(node, key) - return out + return this } - if (is(params, 'string')) { - if (value !== void 0) { - params = { [params]: value } - } else { - return eve('snap.util.getattr.' + params, this).firstDefined() - } + + for (let it of Array.from(node.attributes)) { + out[it.nodeName] = it.nodeValue } - for (let att in params) { - eve('snap.util.attr.' + att, this, params[att]) - } - return this + + return out } /* @@ -1296,12 +1272,7 @@ export class SnapElement { = (array) array of Elements */ children() { - let out = [], - ch = this.node.childNodes - for (let i = 0, ii = ch.length; i < ii; i++) { - out[i] = new Snap(ch[i]) - } - return out + return Array.from(this.node.childNodes).map(n => new Snap(n)) } /*\ @@ -1321,7 +1292,7 @@ export class SnapElement { } equal(name, b) { - return eve('snap.util.equal', this, name, b).firstDefined() + // return eve('snap.util.equal', this, name, b).firstDefined() } addClass(value) { @@ -1385,31 +1356,3 @@ export class SnapElement { return this.transform('' + this.getAlign(way)) } } - -// default -eve.on('snap.util.getattr', function () { - let key = eve.nt().split('.').at(-1) - let css = key.replace(/[A-Z]/g, function (letter) { - return '-' + letter.toLowerCase() - }) - if (CSS_ATTR[css]) { - return this.node.ownerDocument.defaultView - .getComputedStyle(this.node, null) - .getPropertyValue(css) - } else { - return $(this.node, key) - } -}) - -eve.on('snap.util.attr', function (value) { - let key = eve.nt().split('.').at(-1) - - let css = key.replace(/[A-Z]/g, function (letter) { - return '-' + letter.toLowerCase() - }) - if (CSS_ATTR[css]) { - this.node.style[css] = value == null ? E : value - } else { - $(this.node, { [css]: value }) - } -}) diff --git a/src/utils.js b/src/utils.js index afb6b6c..cd570e1 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,6 +10,20 @@ export function uuid(prefix = '') { return prefix + Math.random().toString(16).slice(-8) } +//驼峰转换为连字符线风格 +export function hyphen(target) { + return target.replace(/([a-z\d])([A-Z]+)/g, '$1-$2').toLowerCase() +} + +//连字符转换为驼峰风格 +export function camelize(target) { + //提前判断,提高效率 + if (target.indexOf('-') < 0) { + return target + } + return target.replace(/\-([a-z])/g, (m, s) => s.toUpperCase()) +} + export function is(o, type) { type = String(type).toLowerCase() let _type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase() @@ -54,21 +68,7 @@ export function $(el, attr) { } } if (el.nodeType == 1) { - for (let key in attr) - if (attr.hasOwnProperty(key)) { - let val = String(attr[key]) - if (val) { - if (key.slice(0, 6) == 'xlink:') { - el.setAttributeNS(xlink, key.slice(6), val) - } else if (key.slice(0, 4) == 'xml:') { - el.setAttributeNS(xmlns, key.slice(4), val) - } else { - el.setAttribute(key, val) - } - } else { - el.removeAttribute(key) - } - } + h(el, attr) } else if ('text' in attr) { el.nodeValue = attr.text } @@ -78,6 +78,45 @@ export function $(el, attr) { return el } +export function h(el, props = null, children) { + if (typeof el === 'string') { + el = doc.createElementNS(xmlns, el) + } + + if (props) { + for (let key in props) { + let val = props[key] + key = hyphen(key) + if (val === null) { + el.removeAttribute(key) + } else { + if (key.slice(0, 6) == 'xlink:') { + el.setAttributeNS(xlink, key.slice(6), val) + } else if (key.slice(0, 4) == 'xml:') { + el.setAttributeNS(xmlns, key.slice(4), val) + } else { + el.setAttribute(key, val) + } + } + } + } + + if (children) { + if (Array.isArray(children)) { + let f = doc.createDocumentFragment() + for (let it of children) { + f.appendChild(h('tspan', null, it)) + } + el.appendChild(f) + } else { + el.appendChild(doc.createTextNode(children)) + } + + el.normalize() + } + return el +} + export function clone(obj) { if (typeof obj == 'function' || Object(obj) !== obj) { return obj