123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779 |
- (function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory();
- else if(typeof define === 'function' && define.amd)
- define([], factory);
- else {
- var a = factory();
- for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
- }
- })(window, function() {
- return /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId]) {
- /******/ return installedModules[moduleId].exports;
- /******/ }
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/
- /******/
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
- /******/ }
- /******/ };
- /******/
- /******/ // define __esModule on exports
- /******/ __webpack_require__.r = function(exports) {
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
- /******/ }
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
- /******/ };
- /******/
- /******/ // create a fake namespace object
- /******/ // mode & 1: value is a module id, require it
- /******/ // mode & 2: merge all properties of value into the ns
- /******/ // mode & 4: return value when already ns object
- /******/ // mode & 8|1: behave like require
- /******/ __webpack_require__.t = function(value, mode) {
- /******/ if(mode & 1) value = __webpack_require__(value);
- /******/ if(mode & 8) return value;
- /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
- /******/ var ns = Object.create(null);
- /******/ __webpack_require__.r(ns);
- /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
- /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
- /******/ return ns;
- /******/ };
- /******/
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/
- /******/
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = 1);
- /******/ })
- /************************************************************************/
- /******/ ([
- /* 0 */
- /***/ (function(module, exports) {
- const hex = (color) => {
- let result = null
- if (/^#/.test(color) && (color.length === 7 || color.length === 9)) {
- return color
- // eslint-disable-next-line no-cond-assign
- } else if ((result = /^(rgb|rgba)\((.+)\)/.exec(color)) !== null) {
- return '#' + result[2].split(',').map((part, index) => {
- part = part.trim()
- part = index === 3 ? Math.floor(parseFloat(part) * 255) : parseInt(part, 10)
- part = part.toString(16)
- if (part.length === 1) {
- part = '0' + part
- }
- return part
- }).join('')
- } else {
- return '#00000000'
- }
- }
- const splitLineToCamelCase = (str) => str.split('-').map((part, index) => {
- if (index === 0) {
- return part
- }
- return part[0].toUpperCase() + part.slice(1)
- }).join('')
- const compareVersion = (v1, v2) => {
- v1 = v1.split('.')
- v2 = v2.split('.')
- const len = Math.max(v1.length, v2.length)
- while (v1.length < len) {
- v1.push('0')
- }
- while (v2.length < len) {
- v2.push('0')
- }
- for (let i = 0; i < len; i++) {
- const num1 = parseInt(v1[i], 10)
- const num2 = parseInt(v2[i], 10)
- if (num1 > num2) {
- return 1
- } else if (num1 < num2) {
- return -1
- }
- }
- return 0
- }
- module.exports = {
- hex,
- splitLineToCamelCase,
- compareVersion
- }
- /***/ }),
- /* 1 */
- /***/ (function(module, exports, __webpack_require__) {
- const xmlParse = __webpack_require__(2)
- const {Widget} = __webpack_require__(3)
- const {Draw} = __webpack_require__(5)
- const {compareVersion} = __webpack_require__(0)
- const canvasId = 'weui-canvas'
- Component({
- properties: {
- width: {
- type: Number,
- value: 400
- },
- height: {
- type: Number,
- value: 300
- }
- },
- data: {
- use2dCanvas: false, // 2.9.2 后可用canvas 2d 接口
- },
- lifetimes: {
- attached() {
- const {SDKVersion, pixelRatio: dpr} = wx.getSystemInfoSync()
- const use2dCanvas = compareVersion(SDKVersion, '2.9.2') >= 0
- this.dpr = dpr
- this.setData({use2dCanvas}, () => {
- if (use2dCanvas) {
- const query = this.createSelectorQuery()
- query.select(`#${canvasId}`)
- .fields({node: true, size: true})
- .exec(res => {
- const canvas = res[0].node
- const ctx = canvas.getContext('2d')
- canvas.width = res[0].width * dpr
- canvas.height = res[0].height * dpr
- ctx.scale(dpr, dpr)
- this.ctx = ctx
- this.canvas = canvas
- })
- } else {
- this.ctx = wx.createCanvasContext(canvasId, this)
- }
- })
- }
- },
- methods: {
- async renderToCanvas(args) {
- const {wxml, style} = args
- const ctx = this.ctx
- const canvas = this.canvas
- const use2dCanvas = this.data.use2dCanvas
- if (use2dCanvas && !canvas) {
- return Promise.reject(new Error('renderToCanvas: fail canvas has not been created'))
- }
- ctx.clearRect(0, 0, this.data.width, this.data.height)
- const {root: xom} = xmlParse(wxml)
- const widget = new Widget(xom, style)
- const container = widget.init()
- this.boundary = {
- top: container.layoutBox.top,
- left: container.layoutBox.left,
- width: container.computedStyle.width,
- height: container.computedStyle.height,
- }
- const draw = new Draw(ctx, canvas, use2dCanvas)
- await draw.drawNode(container)
- if (!use2dCanvas) {
- await this.canvasDraw(ctx)
- }
- return Promise.resolve(container)
- },
- canvasDraw(ctx, reserve) {
- return new Promise(resolve => {
- ctx.draw(reserve, () => {
- resolve()
- })
- })
- },
- canvasToTempFilePath(args = {}) {
- const use2dCanvas = this.data.use2dCanvas
- return new Promise((resolve, reject) => {
- const {
- top, left, width, height
- } = this.boundary
- const copyArgs = {
- x: left,
- y: top,
- width,
- height,
- destWidth: width * this.dpr,
- destHeight: height * this.dpr,
- canvasId,
- fileType: args.fileType || 'png',
- quality: args.quality || 1,
- success: resolve,
- fail: reject
- }
- if (use2dCanvas) {
- delete copyArgs.canvasId
- copyArgs.canvas = this.canvas
- }
- wx.canvasToTempFilePath(copyArgs, this)
- })
- }
- }
- })
- /***/ }),
- /* 2 */
- /***/ (function(module, exports) {
- /**
- * Module dependencies.
- */
- /**
- * Expose `parse`.
- */
- /**
- * Parse the given string of `xml`.
- *
- * @param {String} xml
- * @return {Object}
- * @api public
- */
- function parse(xml) {
- xml = xml.trim()
- // strip comments
- xml = xml.replace(/<!--[\s\S]*?-->/g, '')
- return document()
- /**
- * XML document.
- */
- function document() {
- return {
- declaration: declaration(),
- root: tag()
- }
- }
- /**
- * Declaration.
- */
- function declaration() {
- const m = match(/^<\?xml\s*/)
- if (!m) return
- // tag
- const node = {
- attributes: {}
- }
- // attributes
- while (!(eos() || is('?>'))) {
- const attr = attribute()
- if (!attr) return node
- node.attributes[attr.name] = attr.value
- }
- match(/\?>\s*/)
- return node
- }
- /**
- * Tag.
- */
- function tag() {
- const m = match(/^<([\w-:.]+)\s*/)
- if (!m) return
- // name
- const node = {
- name: m[1],
- attributes: {},
- children: []
- }
- // attributes
- while (!(eos() || is('>') || is('?>') || is('/>'))) {
- const attr = attribute()
- if (!attr) return node
- node.attributes[attr.name] = attr.value
- }
- // self closing tag
- if (match(/^\s*\/>\s*/)) {
- return node
- }
- match(/\??>\s*/)
- // content
- node.content = content()
- // children
- let child
- while (child = tag()) {
- node.children.push(child)
- }
- // closing
- match(/^<\/[\w-:.]+>\s*/)
- return node
- }
- /**
- * Text content.
- */
- function content() {
- const m = match(/^([^<]*)/)
- if (m) return m[1]
- return ''
- }
- /**
- * Attribute.
- */
- function attribute() {
- const m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/)
- if (!m) return
- return {name: m[1], value: strip(m[2])}
- }
- /**
- * Strip quotes from `val`.
- */
- function strip(val) {
- return val.replace(/^['"]|['"]$/g, '')
- }
- /**
- * Match `re` and advance the string.
- */
- function match(re) {
- const m = xml.match(re)
- if (!m) return
- xml = xml.slice(m[0].length)
- return m
- }
- /**
- * End-of-source.
- */
- function eos() {
- return xml.length == 0
- }
- /**
- * Check for `prefix`.
- */
- function is(prefix) {
- return xml.indexOf(prefix) == 0
- }
- }
- module.exports = parse
- /***/ }),
- /* 3 */
- /***/ (function(module, exports, __webpack_require__) {
- const Block = __webpack_require__(4)
- const {splitLineToCamelCase} = __webpack_require__(0)
- class Element extends Block {
- constructor(prop) {
- super(prop.style)
- this.name = prop.name
- this.attributes = prop.attributes
- }
- }
- class Widget {
- constructor(xom, style) {
- this.xom = xom
- this.style = style
- this.inheritProps = ['fontSize', 'lineHeight', 'textAlign', 'verticalAlign', 'color']
- }
- init() {
- this.container = this.create(this.xom)
- this.container.layout()
- this.inheritStyle(this.container)
- return this.container
- }
- // 继承父节点的样式
- inheritStyle(node) {
- const parent = node.parent || null
- const children = node.children || {}
- const computedStyle = node.computedStyle
- if (parent) {
- this.inheritProps.forEach(prop => {
- computedStyle[prop] = computedStyle[prop] || parent.computedStyle[prop]
- })
- }
- Object.values(children).forEach(child => {
- this.inheritStyle(child)
- })
- }
- create(node) {
- let classNames = (node.attributes.class || '').split(' ')
- classNames = classNames.map(item => splitLineToCamelCase(item.trim()))
- const style = {}
- classNames.forEach(item => {
- Object.assign(style, this.style[item] || {})
- })
- const args = {name: node.name, style}
- const attrs = Object.keys(node.attributes)
- const attributes = {}
- for (const attr of attrs) {
- const value = node.attributes[attr]
- const CamelAttr = splitLineToCamelCase(attr)
- if (value === '' || value === 'true') {
- attributes[CamelAttr] = true
- } else if (value === 'false') {
- attributes[CamelAttr] = false
- } else {
- attributes[CamelAttr] = value
- }
- }
- attributes.text = node.content
- args.attributes = attributes
- const element = new Element(args)
- node.children.forEach(childNode => {
- const childElement = this.create(childNode)
- element.add(childElement)
- })
- return element
- }
- }
- module.exports = {Widget}
- /***/ }),
- /* 4 */
- /***/ (function(module, exports) {
- module.exports = require("widget-ui");
- /***/ }),
- /* 5 */
- /***/ (function(module, exports) {
- class Draw {
- constructor(context, canvas, use2dCanvas = false) {
- this.ctx = context
- this.canvas = canvas || null
- this.use2dCanvas = use2dCanvas
- }
- roundRect(x, y, w, h, r, fill = true, stroke = false) {
- if (r < 0) return
- const ctx = this.ctx
- ctx.beginPath()
- ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 3 / 2)
- ctx.arc(x + w - r, y + r, r, Math.PI * 3 / 2, 0)
- ctx.arc(x + w - r, y + h - r, r, 0, Math.PI / 2)
- ctx.arc(x + r, y + h - r, r, Math.PI / 2, Math.PI)
- ctx.lineTo(x, y + r)
- if (stroke) ctx.stroke()
- if (fill) ctx.fill()
- }
- drawView(box, style) {
- const ctx = this.ctx
- const {
- left: x, top: y, width: w, height: h
- } = box
- const {
- borderRadius = 0,
- borderWidth = 0,
- borderColor,
- color = '#000',
- backgroundColor = 'transparent',
- } = style
- ctx.save()
- // 外环
- if (borderWidth > 0) {
- ctx.fillStyle = borderColor || color
- this.roundRect(x, y, w, h, borderRadius)
- }
- // 内环
- ctx.fillStyle = backgroundColor
- const innerWidth = w - 2 * borderWidth
- const innerHeight = h - 2 * borderWidth
- const innerRadius = borderRadius - borderWidth >= 0 ? borderRadius - borderWidth : 0
- this.roundRect(x + borderWidth, y + borderWidth, innerWidth, innerHeight, innerRadius)
- ctx.restore()
- }
- async drawImage(img, box, style) {
- await new Promise((resolve, reject) => {
- const ctx = this.ctx
- const canvas = this.canvas
- const {
- borderRadius = 0
- } = style
- const {
- left: x, top: y, width: w, height: h
- } = box
- ctx.save()
- this.roundRect(x, y, w, h, borderRadius, false, false)
- ctx.clip()
- const _drawImage = (img) => {
- if (this.use2dCanvas) {
- const Image = canvas.createImage()
- Image.onload = () => {
- ctx.drawImage(Image, x, y, w, h)
- ctx.restore()
- resolve()
- }
- Image.onerror = () => { reject(new Error(`createImage fail: ${img}`)) }
- Image.src = img
- } else {
- ctx.drawImage(img, x, y, w, h)
- ctx.restore()
- resolve()
- }
- }
- const isTempFile = /^wxfile:\/\//.test(img)
- const isNetworkFile = /^https?:\/\//.test(img)
- if (isTempFile) {
- _drawImage(img)
- } else if (isNetworkFile) {
- wx.downloadFile({
- url: img,
- success(res) {
- if (res.statusCode === 200) {
- _drawImage(res.tempFilePath)
- } else {
- reject(new Error(`downloadFile:fail ${img}`))
- }
- },
- fail() {
- reject(new Error(`downloadFile:fail ${img}`))
- }
- })
- } else {
- reject(new Error(`image format error: ${img}`))
- }
- })
- }
- // eslint-disable-next-line complexity
- drawText(text, box, style) {
- const ctx = this.ctx
- let {
- left: x, top: y, width: w, height: h
- } = box
- let {
- color = '#000',
- lineHeight = '1.4em',
- fontSize = 14,
- textAlign = 'left',
- verticalAlign = 'top',
- backgroundColor = 'transparent'
- } = style
- if (typeof lineHeight === 'string') { // 2em
- lineHeight = Math.ceil(parseFloat(lineHeight.replace('em')) * fontSize)
- }
- if (!text || (lineHeight > h)) return
- ctx.save()
- ctx.textBaseline = 'top'
- ctx.font = `${fontSize}px sans-serif`
- ctx.textAlign = textAlign
- // 背景色
- ctx.fillStyle = backgroundColor
- this.roundRect(x, y, w, h, 0)
- // 文字颜色
- ctx.fillStyle = color
- // 水平布局
- switch (textAlign) {
- case 'left':
- break
- case 'center':
- x += 0.5 * w
- break
- case 'right':
- x += w
- break
- default: break
- }
- const textWidth = ctx.measureText(text).width
- const actualHeight = Math.ceil(textWidth / w) * lineHeight
- let paddingTop = Math.ceil((h - actualHeight) / 2)
- if (paddingTop < 0) paddingTop = 0
- // 垂直布局
- switch (verticalAlign) {
- case 'top':
- break
- case 'middle':
- y += paddingTop
- break
- case 'bottom':
- y += 2 * paddingTop
- break
- default: break
- }
- const inlinePaddingTop = Math.ceil((lineHeight - fontSize) / 2)
- // 不超过一行
- if (textWidth <= w) {
- ctx.fillText(text, x, y + inlinePaddingTop)
- return
- }
- // 多行文本
- const chars = text.split('')
- const _y = y
- // 逐行绘制
- let line = ''
- for (const ch of chars) {
- const testLine = line + ch
- const testWidth = ctx.measureText(testLine).width
- if (testWidth > w) {
- ctx.fillText(line, x, y + inlinePaddingTop)
- y += lineHeight
- line = ch
- if ((y + lineHeight) > (_y + h)) break
- } else {
- line = testLine
- }
- }
- // 避免溢出
- if ((y + lineHeight) <= (_y + h)) {
- ctx.fillText(line, x, y + inlinePaddingTop)
- }
- ctx.restore()
- }
- async drawNode(element) {
- const {layoutBox, computedStyle, name} = element
- const {src, text} = element.attributes
- if (name === 'view') {
- this.drawView(layoutBox, computedStyle)
- } else if (name === 'image') {
- await this.drawImage(src, layoutBox, computedStyle)
- } else if (name === 'text') {
- this.drawText(text, layoutBox, computedStyle)
- }
- const childs = Object.values(element.children)
- for (const child of childs) {
- await this.drawNode(child)
- }
- }
- }
- module.exports = {
- Draw
- }
- /***/ })
- /******/ ]);
- });
|