LibCanvas рдкрд░ рд╕реМрд░ рдкреНрд░рдгрд╛рд▓реА



рдХрд▓ рдПрдЪрдЯреАрдПрдордПрд▓ 5 рдХреИрдирд╡рд╕ рдкрд░ рдПрдХ "рдЖрдХрд╛рд╢рдЧрдВрдЧрд╛" рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рд╡рд┐рд╖рдп, " рдж рд╣рд┐рд╕реНрдЯреНрд░реА рдСрдл рдП рд╣рдмрд╕реНрдкреЛрд░ " рдерд╛, рдЬреЛ рдХрд┐ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдФрд░ рдЕрдкрдиреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рд╕реЗ рдореБрдЭреЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛрдб рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рд┐рдд рдХрд░рддрд╛ рдерд╛ред рдореИрдВрдиреЗ рд╕реЛрдЪрд╛, рдкреНрд░рд▓реЗрдЦрди рдХреЗ рдЕрдВрдд рддрдХ, рдореИрдВрдиреЗ рд╣реИрдмреЗ рдкрд░ рдирдИ рдЪреАрдЬреЗрдВ рдирд╣реАрдВ рд▓рд┐рдЦреАрдВ, рд▓реЗрдХрд┐рди, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦрддреЗ рд╣реИрдВ, рдпрд╣ рдЯреВрдЯ рдЧрдпрд╛) рдЗрд╕рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж рдХрд┐рдмрд┐рдЬрд╝реЙрдЗрдбрд╕ ред

рд╡рд┐рд╖рдп рдореЗрдВ рдЖрдк LibCanvas рдХреЗ рдирд╡реАрдирддрдо рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдПрдХ рд╕реНрдЯрд╛рд░ рд╕рд┐рд╕реНрдЯрдо рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг рджреЗрдЦреЗрдВрдЧреЗред рддреЗрдЬ, рдЕрдиреБрдХреВрд▓рд┐рдд, рд╕рдВрдХреНрд╖рд┐рдкреНрддред

рдореБрдЭреЗ рддреБрд░рдВрдд рдХрд╣рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЯреАрдХреЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реИред рдХрд╛рд░рдг рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ - рдЬрдм рдореИрдВ рдХрд▓ рд╣реЙрдмрд┐рдЯ рд╕реЗ 3 рдмрдЬреЗ рдЖрдпрд╛, рдореИрдВрдиреЗ рдПрдХ рд╕реНрдкрд╖реНрдЯ рд╕рдордп рд╕реАрдорд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА - рд╕рдм рдХреБрдЫ рдХреЗ рд▓рд┐рдП рдПрдХ рдШрдВрдЯреЗ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ ред рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ, рдореИрдВрдиреЗ рд╕реБрдмрд╣ рдирд╛рд╢реНрддреЗ рдореЗрдВ рдХрд░реНрд╕рд░ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдпреЗ рд╡рд┐рд╡рд░рдг рд╣реИрдВ) рдореИрдВ рдШрдВрдЯреЗ рд╕реЗ рдорд┐рд▓рд╛ред

рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦрдХ рдХреЗ рд╡рд┐рдкрд░реАрдд, рдореБрдЭреЗ "рдЕрдкрдиреЗ рджреЗрд╡ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╡рд░реНрдЪреБрдПрд▓рд╣реЛрд╕реНрдЯ, рдЧрд┐рдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА" рдФрд░ рдмрд╛рдХреА рд╕рдм рдХреБрдЫ рдирд╣реАрдВ рдмрдирд╛рдирд╛ рд╣реИ - рдпрд╣ рд╕рдм рдореЗрд░реЗ рд╕рд╛рде libcanvas.github.com рдХреА рд▓рдбрд╝рд╛рдИ рдореЗрдВ рд╣рдореЗрд╢рд╛ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рдорд╛рдирдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рд▓рд┐рдпрд╛ рдФрд░ рддреБрд░рдВрдд рдпреБрджреНрдз рдореЗрдВ рдЪрд▓рд╛ рдЧрдпрд╛, рдЖрдХрд╛рд╢ рдХреЛ рдПрдХ рдкреГрд╖реНрдарднреВрдорд┐ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛, рддрд╛рдХрд┐ рдЕрдХреЗрд▓реЗ рдХрд╛рд▓реЗ рдмрд╛рд▓реЛрдВ рдХреЛ рди рджреЗрдЦреЗрдВ:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>LibCanvas :: Solar</title>
		<link href="/files/styles.css" rel="stylesheet" />
		<style> html, body { background: url(im/sky.png) } </style>
		<script src="/files/js/atom.js"></script>
		<script src="/files/js/libcanvas.js"></script>
	</head>
	<body>
		<p><a href="/">Return to index</a></p>
		<script>
