HTML 5 Canvas Particles - html

http://www.mrspeaker.net/
This guy make his entire background particles but I've been roaming around in Inspect Element to figure out how he did it and can't. I'm not quite sure how it's done does anyone know the code for him to do this?

http://www.mrspeaker.net/wp-content/themes/stuartspeaker/scripts/speaker.js
$( window ).load( function(){
bubbleController.init();
setInterval( function(){
bubbleController.update()
}, 200 );
$( window ).resize(function(){
bubbleController.setBoundaries();
});
if( $( ".leftcolumn" ).length )
{
//main page
var leftColumn = parseInt( $( ".leftcolumn" ).height(), 10 );
var rightColumn = parseInt( $( ".rightcolumn" ).height(), 10 );
/* Going to add extra stuff if the columns are uneven */
}
else{
swapTwitterPix();
}
});
var bubbleController = {
bubbles : [],
screenWidth : 0,
leftEdge : 0,
rightEdge : 0,
channelWidths : [],
minBubbleWidth : 10,
maxBubbleWidth : 100,
init : function(){
this.setBoundaries();
$("<div></div>").attr("id", "bubbleContainer").appendTo( $("body") );
for( var i = 0; i < 18; i++ ) {
var side = ( i % 2 === 0 ) ? 1 : 0;
var bub = new bubble();
this.bubbles.push( bub );
var width = Math.floor( Math.random() * this.maxBubbleWidth ) + this.minBubbleWidth;
bub.init(
this.getXPos( side ),
Math.floor( Math.random() * 800 ),
side,
(Math.random()*20/100).toFixed(2),
width,
Math.floor( ( ( ( this.maxBubbleWidth + this.minBubbleWidth ) - width ) / 8 ) / 5 ) + 1,
"#bubbleContainer" );
}
},
getXPos : function( blnLeftOrRight ) {
var xpos = ( Math.random() * this.channelWidths[ blnLeftOrRight ] );// + ( this.maxBubbleWidth / 2 );
return Math.floor( xpos / ( this.channelWidths[ blnLeftOrRight ] ) * 100 );
},
setBoundaries : function() {
this.screenWidth = $("body").width();
this.leftEdge = $("#outerWrapper").position().left;
this.rightEdge = this.leftEdge + 1040;
this.channelWidths[ 0 ] = this.leftEdge < 150 ? 150 : this.leftEdge;
this.channelWidths[ 1 ] = this.screenWidth - this.rightEdge;
},
update : function() {
$.each( this.bubbles, function() {
this.update();
});
}
};
function bubble(){
this.domRef;
this.diameter;
this.x;
this.xPerc;
this.y;
this.side;
this.opacity;
this.speed;
this.init = function( x, y, side, opacity, diameter, speed, addToElement ){
this.side = side;
this.xPerc = x;
this.y = y;
this.speed = speed;
this.opacity = opacity;
this.diameter = diameter;
this.domRef = $("<div></div")
.addClass( "bubble" )
.css("top", this.y )
.css("left", this.getXPos() )
.css( "opacity", this.opacity )
.appendTo( $( addToElement ) );
//.css("z-index", "-1")
var img = $( "<img></img>" )
//.attr("src", baseUrl + "/images/circle_" + this.colour + "_des.png" )
.attr("src", "/images/circleeye.png" )
.attr("height", this.diameter )
.appendTo( this.domRef )
.show()
/*.load(function(){
// Whoa... cpu == 90% for long fades
$(this).fadeIn( 20000 );
});*/
};
this.getXPos = function() {
this.x = ( bubbleController.channelWidths[ this.side ] * ( this.xPerc / 100 ) ) - ( this.diameter / 2 );
this.x += this.side == 1 ? bubbleController.rightEdge : 0;
return this.x;
};
this.update = function() {
this.y -= this.speed;
this.x = this.getXPos();
if( this.y < -this.diameter ) {
this.y = 800;
this.xPerc = bubbleController.getXPos( this.side );
this.x = this.getXPos();
this.opacity = (Math.random()*15/100).toFixed(2);
this.fireFadeIn();
}
this.updateDom();
};
this.setInit = function(){
};
this.updateDom = function() {
this.domRef
.css("top", this.y )
.css("left", this.x );
};
this.fireFadeIn = function() {
this.domRef
.hide()
.css( "opacity", this.opacity )
.fadeIn( 5000 );
};
}
p.s. there's nothing really HTML5 about this from my quick perusal of the markup and javascript

