Flat, round, designer-friendly pseudo-3D engine for canvas & SVG
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

๐Ÿž #65 add Box face property setter

fix bug updating Box properties to update faces

+109 -62
+2 -2
js/anchor.js
··· 24 24 } 25 25 26 26 Anchor.prototype.create = function( options ) { 27 + this.children = []; 27 28 // set defaults & options 28 29 utils.extend( this, this.constructor.defaults ); 29 30 this.setOptions( options ); ··· 35 36 // origin 36 37 this.origin = new Vector(); 37 38 this.renderOrigin = new Vector(); 38 - // children 39 - this.children = []; 39 + 40 40 if ( this.addTo ) { 41 41 this.addTo.addChild( this ); 42 42 }
+107 -60
js/box.js
··· 24 24 25 25 // ----- Box ----- // 26 26 27 - var boxDefaults = utils.extend( { 27 + var TAU = utils.TAU; 28 + var faceNames = [ 29 + 'frontFace', 30 + 'rearFace', 31 + 'leftFace', 32 + 'rightFace', 33 + 'topFace', 34 + 'bottomFace', 35 + ]; 36 + 37 + var boxDefaults = utils.extend( {}, Shape.defaults ); 38 + delete boxDefaults.path; 39 + faceNames.forEach( function( faceName ) { 40 + boxDefaults[ faceName ] = true; 41 + }); 42 + utils.extend( boxDefaults, { 28 43 width: 1, 29 44 height: 1, 30 45 depth: 1, 31 - frontFace: true, 32 - rearFace: true, 33 - leftFace: true, 34 - rightFace: true, 35 - topFace: true, 36 - bottomFace: true, 37 - }, Shape.defaults ); 38 - // default fill 39 - boxDefaults.fill = true; 40 - delete boxDefaults.path; 46 + fill: true, 47 + }); 41 48 42 49 var Box = Anchor.subclass( boxDefaults ); 43 50 44 - var TAU = utils.TAU; 45 - 46 51 Box.prototype.create = function( options ) { 47 52 Anchor.prototype.create.call( this, options ); 48 53 this.updatePath(); 54 + // HACK reset fill to trigger face setter 55 + this.fill = this.fill; 49 56 }; 50 57 51 58 Box.prototype.updatePath = function() { 52 - this.setFace( 'frontFace', { 53 - width: this.width, 54 - height: this.height, 55 - translate: { z: this.depth/2 }, 56 - }); 57 - this.setFace( 'rearFace', { 58 - width: this.width, 59 - height: this.height, 60 - translate: { z: -this.depth/2 }, 61 - rotate: { y: TAU/2 }, 62 - }); 63 - this.setFace( 'leftFace', { 64 - width: this.depth, 65 - height: this.height, 66 - translate: { x: -this.width/2 }, 67 - rotate: { y: -TAU/4 }, 68 - }); 69 - this.setFace( 'rightFace', { 70 - width: this.depth, 71 - height: this.height, 72 - translate: { x: this.width/2 }, 73 - rotate: { y: TAU/4 }, 74 - }); 75 - this.setFace( 'topFace', { 76 - width: this.width, 77 - height: this.depth, 78 - translate: { y: -this.height/2 }, 79 - rotate: { x: -TAU/4 }, 80 - }); 81 - this.setFace( 'bottomFace', { 82 - width: this.width, 83 - height: this.depth, 84 - translate: { y: this.height/2 }, 85 - rotate: { x: -TAU/4 }, 59 + // reset all faces to trigger setters 60 + faceNames.forEach( function( faceName ) { 61 + this[ faceName ] = this[ faceName ]; 62 + }, this ); 63 + }; 64 + 65 + faceNames.forEach( function( faceName ) { 66 + var _faceName = '_' + faceName; 67 + Object.defineProperty( Box.prototype, faceName, { 68 + get: function() { 69 + return this[ _faceName ]; 70 + }, 71 + set: function( value ) { 72 + this[ _faceName ] = value; 73 + this.setFace( faceName, value ); 74 + }, 86 75 }); 87 - }; 76 + }); 88 77 89 - Box.prototype.setFace = function( faceName, options ) { 90 - var property = this[ faceName ]; 78 + Box.prototype.setFace = function( faceName, value ) { 91 79 var rectProperty = faceName + 'Rect'; 92 80 var rect = this[ rectProperty ]; 93 81 // remove if false 94 - if ( !property ) { 82 + if ( !value ) { 95 83 this.removeChild( rect ); 96 84 return; 97 85 } 98 86 // update & add face 99 - utils.extend( options, { 100 - // set color from option, i.e. `front: '#19F'` 101 - color: typeof property == 'string' ? property : this.color, 102 - stroke: this.stroke, 103 - fill: this.fill, 104 - backface: this.backface, 105 - front: this.front, 106 - visible: this.visible, 107 - }); 87 + var options = this.getFaceOptions( faceName ); 88 + options.color = typeof value == 'string' ? value : this.color; 89 + 108 90 if ( rect ) { 109 91 // update previous 110 92 rect.setOptions( options ); ··· 115 97 rect.updatePath(); 116 98 this.addChild( rect ); 117 99 }; 100 + 101 + Box.prototype.getFaceOptions = function( faceName ) { 102 + return { 103 + frontFace: { 104 + width: this.width, 105 + height: this.height, 106 + translate: { z: this.depth/2 }, 107 + }, 108 + rearFace: { 109 + width: this.width, 110 + height: this.height, 111 + translate: { z: -this.depth/2 }, 112 + rotate: { y: TAU/2 }, 113 + }, 114 + leftFace: { 115 + width: this.depth, 116 + height: this.height, 117 + translate: { x: -this.width/2 }, 118 + rotate: { y: -TAU/4 }, 119 + }, 120 + rightFace: { 121 + width: this.depth, 122 + height: this.height, 123 + translate: { x: this.width/2 }, 124 + rotate: { y: TAU/4 }, 125 + }, 126 + topFace: { 127 + width: this.width, 128 + height: this.depth, 129 + translate: { y: -this.height/2 }, 130 + rotate: { x: -TAU/4 }, 131 + }, 132 + bottomFace: { 133 + width: this.width, 134 + height: this.depth, 135 + translate: { y: this.height/2 }, 136 + rotate: { x: TAU/4 }, 137 + }, 138 + }[ faceName ]; 139 + }; 140 + 141 + // ----- set face properties ----- // 142 + 143 + var childProperties = [ 'color', 'stroke', 'fill', 'backface', 'front', 144 + 'visible' ]; 145 + childProperties.forEach( function( property ) { 146 + // use proxy property for custom getter & setter 147 + var _prop = '_' + property; 148 + Object.defineProperty( Box.prototype, property, { 149 + get: function() { 150 + return this[ _prop ]; 151 + }, 152 + set: function( value ) { 153 + this[ _prop ] = value; 154 + faceNames.forEach( function( faceName ) { 155 + var rect = this[ faceName + 'Rect' ]; 156 + var isFaceColor = typeof this[ faceName ] == 'string'; 157 + var isColorUnderwrite = property == 'color' && isFaceColor; 158 + if ( rect && !isColorUnderwrite ) { 159 + rect[ property ] = value; 160 + } 161 + }, this ); 162 + }, 163 + }); 164 + }); 118 165 119 166 return Box; 120 167