functionbrightness(r, g, b, a, factor) { return [r + factor, g + factor, b + factor, 255]; }
调用时,控制因子factor是亮度。 下图是原图、亮度传45和100的对比:
饱和度
1 2 3 4 5 6 7 8
functionsaturation(r, g, b, a, factor) { // factor取值[-1, 1] const max = Math.max(r, g, b); r += max !== r ? (max - r) * (-factor) : 0; g += max !== g ? (max - g) * (-factor) : 0; b += max !== b ? (max - b) * (-factor) : 0; return [r, g, b, 255]; }
functionpatch(n1, n2) { // Implement this // 1. check if n1 and n2 are of the same type if (n1.tag !== n2.tag) { // 2. if not, replace const parent = n1.el.parentNode const anchor = n1.el.nextSibling parent.removeChild(n1.el) mount(n2, parent, anchor) return }
const el = n2.el = n1.el
// 3. if yes // 3.1 diff props const oldProps = n1.props || {} const newProps = n2.props || {} for (const key in newProps) { const newValue = newProps[key] const oldValue = oldProps[key] if (newValue !== oldValue) { if (newValue != null) { el.setAttribute(key, newValue) } else { el.removeAttribute(key) } } } for (const key in oldProps) { if (!(key in newProps)) { el.removeAttribute(key) } } // 3.2 diff children const oc = n1.children const nc = n2.children if (typeof nc === 'string') { if (nc !== oc) { el.textContent = nc } } elseif (Array.isArray(nc)) { if (Array.isArray(oc)) { // array diff const commonLength = Math.min(oc.length, nc.length) for (let i = 0; i < commonLength; i++) { patch(oc[i], nc[i]) } if (nc.length > oc.length) { nc.slice(oc.length).forEach(c =>mount(c, el)) } elseif (oc.length > nc.length) { oc.slice(nc.length).forEach(c => { el.removeChild(c.el) }) } } else { el.innerHTML = '' nc.forEach(c =>mount(c, el)) } } }
functionreactive(raw) { // use Object.defineProperty // 1. iterate over the existing keys Object.keys(raw).forEach(key => { // 2. for each key: create a corresponding dep const dep = newDep()
// 3. rewrite the property into getter/setter let realValue = raw[key] Object.defineProperty(raw, key, { get() { // 4. call dep methods inside getter/setter dep.depend() return realValue }, set(newValue) { realValue = newValue dep.notify() } }) }) return raw }
// proxy version const reactiveHandlers = { get(target, key) { // how do we get the dep for this key? const value = getDep(target, key).value if (value && typeof value === 'object') { returnreactive(value) } else { return value } }, set(target, key, value) { getDep(target, key).value = value } }
接着是getDep函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
const targetToHashMap = newWeakMap()
functiongetDep(target, key) { let depMap = targetToHashMap.get(target) if (!depMap) { depMap = newMap() targetToHashMap.set(target, depMap) }
let dep = depMap.get(key) if (!dep) { dep = newDep(target[key]) depMap.set(key, dep) }
let b = imageData.data[((50 * (img.width * 4)) + (200 * 4)) + 2];
那么根据行(row)、列(col)读取一个像素点的r/g/b/a值的公式是:
1 2 3 4 5
let rIndex = row * (img.width * 4) + col * 4// data中r值的索引 let r = imageData.data[rIndex]; let g = imageData.data[(rIndex + 1]; let b = imageData.data[(rIndex + 2]; let a = imageData.data[(rIndex + 3];
简单来说,我们先来完成一个没有圆角的向上的tooltip,我们需要这么做: 1、移动到点A:M aX,aY 2、连线到点B:L bX,bY 3、垂直连线到点C:H cX 4、水平连线到点D:V dY 5、垂直连线到点E:H eX 6、水平连线到点F:V fY 7、垂直连线到点G:H gX 8、连线到点A:L aX,aY 9、结束路径:z
点A的坐标是(0,0),其他点的坐标由width,height和offset计算出来:
1 2 3 4 5 6
bx = -offset by = -offset // cy,fy,gy也是一样的 cx = -width / 2// dx也一样 dy = -offset - height // ey也一样 ex = width / 2// fx也一样 gx = offset
整个路径实现出来就会是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functiontopTooltipPath(width, height, offset) { const left = -width / 2 const right = width / 2 const top = -offset - height const bottom = -offset return`M 0,0 L ${-offset},${bottom} H ${left} V ${top} H ${right} V ${bottom} H ${offset} L 0,0 z` }