Check out the speaker.js file. When the page loads, he creates an empty div and adds 18 divs within it that are called "bubbles". Each bubble has an update method that changes its location, slowly creeping up the screen.
Furthermore, he sets a timer on the page to call a page-wide update method every 200 milliseconds. Within the page-wide update method, he calls update on each bubble.
I was going to post the code, but I see qntmfred already has.

Related

How to load .OBJ and .MTL using ThreeJS? (HTML)

I'm trying to load a 3D globe into my HTML site using a ThreeJS script (found below) But it's stitched together with code from other sources, meaning the camera is mapped to MouseX and MouseY positions. I want the object to sit in the center of the page with a simple slow spin, but every time I try and achieve this the object vanishes.
The Javascript:
<script>
var container;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 5, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.z = 250;
scene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.8 );
scene.add( ambientLight );
var pointLight = new THREE.PointLight( 0xFFF1CF, 0.6 , 0 );
camera.add( pointLight );
scene.add( camera );
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {;
};
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load('planet.mtl', function(materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.load('planet.obj', function(object) {
object.position.y = 0;
scene.add(object);
}, onProgress, onError);
});
//
renderer = new THREE.WebGLRenderer( {alpha: true});
renderer.setClearColor( 0x000000, 0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseclick', onmousedown, false);
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX );
mouseY = ( event.clientY );
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
You need to change your code a little bit,
In the 'init' function, change the object loading logic as follows
var mtlLoader = new THREE.MTLLoader();
var objLoader = new THREE.OBJLoader();
mtlLoader.load( 'planet.mtl', function(materials) {
materials.preload();
objLoader.setMaterials(materials);
objLoader.load( 'planet.obj', function( object ){
object.position.set( 0, 0, 0 ); // set the position as (0,0,0)
globe = object; // globe is the object to be added to the scene
scene.add(globe);
animate(); //call the animate function only after the object is loaded
}, onProgress, onError);
} );
And change the render method,
function render() {
globe.rotation.y += 0.01; // this will rotate the object
camera.lookAt( scene.position );
renderer.render( scene, camera );
}

Toggle Button "ENTER VR" not working in three js

