diff --git a/README.md b/README.md index 0be21fbb..684a84d8 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ var viewer = ModelViewer({ // head should slowly drift (overrides lookAt) slowDrift: false, + // An optional seed number for uniquely coloring this fox. + colorSeed: 123, }) // add viewer to DOM diff --git a/bundle.js b/bundle.js index b68ddd79..de2038b5 100644 --- a/bundle.js +++ b/bundle.js @@ -1,7 +1,7 @@ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i '+r+"")}});var createViewer=require("../index"),viewer=createViewer({width:.4,height:.4,followMouse:!0,followMotion:!0});document.body.appendChild(viewer.container); +var createViewer=require("../index");const colorSeed=Math.floor(1e5*Math.random());window.addEventListener("load",()=>{document.querySelector("button.save").addEventListener("click",saveImage),document.querySelector("button.recolor").addEventListener("click",recolor),document.querySelector("button.cycle").addEventListener("click",toggleCycle)});let cycleInterval,cycling=!1;function toggleCycle(){cycling&&cycleInterval?(console.dir(cycleInterval),clearInterval(cycleInterval),cycling=!1):cycling||(cycleInterval=setInterval(recolor,500),cycling=!0)}function saveImage(){download(' '+document.querySelector("svg").innerHTML+"",`custom-fox-${colorSeed}.svg`,"image/svg+xml")}document.addEventListener("keypress",e=>{99===e.keyCode&&saveImage()});var viewer=createViewer({width:.4,height:.4,followMouse:!0,followMotion:!0});function recolor(){viewer.recolor(Math.floor(1e7*Math.random()))}const foxDiv=document.querySelector("body div.fox");function download(e,o,t){var n=new Blob([e],{type:t});if(window.navigator.msSaveOrOpenBlob)window.navigator.msSaveOrOpenBlob(n,o);else{var r=document.createElement("a"),c=URL.createObjectURL(n);r.href=c,r.download=o,document.body.appendChild(r),r.click(),setTimeout(function(){document.body.removeChild(r),window.URL.revokeObjectURL(c)},0)}}foxDiv.appendChild(viewer.container); -},{"../index":3,"copy-to-clipboard":4}],2:[function(require,module,exports){ +},{"../index":3}],2:[function(require,module,exports){ module.exports={ "positions": [ [ @@ -1430,33 +1430,30 @@ module.exports={ } },{}],3:[function(require,module,exports){ -var perspective=require("gl-mat4/perspective"),multiply=require("gl-mat4/multiply"),lookAt=require("gl-mat4/lookAt"),invert=require("gl-mat4/invert"),rotate=require("gl-mat4/rotate"),transform=require("gl-vec3/transformMat4"),foxJSON=require("./fox.json"),SVG_NS="http://www.w3.org/2000/svg";function createNode(t){return document.createElementNS(SVG_NS,t)}function setAttribute(t,e,n){t.setAttributeNS(null,e,n)}module.exports=function(t){var e=t||{},n=!!e.followMouse,r=!!e.followMotion,i=!!e.slowDrift,o=!0,a=[0,0],l=.3,u=e.width||400,s=e.height||400,h=createNode("svg"),f={x:0,y:0},d=foxJSON.positions.length,c=new Float32Array(3*d),w=new Float32Array(3*d),g=[];function v(t){var e=h.getBoundingClientRect();f.x=1-2*(t.x-e.left)/e.width,f.y=1-2*(t.y-e.top)/e.height}function m(t,e){this.svg=t,this.indices=e,this.zIndex=0}e.pxNotRatio||(u=window.innerWidth*(e.width||.25)|0,s=0|(window.innerHeight*e.height||u),"minWidth"in e&&u>>0,this.mti=1;this.mti>>30;this.mt[this.mti]=(1812433253*((4294901760&t)>>>16)<<16)+1812433253*(65535&t)+this.mti,this.mt[this.mti]>>>=0}},MersenneTwister.prototype.init_by_array=function(t,i){var s,h,n;for(this.init_seed(19650218),s=1,h=0,n=this.N>i?this.N:i;n;n--){var r=this.mt[s-1]^this.mt[s-1]>>>30;this.mt[s]=(this.mt[s]^(1664525*((4294901760&r)>>>16)<<16)+1664525*(65535&r))+t[h]+h,this.mt[s]>>>=0,h++,++s>=this.N&&(this.mt[0]=this.mt[this.N-1],s=1),h>=i&&(h=0)}for(n=this.N-1;n;n--){r=this.mt[s-1]^this.mt[s-1]>>>30;this.mt[s]=(this.mt[s]^(1566083941*((4294901760&r)>>>16)<<16)+1566083941*(65535&r))-s,this.mt[s]>>>=0,++s>=this.N&&(this.mt[0]=this.mt[this.N-1],s=1)}this.mt[0]=2147483648},MersenneTwister.prototype.random_int=function(){var t,i=new Array(0,this.MATRIX_A);if(this.mti>=this.N){var s;for(this.mti==this.N+1&&this.init_seed(5489),s=0;s>>1^i[1&t];for(;s>>1^i[1&t];t=this.mt[this.N-1]&this.UPPER_MASK|this.mt[0]&this.LOWER_MASK,this.mt[this.N-1]=this.mt[this.M-1]^t>>>1^i[1&t],this.mti=0}return t=this.mt[this.mti++],t^=t>>>11,t^=t<<7&2636928640,t^=t<<15&4022730752,(t^=t>>>18)>>>0},MersenneTwister.prototype.random_int31=function(){return this.random_int()>>>1},MersenneTwister.prototype.random_incl=function(){return this.random_int()*(1/4294967295)},MersenneTwister.prototype.random=function(){return this.random_int()*(1/4294967296)},MersenneTwister.prototype.random_excl=function(){return(this.random_int()+.5)*(1/4294967296)},MersenneTwister.prototype.random_long=function(){return(67108864*(this.random_int()>>>5)+(this.random_int()>>>6))*(1/9007199254740992)},module.exports=MersenneTwister; },{}]},{},[1]); diff --git a/example/example.js b/example/example.js index 302410da..2e0e816e 100644 --- a/example/example.js +++ b/example/example.js @@ -1,27 +1,81 @@ -var copy = require('copy-to-clipboard') +var createViewer = require('../index') + +const colorSeed = Math.floor(Math.random() * 100000) + +window.addEventListener('load', () => { + const saveButton = document.querySelector('button.save') + saveButton.addEventListener('click', saveImage) + + const recolorButton = document.querySelector('button.recolor') + recolorButton.addEventListener('click', recolor) + + const cycleButton = document.querySelector('button.cycle') + cycleButton.addEventListener('click', toggleCycle) +}) + +let cycling = false +let cycleInterval +function toggleCycle () { + if (cycling && cycleInterval) { + console.dir(cycleInterval) + clearInterval(cycleInterval) + cycling = false + } else if (!cycling) { + cycleInterval = setInterval(recolor, 500) + cycling = true + } +} + + +document.addEventListener('keypress', (event) => { + if (event.keyCode === 99) { // the C key + saveImage() + } +}) -document.addEventListener('keypress', function (event) { - if (event.keyCode === 99) { // the c key +function saveImage () { var svg = document.querySelector('svg') var inner = svg.innerHTML var head = ' ' + '' - var foot = '' - - var full = head + inner + foot; - - copy(full) - } -}) + var foot = '' -var createViewer = require('../index') + var full = head + inner + foot; + download(full, `custom-fox-${colorSeed}.svg`, 'image/svg+xml') +} var viewer = createViewer({ width: 0.4, height: 0.4, followMouse: true, followMotion: true, + // colorSeed, }) -document.body.appendChild(viewer.container) +function recolor() { + viewer.recolor(Math.floor(Math.random() * 10000000)) +} + +const foxDiv = document.querySelector('body div.fox') +foxDiv.appendChild(viewer.container) + +// Function to download data to a file +function download(data, filename, type) { + var file = new Blob([data], {type: type}); + if (window.navigator.msSaveOrOpenBlob) // IE10+ + window.navigator.msSaveOrOpenBlob(file, filename); + else { // Others + var a = document.createElement("a"), + url = URL.createObjectURL(file); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + setTimeout(function() { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); + } +} + diff --git a/index.html b/index.html index 6cb5d071..fac5d55a 100644 --- a/index.html +++ b/index.html @@ -2,16 +2,15 @@ ---- +MetaMask Logo -
+
+

Press C to save SVG

+ + + - - -

Press C to copy the SVG text of the image.

+ diff --git a/index.js b/index.js index 40ffa9a2..ec72fce7 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,19 @@ var invert = require('gl-mat4/invert') var rotate = require('gl-mat4/rotate') var transform = require('gl-vec3/transformMat4') var foxJSON = require('./fox.json') +var colors = [ + '#01888C', // teal + '#FC7500', // bright orange + '#034F5D', // dark teal + '#F73F01', // orangered + '#FC1960', // magenta + '#C7144C', // raspberry + '#F3C100', // goldenrod + '#1598F2', // lightning blue + '#2465E1', // sail blue + '#F19E02', // gold +] +var MersenneTwister = require('mersenne-twister'); var SVG_NS = 'http://www.w3.org/2000/svg' @@ -22,6 +35,11 @@ module.exports = function createLogo (options_) { var followCursor = !!options.followMouse var followMotion = !!options.followMotion var slowDrift = !!options.slowDrift + var colorSeed = options.colorSeed + var twister + if (colorSeed) { + twister = new MersenneTwister(colorSeed) + } var shouldRender = true var DISTANCE = 400 @@ -75,17 +93,28 @@ module.exports = function createLogo (options_) { } })() - function Polygon (svg, indices) { + function Polygon (svg, indices, chunk) { this.svg = svg this.indices = indices this.zIndex = 0 + this.chunk = chunk } var polygons = (function () { var polygons = [] for (var i = 0; i < foxJSON.chunks.length; ++i) { var chunk = foxJSON.chunks[i] - var color = 'rgb(' + chunk.color + ')' + + if (!chunk.polygons) { + chunk.polygons = [] + } + + var color + if (twister) { + color = colors[Math.floor(twister.random() * colors.length)] + } else { + color = 'rgb(' + chunk.color + ')' + } var faces = chunk.faces for (var j = 0; j < faces.length; ++j) { var f = faces[j] @@ -103,7 +132,9 @@ module.exports = function createLogo (options_) { 'points', '0,0, 10,0, 0,10') container.appendChild(polygon) - polygons.push(new Polygon(polygon, f)) + const poly = new Polygon(polygon, f, chunk) + polygons.push(poly) + chunk.polygons.push(poly) } } return polygons @@ -307,11 +338,40 @@ module.exports = function createLogo (options_) { stopAnimation() } + function recolor (colorSeed) { + var twister + if (colorSeed) { + twister = new MersenneTwister(colorSeed) + } + + for(const chunk of foxJSON.chunks) { + let color + if (twister) { + color = colors[Math.floor(twister.random() * colors.length)] + } else { + color = 'rgb(' + chunk.color + ')' + } + + for (const polygon of chunk.polygons) { + setAttribute( + polygon.svg, + 'fill', + color) + setAttribute( + polygon.svg, + 'stroke', + color) + } + } + renderScene() + } + renderScene() return { container: container, lookAt: setLookAt, + recolor: recolor, setFollowMouse: setFollowMouse, setFollowMotion: setFollowMotion, stopAnimation: stopAnimation, diff --git a/package-lock.json b/package-lock.json index 9c08d685..2ed5c8d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1904,6 +1904,11 @@ "inherits": "^2.0.1" } }, + "mersenne-twister": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mersenne-twister/-/mersenne-twister-1.1.0.tgz", + "integrity": "sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o=" + }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", diff --git a/package.json b/package.json index c2e692f2..2dc164ab 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "license": "ISC", "dependencies": { "gl-mat4": "1.1.4", - "gl-vec3": "1.0.3" + "gl-vec3": "1.0.3", + "mersenne-twister": "^1.1.0" }, "devDependencies": { "browserify": "^16.2.2", diff --git a/style.css b/style.css index c6d71951..9d562cdd 100644 --- a/style.css +++ b/style.css @@ -9,9 +9,9 @@ body{ font-family: roboto; } -div{ - height:140px; +div.fox{ overflow: visible; + cursor: none; } svg {