I sell custom equipment and on my site, I have a flash tool where customers can assign colors to glove parts and see what it will look like.
I've been working on a HTML5 version of this tool, so the iPad crowd can do the same thing. Click here for what I've done,
I took kineticjs multiple picture loader and hacked it to load all the pics necessary to stage and the color buttons, which are multiple instances of the same image. In their example, it was only 2 images, so they var name each image, which were manipulative. My goal is to dynamically create variable, based on image name.
I'm using a for loop and if statements to position the parts according to their type. If the image being loaded is a button, the original instance is not added to the stage, but another for loop, with a counter, creates instances and put on the stage. The variable is part string+n (wht0). From here I initiate an eventlistener, when clicked is suppose to hide all glove parts pertaining to the option and show the appropriate color. That code I have already in my AS.
I created an eventlistener on the white buttons (first button) that when clicked, I set it to hide one of the white leather part of glove. But when I click the button, I get the error in console that the glove part (ex wlt_wht), I get an error stating that the object is not defined. But when the image was loaded the variable name came from the current array object being loaded.
I added another variable before the callback call, to convert the content of the array to a string and used the document.write to confirm that the object name is correct, but after creating the object its now [object object]. In flash, you manually assign the movie clip name and target.name is available if you call it.
How can I write the Image obj so I can control the object? In the doc there is a reference for id and name as properties of the object, but when I set these, it did not work with me. Sure, I could have manually created each Kinetic.Image(), but there's no fun in that.. especially with 191 images. Any tip on how I can get around this problem?
Checkout http://jsfiddle.net/jacobsultd/b2BwU/6/ to examine and test script.
function loadImages(sources, callback) {
var assetDir = 'http://dev.nystixs.com/test/inf/';
var fileExt = '.png';
var images = {};
var loadedImages = 0;
var numImages = 0;
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function () {
var db = sources[src].toString();
var dbname = db.slice(-0, -4);
if (++loadedImages >= numImages) {
callback(images, dbname);
}
};
images[src].src = assetDir + sources[src];
//images[src].src = assetDir+sources[src]+".png";
}
}
function initStage(images, db) {
var shapesLayer = new Kinetic.Layer();
var messageLayer = new Kinetic.Layer();
//Loading Images
var xpos = 0;
var ypos = 200;
for (var i in images) {
var glvP = i.slice(0, 3);
db = new Kinetic.Image({
image: images[i],
x: xpos,
y: ypos
});
if (glvP == "wlt") {
shapesLayer.add(db);
db.setPosition(186.95, 7.00);
//db.hide();
shapesLayer.draw();
} else if (glvP == "lin") {
shapesLayer.add(db);
db.setPosition(204.95, 205.00);
} else if (glvP == "plm") {
shapesLayer.add(db);
db.setPosition(311.95, 6.00);
} else if (glvP == "web") {
shapesLayer.add(db);
db.setPosition(315.95, 7.00);
} else if (glvP == "lce") {
shapesLayer.add(db);
db.setPosition(162.95, 3.00);
} else if (glvP == "thb") {
shapesLayer.add(db);
db.setPosition(63.00, 28.60);
} else if (glvP == "bfg") {
shapesLayer.add(db);
db.setPosition(167.95, 7.00);
} else if (glvP == "wst") {
shapesLayer.add(db);
db.setPosition(208.95, 234.00);
} else if (glvP == "fpd") {
shapesLayer.add(db);
db.setPosition(252.95, 82.00);
} else if (glvP == "bac") {
shapesLayer.add(db);
db.setPosition(0, 0);
} else if (glvP == "bnd") {
shapesLayer.add(db);
db.setPosition(196.95, 164.00);
} else {}
var rect = new Kinetic.Rect({
x: 710,
y: 6,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 200,
height: 325,
shadowColor: 'white',
shadowBlur: 10,
shadowOffset: [5, 5],
shadowOpacity: 0.2,
cornerRadius: 10
});
shapesLayer.add(rect);
// End of Glove Parts Tabs
//Load Color Buttons
if (glvP == "wht") {
xpos = -5.00;
bpos = 375;
var zpos = -5.00;
var tpos = -5.00;
db.setPosition(xpos, bpos);
//shapesLayer.add(db);
var n = 0;
for (n = 0; n < 12; n++) {
if (n < 4) {
var glvB = "wht" + n;
var btn = glvB;
glvB = new Kinetic.Image({
image: images[i],
width: 18,
height: 18,
id: 'wht0'
});
glvB.on('mouseout', function () {
blankText('');
});
glvB.on('mouseover', function () {
writeColors('White', btn);
});
glvB.on('click', function () {
console.log(glvB + " clicked");
wht.hide();
shapesLayer.draw();
});
glvB.setPosition((xpos + 20), bpos);
shapesLayer.add(glvB);
xpos = (xpos + 230);
}
You can use your .png image filenames to automate your color-button coding efforts.
No need to manually code 10 glove components X 21 colors per component (210 color buttons).
Assume you’ve split the each image URL (filename) to get the color and glove-type.
Then you can create all 210 color buttons with one piece of reusable code.
Demo: http://jsfiddle.net/m1erickson/H5FDc/
Example Code:
// Usage:
addColorButton(100,100,"red","fingers");
// 1 function to add 210 color-buttons
function addColorButton(x,y,color,component){
// create this button
var button=new Kinetic.Image({
x:x,
y:y,
image: imageArray[ color+"-color-button" ],
});
// save the color as a property on this button
button.gloveColor=color;
// save the glove component name as a property on this button
button.gloveComponent=component; // eg, "fingers"
// resuable click handler
// Will change the gloves "#fingers" to "red-fingers-image"
button.on("click",function(){
// eg. get the image "red-fingers-image"
var newImage = imageArray[this.gloveColor+"-"+this.gloveComponent+"-image"];
// eg. get the Kinetic.Image with id:”finger”
var glovePart = layer.find("#"+this.gloveComponent”][0];
// change the Kinetic id:finger’s image
// to the red-fingers-image
glovePart.setImage(newImage);
layer.draw();
});
layer.add(button);
}
Related
I am trying to get data from my firestore database and use that data to create a canvas. My goal is to load a set of images and maps to return several canvases.
I am constantly getting this error:
Uncaught (in promise) TypeError: Cannot read property 'getContext' of null
I have tried using setTimeout()'s to delay the speed to help the data load quicker, but nothing seems to work.
var gImgObj;
var gMeme = [];
var gCtx;
var canvas;
function memeDivGet(theId){
setTimeout(function(){
db.collection("memeInfo").where("creator", "==", theId)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
db.collection("memeInfo").doc(doc.id).collection("MIMG")
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
//alert(doc.data())
// alert("here")
console.log(doc.data().Coordinates[0].fontSize)
gMeme.push(doc.data().BaseIMG)
for (var i = 0; i < doc.data().Coordinates.length; i++) {
// alert("here" + i)
gMeme.push({
line: "line",
size: doc.data().Coordinates[i].fontSize,
align: doc.data().Coordinates[i].align,
color: doc.data().Coordinates[i].color, // in color picker, if choosing color from platte notice it stays "solid".
fontFamily: doc.data().Coordinates[i].fontStyle,
lineWidth: 2, // outline width
x: doc.data().Coordinates[i].xPos,
y: doc.data().Coordinates[i].yPos,
text: doc.data().Text[i]
})
}
//console.log(doc.data().BaseIMG)
initCanvas(doc.data().BaseIMG);
})
})
})
})
},1500)
}
function initCanvas(link) {
var canvas = document.querySelector('#canvasImage');
gCtx = canvas.getContext('2d');
gImgObj = new Image();
// console.log(link)
//alert(gMeme[0])
gImgObj.src = link;
gImgObj.onload = function () {
canvas.width = gImgObj.width;
canvas.height = gImgObj.height;
drawCanvas();
};
//console.log("HERE4")
}
function drawCanvas() {
//alert(gMeme)
gCtx.drawImage(gImgObj, 0, 0);
for (var i = 0; i < gMeme.length; i++) {
if(i > 1){
drawTxt(gMeme[i]);
}
}
for (var i = 0; i < gMeme.length - 1; i++) {
drawTxt(gMeme[i + 1]);
}
// gMeme.txts.forEach(function (txt) {
// drawTxt(txt);
// });
}
function drawTxt(txt) {
gCtx.font = txt.size + 'px' + ' ' + txt.fontFamily;
gCtx.textAlign = txt.align;
gCtx.fillStyle = txt.color;
gCtx.fillText(txt.text, txt.x, txt.y);
}
What I want to return is a set of canvases with the parameters I want.
My database is set up in this way for this section of the code:
(fooIds meaning a random id set by firebase)
Collection 'MemeInfo'
Document (fooIds)
SubCollection 'MIMG'
Document 'A'
Inside Each fooId Document, there is a creatorId which helps the computer find who created this meme, I use this to locate the document I am supposed to use for this particular creator's account.
"gMeme" is an array containing information from the database.
An "A Document" has a BaseIMG (the background image), a coordinates array with maps inside (containing the size, color, fontFamily, and other parameters), and a text array with strings inside. There is an image of an "A Document" attached.
I understand that this is quite confusing so if you have any questions please ask them in the comments section.
i am trying to get cells from a photo with a table. i have the coordonates of the cells in the image. now i want to view my cells using a konvajs library. the problem is that the table is 30x30. so i have 900 cells. when using kanva.image 900 times the browser stop working, because it tries to load 900 time the same image. i want to load one time the image and use it for croping 900 time. here are my code:
function add_i(layer,cell,row,weight,k,cloneI){
layer.add(cloneI);
cloneI.crop({
x: parseInt(cell.x),
y: parseInt(row.y),
width: cell.width,
height: row.height
});
cloneI.width(cell.width);
cloneI.height(row.height);
cloneI.y(row.y);
cloneI.x(cell.x);
}
layerP.push( new Konva.Layer());
if(weight.stage == 'pred'){
var cloneI = new Konva.Image({
id:'img_'+k,
draggable: true
});
var clone = new Image();
clone.onload = function() {
cloneI.image(clone);
layerP[0].draw();
};
for (var i in weight.predictions){
var row = weight.predictions[i];
for (var j in row.cells){
var cell = row.cells[j];
add_i(layerP[0],cell,row,weight,k,cloneI.clone());
k+=1;
}
if(i==4 && false)
break;
}
clone.src = weight.path_i;
stage.add(layerP[0]);
}
I think you should move your add_i into clone.onload like this:
function add_i(layer, cell, row, weight, k, cloneI) {
layer.add(cloneI);
cloneI.crop({
x: parseInt(cell.x),
y: parseInt(row.y),
width: cell.width,
height: row.height
});
cloneI.width(cell.width);
cloneI.height(row.height);
cloneI.y(row.y);
cloneI.x(cell.x);
}
layerP.push(new Konva.Layer());
if (weight.stage == 'pred') {
var clone = new Image();
clone.onload = function() {
var cloneI = new Konva.Image({
id: 'img_' + k,
draggable: true,
image: clone
});
for (var i in weight.predictions) {
var row = weight.predictions[i];
for (var j in row.cells) {
var cell = row.cells[j];
add_i(layerP[0], cell, row, weight, k, cloneI.clone());
k += 1;
}
if (i == 4 && false)
break;
}
layerP[0].draw();
};
clone.src = weight.path_i;
stage.add(layerP[0]);
}
cause the add_i is invoked before the onload callback because of that Konva.Image i.e. cloneI does not have native image instance when it's used.
Any ideas how to make switchable characters I have a html game it's finished but I want to implement a way to switch my main character.
Simple coding using Phaser framework
upload function() {
this.game.load.sprite ("bird" assets/bird.png);
this.game.load.sprite ("bird2" assets/bird2.png);
this.game.load.sprite ("bird3" assets/bird3.png);
},
create function() {
this.game.add.sprite (0, 0 "bird" );
},
I want to be able to switch my playable character the "bird" with the "bird2" or "bird3" through a selection button if a player selects a switch character button for the playable character to switch to that. I'm pretty sure this is something simple but I'm still pretty new with coding.
I want a button where I press then I can switch the character
(Button 1) switches to bird2
"if button 1 is selected button two and current bird are disabled"-only bird2 is visible
(Button 2) switches to bird3
"if button 2 is selected button one and current bird are disabled"-only bird3 is visible
Edit This is My current code and states
var MainState = {
//load the game assets before the game starts
preload: function () {
this.load.image('background', 'assets/spring2.png');
this.load.spritesheet('bird', 'assets/bird.png',52 ,28, 7);
this.load.spritesheet('bird2', 'assets/bird2.png',52 ,28, 7);
this.load.spritesheet('bird3', 'assets/bird3.png',52 ,28, 7);
this.load.image('pipe', 'assets/pipe4.png');
},
//executed after everything is loaded
create: function () {
this.background = game.add.tileSprite(0, game.height-736,game.width, 736, 'background');
this.background.autoScroll(-20,0);
/////Bird///////////////////////////////////////////////////
this.bird = this.game.add.sprite(100, 200, 'bird');
this.bird.animations.add('fly');
this.bird.animations.play('fly', 50, true);
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.bird);
this.bird.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
this.bird.body.collideWorldBounds=true;
this.bird.body.immovable= true;
game.input.onDown.add(this.jump, this); //////touch screen jump
spaceKey.onDown.add(this.jump, this);
///////////////////////////////////////////////////////Pipes
this.pipes = game.add.group();
//timer
this.timer = game.time.events.loop(1600, this.addRowOfPipes, this); /////////////timer for pipes
///Bird anchor
this.bird.anchor.setTo(-0.2, 0.5)
},
// this is execated multiple times per second
update: function () {
if (this.bird.y < 0 || this.bird.y > 480)
game.state.start("StateOver");
///Collision
game.physics.arcade.overlap(
this.bird, this.pipes, this.restartGame, null, this);
///Bird Angle
if (this.bird.angle < 30)
this.bird.angle += 1;
///////////////music stop w top+bottom collision
if (this.bird.y < 0 || this.bird.y > 479)
music.stop();
},
jump: function () {
//this is for so the bird wount fly once dead
if (this.bird.alive == false)
return;
// Add a vertical velocity to the bird
this.bird.body.velocity.y = -350;
// Jump Animation
var animation = game.add.tween(this.bird);
// Change the angle of the bird to -20° in 100 milliseconds
animation.to({angle: -20}, 100);
// And start the animation
animation.start();
game.add.tween(this.bird).to({angle: -20}, 100).start();
},
restartGame: function () {
// Start the 'main' state, which restarts the game
game.state.start(game.state.StateOver); /////////////////////changed from current #########
///Hit pipe Null
game.physics.arcade.overlap(
this.bird, this.pipes, this.hitPipe, null, this);
},
addRowOfPipes: function() {
var hole = Math.floor(Math.random() * 5) + 1; ///Math.floor(Math.random() * 5) + 1;
for (var i = 0; i < 10 ; i++) ///// (var i = 0; i < 8; i++)
if (i != hole && i != hole + 1) ///// if (i != hole && i != hole + 1)
this.addOnePipe(440, i * 50 ); ///// 640 starting point of pipe 240 point of down ////this.addOnePipe(480, i * 60 + 10);
},
addOnePipe: function(x, y) {
var pipe = game.add.sprite(x, y, 'pipe');
this.pipes.add(pipe);
game.physics.arcade.enable(pipe);
pipe.body.velocity.x = -200;
pipe.checkWorldBounds = true;
pipe.outOfBoundsKill = true;
},
hitPipe: function() {
// If the bird has already hit a pipe, do nothing
// It means the bird is already falling off the screen
if (this.bird.alive == false)
return;
else {
game.state.start("StateOver");
}
// Set the alive property of the bird to false
this.bird.alive = false;
// Prevent new pipes from appearing
game.time.events.remove(this.timer);
// Go through all the pipes, and stop their movement
this.pipes.forEach(function(p){
p.body.velocity.x = 0;
}, this);
},
};
character.js
var characters={
preload:function()
{
game.load.spritesheet('button', 'assets/button.png', 215, 53, 8);
game.load.image("background", "assets/characterbackground.png");
game.load.image("pajaro", "assets/storeicon.png");
game.load.image("logo", "assets/extra/storef.png");
this.load.spritesheet('bird', 'assets/bird.png',52 ,28, 7);
this.load.spritesheet('bird2', 'assets/bird2.png',52 ,28, 7);
this.load.spritesheet('bird3', 'assets/bird3.png',52 ,28, 7);
game.load.spritesheet("button2", 'assets/button2.png', 100, 10, 10);
},
create:function()
{
bird = game.add.image(140, 150, 'pajaro');
logo = game.add.image (20, 350, 'logo');
this.background = game.add.tileSprite(0, game.height-736,game.width, 736, 'background');
this.background.autoScroll(-100,0);
this.btnMainMenu=game.add.button(130,500,'button',this.mainMenu,this,4,5,4);
this.btnbird=game.add.button(180,600,"button2",this.changebird2,this,0,1,0);
},
mainMenu:function()
{
game.state.start("stateTitle");
},
update:function()
{
// bird.x +=1;
},
changebird2: function(){
},
};
Instead of creating three sprites that you either hide or show, I might recommend just changing what texture is loaded when the sprite is created/added.
To do this you'll need to store a reference to the playable character, which you probably already have.
// On the game itself, add a reference.
this.bird = null;
// In your preload, load the different images.
this.load.image('bird', 'assets/bird.png');
this.load.image('bird2', 'assets/bird2.png');
this.load.image('bird3', 'assets/bird3.png');
// When creating, default to one.
this.bird = this.game.add.sprite(0, 0, 'bird');
// In your function where they select a new skin, you can load in a different texture.
this.bird.loadTexture('bird3');
Alternatively, you could store the key that should be used on the game.
// On the game itself, track which key to use.
this.birdSkin = 'bird';
// You'll still have to load your possible textures.
this.load.image('bird', 'assets/bird.png');
this.load.image('bird2', 'assets/bird2.png');
this.load.image('bird3', 'assets/bird3.png');
// Now when creating just use the variable.
this.bird.loadTexture(this.birdSkin);
The Phaser init() will allow 0 or more parameters to be passed in (see the end of Phaser Tutorial: understanding Phaser states), which is where you could populate this.birdSkin.
I would look at what states you're using to determine what's best for you. If you have one state for the game and another for selecting which image/texture is used, than the second option might be better.
Update for Character State
Given your comments and what I saw in your code, I created a short example that you could tweak for your use.
There's a JSFiddle available, but the code is also included below.
var mainState = {
preload: function() {
// Load the three sprites that they can choose between.
this.load.crossOrigin = 'anonymous';
this.load.image('ball', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-blue.png');
this.load.image('ball2', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-green.png');
this.load.image('ball3', 'https://raw.githubusercontent.com/photonstorm/phaser-examples/master/examples/assets/sprites/orb-red.png');
},
create: function() {
this.ball = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, this.game.global.skin);
this.ball.anchor.setTo(0.5);
// Let the ball be acted upon. This will allow the player to change the sprite used.
this.ball.inputEnabled = true;
this.ball.events.onInputDown.add(this.changeCharacter, this);
},
update: function() {
},
changeCharacter: function() {
game.state.start('character');
}
};
var characterState = {
preload: function() {
},
create: function() {
// For this, add our three possible ball skins.
this.ball1 = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY / 2, 'ball');
this.ball1.anchor.setTo(0.5);
this.ball1.inputEnabled = true;
this.ball2 = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, 'ball2');
this.ball2.anchor.setTo(0.5);
this.ball2.inputEnabled = true;
this.ball3 = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY * 1.5, 'ball3');
this.ball3.anchor.setTo(0.5);
this.ball3.inputEnabled = true;
// Use the selected ball's sprite in our main game.
this.ball1.events.onInputDown.add(this.selectBall, this);
this.ball2.events.onInputDown.add(this.selectBall, this);
this.ball3.events.onInputDown.add(this.selectBall, this);
},
update: function() {
},
selectBall: function(sprite, pointer) {
// Grab the key of the sprite and save it to our global variable.
this.game.global.skin = sprite.key;
this.game.state.start('main');
}
};
var game = new Phaser.Game(200, 200);
// Create a global object that we can add custom variables to.
game.global = {
skin: 'ball'
};
game.state.add('main', mainState);
game.state.add('character', characterState);
game.state.start('main');
This actually simplifies things a bit, in that it just uses a global variable (I've been using TypeScript the last handful of months, so there's probably a better way to declare this).
I have stripped back my Fiddle to show my issue.
I have a Rectagle that I am looping so it gives a different name with multiple instances. I can add and remove the rectangles fine. My issue is that I am replacing this rectangle with an image and I can get it to loop ok, but it will only remove 1 image and not them all. I think I am doing something wrong with the name, but i can not see the wood through the trees.
JSFiddle
var canvas = new fabric.Canvas('c', { selection: false });
var land = [];
var turret = [];
var wh=[];
var op=[];
//////////////////////////////////////////////////////////////////
// Outpost Level Dropmenu Select
$(document).ready(function () {$('#method').change(
function () {
var method = $('option:selected').val();
if (this.value == "0") {
for (var i=0; i<96; i++){
canvas.remove(land[i]);
canvas.remove(turret[i]);
canvas.remove(wh[i]);
canvas.remove(op[i]);
};
} else if (this.value == "1") {
//Clear All
for (var i=0; i<96; i++){
canvas.remove(land[i]);
canvas.remove(turret[i]);
canvas.remove(wh[i]);
};
//Add Buildings
for (var i=0; i<40; i++){
land[i] = new fabric.Rect({
fill: 'green',left: 25,top: 25,width: 25,height: 25,
perPixelTargetFind: true,hasBorders: false,hasControls:false, hasRotatingPoint: false,
});
canvas.add(land[i])
};
for (var i=0; i<6; i++){
turret[i] = new fabric.Rect({
fill: 'brown',left: 75,top: 25,width: 15,height: 15,
perPixelTargetFind: true,hasBorders: false,hasControls: false,hasRotatingPoint: false,
});
canvas.add(turret[i])
};
for (var i=0; i<3; i++){
fabric.Image.fromURL('http://www.ahoymearty.co.uk/baseplanner2/images/buildings/warehouse.png', function(myImgwh) {wh[i] = myImgwh.set({ left: 25, top: 75 ,width:25,height:25, hasControls: false, hasRoatatingPoint: false,stroke: 'blue',strokeWidth: 1,
});
canvas.add(wh[i]);
});
};
}
});
});
All 3 of your images are added async with a reference to i and the reference to i is 3 when all images are added. if you look at your 'wh' array you have a bunch of undefineds and then only 1 object added to the array. that is why you can only delete one object.
this JSFiddle just gets a new id in the callback which sets the array up correctly and then they can be deleted since you will now have all the proper references.
if it's acceptable to clear the whole canvas then this you can use the context -fiddle here https://fiddle.jshell.net/2xozu3wk/ as discussed in this query How to undraw, hide, remove, or delete an image from an html canvas? I think all but one of your images is being committed to the canvas and images paint pixels in a manner that's not so easy to clean up. Alternatively you can blank the canvas and reinstate elements you wish to retain but be prepared for a flicker?
var canvas = new fabric.Canvas('c', { selection: false });
var context = canvas.getContext('2d');
.
.
.
if (this.value == "0") {
context.clearRect(0, 0, canvas.width, canvas.height);
}
don't know if that helps
I am trying to re-size a circle using papeJS but since i used two onMouseDrag function it if conflicting. I am unable to create it. Can anyone help me. Here is the fiddle with circle
Here is the code.
<script type="text/paperscript" canvas="canvas">
var raster = new Raster({
source: 'Chrysanthemum.jpg',
position: view.center
});
var path = null;
var circles = [];
var isDrawing = false;
var draggingIndex = -1;
var segment, movePath;
var resize = false;
project.activeLayer.selected = false;
function onMouseDrag(event) {
if (!isDrawing && circles.length > 0) {
for (var ix = 0; ix < circles.length; ix++) {
if (circles[ix].contains(event.point)) {
draggingIndex = ix;
break;
}
}
}
if (draggingIndex > -1) {
circles[draggingIndex].position = event.point;
} else {
path = new Path.Circle({
center: event.point,
radius: (event.downPoint - event.point).length,
fillColor: null,
strokeColor: 'black',
strokeWidth: 10
});
path.removeOnDrag();
isDrawing = true;
}
}
;
function onMouseUp(event) {
if (isDrawing) {
circles.push(path);
}
isDrawing = false;
draggingIndex = -1;
}
;
function onMouseMove(event) {
project.activeLayer.selected = false;
if (event.item)
event.item.selected = true;
resize = true;
}
var segment, path;
var movePath = false;
function onMouseDown(event) {
segment = path = null;
var hitResult = project.hitTest(event.point, hitOptions);
if (!hitResult)
return;
if (hitResult) {
path = hitResult.item;
if (hitResult.type == 'segment') {
segment = hitResult.segment;
} else if (hitResult.type == 'stroke') {
var location = hitResult.location;
segment = path.insert(location.index + 1, event.point);
path.smooth();
}
}
movePath = hitResult.type == 'fill';
if (movePath)
project.activeLayer.addChild(hitResult.item);
}
</script>
First, your code (on jsfiddle) does not run.
The paperjs external resource returned a 404. https://raw.github.com/paperjs/paper.js/master/dist/paper.js works for paperjs.
The raster source was for a local file, not a URI.
In onMouseDown, project.hitTest references an undefined hitOptions.
It seems from your question that you want to be able to drag the circle segments to resize the circle, and you tried using two onMouseDrag functions to do that, which would not work. Instead, both operations should be in the same onMouseDrag, using if-then-else to choose between them. To make this work as expected, the item that was hit should be stored in onMouseDown instead of whatever circle your code finds at the beginning of onMouseDrag. For example, here onMouseDrag can either "move" or "resize" (jsfiddle here):
<script type="text/paperscript" canvas="myCanvas">
var raster = new Raster({
source: 'http://i140.photobucket.com/albums/r10/Array39/Chrysanthemum.jpg',
position: view.center
});
var circles = [];
var hitItem = null;
var currentAction = null;
function onMouseMove(event) {
project.activeLayer.selected = false;
if (event.item) {
event.item.selected = true;
}
}
function onMouseDown(event) {
hitItem = null;
var aColor = new Color('black');
for (var i = 0; i < circles.length; i++) {
circles[i].fillColor = aColor;
}
view.draw();
var hitResult = project.hitTest(event.point);
for (var i = 0; i < circles.length; i++) {
circles[i].fillColor = null;
}
view.draw();
if (!hitResult) {
return; //only happens if we don't even hit the raster
}
hitItem = hitResult.item;
if (circles.indexOf(hitItem) < 0) {
var newCircle = new Path.Circle({
center: event.point,
radius: 2,
strokeColor: 'black',
strokeWidth: 10
});
hitItem = newCircle;
circles.push(hitItem);
currentAction = 'resize';
return;
}
if (hitResult.type == 'segment') {
currentAction = 'resize';
} else if (hitResult.type == 'stroke') {
hitItem.insert(hitResult.location.index + 1, event.point);
hitItem.smooth();
currentAction = 'resize';
} else if (hitResult.type == 'fill') {
currentAction = 'move';
}
}
function onMouseDrag(event) {
if (!hitItem) {
return;
}
if (currentAction == 'move') {
hitItem.position = event.point;
} else if (currentAction == 'resize') {
if ((event.downPoint - event.point).length >= 1) {
hitItem.fitBounds(new Rectangle(event.downPoint, event.point), true);
}
}
};
</script>
<canvas id="myCanvas"></canvas>
Also note:
In onMouseDown, the function returns if !hitResult, so you do not need to test if (hitResult) right after that return.
Naming variables the same as objects makes searching more difficult, e.g., in your code path is an instance of Path.
Using the same variable for different purposes makes code more difficult to parse, e.g., in your code path is used to create new circles as well as to store which circle has been selected.
You have multiple variables defined twice: path, movePath, and segment.
If a variable will only be used in a single function, e.g., movePath and segment, then it makes the code more readable if the variable is defined in that function. Also, movePath is only used in a single if-statement, which just adds items back to the layer, but the only items not in the layer have been removed when the circle was originally drawn. Since those items cannot be hit, the item that was hit must already be in the layer.
The variable segment is not used.
It makes the code flow/read better if the functions are ordered logically. In this case, onMouseMove should go first because it happens before the button is clicked. Then onMouseDown goes next because it must happen before the other actions. Then onMouseDrag, and finally onMouseUp.
Instead of creating new circles in onMouseDrag and then throwing them away on the next drag, it makes more sense to create one in onMouseDown if there was no item hit, or if the hit item is not a circle. Then in onMouseDown, you just resize that circle. Path.scale or Path.fitBounds can be used for such resizing.
Instead of using multiple boolean variables to keep track of the current action (e.g., resize vs move), it is more logical to have a single variable keeping track of the current action.
Instead of your code to find whether the point is within a circle, the code I am using temporarily sets the circles' fillColor, do the hitTest, and then clears the circles' fillColor. I did this because when you hit a stroke, the shape of the circle changes, for which your code to find the draggingIndex does not account.