i am using google Chrome (59.0.3071.125) in my mobile
i was Enabled : WebVR , Gamepad in my chrome using chrome://flags/ to support WEBVR when i tried first time it worked
BUT after 2 days now its givig this exception:
Uncaught (in promise) DOMException: Presentation request was denied.
I have no clue why.
i tried to search around but i found nothing
below is the code of https://threejs.org/examples/?q=vr#webvr_cubes i have tried
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webvr - cubes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
<style>
body {
font-family: Monospace;
background-color: #101010;
color: #fff;
margin: 0px;
overflow: hidden;
}
a {
color: #f00;
}
</style>
</head>
<body>
<script src="../build/three.js"></script>
<script src="js/controls/VRControls.js"></script>
<script src="js/effects/VREffect.js"></script>
<script src="js/vr/WebVR.js"></script>
<script>
if ( WEBVR.isAvailable() === false ) {
document.body.appendChild( WEBVR.getMessage() );
}
//
var clock = new THREE.Clock();
var container;
var camera, scene, raycaster, renderer;
var effect, controls;
var room;
var isMouseDown = false;
var INTERSECTED;
var crosshair;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'three.js webgl - interactive cubes';
container.appendChild( info );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 10 );
scene.add( camera );
crosshair = new THREE.Mesh(
new THREE.RingGeometry( 0.02, 0.04, 32 ),
new THREE.MeshBasicMaterial( {
color: 0xffffff,
opacity: 0.5,
transparent: true
} )
);
crosshair.position.z = - 2;
camera.add( crosshair );
room = new THREE.Mesh(
new THREE.BoxGeometry( 6, 6, 6, 8, 8, 8 ),
new THREE.MeshBasicMaterial( { color: 0x404040, wireframe: true } )
);
scene.add( room );
scene.add( new THREE.HemisphereLight( 0x606060, 0x404040 ) );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 ).normalize();
scene.add( light );
var geometry = new THREE.BoxGeometry( 0.15, 0.15, 0.15 );
for ( var i = 0; i < 200; i ++ ) {
var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
object.position.x = Math.random() * 4 - 2;
object.position.y = Math.random() * 4 - 2;
object.position.z = Math.random() * 4 - 2;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
object.scale.x = Math.random() + 0.5;
object.scale.y = Math.random() + 0.5;
object.scale.z = Math.random() + 0.5;
object.userData.velocity = new THREE.Vector3();
object.userData.velocity.x = Math.random() * 0.01 - 0.005;
object.userData.velocity.y = Math.random() * 0.01 - 0.005;
object.userData.velocity.z = Math.random() * 0.01 - 0.005;
room.add( object );
}
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0x505050 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container.appendChild( renderer.domElement );
controls = new THREE.VRControls( camera );
effect = new THREE.VREffect( renderer );
WEBVR.getVRDisplay( function ( display ) {
document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
} );
renderer.domElement.addEventListener( 'mousedown', onMouseDown, false );
renderer.domElement.addEventListener( 'mouseup', onMouseUp, false );
renderer.domElement.addEventListener( 'touchstart', onMouseDown, false );
renderer.domElement.addEventListener( 'touchend', onMouseUp, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onMouseDown() {
isMouseDown = true;
}
function onMouseUp() {
isMouseDown = false;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
effect.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
effect.requestAnimationFrame( animate );
render();
}
function render() {
var delta = clock.getDelta() * 60;
if ( isMouseDown === true ) {
var cube = room.children[ 0 ];
room.remove( cube );
cube.position.set( 0, 0, - 0.75 );
cube.position.applyQuaternion( camera.quaternion );
cube.userData.velocity.x = ( Math.random() - 0.5 ) * 0.02 * delta;
cube.userData.velocity.y = ( Math.random() - 0.5 ) * 0.02 * delta;
cube.userData.velocity.z = ( Math.random() * 0.01 - 0.05 ) * delta;
cube.userData.velocity.applyQuaternion( camera.quaternion );
room.add( cube );
}
// find intersections
raycaster.setFromCamera( { x: 0, y: 0 }, camera );
var intersects = raycaster.intersectObjects( room.children );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex( 0xff0000 );
}
} else {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = undefined;
}
// Keep cubes inside room
for ( var i = 0; i < room.children.length; i ++ ) {
var cube = room.children[ i ];
cube.userData.velocity.multiplyScalar( 1 - ( 0.001 * delta ) );
cube.position.add( cube.userData.velocity );
if ( cube.position.x < - 3 || cube.position.x > 3 ) {
cube.position.x = THREE.Math.clamp( cube.position.x, - 3, 3 );
cube.userData.velocity.x = - cube.userData.velocity.x;
}
if ( cube.position.y < - 3 || cube.position.y > 3 ) {
cube.position.y = THREE.Math.clamp( cube.position.y, - 3, 3 );
cube.userData.velocity.y = - cube.userData.velocity.y;
}
if ( cube.position.z < - 3 || cube.position.z > 3 ) {
cube.position.z = THREE.Math.clamp( cube.position.z, - 3, 3 );
cube.userData.velocity.z = - cube.userData.velocity.z;
}
cube.rotation.x += cube.userData.velocity.x * 2 * delta;
cube.rotation.y += cube.userData.velocity.y * 2 * delta;
cube.rotation.z += cube.userData.velocity.z * 2 * delta;
}
controls.update();
effect.render( scene, camera );
}
</script>
</body>
</html>
I just hit a very similar issue. It seems that VRButton does not work well with requestAnimationFrame. Instead you need to use renderer.setAnimiationLoop.
Your code:
function animate() {
effect.requestAnimationFrame( animate );
render();
}
Change it to this:
function animate() {
renderer.setAnimationLoop(() => { render(); });
}

three.js json loadingmanager model not displayed