new function () {
	LibCanvas.extract();

	atom.dom(function () {
		new Solar.Controller();
	});
};
		</script>
		<script src="js/controller.js"></script>
	</body>
</html>



. тАФ , , . тАФ . , .
/** @class Solar.Controller */
atom.declare('Solar.Controller', {
	initialize: function () {
		this.size = new Size(840, 840);

		this.app = new App({ size: this.size });

		atom.ImagePreloader.run({
			planets: 'im/planets.png',
			sun    : 'im/sun.png'
		}, this.start.bind(this));
	},
	
	start: function (images) {
		// images ready
		this.app.resources.set( 'images', images );
	}
});


. , - . intersection: all, invoke: true, onUpdate
/** @class Solar.Controller */
	// ..
	initialize: function () {
	// ..
		this.geoLayer = this.app.createLayer({
			name: 'geo',
			invoke: true,
			intersection: 'all',
			zIndex: 2
		});
	// ..


, тАФ . . , , App.Element, :
/** @class Solar.Sun */
atom.declare('Solar.Sun', App.Element, {

	renderTo: function (ctx, resources) {
		ctx.drawImage({
			image : resources.get('images').get('sun'),
			center: this.shape.center
		});
	}

});


:
/** @class Solar.Controller */
	// ..
	start: function (images) {
	// ..
		this.sun = new Solar.Sun(this.geoLayer, {
			shape: new Circle(this.app.rectangle.center, 50)
		});
	// ..


:



тАФ . 12 . 90 , 26 . 40 , 20 .

/** @class Solar.Controller */
atom.declare('Solar.Controller', {
	names : 'Selene Mimas Ares Enceladus Tethys Dione Zeus Rhea Titan Janus Hyperion Iapetus'
		.split(' '),
	
	// ..
	start: function (images) {
	// ..
		for (var i = 12; i--;) {
			var planet = new Solar.Planet(this.geoLayer, {
				sun   : this.sun,
				radius: 90 + i * 26,
				time  : 40 + i * 20,
				image : i,
				zIndex: 0,
				name  : this.names[i]
			});
		}
	// ..


тАФ , .

	this.center = this.solarCenter.clone();
	this.center.move([ this.radius, 0 ]);


тАФ 360 'time' 360/1000 :

	this.rotatePerMs = (360).degree() / 1000 / this.settings.get('time');


тАФ :

	getImagePart: function () {
		var x = this.settings.get('image');

		return this.layer.app.resources.get('images')
			.get('planets')
			.sprite(new Rectangle([ x*this.size.width,0 ],this.size));
	},


тАФ LibCanvas.Point.rotate. normalizeAngle , 0 360 .

	rotate: function (angle) {
		if (angle == null) angle = Number.random(0, 360).degree();

		this.angle = (this.angle + angle).normalizeAngle();
		this.center.rotate(angle, this.solarCenter);

		return this;
	},


тАФ onUpdate , , . onUpdate, renderTo тАФ LibCanvas , .
	onUpdate: function (time) {
		this.rotate(time * this.rotatePerMs);
		this.redraw();
	},


тАФ :

	renderTo: function (ctx) {
		ctx.drawImage({
			image : this.image,
			center: this.center,
			angle : this.angle
		});
	}


/** @class Solar.Planet */
atom.declare('Solar.Planet', App.Element, {

	angle: 0,

	configure: function () {
		this.size = new Size(26, 26);

		this.center = this.solarCenter.clone();
		this.center.move([ this.radius, 0 ]);

		this.rotatePerMs = (360).degree() / 1000 / this.settings.get('time');
		this.shape = new Circle(this.center, this.size.width/2);
		this.image  = this.getImagePart();
		this.rotate();
	},

	getImagePart: function () {
		var x = this.settings.get('image');

		return this.layer.app.resources.get('images')
			.get('planets')
			.sprite(new Rectangle([x*this.size.width,0],this.size));
	},

	get radius () {
		return this.settings.get('radius');
	},

	get solarCenter () {
		return this.settings.get('sun').shape.center;
	},

	rotate: function (angle) {
		if (angle == null) angle = Number.random(0, 360).degree();

		this.angle = (this.angle + angle).normalizeAngle();
		this.center.rotate(angle, this.solarCenter);

		return this;
	},

	onUpdate: function (time) {
		this.rotate(time * this.rotatePerMs);
		this.redraw();
	},

	renderTo: function (ctx) {
		ctx.drawImage({
			image : this.image,
			center: this.center,
			angle : this.angle
		});
	}

});



:



тАФ . , .
-, . тАФ , . тАФ , .

. onUpdate , . - , , . , ,
/** @class Solar.Controller */
	// ..
	initialize: function () {
	// ..
		this.orbitLayer = this.app.createLayer({
			name: 'orbit',
			intersection: 'manual',
			zIndex: 1
		});
	// ..
	
	start: function (images) {
	// ..
		for (var i = 12; i--;) {
			var planet = new Solar.Planet(this.geoLayer, {
				// ..
			});
			planet.createOrbit(this.orbitLayer, i); // <===

			// ..
		}
	// ..
	


/** @class Solar.Planet */
	// ..
	createOrbit: function (layer, z) {
		return this.orbit = new Solar.Orbit(layer, { planet: this, zIndex: z });
	},
	// ..


. Circle, , renderTo stroke' . , clearPrevious, тАФ BoundingRectangle, ctx.clear(this.shape, true):
/** @class Solar.Orbit */
atom.declare('Solar.Orbit', App.Element, {

	configure: function () {
		this.shape = new Circle(this.planet.solarCenter, this.planet.radius);
	},

	get planet () {
		return this.settings.get('planet');
	},

	clearPrevious: function (ctx) {
		ctx.clear(this.shape, true);
	},

	renderTo: function (ctx, resources) {
		ctx.stroke(this.shape, 'rgba(0,192,255,0.5)');
	}

});


, .



LibCanvas.Mouse, dom- LibCanvas.App.MouseHandler,
/** @class Solar.Controller */

	// ..
	start: function (images) {
		var mouse, mouseHandler;

		mouse = new Mouse(this.app.container.bounds);
		mouseHandler = new App.MouseHandler({ mouse: mouse, app: this.app });

		this.app.resources.set({
			images: images,
			mouse : mouse,
			mouseHandler: mouseHandler
		});
		
		// ..
		
		for (var i = 12; i--;) {
			var planet = new Solar.Planet(this.geoLayer, {
				// ..
			});
			planet.createOrbit(this.orbitLayer, i);
			
			mouseHandler.subscribe( planet );
			mouseHandler.subscribe( planet.orbit );
		}
	}
	
	// ..


, . . . .. . , isTriggerPoint. 13 .
/** @class Solar.Orbit */

	// ..
	isTriggerPoint: function (point) {
		var distance = this.planet.solarCenter.distanceTo(point);

		return (this.planet.radius - distance).abs() < 13;
	},
	
	// ..


, , тАФ hover Clickable :

/** @class Solar.Orbit */

	// ..
	configure: function () {
		// ..
		new App.Clickable( this, this.redraw ).start();
	},
	// ..

	renderTo: function (ctx, resources) {
		if (this.hover) {
			ctx.stroke(this.shape, 'rgba(255,64,64,0.8)');
		} else {
			ctx.stroke(this.shape, 'rgba(0,192,255,0.5)');
		}
	}
	// ..




, . . , hover :

/** @class Solar.Orbit */

	// ..
	
	isHover: function () {
		return this.hover || this.planet.hover;
	},

	renderTo: function (ctx, resources) {
		if (this.isHover()) {
		// ..
	}
	// ..


.. - ( ) тАФ redraw onUpdate
/** @class Solar.Planet */

	// ..
	configure: function () {
		// ..
		new App.Clickable( this, this.redraw ).start();
	},
	// ..

	onUpdate: function (time) {
		// ..
		if (this.orbit.isHover()) this.orbit.redraw();
	},
	// ..


hover . . . shape , shape . :

/** @class Solar.Orbit */
	// ..
	renderTo: function (ctx, resources) {
		if (this.isHover()) {
			ctx.save();
			ctx.set({ strokeStyle: 'rgb(0,192,255)', lineWidth: 3 });
			ctx.stroke(this.shape);
			ctx.clear(this.planet.shape);
			ctx.stroke(this.planet.shape);
			ctx.restore();
		} else {
			ctx.stroke(this.shape, 'rgba(0,192,255,0.5)');
		}
	}


тАФ ┬л┬╗ , , , ┬л┬╗ . LibCanvas тАФ saveCurrentBoundingShape, , , . , :
/** @class Solar.Orbit */
	// ..

	saveCurrentBoundingShape: function () {
		if (this.isHover()) {
			this.previousBoundingShape = this.planet.shape.clone().grow(6);
		} else {
			this.previousBoundingShape = null;
		}
		return this;
	},


. тАФ . тАФ , , :
/** @class Solar.Orbit */
	// ..

	clearPrevious: function (ctx) {
		if (this.previousBoundingShape) {
			ctx.save();
			ctx.set({ lineWidth: 4 });
			ctx.clear(this.previousBoundingShape);
			ctx.clear(this.shape, true);
			ctx.restore();
		} else {
			ctx.clear(this.shape, true);
		}
	},


:



, тАФ . mouseover mouseout Solar.Planet, , .. тАФ mouseout . , .
/** @class Solar.Planet */
	// ..

	configure: function () {
		// ..
		this.mousePoint = this.layer.app.resources.get('mouse').point;
		this.info = new Solar.Info(this.layer, { planet: this, zIndex: 1 });
	},

	checkStatus: function (visible) {
		if (this.info.isVisible() != visible) {
			this.info[visible ? 'show' : 'hide']();
		}
	},

	onUpdate: function (time) {
		// ..
		this.checkStatus(this.isTriggerPoint(this.mousePoint));
		//       
		if (this.info.isVisible()) this.info.updateShape(this.shape.center);
	},
	
	// ..


settings: { hidden: true } тАФ LibCanvas. , , . Solar.Info, .

/** @class Solar.Info */
atom.declare('Solar.Info', App.Element, {

	settings: { hidden: true },

	get planet () {
		return this.settings.get('planet');
	},

	configure: function () {
		this.shape = new Rectangle(0,0,100,30);
	},

	updateShape: function (from) {
		this.shape.moveTo(from).move([20,10])
	},

	show: function () {
		this.settings.set({ hidden: false });
		this.redraw();
	},

	hide: function () {
		this.settings.set({ hidden: true });
		this.redraw();
	},

	renderTo: function (ctx) {
		ctx.fill(this.shape, '#002244');
		ctx.text({
			to   : this.shape,
			text : this.planet.settings.get('name'),
			color: '#0ff',
			align: 'center',
			optimize: false,
			padding: 3
		})
	}
});


:

, тАФ :
/** @class Solar.Planet */
	// ..

	checkStatus: function (visible) {
		if (this.info.isVisible() != visible) {
			this.info[visible ? 'show' : 'hide']();
			this.layer.dom.element.css('cursor', visible ? 'pointer' : 'default');
		}
	},
	
	// ..



GitHub, .

:
1.
2.

. (program) тАФ . 100%.

:


LibCanvas:


:


(/ ):

тАФ 100%, 44 fps:


LibCanvas тАФ 40%, 60 fps:


, , . , тАФ shocksilien@gmail.com

Source: https://habr.com/ru/post/In163893/


All Articles