From a1460da565df45355493e2155e9f0845e480623a Mon Sep 17 00:00:00 2001 From: heidao Date: Thu, 6 Dec 2018 12:27:07 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E6=B8=90=E5=8F=98=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/gradient.js | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/pen.js | 9 ++++ 2 files changed, 135 insertions(+) create mode 100644 lib/gradient.js diff --git a/lib/gradient.js b/lib/gradient.js new file mode 100644 index 0000000..eac9a2f --- /dev/null +++ b/lib/gradient.js @@ -0,0 +1,126 @@ +/* eslint-disable */ +// 当ctx传入当前文件,const grd = ctx.createCircularGradient() 和 +// const grd = this.ctx.createLinearGradient() 无效,因此只能分开处理 +// 先分析,在外部创建grd,再传入使用就可以 + +!(function () { + + var api = { + toPoint: function(percent) { + let str = percent.replace('%', ''); + str /= 100; + return str; + }, + + analizeRadial: function(bg, width, height) { + let count = 0; + const coordinate = bg.match(/(?:(\d{1,3})[,])/g); + const colors = bg.match(/((?:#(?:\w{6}|\w{3}))|(?:rgba[(](?:(?:\d{1,3})\W\s){3}\d[)]))/g); + const status = bg.match(/\d{1,3}[%]/g); + for (let i = 0; i < colors.length; i++) { + if (colors[i].startsWith('rgba')) { + count += 3; + } + } + const length = coordinate.length - count; + switch (length) { + case 3: radialParams.coordinate = [coordinate[0].replace(',', ''), coordinate[1].replace(',', ''), coordinate[2].replace(',', '')]; break; + case 2: radialParams.coordinate = [coordinate[0].replace(',', ''), coordinate[1].replace(',', ''), Math.sqrt(width * width / 4 + height * height / 4)]; break; + case 1: radialParams.coordinate = [0, 0, coordinate[0].replace(',', '')]; break; + default: radialParams.coordinate = [0, 0, Math.sqrt(width * width / 4 + height * height / 4)]; break; + } + radialParams.colors = colors; + radialParams.status = status; + return radialParams.coordinate; + }, + + radialEffect: function(width, height, grd, ctx) { + if (radialParams.status && radialParams.status[0] && radialParams.status.length === radialParams.colors.length) { + for (let i = 0; i < radialParams.colors.length; i++) { + grd.addColorStop(this.toPoint(radialParams.status[i]), radialParams.colors[i]); + } + } else { + for (let i = 0; i < radialParams.colors.length; i++) { + grd.addColorStop(i / (radialParams.colors.length - 1), radialParams.colors[i]); + } + } + ctx.setFillStyle(grd); + ctx.fillRect(-(width / 2), -(height / 2), width, height); + }, + + analizeLinear: function(bg, width, height) { + const direction = bg.match(/([-]?\d{1,3})deg/); + const colors = bg.match(/((?:#(?:\w{6}|\w{3}))|(?:rgba[(](?:(?:\d{1,3})\W\s){3}\d[)]))/g); + const status = bg.match(/\d{1,3}[%]/g); + const dir = direction && direction[1] ? parseFloat(direction[1]) : 0; + switch (dir) { + case 0: console.log('case 0:'); linearParams.coordinate = [0, -height / 2, 0, height / 2]; break; + case 90: console.log('case 90:'); linearParams.coordinate = [width / 2, 0, -width / 2, 0]; break; + case -90: console.log('case -90:'); linearParams.coordinate = [-width / 2, 0, width / 2, 0]; break; + case 180: console.log('case 180:'); linearParams.coordinate = [0, height / 2, 0, -height / 2]; break; + case -180: console.log('case -180:'); linearParams.coordinate = [0, -height / 2, 0, height / 2]; break; + default: + console.log('default:'); + let x1 = 0; + let y1 = 0; + let x2 = 0; + let y2 = 0; + if (direction[1] > 0 && direction[1] < 90) { + x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else if (direction[1] > -180 && direction[1] < -90) { + x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else if (direction[1] > 90 && direction[1] < 180) { + x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else { + x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } + linearParams.coordinate = [x1, y1, x2, y2]; + break; + } + linearParams.colors = colors; + linearParams.status = status; + return linearParams.coordinate; + }, + + linearEffect: function(width, height, grd, ctx) { + if (linearParams.status && linearParams.status[0] && linearParams.status.length === linearParams.colors.length) { + for (let i = 0; i < linearParams.colors.length; i++) { + grd.addColorStop(this.toPoint(linearParams.status[i]), linearParams.colors[i]); + } + } else { + for (let i = 0; i < linearParams.colors.length; i++) { + grd.addColorStop(i / (linearParams.colors.length - 1), linearParams.colors[i]); + } + } + ctx.setFillStyle(grd); + ctx.fillRect(-(width / 2), -(height / 2), width, height); + }, + } + + const linearParams = { + coordinate: [], + colors: [], + status: [], + } + + const radialParams = { + coordinate: [], + colors: [], + status: [], + } + + module.exports = { api } + +})(); diff --git a/lib/pen.js b/lib/pen.js index 0d49efd..b7a21f7 100644 --- a/lib/pen.js +++ b/lib/pen.js @@ -1,4 +1,5 @@ const QR = require('./qrcode.js'); +const GD = require('./gradient.js'); export default class Painter { constructor(ctx, data) { @@ -38,6 +39,14 @@ export default class Painter { // 背景填充颜色 this.ctx.setFillStyle(bg); this.ctx.fillRect(-(width / 2), -(height / 2), width, height); + } else if (bg.startsWith('linear')) { + const param = GD.api.analizeLinear(bg, width, height); + const grd = this.ctx.createLinearGradient(param[0], param[1], param[2], param[3]); + GD.api.linearEffect(width, height, grd, this.ctx); + } else if (bg.startsWith('radial')) { + const param = GD.api.analizeRadial(bg, width, height); + const grd = this.ctx.createCircularGradient(param[0], param[1], param[2]); + GD.api.radialEffect(width, height, grd, this.ctx); } else { // 背景填充图片 this.ctx.drawImage(bg, -(width / 2), -(height / 2), width, height); From 9b30e002c10d09883fa6bb382e8265e46f3177f3 Mon Sep 17 00:00:00 2001 From: CPPAlien Date: Fri, 4 Jan 2019 14:41:32 +0800 Subject: [PATCH 2/2] =?UTF-8?q?rect=20=E6=94=AF=E6=8C=81=E6=B8=90=E5=8F=98?= =?UTF-8?q?=E8=89=B2=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9Bbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/gradient.js | 186 +++++++++++++++++++++--------------------------- lib/pen.js | 16 ++--- 2 files changed, 88 insertions(+), 114 deletions(-) diff --git a/lib/gradient.js b/lib/gradient.js index eac9a2f..9252523 100644 --- a/lib/gradient.js +++ b/lib/gradient.js @@ -6,119 +6,95 @@ !(function () { var api = { - toPoint: function(percent) { - let str = percent.replace('%', ''); - str /= 100; - return str; + isGradient: function(bg) { + if (bg.startsWith('linear') || bg.startsWith('radial')) { + return true; + } + return false; }, - analizeRadial: function(bg, width, height) { - let count = 0; - const coordinate = bg.match(/(?:(\d{1,3})[,])/g); - const colors = bg.match(/((?:#(?:\w{6}|\w{3}))|(?:rgba[(](?:(?:\d{1,3})\W\s){3}\d[)]))/g); - const status = bg.match(/\d{1,3}[%]/g); - for (let i = 0; i < colors.length; i++) { - if (colors[i].startsWith('rgba')) { - count += 3; - } + doGradient: function(bg, width, height, ctx) { + if (bg.startsWith('linear')) { + linearEffect(width, height, bg, ctx); + } else if (bg.startsWith('radial')) { + radialEffect(width, height, bg, ctx); } - const length = coordinate.length - count; - switch (length) { - case 3: radialParams.coordinate = [coordinate[0].replace(',', ''), coordinate[1].replace(',', ''), coordinate[2].replace(',', '')]; break; - case 2: radialParams.coordinate = [coordinate[0].replace(',', ''), coordinate[1].replace(',', ''), Math.sqrt(width * width / 4 + height * height / 4)]; break; - case 1: radialParams.coordinate = [0, 0, coordinate[0].replace(',', '')]; break; - default: radialParams.coordinate = [0, 0, Math.sqrt(width * width / 4 + height * height / 4)]; break; - } - radialParams.colors = colors; - radialParams.status = status; - return radialParams.coordinate; - }, - - radialEffect: function(width, height, grd, ctx) { - if (radialParams.status && radialParams.status[0] && radialParams.status.length === radialParams.colors.length) { - for (let i = 0; i < radialParams.colors.length; i++) { - grd.addColorStop(this.toPoint(radialParams.status[i]), radialParams.colors[i]); - } - } else { - for (let i = 0; i < radialParams.colors.length; i++) { - grd.addColorStop(i / (radialParams.colors.length - 1), radialParams.colors[i]); - } - } - ctx.setFillStyle(grd); - ctx.fillRect(-(width / 2), -(height / 2), width, height); - }, - - analizeLinear: function(bg, width, height) { - const direction = bg.match(/([-]?\d{1,3})deg/); - const colors = bg.match(/((?:#(?:\w{6}|\w{3}))|(?:rgba[(](?:(?:\d{1,3})\W\s){3}\d[)]))/g); - const status = bg.match(/\d{1,3}[%]/g); - const dir = direction && direction[1] ? parseFloat(direction[1]) : 0; - switch (dir) { - case 0: console.log('case 0:'); linearParams.coordinate = [0, -height / 2, 0, height / 2]; break; - case 90: console.log('case 90:'); linearParams.coordinate = [width / 2, 0, -width / 2, 0]; break; - case -90: console.log('case -90:'); linearParams.coordinate = [-width / 2, 0, width / 2, 0]; break; - case 180: console.log('case 180:'); linearParams.coordinate = [0, height / 2, 0, -height / 2]; break; - case -180: console.log('case -180:'); linearParams.coordinate = [0, -height / 2, 0, height / 2]; break; - default: - console.log('default:'); - let x1 = 0; - let y1 = 0; - let x2 = 0; - let y2 = 0; - if (direction[1] > 0 && direction[1] < 90) { - x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; - y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; - x2 = -x1; - y1 = -y2; - } else if (direction[1] > -180 && direction[1] < -90) { - x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; - y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; - x2 = -x1; - y1 = -y2; - } else if (direction[1] > 90 && direction[1] < 180) { - x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; - y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; - x2 = -x1; - y1 = -y2; - } else { - x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; - y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; - x2 = -x1; - y1 = -y2; - } - linearParams.coordinate = [x1, y1, x2, y2]; - break; - } - linearParams.colors = colors; - linearParams.status = status; - return linearParams.coordinate; - }, - - linearEffect: function(width, height, grd, ctx) { - if (linearParams.status && linearParams.status[0] && linearParams.status.length === linearParams.colors.length) { - for (let i = 0; i < linearParams.colors.length; i++) { - grd.addColorStop(this.toPoint(linearParams.status[i]), linearParams.colors[i]); - } - } else { - for (let i = 0; i < linearParams.colors.length; i++) { - grd.addColorStop(i / (linearParams.colors.length - 1), linearParams.colors[i]); - } - } - ctx.setFillStyle(grd); - ctx.fillRect(-(width / 2), -(height / 2), width, height); }, } - const linearParams = { - coordinate: [], - colors: [], - status: [], + function analizeGrad(string) { + const colorPercents = string.substring(0, string.length - 1).split("%,"); + const colors = []; + const percents = []; + for (let colorPercent of colorPercents) { + colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(" ")).trim()); + percents.push(colorPercent.substring(colorPercent.lastIndexOf(" "), colorPercent.length) / 100); + } + return {colors: colors, percents: percents}; } - const radialParams = { - coordinate: [], - colors: [], - status: [], + function radialEffect(width, height, bg, ctx) { + const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]); + const grd = ctx.createCircularGradient(0, 0, width < height ? height / 2 : width / 2); + for (let i = 0; i < colorPer.colors.length; i++) { + grd.addColorStop(colorPer.percents[i], colorPer.colors[i]); + } + ctx.setFillStyle(grd); + ctx.fillRect(-(width / 2), -(height / 2), width, height); + } + + function analizeLinear(bg, width, height) { + const direction = bg.match(/([-]?\d{1,3})deg/); + const dir = direction && direction[1] ? parseFloat(direction[1]) : 0; + let coordinate; + switch (dir) { + case 0: console.log('case 0:'); coordinate = [0, -height / 2, 0, height / 2]; break; + case 90: console.log('case 90:'); coordinate = [width / 2, 0, -width / 2, 0]; break; + case -90: console.log('case -90:'); coordinate = [-width / 2, 0, width / 2, 0]; break; + case 180: console.log('case 180:'); coordinate = [0, height / 2, 0, -height / 2]; break; + case -180: console.log('case -180:'); coordinate = [0, -height / 2, 0, height / 2]; break; + default: + let x1 = 0; + let y1 = 0; + let x2 = 0; + let y2 = 0; + if (direction[1] > 0 && direction[1] < 90) { + x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else if (direction[1] > -180 && direction[1] < -90) { + x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else if (direction[1] > 90 && direction[1] < 180) { + x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } else { + x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2; + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1; + x2 = -x1; + y1 = -y2; + } + coordinate = [x1, y1, x2, y2]; + break; + } + return coordinate; + } + + function linearEffect(width, height, bg, ctx) { + const param = analizeLinear(bg, width, height); + const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]); + const content = bg.match(/linear-gradient\((.+)\)/)[1]; + const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1)); + for (let i = 0; i < colorPer.colors.length; i++) { + grd.addColorStop(colorPer.percents[i], colorPer.colors[i]); + } + ctx.setFillStyle(grd); + ctx.fillRect(-(width / 2), -(height / 2), width, height); } module.exports = { api } diff --git a/lib/pen.js b/lib/pen.js index b7a21f7..1dd53b2 100644 --- a/lib/pen.js +++ b/lib/pen.js @@ -39,14 +39,8 @@ export default class Painter { // 背景填充颜色 this.ctx.setFillStyle(bg); this.ctx.fillRect(-(width / 2), -(height / 2), width, height); - } else if (bg.startsWith('linear')) { - const param = GD.api.analizeLinear(bg, width, height); - const grd = this.ctx.createLinearGradient(param[0], param[1], param[2], param[3]); - GD.api.linearEffect(width, height, grd, this.ctx); - } else if (bg.startsWith('radial')) { - const param = GD.api.analizeRadial(bg, width, height); - const grd = this.ctx.createCircularGradient(param[0], param[1], param[2]); - GD.api.radialEffect(width, height, grd, this.ctx); + } else if (GD.api.isGradient(bg)) { + GD.api.doGradient(bg, width, height, this.ctx); } else { // 背景填充图片 this.ctx.drawImage(bg, -(width / 2), -(height / 2), width, height); @@ -355,7 +349,11 @@ export default class Painter { width, height, } = this._preProcess(view); - this.ctx.setFillStyle(view.css.color); + if (GD.api.isGradient(view.css.color)) { + GD.api.doGradient(view.css.color, width, height, this.ctx); + } else { + this.ctx.setFillStyle(view.css.color); + } this.ctx.fillRect(-(width / 2), -(height / 2), width, height); this.ctx.restore(); this._doBorder(view, width, height);