SVG中的pattern元素,让预定义图形以固定间隔在x轴和y轴上重复或平铺,从而覆盖需要涂色或添加纹理的区域。
在defs中预定义pattern图案元素,在图形元素上使用属性fill="url(#id)"
或stroke="url(#id)"
来引用填充或描边的图案。
DOM工具
操作SVG及其图形元素DOM的方法,包括选择、创建、设置属性等。
const tool = (root => { const doc = root.document const xlink = 'http://www.w3.org/1999/xlink' const xmlns = 'http://www.w3.org/2000/svg' const tool = {}
tool.select = (el, str) => { if (!str) { str = el el = doc } return doc.querySelector(str) }
tool.selectAll = (el, str) => { if (!str) { str = el el = doc } return doc.querySelectorAll(str) }
tool.attr = (el, attr) => { for (let key in attr) { const val = String(attr[key]) if (val) { if (key.substring(0, 6) == 'xlink:') { el.setAttributeNS(xlink, key.substring(6), val) } else if (key.substring(0, 4) == "xml:") { el.setAttributeNS(xmlns, key.substring(4), val) } else { el.setAttribute(key, val) } } else { el.removeAttribute(key) } } }
tool.create = el => doc.createElementNS(xmlns, el)
return tool})(window || this)
纹理类
class LineTexture { constructor(args) { this.size = args.size || 20 this.stroke = args.stroke || '#a9aca5' this.strokeWidth = args.strokeWidth || 2 this.background = args.background || '' this.orientations = args.orientations || ['2/8'] this.svg = args.svg this.id = this.random() this.svg && this.init() }
path(orientation) { const s = this.size switch (orientation) { case '0/8': return `M${s/4},0 l0,${s} M${3/4*s},0 l0,${s}` case '1/8': return `M${s/4},0 l${s/2},${s} M${-s/4},0 l${s/2},${s} M${s*3/4},0 l${s/2},${s}` case '2/8': // 省略... } }
url() { return `url(#${this.id})` }
init() { const svg = this.svg.nodeType ? this.svg : tool.select(this.svg) const defs = tool.select(svg, 'defs') const pattern = tool.create('pattern')
tool.attr(pattern, { id: this.id, width: this.size, height: this.size, patternUnits: 'userSpaceOnUse' })
if (this.background) { const rect = tool.create('rect') tool.attr(rect, { width: this.size, height: this.size, fill: this.background }) pattern.appendChild(rect) }
this.orientations.forEach(o => { const path = tool.create('path') tool.attr(path, { stroke: this.stroke, 'stroke-width': this.strokeWidth, 'stroke-linecap': 'square', d: this.path(o) }) pattern.appendChild(path) })
defs.appendChild(pattern) }
random() { return Math.random().toString(36) .replace(/[^a-z]+/g, '') .slice(0, 5) }}
实现
选择SVG画布,设置其尺寸;找到全部path路径子元素;为每个path初始化纹理实例对象LineTexture,并设置纹理pattern的id引用填充。
const svg = tool.select('#tibet')const width = Math.min(svg.parentNode.clientWidth, 410)const height = width * 440 / 820tool.attr(svg, { width, height})const pathList = tool.selectAll(svg, 'path')const colors = ['#f2f6ed', '#f3f6ee', '#f3f7ef', '#f4f7f0', '#f5f8f1', '#f5f8f2', '#f6f9f3']
Array.prototype.forEach.call(pathList, (path, i) => { const url = new LineTexture({ svg, background: colors[i], orientations: [`${i}/8`] }).url()
tool.attr(path, { fill: url })})