update
parent
d6344dde16
commit
00889573db
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/03/26 10:37:00
|
||||
*/
|
||||
|
||||
import { $, h } from './utils.js'
|
||||
|
||||
export class Component {
|
||||
#node
|
||||
type = null
|
||||
|
||||
constructor(el) {
|
||||
this.#node = el
|
||||
this.type = el.tagName.toLowerCase()
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.#node
|
||||
}
|
||||
|
||||
get textContent() {
|
||||
return this.#node.textContent
|
||||
}
|
||||
|
||||
set textContent(val) {
|
||||
this.#node.textContent = val
|
||||
}
|
||||
|
||||
#create(name, attr, child) {
|
||||
let node = h(name, attr, child)
|
||||
this.#node.appendChild(node)
|
||||
return new Component(node)
|
||||
}
|
||||
|
||||
append(...elems) {
|
||||
for (let el of elems) {
|
||||
this.#node.appendChild(el instanceof Component ? el.node : el)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
select(selector) {
|
||||
let node = $(selector, this.#node)
|
||||
if (node) {
|
||||
return new Component(node)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
attr(key, val) {
|
||||
let node = this.node
|
||||
let out = {}
|
||||
|
||||
if (key) {
|
||||
if (typeof key === 'string') {
|
||||
if (val === void 0) {
|
||||
return node.getAttribute(key)
|
||||
} else {
|
||||
key = { [key]: val }
|
||||
}
|
||||
}
|
||||
|
||||
h(node, key)
|
||||
return this
|
||||
}
|
||||
|
||||
// 无任何参数时, 返回节点所有的属性
|
||||
for (let it of Array.from(node.attributes)) {
|
||||
out[it.nodeName] = it.nodeValue
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
g(...args) {
|
||||
let el = this.#create('g')
|
||||
if (args.length) {
|
||||
el.append(...args)
|
||||
}
|
||||
return el
|
||||
}
|
||||
|
||||
style(content) {
|
||||
let node = this.select('style')
|
||||
if (node === null) {
|
||||
node = this.#create('style')
|
||||
}
|
||||
node.textContent += content
|
||||
return node
|
||||
}
|
||||
|
||||
rect(x, y, width, height) {
|
||||
return this.#create('rect', { x, y, width, height })
|
||||
}
|
||||
|
||||
text(x = 0, y = 0, text = '') {
|
||||
return this.#create('text', { x, y }, text)
|
||||
}
|
||||
|
||||
// 使用foreignObject实现文本自动换行等排版
|
||||
autoText(x = 0, y = 0, width, height, text = '') {
|
||||
return this.#create('foreignObject', { x, y, width, height }, text)
|
||||
}
|
||||
|
||||
path(d) {
|
||||
return this.#create('path', { d })
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/03/26 10:07:25
|
||||
*/
|
||||
|
||||
import { $, h, type } from './utils.js'
|
||||
import { xmlns, doc, win } from './lib/constants.js'
|
||||
|
||||
import { Component } from './elem.js'
|
||||
|
||||
export function createSvg(el) {
|
||||
if (el) {
|
||||
if (type(el) === 'string') {
|
||||
el = $(el)
|
||||
}
|
||||
h(el, { xmlns })
|
||||
} else {
|
||||
el = h('svg', { xmlns })
|
||||
}
|
||||
|
||||
return new Component(el)
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* {颜色格式转换}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/03/26 10:07:01
|
||||
*/
|
||||
|
||||
// H: 色相, S: 饱和度, B/V: 亮度
|
||||
export function hsb2rgb(hsb) {
|
||||
let h = hsb.h
|
||||
let s = Math.round((hsb.s * 255) / 100)
|
||||
let v = Math.round((hsb.b * 255) / 100)
|
||||
let r = 0
|
||||
let g = 0
|
||||
let b = 0
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = v
|
||||
} else {
|
||||
let t1 = v
|
||||
let t2 = ((255 - s) * v) / 255
|
||||
let t3 = ((t1 - t2) * (h % 60)) / 60
|
||||
|
||||
//
|
||||
if (h === 360) {
|
||||
h = 0
|
||||
}
|
||||
|
||||
if (h < 60) {
|
||||
r = t1
|
||||
g = t2 + t3
|
||||
b = t2
|
||||
} else if (h < 120) {
|
||||
r = t1 - t3
|
||||
g = t1
|
||||
b = t2
|
||||
} else if (h < 180) {
|
||||
r = t2
|
||||
g = t1
|
||||
b = t2 + t3
|
||||
} else if (h < 240) {
|
||||
r = t2
|
||||
g = t1 - t3
|
||||
b = t1
|
||||
} else if (h < 300) {
|
||||
r = t2 + t3
|
||||
g = t2
|
||||
b = t1
|
||||
} else if (h < 360) {
|
||||
r = t1
|
||||
g = t2
|
||||
b = t1 - t3
|
||||
}
|
||||
}
|
||||
r = Math.round(r)
|
||||
g = Math.round(g)
|
||||
b = Math.round(b)
|
||||
|
||||
return { r, g, b }
|
||||
}
|
||||
|
||||
export function rgb2hex({ r, g, b }, a) {
|
||||
let hex = [r, g, b].map(it => it.toString(16).padStart(2, '0')).join('')
|
||||
if (a !== void 0) {
|
||||
hex += (~~((a / 100) * 255)).toString(16)
|
||||
}
|
||||
return hex
|
||||
}
|
||||
|
||||
export function hex2rgb(hex) {
|
||||
let r, g, b, a
|
||||
|
||||
hex = hex.replace(/^#/, '')
|
||||
|
||||
switch (hex.length) {
|
||||
case 3:
|
||||
case 4:
|
||||
r = hex[0].repeat(2)
|
||||
g = hex[1].repeat(2)
|
||||
b = hex[2].repeat(2)
|
||||
a = (hex[3] || 'f').repeat(2)
|
||||
|
||||
break
|
||||
|
||||
case 6:
|
||||
case 8:
|
||||
r = hex.slice(0, 2)
|
||||
g = hex.slice(2, 4)
|
||||
b = hex.slice(4, 6)
|
||||
a = hex.slice(6, 8) || 'ff'
|
||||
break
|
||||
}
|
||||
|
||||
r = parseInt(r, 16)
|
||||
g = parseInt(g, 16)
|
||||
b = parseInt(b, 16)
|
||||
a = ~~((parseInt(a, 16) * 100) / 255)
|
||||
|
||||
return { r, g, b, a }
|
||||
}
|
||||
|
||||
export function rgb2hsb({ r, g, b }) {
|
||||
let hsb = { h: 0, s: 0, b: 0 }
|
||||
let max = Math.max(r, g, b)
|
||||
let min = Math.min(r, g, b)
|
||||
let delta = max - min
|
||||
|
||||
hsb.b = max
|
||||
hsb.s = max === 0 ? 0 : (delta * 255) / max
|
||||
|
||||
if (hsb.s === 0) {
|
||||
hsb.h = -1
|
||||
} else {
|
||||
if (r === max) {
|
||||
hsb.h = (g - b) / delta
|
||||
} else if (g === max) {
|
||||
hsb.h = 2 + (b - r) / delta
|
||||
} else {
|
||||
hsb.h = 4 + (r - g) / delta
|
||||
}
|
||||
}
|
||||
hsb.h *= 60
|
||||
|
||||
if (hsb.h < 0) {
|
||||
hsb.h += 360
|
||||
}
|
||||
|
||||
hsb.s *= 100 / 255
|
||||
hsb.b *= 100 / 255
|
||||
|
||||
return hsb
|
||||
}
|
||||
|
||||
export function hex2hsb(hex) {
|
||||
return rgb2hsb(hex2rgb(hex))
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* {一些常量}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/03/06 16:25:01
|
||||
*/
|
||||
|
||||
export const doc = document
|
||||
export const win = window
|
||||
export const xlink = 'http://www.w3.org/1999/xlink'
|
||||
export const xmlns = 'http://www.w3.org/2000/svg'
|
||||
export const xhtmlns = 'http://www.w3.org/1999/xhtml'
|
||||
|
||||
export const HTML_TAGS = ['div', 'span', 'p']
|
||||
|
||||
export const CSS_ATTR = {
|
||||
'alignment-baseline': 1,
|
||||
'baseline-shift': 1,
|
||||
clip: 1,
|
||||
'clip-path': 1,
|
||||
'clip-rule': 1,
|
||||
color: 1,
|
||||
'color-interpolation': 1,
|
||||
'color-interpolation-filters': 1,
|
||||
'color-profile': 1,
|
||||
'color-rendering': 1,
|
||||
cursor: 1,
|
||||
direction: 1,
|
||||
display: 1,
|
||||
'dominant-baseline': 1,
|
||||
'enable-background': 1,
|
||||
fill: 1,
|
||||
'fill-opacity': 1,
|
||||
'fill-rule': 1,
|
||||
filter: 1,
|
||||
'flood-color': 1,
|
||||
'flood-opacity': 1,
|
||||
font: 1,
|
||||
'font-family': 1,
|
||||
'font-size': 1,
|
||||
'font-size-adjust': 1,
|
||||
'font-stretch': 1,
|
||||
'font-style': 1,
|
||||
'font-variant': 1,
|
||||
'font-weight': 1,
|
||||
'glyph-orientation-horizontal': 1,
|
||||
'glyph-orientation-vertical': 1,
|
||||
'image-rendering': 1,
|
||||
kerning: 1,
|
||||
'letter-spacing': 1,
|
||||
'lighting-color': 1,
|
||||
marker: 1,
|
||||
'marker-end': 1,
|
||||
'marker-mid': 1,
|
||||
'marker-start': 1,
|
||||
mask: 1,
|
||||
opacity: 1,
|
||||
overflow: 1,
|
||||
'pointer-events': 1,
|
||||
'shape-rendering': 1,
|
||||
'stop-color': 1,
|
||||
'stop-opacity': 1,
|
||||
stroke: 1,
|
||||
'stroke-dasharray': 1,
|
||||
'stroke-dashoffset': 1,
|
||||
'stroke-linecap': 1,
|
||||
'stroke-linejoin': 1,
|
||||
'stroke-miterlimit': 1,
|
||||
'stroke-opacity': 1,
|
||||
'stroke-width': 1,
|
||||
'text-anchor': 1,
|
||||
'text-decoration': 1,
|
||||
'text-rendering': 1,
|
||||
'unicode-bidi': 1,
|
||||
visibility: 1,
|
||||
'word-spacing': 1,
|
||||
'writing-mode': 1
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/03/06 09:55:31
|
||||
*/
|
||||
|
||||
import { xlink, xmlns, xhtmlns, HTML_TAGS, doc, win } from './lib/constants.js'
|
||||
|
||||
export function uuid(prefix = '') {
|
||||
return prefix + Math.random().toString(16).slice(-8)
|
||||
}
|
||||
|
||||
export function noop() {}
|
||||
|
||||
//驼峰转换为连字符线风格
|
||||
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 type(o) {
|
||||
if (o === null) {
|
||||
return null
|
||||
}
|
||||
return Object.prototype.toString.call(o).slice(8, -1).toLowerCase()
|
||||
}
|
||||
|
||||
export function $(selector, container, multi) {
|
||||
let fn = multi ? 'querySelectorAll' : 'querySelector'
|
||||
if (container) {
|
||||
return container[fn](selector)
|
||||
}
|
||||
return document.body[fn](selector)
|
||||
}
|
||||
|
||||
export function $$(selector, container) {
|
||||
return $(selector, container, true)
|
||||
}
|
||||
|
||||
export function h(el, props = null, children) {
|
||||
if (typeof el === 'string') {
|
||||
el = doc.createElementNS(HTML_TAGS.includes(el) ? xhtmlns : xmlns, el)
|
||||
}
|
||||
|
||||
if (props) {
|
||||
for (let key in props) {
|
||||
let val = props[key]
|
||||
if (val === void 0) {
|
||||
continue
|
||||
}
|
||||
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)) {
|
||||
children = children.join('')
|
||||
}
|
||||
|
||||
if (el.tagName.toLowerCase() === 'foreignobject') {
|
||||
let f = h('div', { xmlns: 'http://www.w3.org/1999/xhtml' })
|
||||
let p = h('p', null, children)
|
||||
f.appendChild(p)
|
||||
|
||||
h(el, { xmlns })
|
||||
el.appendChild(f)
|
||||
} else {
|
||||
el.appendChild(doc.createTextNode(children))
|
||||
}
|
||||
|
||||
el.normalize()
|
||||
}
|
||||
return el
|
||||
}
|
||||
|
||||
window.h = h
|
||||
|
||||
export function clone(obj) {
|
||||
if (typeof obj == 'function' || Object(obj) !== obj) {
|
||||
return obj
|
||||
}
|
||||
let res = new obj.constructor()
|
||||
for (let key in obj)
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
res[key] = clone(obj[key])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export function preload(src, f) {
|
||||
let img = new Image()
|
||||
|
||||
img.onload = function () {
|
||||
f.call(img)
|
||||
}
|
||||
img.src = src
|
||||
}
|
||||
|
||||
function repush(arr, item) {
|
||||
let l = arr.length - 1 // 要减1, 最后如果本身在最后, 不用变
|
||||
for (let i = 0; i < l; i++) {
|
||||
if (arr[i] === item) {
|
||||
;[arr[i], arr[l]] = [arr[l], arr[i]]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function cacher(fn, scope, postprocessor) {
|
||||
function newf(...args) {
|
||||
let key = args.join('\u2400'),
|
||||
cache = (newf.cache = newf.cache || {}),
|
||||
count = (newf.count = newf.count || [])
|
||||
if (cache.hasOwnProperty(key)) {
|
||||
repush(count, key)
|
||||
return postprocessor ? postprocessor(cache[key]) : cache[key]
|
||||
}
|
||||
count.length >= 1e3 && delete cache[count.shift()]
|
||||
count.push(key)
|
||||
cache[key] = fn.apply(scope, args)
|
||||
return postprocessor ? postprocessor(cache[key]) : cache[key]
|
||||
}
|
||||
return newf
|
||||
}
|
||||
|
||||
export function jsonFiller(root, o) {
|
||||
for (let i = 0, ii = root.length; i < ii; i++) {
|
||||
let item = {
|
||||
type: root[i].type,
|
||||
attr: root[i].attr()
|
||||
},
|
||||
children = root[i].children()
|
||||
o.push(item)
|
||||
if (children.length) {
|
||||
jsonFiller(children, (item.childNodes = []))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function extend(origin, target) {
|
||||
let methods = Object.getOwnPropertyNames(target).filter(
|
||||
n => n !== 'constructor'
|
||||
)
|
||||
for (let k of methods) {
|
||||
Object.defineProperty(origin, k, { value: target[k] })
|
||||
}
|
||||
}
|
||||
|
||||
export function url(id) {
|
||||
return "url('#" + id + "')"
|
||||
}
|
Loading…
Reference in New Issue