I want to preload all models and textures with a loadingbar in my project. For that i use the LoadingManger from three.js but i have problems with preloading the json Models. They load but i am unable to display them. Here is an example.
You can see in the console that 200 Meshs are created. 100 For the Asteroids and 100 for the Ships.
Withoud the LoadingManger i can display the models (asteroids) so there should be no problem with the model. You can see in the example Asteroids that are loaded without the loading manager.
Here my simplified code for the problem
$(function(){
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var debugScene = true;
var controler, camera, controls, scene, renderer;
var objectControls;
var ship1geometry,ship1material;
////////////////////////////////////////////////////////
//LOADMANGER
////////////////////////////////////////////////////////
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
$('#loader').css({width:(Math.round(loaded / total *100))+"%"});
console.log( item, loaded, total );
};
manager.onLoad = function () {
$('#loaderholder').fadeOut(function(){
init();
animate();
});
console.log('all items loaded');
};
manager.onError = function () {
console.log('there has been an error');
};
var loader = new THREE.JSONLoader(manager); // init the loader util
loader.load('models/shiptest.json', function (ship1geometry) {
var ship1material = new THREE.MeshFaceMaterial();
}, "models");
function init() {
var width = window.innerWidth;
var height = window.innerHeight;
camera = new THREE.PerspectiveCamera( 45, width / height, 1, 10000000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1500;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor("black");
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.autoClear = false;
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
controls.minDistance = 50;
controls.maxDistance = 300000;
controls.autoRotate = false;
controls.autoRotateSpeed = 0.05;
controls.target.x = 0;
controls.target.y = 0;
controls.target.z = 0;
light = new THREE.AmbientLight( 0x666666 );
scene.add( light );
light = new THREE.PointLight( 0xffffff, 1, 10000 );
light.position.set( 0, 0, 0 );
var params = { recursive: true };
objectControls = new ObjectControls( camera, params );
shipCount = 100;
for (var p = 0; p < shipCount; p++) {
var pX = Math.random() * 5000 - 2500;
var pZ = Math.random() * 5000 - 2500;
var ship = createShipMesh(pX,0,pZ,0,0,0,ship1geometry,ship1material);
scene.add(ship);
}
var loader = new THREE.JSONLoader();
loader.load('models/asteroid.json', function (geometry, mat) {
var material = new THREE.MeshFaceMaterial( mat );
asteroidCount = 100;
for (var p = 0; p < asteroidCount; p++) {
var pX = Math.random() * 5000 - 2500;
var pZ = Math.random() * 5000 - 2500;
var mesh = new THREE.Mesh(geometry,material);
mesh.rotation.y = -Math.PI/Math.random();
mesh.position.set( pX, 0, pZ );
scene.add(mesh);
}
}, "textures");
window.addEventListener( 'resize', onWindowResize, false );
if(debugScene){
var gridHelper = new THREE.GridHelper( 900000, 10000 );
gridHelper.setColors( 0x0000ff, 0x808080 );
scene.add( gridHelper );
var axisHelper = new THREE.AxisHelper( 500 );
scene.add( axisHelper );
console.log(scene);
}
}
function onWindowResize() {
var width = window.innerWidth;
var height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var lastTimeMsec= null;
var nowMsec= null;
function animate() {
requestAnimationFrame( animate );
render();
update();
}
function update(){
controls.update();
objectControls.update();
}
function render() {
renderer.render( scene, camera );
}
function createShipMesh(positionX,positionY,positionZ,centerX,centerY,centerZ,geometry,material){
positionX = centerX + positionX;
positionY = centerY + positionY;
positionZ = centerZ + positionZ;
var mesh = new THREE.Mesh(geometry,material);
mesh.rotation.y = -Math.PI/Math.random();
mesh.position.set( positionX, positionY, positionZ );
objectControls.add( mesh );
mesh.select = function(){
controls.target.x = position.x;
controls.target.y = position.y;
controls.target.z = position.z;
controls.dollyIn(2);
controls.minDistance = 20;
}
return mesh;
}
});
Okay i found the problem on my own. the Loading Manager works with json but my mistake was to set the variable ship1geometry global and was thinking that the loader would overwrite this variable so that i can use it later in the scene. That was wrong. I just needed to assign the response from the loader in my globaly set variable. So here is the right code
var ship1geometry,ship1material
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
$('#loader').css({width:(Math.round(loaded / total *100))+"%"});
console.log( item, loaded, total );
};
manager.onLoad = function () {
$('#loaderholder').fadeOut(function(){
init();
animate();
});
console.log('all items loaded');
};
manager.onError = function () {
console.log('there has been an error');
};
var loader = new THREE.JSONLoader(manager); // init the loader util
loader.load('models/shiptest.json', function (geometry,mat) {
ship1geometry = geometry;
ship1material = new THREE.MeshLambertMaterial({map:mat });
}, "textures");
function init(){
...
}

kineticjs show image anchors on click

