├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── materialImage.es5.js └── materialImage.min.js ├── gulpfile.js ├── index.html ├── package.json └── src ├── colors.js └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | index.html 2 | dist 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | 'env': { 5 | 'browser': true, 6 | }, 7 | parserOptions: { 8 | ecmaVersion: 6, 9 | sourceType: 'module' 10 | }, 11 | extends: 'airbnb-base', 12 | plugins: [ 13 | 'html' 14 | ], 15 | 'rules': { 16 | 'import/extensions': ['error', 'always', { 17 | 'js': 'never' 18 | }], 19 | 'arrow-parens': ["error", "as-needed"], 20 | // allow debugger during development 21 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 22 | 'no-console': process.env.NODE_ENV === 'production' ? 2 : 0, 23 | 'no-underscore-dangle': 0, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules 8 | jspm_packages 9 | 10 | # Optional npm cache directory 11 | .npm 12 | 13 | # Optional REPL history 14 | .node_repl_history 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Yusen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaterialImage 2 | Working! 3 | 4 | ```bash 5 | $ npm i material-image -S 6 | ``` 7 | 8 | ## 使用方法 9 | 10 | ### ES6 Module: 11 | ``` javascript 12 | import MaterialImage from 'material-image'; 13 | 14 | const myDom = document.querySelector('.my-dom'); 15 | new MaterialImage({ 16 | el: myDom, 17 | }); 18 | ``` 19 | 20 | ### Script: 21 | ``` html 22 | 23 | 24 | 30 | ``` 31 | 32 | ### Configs: 33 | | 参数 | 类型 | 默认值 | 描述 | 34 | | ------------- |:-------------:|:-------:| :------------------:| 35 | | el | Element | body | 插入canvas的DOM节点 | 36 | | debug | Boolean | false | 调试模式开关 | 37 | | output | String | background | 三种输出模式,可选值:`background`、`image`、`canvas` | 38 | | imageType | String | jpeg | 输出为图片时(`background`、`image`)的图片类型 | 39 | | quality | Number | 1 | 输出为图片时(`background`、`image`)的图片质量,取值 `0~1` 之间 | 40 | 41 | ### Methods: 42 | | 名称 | 描述 | 43 | | ------------- |:--------------:| 44 | | protract | 重新绘制canvas | 45 | | adjust | 调整canvas尺寸 | 46 | | destroy | 移除canvas节点 | 47 | | toDataUrl | 生成 base64Url,参数 `(imageType, quality)` | 48 | 49 | ## 生成策略 50 | 51 | 随机一定数量的颜色,再随机画出不同尺寸、位置的图形(矩形和圆)。 52 | 53 | ## 开发计划 54 | 55 | 预定几种生成策略,比如同心圆、连续一定角度排列的矩形等。 56 | 添加元素移动效果。 57 | 58 | **Wait me!** 59 | -------------------------------------------------------------------------------- /dist/materialImage.es5.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | if (typeof define === "function" && define.amd) { 3 | define(['module'], factory); 4 | } else if (typeof exports !== "undefined") { 5 | factory(module); 6 | } else { 7 | var mod = { 8 | exports: {} 9 | }; 10 | factory(mod); 11 | global.MaterialImage = mod.exports; 12 | } 13 | })(this, function (module) { 14 | 'use strict'; 15 | 16 | function _toArray(arr) { 17 | return Array.isArray(arr) ? arr : Array.from(arr); 18 | } 19 | 20 | function _classCallCheck(instance, Constructor) { 21 | if (!(instance instanceof Constructor)) { 22 | throw new TypeError("Cannot call a class as a function"); 23 | } 24 | } 25 | 26 | var _createClass = function () { 27 | function defineProperties(target, props) { 28 | for (var i = 0; i < props.length; i++) { 29 | var descriptor = props[i]; 30 | descriptor.enumerable = descriptor.enumerable || false; 31 | descriptor.configurable = true; 32 | if ("value" in descriptor) descriptor.writable = true; 33 | Object.defineProperty(target, descriptor.key, descriptor); 34 | } 35 | } 36 | 37 | return function (Constructor, protoProps, staticProps) { 38 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 39 | if (staticProps) defineProperties(Constructor, staticProps); 40 | return Constructor; 41 | }; 42 | }(); 43 | 44 | /*! 45 | * yusen 46 | * https://github.com/yscoder/MaterialImage 47 | * MIT LICENSE 48 | */ 49 | 50 | var colorPlate = ['#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E53935', '#D32F2F', '#C62828', '#B71C1C', '#FF8A80', '#FF5252', '#FF1744', '#D50000', '#FCE4EC', '#F8BBD0', '#F48FB1', '#F06292', '#EC407A', '#E91E63', '#D81B60', '#C2185B', '#AD1457', '#880E4F', '#FF80AB', '#FF4081', '#F50057', '#C51162', '#F3E5F5', '#E1BEE7', '#CE93D8', '#BA68C8', '#AB47BC', '#9C27B0', '#8E24AA', '#7B1FA2', '#6A1B9A', '#4A148C', '#EA80FC', '#E040FB', '#D500F9', '#AA00FF', '#EDE7F6', '#D1C4E9', '#B39DDB', '#9575CD', '#7E57C2', '#673AB7', '#5E35B1', '#512DA8', '#4527A0', '#311B92', '#B388FF', '#7C4DFF', '#651FFF', '#6200EA', '#E8EAF6', '#C5CAE9', '#9FA8DA', '#7986CB', '#5C6BC0', '#3F51B5', '#3949AB', '#303F9F', '#283593', '#1A237E', '#8C9EFF', '#536DFE', '#3D5AFE', '#304FFE', '#E3F2FD', '#BBDEFB', '#90CAF9', '#64B5F6', '#42A5F5', '#2196F3', '#1E88E5', '#1976D2', '#1565C0', '#0D47A1', '#82B1FF', '#448AFF', '#2979FF', '#2962FF', '#E1F5FE', '#B3E5FC', '#81D4FA', '#4FC3F7', '#29B6F6', '#03A9F4', '#039BE5', '#0288D1', '#0277BD', '#01579B', '#80D8FF', '#40C4FF', '#00B0FF', '#0091EA', '#E0F2F1', '#B2DFDB', '#80CBC4', '#4DB6AC', '#26A69A', '#009688', '#00897B', '#00796B', '#00695C', '#004D40', '#A7FFEB', '#64FFDA', '#1DE9B6', '#00BFA5', '#E0F7FA', '#B2EBF2', '#80DEEA', '#4DD0E1', '#26C6DA', '#00BCD4', '#00ACC1', '#0097A7', '#00838F', '#006064', '#84FFFF', '#18FFFF', '#00E5FF', '#00B8D4', '#E8F5E9', '#C8E6C9', '#A5D6A7', '#81C784', '#66BB6A', '#4CAF50', '#43A047', '#388E3C', '#2E7D32', '#1B5E20', '#B9F6CA', '#69F0AE', '#00E676', '#00C853', '#F1F8E9', '#DCEDC8', '#C5E1A5', '#AED581', '#9CCC65', '#8BC34A', '#7CB342', '#689F38', '#558B2F', '#33691E', '#CCFF90', '#B2FF59', '#76FF03', '#64DD17', '#F9FBE7', '#F0F4C3', '#E6EE9C', '#DCE775', '#D4E157', '#CDDC39', '#C0CA33', '#AFB42B', '#9E9D24', '#827717', '#F4FF81', '#EEFF41', '#C6FF00', '#AEEA00', '#FFFDE7', '#FFF9C4', '#FFF59D', '#FFF176', '#FFEE58', '#FFEB3B', '#FDD835', '#FBC02D', '#F9A825', '#F57F17', '#FFFF8D', '#FFFF00', '#FFEA00', '#FFD600', '#FFF8E1', '#FFECB3', '#FFE082', '#FFD54F', '#FFCA28', '#FFC107', '#FFB300', '#FFA000', '#FF8F00', '#FF6F00', '#FFE57F', '#FFD740', '#FFC400', '#FFAB00', '#FFF3E0', '#FFE0B2', '#FFCC80', '#FFB74D', '#FFA726', '#FF9800', '#FB8C00', '#F57C00', '#EF6C00', '#E65100', '#FFD180', '#FFAB40', '#FF9100', '#FF6D00', '#FBE9E7', '#FFCCBC', '#FFAB91', '#FF8A65', '#FF7043', '#FF5722', '#F4511E', '#E64A19', '#D84315', '#BF360C', '#FF9E80', '#FF6E40', '#FF3D00', '#DD2C00', '#FAFAFA', '#F5F5F5', '#EEEEEE', '#E0E0E0', '#BDBDBD', '#9E9E9E', '#757575', '#616161', '#424242', '#212121', '#ECEFF1', '#CFD8DC', '#B0BEC5', '#90A4AE', '#78909C', '#607D8B', '#546E7A', '#455A64', '#37474F', '#263238', '#EFEBE9', '#D7CCC8', '#BCAAA4', '#A1887F', '#8D6E63', '#795548', '#6D4C41', '#5D4037', '#4E342E', '#3E2723']; 51 | 52 | var random = function random(min, max) { 53 | return Math.floor(Math.random() * (max - min + 1) + min); 54 | }; 55 | 56 | var getRandomColor = function getRandomColor() { 57 | return colorPlate[random(0, colorPlate.length - 1)]; 58 | }; 59 | 60 | var getColors = function getColors(count) { 61 | var colors = []; 62 | for (var i = 0; i <= count;) { 63 | var color = getRandomColor(); 64 | if (colors.indexOf(color) === -1) { 65 | colors.push(color); 66 | i += 1; 67 | } 68 | } 69 | return colors; 70 | }; 71 | 72 | var createCanvas = function createCanvas(width, height) { 73 | var canvas = document.createElement('canvas'); 74 | canvas.width = width; 75 | canvas.height = height; 76 | return canvas; 77 | }; 78 | 79 | var getShape = function getShape() { 80 | return ['rect', 'arc'][random(0, 1)]; 81 | }; 82 | 83 | var Drawer = function () { 84 | function Drawer(canvas) { 85 | _classCallCheck(this, Drawer); 86 | 87 | this.ctx = canvas.getContext('2d'); 88 | } 89 | 90 | _createClass(Drawer, [{ 91 | key: 'shadow', 92 | value: function shadow(_ref) { 93 | var blur = _ref.blur, 94 | _ref$x = _ref.x, 95 | x = _ref$x === undefined ? 1 : _ref$x, 96 | _ref$y = _ref.y, 97 | y = _ref$y === undefined ? 1 : _ref$y, 98 | _ref$color = _ref.color, 99 | color = _ref$color === undefined ? 'rgba(0, 0, 0, .3)' : _ref$color; 100 | 101 | this.ctx.shadowBlur = blur; 102 | this.ctx.shadowOffsetX = x; 103 | this.ctx.shadowOffsetY = y; 104 | this.ctx.shadowColor = color; 105 | } 106 | }, { 107 | key: 'rect', 108 | value: function rect(_ref2) { 109 | var width = _ref2.width, 110 | height = _ref2.height; 111 | 112 | var r = random(10, 360) * Math.PI / 180; 113 | var w = random(100, Math.max(width, height)) * (random(-10, 10) || 1); 114 | var h = random(100, Math.min(width, height)) * (random(-10, 10) || 1); 115 | this.ctx.rotate(r); 116 | this.ctx.rect(0, 0, w, h); 117 | this.ctx.rotate(-r); 118 | } 119 | }, { 120 | key: 'arc', 121 | value: function arc(_ref3) { 122 | var width = _ref3.width, 123 | height = _ref3.height; 124 | 125 | var r = random(100, Math.min(width, height) / 2); 126 | this.ctx.arc(0, 0, r, 0, 2 * Math.PI); 127 | } 128 | }, { 129 | key: 'draw', 130 | value: function draw(sharp, option) { 131 | var width = option.width, 132 | height = option.height, 133 | color = option.color; 134 | 135 | 136 | this.ctx.beginPath(); 137 | this.shadow({ 138 | blur: 20 139 | }); 140 | 141 | var x = random(0, width); 142 | var y = random(0, height); 143 | this.ctx.translate(x, y); 144 | this[sharp](option); 145 | this.ctx.closePath(); 146 | this.ctx.fillStyle = color; 147 | this.ctx.fill(); 148 | this.ctx.translate(-x, -y); 149 | } 150 | }, { 151 | key: 'fill', 152 | value: function fill(color, width, height) { 153 | this.ctx.fillStyle = color; 154 | this.ctx.fillRect(0, 0, width, height); 155 | } 156 | }]); 157 | 158 | return Drawer; 159 | }(); 160 | 161 | var MaterialImage = function () { 162 | function MaterialImage() { 163 | var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 164 | 165 | _classCallCheck(this, MaterialImage); 166 | 167 | var _config$el = config.el, 168 | el = _config$el === undefined ? document.querySelector('body') : _config$el, 169 | _config$debug = config.debug, 170 | debug = _config$debug === undefined ? false : _config$debug, 171 | _config$output = config.output, 172 | output = _config$output === undefined ? 'background' : _config$output, 173 | imageType = config.imageType, 174 | quality = config.quality; 175 | 176 | 177 | var width = el.clientWidth; 178 | var height = el.clientHeight; 179 | 180 | this.debug = debug; 181 | this.element = el; 182 | this.width = width; 183 | this.height = height; 184 | this.outputType = output; 185 | this.outputOption = { 186 | imageType: imageType, 187 | quality: quality 188 | }; 189 | this.canvas = createCanvas(width, height); 190 | this.render(); 191 | this.protract(); 192 | } 193 | 194 | _createClass(MaterialImage, [{ 195 | key: 'output', 196 | value: function output() { 197 | if (this.outputType === 'canvas') return; 198 | 199 | var dataUrl = this.toDataUrl(this.outputOption); 200 | switch (this.outputType) { 201 | case 'background': 202 | this.element.style.backgroundImage = 'url("' + dataUrl + '")'; 203 | break; 204 | case 'image': 205 | this.img.src = dataUrl; 206 | break; 207 | default: 208 | break; 209 | } 210 | } 211 | }, { 212 | key: 'protract', 213 | value: function protract() { 214 | var _this = this; 215 | 216 | var count = random(0, 8) + 6; 217 | 218 | var _getColors = getColors(count), 219 | _getColors2 = _toArray(_getColors), 220 | background = _getColors2[0], 221 | colors = _getColors2.slice(1); 222 | 223 | var drawer = new Drawer(this.canvas); 224 | var width = this.width; 225 | var height = this.height; 226 | 227 | drawer.fill(background, width, height); 228 | 229 | var i = 0; 230 | if (!this.debug) { 231 | while (i < count) { 232 | drawer.draw(getShape(), { 233 | color: colors[i], 234 | width: width, 235 | height: height 236 | }); 237 | i += 1; 238 | } 239 | this.output(); 240 | } else { 241 | var debugDraw = function debugDraw() { 242 | drawer.draw(getShape(), { 243 | color: colors[i], 244 | width: width, 245 | height: height 246 | }); 247 | _this.output(); 248 | i += 1; 249 | if (i < count) { 250 | setTimeout(debugDraw, 1000); 251 | } 252 | }; 253 | setTimeout(debugDraw, 1000); 254 | } 255 | } 256 | }, { 257 | key: 'adjust', 258 | value: function adjust() { 259 | var canvas = this.canvas; 260 | var element = this.element; 261 | 262 | canvas.width = element.clientWidth; 263 | canvas.height = element.clientHeight; 264 | 265 | this.protract(); 266 | } 267 | }, { 268 | key: 'toDataUrl', 269 | value: function toDataUrl() { 270 | var imageType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'jpeg'; 271 | var quality = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; 272 | 273 | return this.canvas.toDataURL('image/' + imageType, quality); 274 | } 275 | }, { 276 | key: 'render', 277 | value: function render() { 278 | switch (this.outputType) { 279 | case 'canvas': 280 | this.element.appendChild(this.canvas); 281 | break; 282 | case 'background': 283 | this.element.style.cssText += '\n background-repeat: no-repeat;\n background-size: cover;'; 284 | break; 285 | case 'image': 286 | this.img = document.createElement('img'); 287 | this.img.style.cssText = 'width: 100%; height: 100%'; 288 | this.element.appendChild(this.img); 289 | break; 290 | default: 291 | break; 292 | } 293 | } 294 | }, { 295 | key: 'destroy', 296 | value: function destroy() { 297 | switch (this.outputType) { 298 | case 'canvas': 299 | this.canvas.remove(); 300 | break; 301 | case 'background': 302 | { 303 | var cssText = this.element.style.cssText; 304 | this.element.style.cssText = cssText.replace(/background[^;]+;/g, ''); 305 | break; 306 | } 307 | case 'image': 308 | this.img.remove(); 309 | break; 310 | default: 311 | break; 312 | } 313 | } 314 | }]); 315 | 316 | return MaterialImage; 317 | }(); 318 | 319 | module.exports = MaterialImage; 320 | }); -------------------------------------------------------------------------------- /dist/materialImage.min.js: -------------------------------------------------------------------------------- 1 | !function(t,F){if("function"==typeof define&&define.amd)define(["module"],F);else if("undefined"!=typeof exports)F(module);else{var e={exports:{}};F(e),t.MaterialImage=e.exports}}(this,function(t){"use strict";function F(t){return Array.isArray(t)?t:Array.from(t)}function e(t,F){if(!(t instanceof F))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(t,F){for(var e=0;e0&&void 0!==arguments[0]?arguments[0]:{};e(this,t);var i=F.el,a=void 0===i?document.querySelector("body"):i,n=F.debug,r=void 0!==n&&n,s=F.output,h=void 0===s?"background":s,o=F.imageType,c=F.quality,u=a.clientWidth,C=a.clientHeight;this.debug=r,this.element=a,this.width=u,this.height=C,this.outputType=h,this.outputOption={imageType:o,quality:c},this.canvas=E(u,C),this.render(),this.protract()}return i(t,[{key:"output",value:function(){if("canvas"!==this.outputType){var t=this.toDataUrl(this.outputOption);switch(this.outputType){case"background":this.element.style.backgroundImage='url("'+t+'")';break;case"image":this.img.src=t}}}},{key:"protract",value:function(){var t=this,e=n(0,8)+6,i=s(e),a=F(i),r=a[0],E=a.slice(1),c=new o(this.canvas),u=this.width,C=this.height;c.fill(r,u,C);var l=0;if(this.debug){var A=function F(){c.draw(h(),{color:E[l],width:u,height:C}),t.output(),(l+=1)0&&void 0!==arguments[0]?arguments[0]:"jpeg",F=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return this.canvas.toDataURL("image/"+t,F)}},{key:"render",value:function(){switch(this.outputType){case"canvas":this.element.appendChild(this.canvas);break;case"background":this.element.style.cssText+="\n background-repeat: no-repeat;\n background-size: cover;";break;case"image":this.img=document.createElement("img"),this.img.style.cssText="width: 100%; height: 100%",this.element.appendChild(this.img)}}},{key:"destroy",value:function(){switch(this.outputType){case"canvas":this.canvas.remove();break;case"background":var t=this.element.style.cssText;this.element.style.cssText=t.replace(/background[^;]+;/g,"");break;case"image":this.img.remove()}}}]),t}();t.exports=c}); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const babel = require('gulp-babel'); 3 | const uglify = require('gulp-uglify'); 4 | const rename = require('gulp-rename'); 5 | const browserSync = require('browser-sync'); 6 | const eslint = require('gulp-eslint'); 7 | 8 | const src = './src/'; 9 | const dist = './dist/'; 10 | 11 | const buildEs5 = () => gulp.src(`${src}index.js`) 12 | .pipe(rename('MaterialImage.js')) 13 | .pipe(babel({ 14 | presets: ['es2015'], 15 | plugins: [ 16 | ['transform-es2015-modules-umd', { 17 | globals: { 18 | 'es6-promise': 'Promise', 19 | }, 20 | }], 21 | ], 22 | })) 23 | .pipe(rename('materialImage.es5.js')) 24 | .pipe(gulp.dest('dist')); 25 | 26 | gulp.task('build', () => buildEs5() 27 | .pipe(uglify({ 28 | preserveComments: 'license', 29 | })) 30 | .pipe(rename('materialImage.min.js')) 31 | .pipe(gulp.dest(dist))); 32 | 33 | gulp.task('es5', () => buildEs5()); 34 | 35 | gulp.task('dev', () => { 36 | browserSync.init({ 37 | server: { 38 | baseDir: './', 39 | }, 40 | }); 41 | 42 | gulp.watch('index.html', browserSync.reload); 43 | gulp.watch(`${src}*.*`, ['es5']).on('change', browserSync.reload); 44 | }); 45 | 46 | gulp.task('lint', () => gulp.src(`${src}index.js`) 47 | .pipe(eslint()) 48 | .pipe(eslint.format())); 49 | 50 | gulp.task('default', ['build']); 51 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MaterialImage 6 | 20 | 21 | 22 | 23 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-image", 3 | "version": "0.2.5", 4 | "description": "Generate random material design background image.", 5 | "main": "dist/materialImage.min.js", 6 | "keywords": [ 7 | "material", 8 | "design", 9 | "background", 10 | "random", 11 | "image" 12 | ], 13 | "author": "yusen", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "babel-eslint": "^7.2.1", 17 | "babel-plugin-transform-es2015-modules-umd": "^6.24.0", 18 | "babel-preset-es2015": "^6.24.0", 19 | "browser-sync": "^2.18.2", 20 | "eslint-config-airbnb-base": "^11.1.3", 21 | "eslint-friendly-formatter": "^2.0.7", 22 | "eslint-import-resolver-webpack": "^0.8.1", 23 | "eslint-loader": "^1.6.1", 24 | "eslint-plugin-html": "^2.0.0", 25 | "eslint-plugin-import": "^2.2.0", 26 | "gulp": "^3.9.1", 27 | "gulp-babel": "^6.1.2", 28 | "gulp-eslint": "^3.0.1", 29 | "gulp-rename": "^1.2.2", 30 | "gulp-uglify": "^2.1.2" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/yscoder/MaterialImage.git" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/colors.js: -------------------------------------------------------------------------------- 1 | export default { 2 | "red": ["#FFEBEE", "#FFCDD2", "#EF9A9A", "#E57373", "#EF5350", "#F44336", "#E53935", "#D32F2F", "#C62828", "#B71C1C", "#FF8A80", "#FF5252", "#FF1744", "#D50000"], 3 | "pink": ["#FCE4EC", "#F8BBD0", "#F48FB1", "#F06292", "#EC407A", "#E91E63", "#D81B60", "#C2185B", "#AD1457", "#880E4F", "#FF80AB", "#FF4081", "#F50057", "#C51162"], 4 | "purple": ["#F3E5F5", "#E1BEE7", "#CE93D8", "#BA68C8", "#AB47BC", "#9C27B0", "#8E24AA", "#7B1FA2", "#6A1B9A", "#4A148C", "#EA80FC", "#E040FB", "#D500F9", "#AA00FF"], 5 | "deepPurple": ["#EDE7F6", "#D1C4E9", "#B39DDB", "#9575CD", "#7E57C2", "#673AB7", "#5E35B1", "#512DA8", "#4527A0", "#311B92", "#B388FF", "#7C4DFF", "#651FFF", "#6200EA"], 6 | "indigo": ["#E8EAF6", "#C5CAE9", "#9FA8DA", "#7986CB", "#5C6BC0", "#3F51B5", "#3949AB", "#303F9F", "#283593", "#1A237E", "#8C9EFF", "#536DFE", "#3D5AFE", "#304FFE"], 7 | "blue": ["#E3F2FD", "#BBDEFB", "#90CAF9", "#64B5F6", "#42A5F5", "#2196F3", "#1E88E5", "#1976D2", "#1565C0", "#0D47A1", "#82B1FF", "#448AFF", "#2979FF", "#2962FF"], 8 | "lightBlue": ["#E1F5FE", "#B3E5FC", "#81D4FA", "#4FC3F7", "#29B6F6", "#03A9F4", "#039BE5", "#0288D1", "#0277BD", "#01579B", "#80D8FF", "#40C4FF", "#00B0FF", "#0091EA"], 9 | "teal": ["#E0F2F1", "#B2DFDB", "#80CBC4", "#4DB6AC", "#26A69A", "#009688", "#00897B", "#00796B", "#00695C", "#004D40", "#A7FFEB", "#64FFDA", "#1DE9B6", "#00BFA5"], 10 | "cyan": ["#E0F7FA", "#B2EBF2", "#80DEEA", "#4DD0E1", "#26C6DA", "#00BCD4", "#00ACC1", "#0097A7", "#00838F", "#006064", "#84FFFF", "#18FFFF", "#00E5FF", "#00B8D4"], 11 | "green": ["#E8F5E9", "#C8E6C9", "#A5D6A7", "#81C784", "#66BB6A", "#4CAF50", "#43A047", "#388E3C", "#2E7D32", "#1B5E20", "#B9F6CA", "#69F0AE", "#00E676", "#00C853"], 12 | "lightGreen": ["#F1F8E9", "#DCEDC8", "#C5E1A5", "#AED581", "#9CCC65", "#8BC34A", "#7CB342", "#689F38", "#558B2F", "#33691E", "#CCFF90", "#B2FF59", "#76FF03", "#64DD17"], 13 | "lime": ["#F9FBE7", "#F0F4C3", "#E6EE9C", "#DCE775", "#D4E157", "#CDDC39", "#C0CA33", "#AFB42B", "#9E9D24", "#827717", "#F4FF81", "#EEFF41", "#C6FF00", "#AEEA00"], 14 | "yellow": ["#FFFDE7", "#FFF9C4", "#FFF59D", "#FFF176", "#FFEE58", "#FFEB3B", "#FDD835", "#FBC02D", "#F9A825", "#F57F17", "#FFFF8D", "#FFFF00", "#FFEA00", "#FFD600"], 15 | "amber": ["#FFF8E1", "#FFECB3", "#FFE082", "#FFD54F", "#FFCA28", "#FFC107", "#FFB300", "#FFA000", "#FF8F00", "#FF6F00", "#FFE57F", "#FFD740", "#FFC400", "#FFAB00"], 16 | "orange": ["#FFF3E0", "#FFE0B2", "#FFCC80", "#FFB74D", "#FFA726", "#FF9800", "#FB8C00", "#F57C00", "#EF6C00", "#E65100", "#FFD180", "#FFAB40", "#FF9100", "#FF6D00"], 17 | "deepOrange": ["#FBE9E7", "#FFCCBC", "#FFAB91", "#FF8A65", "#FF7043", "#FF5722", "#F4511E", "#E64A19", "#D84315", "#BF360C", "#FF9E80", "#FF6E40", "#FF3D00", "#DD2C00"], 18 | "grey": ["#FAFAFA", "#F5F5F5", "#EEEEEE", "#E0E0E0", "#BDBDBD", "#9E9E9E", "#757575", "#616161", "#424242", "#212121"], 19 | "blueGrey": ["#ECEFF1", "#CFD8DC", "#B0BEC5", "#90A4AE", "#78909C", "#607D8B", "#546E7A", "#455A64", "#37474F", "#263238"], 20 | "brown": ["#EFEBE9", "#D7CCC8", "#BCAAA4", "#A1887F", "#8D6E63", "#795548", "#6D4C41", "#5D4037", "#4E342E", "#3E2723"] 21 | } 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * yusen 3 | * https://github.com/yscoder/MaterialImage 4 | * MIT LICENSE 5 | */ 6 | 7 | const colorPlate = [ 8 | '#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E53935', '#D32F2F', '#C62828', '#B71C1C', '#FF8A80', '#FF5252', '#FF1744', '#D50000', '#FCE4EC', '#F8BBD0', '#F48FB1', '#F06292', '#EC407A', '#E91E63', '#D81B60', '#C2185B', '#AD1457', '#880E4F', '#FF80AB', '#FF4081', '#F50057', '#C51162', '#F3E5F5', '#E1BEE7', '#CE93D8', '#BA68C8', '#AB47BC', '#9C27B0', '#8E24AA', '#7B1FA2', '#6A1B9A', '#4A148C', '#EA80FC', '#E040FB', '#D500F9', '#AA00FF', '#EDE7F6', '#D1C4E9', '#B39DDB', '#9575CD', '#7E57C2', '#673AB7', '#5E35B1', '#512DA8', '#4527A0', '#311B92', '#B388FF', '#7C4DFF', '#651FFF', '#6200EA', '#E8EAF6', '#C5CAE9', '#9FA8DA', '#7986CB', '#5C6BC0', '#3F51B5', '#3949AB', '#303F9F', '#283593', '#1A237E', '#8C9EFF', '#536DFE', '#3D5AFE', '#304FFE', '#E3F2FD', '#BBDEFB', '#90CAF9', '#64B5F6', '#42A5F5', '#2196F3', '#1E88E5', '#1976D2', '#1565C0', '#0D47A1', '#82B1FF', '#448AFF', '#2979FF', '#2962FF', '#E1F5FE', '#B3E5FC', '#81D4FA', '#4FC3F7', '#29B6F6', '#03A9F4', '#039BE5', '#0288D1', '#0277BD', '#01579B', '#80D8FF', '#40C4FF', '#00B0FF', '#0091EA', '#E0F2F1', '#B2DFDB', '#80CBC4', '#4DB6AC', '#26A69A', '#009688', '#00897B', '#00796B', '#00695C', '#004D40', '#A7FFEB', '#64FFDA', '#1DE9B6', '#00BFA5', '#E0F7FA', '#B2EBF2', '#80DEEA', '#4DD0E1', '#26C6DA', '#00BCD4', '#00ACC1', '#0097A7', '#00838F', '#006064', '#84FFFF', '#18FFFF', '#00E5FF', '#00B8D4', '#E8F5E9', '#C8E6C9', '#A5D6A7', '#81C784', '#66BB6A', '#4CAF50', '#43A047', '#388E3C', '#2E7D32', '#1B5E20', '#B9F6CA', '#69F0AE', '#00E676', '#00C853', '#F1F8E9', '#DCEDC8', '#C5E1A5', '#AED581', '#9CCC65', '#8BC34A', '#7CB342', '#689F38', '#558B2F', '#33691E', '#CCFF90', '#B2FF59', '#76FF03', '#64DD17', '#F9FBE7', '#F0F4C3', '#E6EE9C', '#DCE775', '#D4E157', '#CDDC39', '#C0CA33', '#AFB42B', '#9E9D24', '#827717', '#F4FF81', '#EEFF41', '#C6FF00', '#AEEA00', '#FFFDE7', '#FFF9C4', '#FFF59D', '#FFF176', '#FFEE58', '#FFEB3B', '#FDD835', '#FBC02D', '#F9A825', '#F57F17', '#FFFF8D', '#FFFF00', '#FFEA00', '#FFD600', '#FFF8E1', '#FFECB3', '#FFE082', '#FFD54F', '#FFCA28', '#FFC107', '#FFB300', '#FFA000', '#FF8F00', '#FF6F00', '#FFE57F', '#FFD740', '#FFC400', '#FFAB00', '#FFF3E0', '#FFE0B2', '#FFCC80', '#FFB74D', '#FFA726', '#FF9800', '#FB8C00', '#F57C00', '#EF6C00', '#E65100', '#FFD180', '#FFAB40', '#FF9100', '#FF6D00', '#FBE9E7', '#FFCCBC', '#FFAB91', '#FF8A65', '#FF7043', '#FF5722', '#F4511E', '#E64A19', '#D84315', '#BF360C', '#FF9E80', '#FF6E40', '#FF3D00', '#DD2C00', '#FAFAFA', '#F5F5F5', '#EEEEEE', '#E0E0E0', '#BDBDBD', '#9E9E9E', '#757575', '#616161', '#424242', '#212121', '#ECEFF1', '#CFD8DC', '#B0BEC5', '#90A4AE', '#78909C', '#607D8B', '#546E7A', '#455A64', '#37474F', '#263238', '#EFEBE9', '#D7CCC8', '#BCAAA4', '#A1887F', '#8D6E63', '#795548', '#6D4C41', '#5D4037', '#4E342E', '#3E2723', 9 | ]; 10 | 11 | const random = (min, max) => Math.floor((Math.random() * ((max - min) + 1)) + min); 12 | 13 | const getRandomColor = () => colorPlate[random(0, colorPlate.length - 1)]; 14 | 15 | const getColors = count => { 16 | const colors = []; 17 | for (let i = 0; i <= count;) { 18 | const color = getRandomColor(); 19 | if (colors.indexOf(color) === -1) { 20 | colors.push(color); 21 | i += 1; 22 | } 23 | } 24 | return colors; 25 | }; 26 | 27 | const createCanvas = (width, height) => { 28 | const canvas = document.createElement('canvas'); 29 | canvas.width = width; 30 | canvas.height = height; 31 | return canvas; 32 | }; 33 | 34 | const getShape = () => ['rect', 'arc'][random(0, 1)]; 35 | 36 | class Drawer { 37 | constructor(canvas) { 38 | this.ctx = canvas.getContext('2d'); 39 | } 40 | 41 | shadow({ blur, x = 1, y = 1, color = 'rgba(0, 0, 0, .3)' }) { 42 | this.ctx.shadowBlur = blur; 43 | this.ctx.shadowOffsetX = x; 44 | this.ctx.shadowOffsetY = y; 45 | this.ctx.shadowColor = color; 46 | } 47 | 48 | rect({ width, height }) { 49 | const r = (random(10, 360) * Math.PI) / 180; 50 | const w = random(100, Math.max(width, height)) * (random(-10, 10) || 1); 51 | const h = random(100, Math.min(width, height)) * (random(-10, 10) || 1); 52 | this.ctx.rotate(r); 53 | this.ctx.rect(0, 0, w, h); 54 | this.ctx.rotate(-r); 55 | } 56 | 57 | arc({ width, height }) { 58 | const r = random(100, Math.min(width, height) / 2); 59 | this.ctx.arc(0, 0, r, 0, 2 * Math.PI); 60 | } 61 | 62 | draw(sharp, option) { 63 | const { width, height, color } = option; 64 | 65 | this.ctx.beginPath(); 66 | this.shadow({ 67 | blur: 20, 68 | }); 69 | 70 | const x = random(0, width); 71 | const y = random(0, height); 72 | this.ctx.translate(x, y); 73 | this[sharp](option); 74 | this.ctx.closePath(); 75 | this.ctx.fillStyle = color; 76 | this.ctx.fill(); 77 | this.ctx.translate(-x, -y); 78 | } 79 | 80 | fill(color, width, height) { 81 | this.ctx.fillStyle = color; 82 | this.ctx.fillRect(0, 0, width, height); 83 | } 84 | } 85 | 86 | class MaterialImage { 87 | constructor(config = {}) { 88 | const { 89 | el = document.querySelector('body'), 90 | debug = false, 91 | output = 'background', 92 | imageType, 93 | quality } = config; 94 | 95 | const width = el.clientWidth; 96 | const height = el.clientHeight; 97 | 98 | this.debug = debug; 99 | this.element = el; 100 | this.width = width; 101 | this.height = height; 102 | this.outputType = output; 103 | this.outputOption = { 104 | imageType, 105 | quality, 106 | }; 107 | this.canvas = createCanvas(width, height); 108 | this.render(); 109 | this.protract(); 110 | } 111 | 112 | output() { 113 | if (this.outputType === 'canvas') return; 114 | 115 | const dataUrl = this.toDataUrl(this.outputOption); 116 | switch (this.outputType) { 117 | case 'background': 118 | this.element.style.backgroundImage = `url("${dataUrl}")`; 119 | break; 120 | case 'image': 121 | this.img.src = dataUrl; 122 | break; 123 | default: 124 | break; 125 | } 126 | } 127 | 128 | protract() { 129 | const count = random(0, 8) + 6; 130 | const [background, ...colors] = getColors(count); 131 | const drawer = new Drawer(this.canvas); 132 | const width = this.width; 133 | const height = this.height; 134 | 135 | drawer.fill(background, width, height); 136 | 137 | let i = 0; 138 | if (!this.debug) { 139 | while (i < count) { 140 | drawer.draw(getShape(), { 141 | color: colors[i], 142 | width, 143 | height, 144 | }); 145 | i += 1; 146 | } 147 | this.output(); 148 | } else { 149 | const debugDraw = () => { 150 | drawer.draw(getShape(), { 151 | color: colors[i], 152 | width, 153 | height, 154 | }); 155 | this.output(); 156 | i += 1; 157 | if (i < count) { 158 | setTimeout(debugDraw, 1000); 159 | } 160 | }; 161 | setTimeout(debugDraw, 1000); 162 | } 163 | } 164 | 165 | adjust() { 166 | const canvas = this.canvas; 167 | const element = this.element; 168 | 169 | canvas.width = element.clientWidth; 170 | canvas.height = element.clientHeight; 171 | 172 | this.protract(); 173 | } 174 | 175 | toDataUrl(imageType = 'jpeg', quality = 1) { 176 | return this.canvas.toDataURL(`image/${imageType}`, quality); 177 | } 178 | 179 | render() { 180 | switch (this.outputType) { 181 | case 'canvas': 182 | this.element.appendChild(this.canvas); 183 | break; 184 | case 'background': 185 | this.element.style.cssText += ` 186 | background-repeat: no-repeat; 187 | background-size: cover;`; 188 | break; 189 | case 'image': 190 | this.img = document.createElement('img'); 191 | this.img.style.cssText = 'width: 100%; height: 100%'; 192 | this.element.appendChild(this.img); 193 | break; 194 | default: 195 | break; 196 | } 197 | } 198 | 199 | destroy() { 200 | switch (this.outputType) { 201 | case 'canvas': 202 | this.canvas.remove(); 203 | break; 204 | case 'background': { 205 | const cssText = this.element.style.cssText; 206 | this.element.style.cssText = cssText.replace(/background[^;]+;/g, ''); 207 | break; 208 | } 209 | case 'image': 210 | this.img.remove(); 211 | break; 212 | default: 213 | break; 214 | } 215 | } 216 | } 217 | 218 | module.exports = MaterialImage; 219 | --------------------------------------------------------------------------------