UNPKG

zdog

Version:

Round, flat, designer-friendly pseudo-3D engine

164 lines (138 loc) 4.35 kB
/** * Cylinder composite shape */ ( function( root, factory ) { // module definition if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( require('./boilerplate'), require('./path-command'), require('./shape'), require('./group'), require('./ellipse') ); } else { // browser global var Zdog = root.Zdog; Zdog.Cylinder = factory( Zdog, Zdog.PathCommand, Zdog.Shape, Zdog.Group, Zdog.Ellipse ); } }( this, function factory( utils, PathCommand, Shape, Group, Ellipse ) { function noop() {} // ----- CylinderGroup ----- // var CylinderGroup = Group.subclass({ color: '#333', updateSort: true, }); CylinderGroup.prototype.create = function() { Group.prototype.create.apply( this, arguments ); this.pathCommands = [ new PathCommand( 'move', [ {} ] ), new PathCommand( 'line', [ {} ] ), ]; }; CylinderGroup.prototype.render = function( ctx, renderer ) { this.renderCylinderSurface( ctx, renderer ); Group.prototype.render.apply( this, arguments ); }; CylinderGroup.prototype.renderCylinderSurface = function( ctx, renderer ) { if ( !this.visible ) { return; } // render cylinder surface var elem = this.getRenderElement( ctx, renderer ); var frontBase = this.frontBase; var rearBase = this.rearBase; var scale = frontBase.renderNormal.magnitude(); var strokeWidth = frontBase.diameter * scale + frontBase.getLineWidth(); // set path command render points this.pathCommands[0].renderPoints[0].set( frontBase.renderOrigin ); this.pathCommands[1].renderPoints[0].set( rearBase.renderOrigin ); if ( renderer.isCanvas ) { ctx.lineCap = 'butt'; // nice } renderer.renderPath( ctx, elem, this.pathCommands ); renderer.stroke( ctx, elem, true, this.color, strokeWidth ); renderer.end( ctx, elem ); if ( renderer.isCanvas ) { ctx.lineCap = 'round'; // reset } }; var svgURI = 'http://www.w3.org/2000/svg'; CylinderGroup.prototype.getRenderElement = function( ctx, renderer ) { if ( !renderer.isSvg ) { return; } if ( !this.svgElement ) { // create svgElement this.svgElement = document.createElementNS( svgURI, 'path' ); } return this.svgElement; }; // prevent double-creation in parent.copyGraph() // only create in Cylinder.create() CylinderGroup.prototype.copyGraph = noop; // ----- CylinderEllipse ----- // var CylinderEllipse = Ellipse.subclass(); CylinderEllipse.prototype.copyGraph = noop; // ----- Cylinder ----- // var Cylinder = Shape.subclass({ diameter: 1, length: 1, frontFace: undefined, fill: true, }); var TAU = utils.TAU; Cylinder.prototype.create = function( /* options */) { // call super Shape.prototype.create.apply( this, arguments ); // composite shape, create child shapes // CylinderGroup to render cylinder surface then bases this.group = new CylinderGroup({ addTo: this, color: this.color, visible: this.visible, }); var baseZ = this.length / 2; var baseColor = this.backface || true; // front outside base this.frontBase = this.group.frontBase = new Ellipse({ addTo: this.group, diameter: this.diameter, translate: { z: baseZ }, rotate: { y: TAU/2 }, color: this.color, stroke: this.stroke, fill: this.fill, backface: this.frontFace || baseColor, visible: this.visible, }); // back outside base this.rearBase = this.group.rearBase = this.frontBase.copy({ translate: { z: -baseZ }, rotate: { y: 0 }, backface: baseColor, }); }; // Cylinder shape does not render anything Cylinder.prototype.render = function() {}; // ----- set child properties ----- // var childProperties = [ 'stroke', 'fill', 'color', 'visible' ]; childProperties.forEach( function( property ) { // use proxy property for custom getter & setter var _prop = '_' + property; Object.defineProperty( Cylinder.prototype, property, { get: function() { return this[ _prop ]; }, set: function( value ) { this[ _prop ] = value; // set property on children if ( this.frontBase ) { this.frontBase[ property ] = value; this.rearBase[ property ] = value; this.group[ property ] = value; } }, } ); } ); // TODO child property setter for backface, frontBaseColor, & rearBaseColor return Cylinder; } ) );