I have a kineticjs canvas with image upload and text input, both functions are working fine but I can't get the image resize anchors to show... I need to get the image resize anchors to show "onClick" of the image.
any help is much appreciated :)
thanks in advance.
here is the js
var stage = new Kinetic.Stage({
container: 'container',
width: 375,
height: 200
});
var layer = new Kinetic.Layer();
//image loader
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
layer.add(new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
text.moveToTop();
stage.draw();
};
console.log(event);
img.src = event.target.result;
};
reader.readAsDataURL(e.target.files[0]);
}
// parameters
var resizerRadius = 3;
var rr = resizerRadius * resizerRadius;
// constant
var pi2 = Math.PI * 2;
function draw(img, withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
var view = img.view;
ctx.drawImage(img, 0, 0, img.width, img.height, view.left, view.top, view.width, view.height);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(view.left, view.top);
drawDragAnchor(view.left + view.width, view.top);
drawDragAnchor(view.left + view.width, view.top + view.height);
drawDragAnchor(view.left, view.top + view.height);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.rect(view.left, view.top, view.width, view.height);
ctx.stroke();
}
drawText();
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function drawText(){
var x = 40,
y = 100;
ctx.font = "bold 20px sans-serif";
ctx.fillStyle = "black";
ctx.fillText($("#textBox").val(), x, y);
}
// -------------------------------------------
// - Hit Testing -
// -------------------------------------------
// return 0,1,2, or 3 if (x,y) hits the respective anchor
// of the given view.
// return -1 if no anchor hit.
function anchorHitTest(view, x, y) {
var dx, dy;
x -= view.left;
y -= view.top;
// top-left
dx = x;
dy = y;
if (dx * dx + dy * dy <= rr) return (0);
// top-right
dx = x - view.width;
dy = y;
if (dx * dx + dy * dy <= rr) return (1);
// bottom-right
dx = x - view.width;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (2);
// bottom-left
dx = x;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (3);
return (-1);
}
// return true if (x,y) lies within the view
function hitImage(view, x, y) {
x -= view.left;
y -= view.top;
return (x > 0 && x < view.width && y > 0 && y < view.height);
}
// -------------------------------------------
// - Mouse -
// -------------------------------------------
var mousePos = {
x: 0,
y: 0
};
var draggingImage = false;
var startX, startY;
var isDown = false;
var currentImg = null;
var draggingResizer;
function updateMousePos(e) {
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
updateMousePos = function (e) {
mousePos.x = parseInt(e.clientX - offsetX);
mousePos.y = parseInt(e.clientY - offsetY);
};
return updateMousePos(e);
}
function handleMouseDown(e) {
updateMousePos(e);
// here you could make a loop to see which image / anchor was clicked
draggingResizer = anchorHitTest(img.view, mousePos.x, mousePos.y);
draggingImage = draggingResizer < 0 && hitImage(img.view, mousePos.x, mousePos.y);
//
if (draggingResizer<0 && !draggingImage) return;
startX = mousePos.x;
startY = mousePos.y;
currentImg = img;
}
function handleMouseUp(e) {
if (!currentImg) return;
draggingResizer = -1;
draggingImage = false;
draw(currentImg, true, false);
currentImg = null;
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (!currentImg) return;
updateMousePos(e);
var view = currentImg.view;
if (draggingResizer > -1) {
var oldView = {
left: view.left,
top: view.top,
width: view.width,
height: view.height
};
// resize the image
switch (draggingResizer) {
case 0:
cl('ttoo');
//top-left
view.left = mousePos.x;
view.top = mousePos.y;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 1:
//top-right
// view.left unchanged
view.top = mousePos.y;
view.width = mousePos.x - oldView.left;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 2:
//bottom-right
view.width = mousePos.x - oldView.left;
view.height = mousePos.y - oldView.top;
break;
case 3:
//bottom-left
view.left = mousePos.x;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = mousePos.y - (oldView.top);
break;
}
if (view.width < 25) view.width = 25;
if (view.height < 25) view.height = 25;
// redraw the image with resizing anchors
draw(currentImg, true, true);
} else if (draggingImage) {
imageClick = false;
// move the image by the amount of the latest drag
var dx = mousePos.x - startX;
var dy = mousePos.y - startY;
view.left += dx;
view.top += dy;
// reset the startXY for next time
startX = mousePos.x;
startY = mousePos.y;
// redraw the image with border
draw(currentImg, false, true);
}
}
var text = new Kinetic.Text({
x: 20,
y: 30,
text: '',
fontSize: '30',
fontFamily: 'Calibri',
fill: 'black',
draggable: true
});
stage.add(layer);
layer.add(text);
document.getElementById("textBox").addEventListener("keyup", function () {
text.setText(this.value);
layer.draw();
}, true);
document.getElementById("textSize").addEventListener("change", function () {
var size = this.value;
text.fontSize(size);
layer.draw();
}, true);
document.getElementById("fontFamily").addEventListener("change", function () {
var font = this.value;
text.fontFamily(font);
layer.draw();
}, true);
document.getElementById("fontStyle").addEventListener("change", function () {
var style = this.value;
text.fontStyle(style);
layer.draw();
}, true);
document.getElementById("fill").addEventListener("change", function () {
var colour = this.value;
text.fill(colour);
layer.draw();
}, true);
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
// utility
function cl() {
console.log.apply(console, arguments);
}
can provide jsFiddle if needed :)
You're trying to mix KineticJS with html canvas drawing commands.
That combination doesn't work because KineticJS does its magic by taking over the canvas--leaving no ability to call native canvas commands like context.beginPath.
// these 2 don't play together
... new Kinetic.Image ...
... ctx.beginPath ...
Anyway, Here's the answer to your question (in case you choose KineticJS for your project)
Kinetic.Image can be asked to execute a function when the image is clicked like this:
var image=new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
image.on("click",function(){
// The image was clicked
// Show your anchors now
});
layer.add(image);
[ Addition: Example of Kinetic.Image resizing ]
I don't like the overhead and complexity of maintaining anchors to resize Kinetic.Images.
Here's an example that lets you drag on the right side of the image to scale it proportionally:
http://jsfiddle.net/m1erickson/p8bpC/
You could modify this code to add cosmetic resizing grabbers (the grabbers are not necessary, but if you prefer the "anchor" look, you can add them).
You can refer to this question, the answers are guided and constructive, and contain a jsfiddle with the exact same behavior that you need.
Kinetic JS - how do you hide all the anchors for a given group ID

Drawing an honeycomb with as3

I'm trying to create an honeycomb with as3 but I have some problem on cells positioning.
I've already created the cells (not with code) and for cycled them to a funcion and send to it the parameters which what I thought was need (the honeycomb cell is allready on a sprite container in the center of the stage).
to see the structure of the cycle and which parameters passes, please see the example below, the only thing i calculate in placeCell is the angle which I should obtain directly inside tha called function
alt text http://img293.imageshack.us/img293/1064/honeycomb.png
Note: the angle is reversed but it isn't important, and the color are useful in example only for visually divide cases.
My for cycle calls placeCell and passes cell, current_case, counter (index) and the honeycomb cell_lv (cell level).
I thought it was what i needed but I'm not skilled in geometry and trigonometry, so I don't know how to position cells correctly:
import flash.display.Sprite;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
function createHoneycomb (cells:int):void {
var honeycomb:Sprite = new Sprite ();
addChild (honeycomb);
var cell_lv:int = 1;
var increment:int = 6;
var tot_cur_cells:int = 1;
var current_case:int = 0;
var case_counter:int = 1;
var case_length:int = 1;
var max_cases:int = 6;
var nucleus:Sprite = new cell (); // hexagon from library
honeycomb.addChild (nucleus);
for (var i:int = 1; i <= cells; i ++) {
if (case_counter < case_length) {
case_counter ++;
} else {
current_case ++;
if (current_case > max_cases) current_case = 1;
case_counter = 1;
}
if (i == tot_cur_cells) { // if i reach the current level
if (i > 1) cell_lv ++;
case_length = cell_lv;
tot_cur_cells += (increment * cell_lv);
}
var current_cell:Sprite = new cell (); // hexagon from library
honeycomb.addChild (current_cell);
placeCell (current_cell, case_counter, current_case, cell_lv);
}
function centerHoneycomb (e:Event):void {
honeycomb.x = stage.stageWidth / 2
honeycomb.y = Math.round (stage.stageHeight / 2);
}
stage.addEventListener (Event.RESIZE, centerHoneycomb)
stage.dispatchEvent (new Event (Event.RESIZE));
}
function placeCell (cell:Sprite, counter:int, current_case:int, cell_lv:int):void {
var margin:int = 2;
// THIS IS MY PROBLEM
var start_degree:Number = (360 / (cell_lv * 6));
var angle:Number = (start_degree * ((current_case - 1) + counter) - start_degree);
var radius:Number = (cell.width + margin) * cell_lv;
cell.x = radius * Math.cos (angle);
cell.y = radius * Math.sin (angle);
// end of the problem
if (angle != 0) trace ("LV " + cell_lv + " current_case " + current_case + " counter " + counter + " angle " + angle + " radius " + radius);
else trace ("LV " + cell_lv + " current_case " + current_case + " counter " + counter + " angle " + angle + " radius " + radius);
}
createHoneycomb (64);
if you copy and paste this code, it works but you need to create an hexagon and call it in the actionscript library as cell
how can I do to solve it?
I've also thought to use a switch with the cases to align it, but i think is a little bit buggy doing this
Okay, I really loved this question. It was interesting, and challenging, and I got a working result. I didn’t use any of your code as the base though, but started from scratch, so depending on your final use, you might need to change a bit.
I did however created similar variables to those inside of your cells (in the picture). For each cell you have the following properties:
the iterating variable i is equally to your cell number
the radius r equals your level, and expresses the distance from the center (with 0 being the center)
the position p expresses the position in the current radius
the sector s equals your case, but starts with zero
p % r equals your index
I don’t have an angle, simply because I don’t position the individual hexagons using an angle. Instead I base the position of the (fixed) positions of the hexagons at radius 1 and calculate the missing ones in between.
The following code shows my implementation with 61 (60 + the center; but it’s configurable). You can also see the code in action on Wonderfl.
package
{
import flash.display.Sprite;
public class Comb extends Sprite
{
public function Comb ()
{
Hexagon.scale = 0.5;
this.x = stage.stageWidth / 2;
this.y = stage.stageHeight / 2;
// draw honeycomb with 60 cells
drawComb( 60 );
}
private function drawComb ( n:uint ):void
{
var colors:Array = new Array( 0x33CC33, 0x006699, 0xCC3300, 0x663399, 0xFF9900, 0x336666 );
var sectors:Array = new Array(
new Array( 2, 0 ),
new Array( 1, 1 ),
new Array( -1, 1 ),
new Array( -2, 0 ),
new Array( -1, -1 ),
new Array( 1, -1 ) );
var w:Number = 0.50 * Hexagon.hxWidth;
var h:Number = 0.75 * Hexagon.hxHeight;
var r:uint, p:uint, s:uint;
var hx:Hexagon;
for ( var i:uint = 0; i <= n; i++ )
{
r = getRadius( i );
p = getPosition( i, r );
s = getSector( i, r, p );
// create hexagon
if ( r == 0 )
hx = new Hexagon( 0xCCCCCC );
else
hx = new Hexagon( colors[s] );
hx.x = w * ( r * sectors[s][0] - ( p % r ) * ( sectors[s][0] - sectors[ ( s + 1 ) % 6 ][0] ) );
hx.y = h * ( r * sectors[s][1] - ( p % r ) * ( sectors[s][1] - sectors[ ( s + 1 ) % 6 ][1] ) );
addChild( hx );
}
}
private function getRadius ( i:uint ):uint
{
var r:uint = 0;
while ( i > r * 6 )
i -= r++ * 6;
return r;
}
private function getPosition ( i:uint, r:uint ):uint
{
if ( r == 0 )
return i;
while ( r-- > 0 )
i -= r * 6;
return i - 1;
}
private function getSector ( i:uint, r:uint, s:uint ):uint
{
return Math.floor( s / r );
}
}
}
import flash.display.Shape;
class Hexagon extends Shape
{
public static var hxWidth:Number = 90;
public static var hxHeight:Number = 100;
private static var _scale:Number = 1;
public function Hexagon ( color:uint )
{
graphics.beginFill( color );
graphics.lineStyle( 3, 0xFFFFFF );
graphics.moveTo( 0, -50 );
graphics.lineTo( 45, -25 );
graphics.lineTo( 45, 25 );
graphics.lineTo( 0, 50 ),
graphics.lineTo( -45, 25 );
graphics.lineTo( -45, -25 );
graphics.lineTo( 0, -50 );
this.scaleX = this.scaleY = _scale;
}
public static function set scale ( value:Number ):void
{
_scale = value;
hxWidth = value * 90;
hxHeight = value * 100;
}
public static function get scale ():Number
{
return _scale;
}
}