I have a surface where i draw some kind of dynamic image based on the data from my backend, on click of a certain area, i want different data to be published. but my following code always takes last data drawn to publish.
function renderICD() {
var totalx=1200;
var totaly=1000;
var xOffset = 150;
var yOffset = 20;
surface = dojox.gfx.createSurface("icdTab",totalx+2,totaly+2);
var grid = surface.createGroup();
var step = 1;
var xyHolder = {};
var group = grid.createGroup();
for(var ii=0;ii<2;ii++)
{
var x = (step-1) * (75+85);
step++;
var group = grid.createGroup();
group.createRect({x:xOffset+x+33, y:yOffset+20+90, width: 10, height: 10}).setFill([255, 255, 255, 0.9])
.setStroke({color:'black' , width:2});
dojo.connect(group.getEventSource(),"onclick",function(e) {
var internal = ii;
alert("publishing "+internal);
//shape was clicked, now do something!
});
grid.createText({x:xOffset+x+33, y:yOffset+20+80, text:ii,align:"middle"})
.setFill('red')
.setFont({size: '10px',weight: "bold"});
}
}
As i understand, only 1 instance of function written to handle event is present, but what i am trying to handle is 2 different events.
How can i achieve this?
Snapshot of surface with 2 rects, when i click on both rects, i get '2' in my alert.
JavaScript has functional scope, not block scope, so you only have one ii variable, which is always equal to "2" by the time you click on a rect. There are many ways to fix this, example below :
function renderICD() {
var totalx=1200;
var totaly=1000;
var xOffset = 150;
var yOffset = 20;
surface = dojox.gfx.createSurface("icdTab",totalx+2,totaly+2);
var grid = surface.createGroup();
var step = 1;
var xyHolder = {};
var group = grid.createGroup();
dojo.forEach([0,1], function(item, ii) {
var x = (step-1) * (75+85);
step++;
var group = grid.createGroup();
group.createRect({x:xOffset+x+33, y:yOffset+20+90, width: 10, height: 10}).setFill([255, 255, 255, 0.9])
.setStroke({color:'black' , width:2});
dojo.connect(group.getEventSource(),"onclick",function(e) {
var internal = ii;
alert("publishing "+internal);
//shape was clicked, now do something!
});
grid.createText({x:xOffset+x+33, y:yOffset+20+80, text:ii,align:"middle"})
.setFill('red')
.setFont({size: '10px',weight: "bold"});
});
}
Related
I thought the best way to learn neural networks would be to create one from scratch in JavaScript using the MNIST database of images, each image displaying a single handwritten number from 0 to 9. Each image is 784 pixels, each pixel value being either 1 (white) or 0 (black).
Now before I start posting any code, I wanted to first keep things abstract and talk out my problem to see if I'm just missing something very basic and embarrassing.
NN basic specs are:
784 input values 2 hidden layers
each containing 50 neurons 10
output neurons representing labels 0 to 9
beta = 0 in every layer
learning rate = 0.01 initial weights set using xavier
activation function = sigmoid throughout for now
When I run this NN over a 1000 images or so, all the outputs slowly descend to around 0.1 and then basically all hover there forever. When I watch a single image flow through the NN and then backprop, this actually makes sense. Most of the time, in fact 90% of the time, the true value for a single output will be zero. Therefore, for a single output, if I run 10 images through, 9 of those images will want the output to move towards truth=zero, while only 1 images will want it to move up to truth=one. I actually see happen in the numbers....you can see a single output value slowly descend towards truth=zero a bunch of times, then get a temporary bump up when truth=one.
I hope this makes sense....basically my NN would rather reduce my total error by moving all my outputs closer to truth=zero. It's almost as if I need to adjust my learning rate to be 10x greater when adjusting my weights towards truth=one...but then I suspect this would just adjust all my outputs to 0.5.
I've been through my code so many times, and I believe my math is good, but of course I could be missing something. That said...I thought I'd start here first and see if anyone else has seen this.
EDIT....raw code containing NN classes. Sorry, bit messy. Basically you call a new network class, then run network.addlayer to populate layers, neurons, and set weights. From there you can start training by call network.inputTrainingData, which accepts the binary array of 784 pixels, and the truth value for the image. And finally, you can network backPropogate after every image.
class network {
layers = [];
learning_rate = 0.01;
inputCnt = 784;
labels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
xValues = [];
truth = [];
constructor() {
}
addLayer(neuronCnt, isOutputLayer) {
//note...we're not adding an "input layer....why do that when you can just feed the inputs into the first hidden layer?
if (isOutputLayer) {
this.layers.push(new layer(this.labels.length, this.layers[this.layers.length - 1].neurons.length, isOutputLayer));
} else if(this.layers.length) {
this.layers.push(new layer(neuronCnt, this.layers[this.layers.length - 1].neurons.length, isOutputLayer));
} else {
this.layers.push(new layer(neuronCnt, this.inputCnt, isOutputLayer));
}
}
get numberOfLayers() {
return this.layers.length;
}
inputTrainingData(data, truth) {
this.xValues = data;
this.xValues.forEach(function (x, i) {
if (x == 0) { x = 0.0001; };
})
this.truth = truth;
var $this = this;
this.layers.forEach(function (layer, index) {
layer.input($this.xValues);
$this.xValues = layer.output();
});
}
backPropogate() {
var $this = this;
var prev_layer = 0;
var t = this.getTruth();
for (var i = this.layers.length-1; i >= 0; i--) {
this.layers[i].backPropogate(t, $this.learning_rate, prev_layer);
prev_layer = this.layers[i];
}
}
getTruth() {
var truth = [];
var $this = this;
this.labels.forEach(function (label, index) {
if ($this.truth == label) {
truth.push(1);
} else {
truth.push(0);
}
})
return truth;
}
}
class layer {
neurons = [];
inputs = [];
outputs = [];
final_deriv = [];
hidden_deriv = [];
beta = 0; //Math.random();
isOutputLayer = false;
constructor(neuronCnt, prevLayerNeuronCnt, _isOutputLayer) {
this.isOutputLayer = _isOutputLayer;
var i;
for (i = 0; i < neuronCnt; i++) {
var newNeuron = new neuron(neuronCnt, prevLayerNeuronCnt);
this.neurons.push(newNeuron);
}
}
input(xValues) {
this.inputs = xValues;
var $this = this;
this.neurons.forEach(function (neuron, index) {
neuron.input(xValues, $this.beta);
});
}
output() {
this.outputs = [];
var $this = this;
this.neurons.forEach(function (neuron, index) {
$this.outputs.push(neuron.output($this.isOutputLayer));
})
return this.outputs;
}
backPropogate(truth, learning_rate, prev_layer) {
var $this = this;
this.neurons.forEach(function (neuron, index) {
neuron.backPropogateWeights(truth[index], learning_rate, prev_layer, index);
//neuron.backPropogateBeta(truth[index], prev_layer);
});
}
}
class neuron {
xValues = 0;
b = 0;
weights = [];
h = 0;
neuron_deriv = 1;
weights_deriv = [];
constructor(neuronCnt, prevLayerNeuronCnt) {
var i;
var xavier = 1 / prevLayerNeuronCnt;
for (i = 0; i < prevLayerNeuronCnt; i++) {
var rnd = (Math.random() - 0.5) * xavier;
//rnd = ((Math.random() * 2) - 1) * xavier;
this.weights.push(rnd);
}
}
input(xValues, beta) {
this.xValues = xValues;
this.b = beta;
}
output(isOutputLayer) {
var func = 0;
var $this = this;
this.xValues.forEach(function (x, index) {
func += x * $this.weights[index];
});
func += this.b;
var sigmoid = 1 / (1 + Math.exp(-func));
$this.h = sigmoid;
$this.neuron_deriv = (sigmoid * (1 - sigmoid));
return this.h;
}
backPropogateWeights(truth, learning_rate, prev_layer, cnt) {
var $this = this;
var prevSumError = 1;
if (prev_layer == 0) {
//var SqError = Math.pow((this.h - truth), 2)/2;
var dEdH = (this.h - truth);
this.neuron_deriv = this.neuron_deriv * dEdH;
} else {
prevSumError = 0;
prev_layer.neurons.forEach(function (neuron, index) {
prevSumError += neuron.weights_deriv[cnt];
});
}
this.weights.forEach(function (weight, index) {
$this.weights_deriv.push($this.neuron_deriv * weight * prevSumError);
});
for (var i = 0; i < this.weights.length; i++) {
var slope = $this.neuron_deriv * $this.xValues[i] * prevSumError;
var weightAdjust = learning_rate * slope;
$this.weights[i] = $this.weights[i] - weightAdjust;
}
}
}
This took a very long time to debug. It was the weights. I was using an xavier function to randomize all the weights, but when I opened up the weight range between -2.5 to 2.5, everything just started worked.
Here was my debug process if it helps anyone else:
- Repeated all my code calculations by hand to ensure code was running correctly
- Reduced entire neural network to bare minimal number of layers and neurons.
- Trained on a single image, then two, then three.
- First breakthrough was when I trained on just two images and eliminated ALL hidden layer....it actually learned!
- From here I slowly added in a layer and a few more images.
- It's at this point I started to expand my weight range....and I could see it was starting to learn.
- Finally I blew out my weight range, went back to my original setup, and boom! worked!
It's still not learning as fast I it should, based on the same implementation by Andrej Kaparthy in his ConvNetJS....but at least I'm now in a position to start tweaking.
I have the following graph with 3 datasets. Everything works fine except for one small bug. I want to tooltip to be placed only on the first dataset, as it currently is placed on the average position of all datasets.
Here is a screenshot:
I know that ChartJS has the positioners function (the one below), but I can't figure out how to ignore the other 2 datasets so the tooltip is sticked only to the first line graph
Chart.Tooltip.positioners.top = function (elements, eventPosition) {
const tooltip = this;
return ;
};
You can also define a custom position function for tooltips. like this,
Chart.Tooltip.positioners.custom = function(elements, eventPosition) {
var x = eventPosition.x;
var y = eventPosition.y;
var minDistance = Number.POSITIVE_INFINITY;
var i, len, nearestElement;
var top_element = elements[0];
for (i = 0, len = elements.length; i < len; ++i) {
console.log(elements[i].tooltipPosition().y);
if (elements[i].tooltipPosition().y < top_element.tooltipPosition().y) {
top_element = elements[i];
}
}
var tp = top_element.tooltipPosition();
x = tp.x;
y = tp.y;
return {
x: x,
y: y
};
};
Once done, you can specify it in tooltips.options.
More information :
https://www.chartjs.org/docs/latest/configuration/tooltip.html#position-modes
Hope it helps!
is there a way to modify this code for animate cc to make object in the stage and interact with it ?
it is a bit of pain to make drag and drop in createjs for animate cc
there is nothing in the web that describe how to do it for animate cc or flash cc even the documentation has nothing to tell about drag and drop in the canvas
//Stage
var stage = new createjs.Stage("demoCanvas");
//VARIABLES
//Drag Object Size
dragRadius = 40;
//Destination Size
destHeight = 100;
destWidth = 100;
//Circle Creation
var label = new createjs.Text("DRAG ME", "14px Lato", "#fff");
label.textAlign="center";
label.y -= 7;
var circle = new createjs.Shape();
circle.graphics.setStrokeStyle(2).beginStroke("black")
.beginFill("red").drawCircle(0,0, dragRadius);
//Drag Object Creation
//Placed inside a container to hold both label and shape
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
dragger.setBounds(100, 100, dragRadius*2, dragRadius*2);
//DragRadius * 2 because 2*r = width of the bounding box
var label2 = new createjs.Text("HERE", "bold 14px Lato", "#000");
label2.textAlign = "center";
label2.x += 50;
label2.y += 40;
var box = new createjs.Shape();
box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
var destination = new createjs.Container();
destination.x = 350;
destination.y = 50;
destination.setBounds(350, 50, destHeight, destWidth);
destination.addChild(label2, box);
//DRAG FUNCTIONALITY =====================
dragger.on("pressmove", function(evt){
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
stage.update(); //much smoother because it refreshes the screen every pixel movement instead of the FPS set on the Ticker
if(intersect(evt.currentTarget, destination)){
evt.currentTarget.alpha=0.2;
box.graphics.clear();
box.graphics.setStrokeStyle(3)
.beginStroke("#0066A4")
.rect(0, 0, destHeight, destWidth);
}else{
evt.currentTarget.alpha=1;
box.graphics.clear(); box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
}
});
//Mouse UP and SNAP====================
dragger.on("pressup", function(evt) {
if(intersect(evt.currentTarget, destination)){
dragger.x = destination.x + destWidth/2;
dragger.y = destination.y + destHeight/2;
dragger.alpha = 1;
box.graphics.clear();
box.graphics.setStrokeStyle(2).beginStroke("black").rect(0, 0, destHeight, destWidth);
stage.update(evt);
}
});
//Tests if two objects are intersecting
//Sees if obj1 passes through the first and last line of its
//bounding box in the x and y sectors
//Utilizes globalToLocal to get the x and y of obj1 in relation
//to obj2
//PRE: Must have bounds set for each object
//Post: Returns true or false
function intersect(obj1, obj2){
var objBounds1 = obj1.getBounds().clone();
var objBounds2 = obj2.getBounds().clone();
var pt = obj1.globalToLocal(objBounds2.x, objBounds2.y);
var h1 = -(objBounds1.height / 2 + objBounds2.height);
var h2 = objBounds2.width / 2;
var w1 = -(objBounds1.width / 2 + objBounds2.width);
var w2 = objBounds2.width / 2;
if(pt.x > w2 || pt.x < w1) return false;
if(pt.y > h2 || pt.y < h1) return false;
return true;
}
//Adds the object into stage
stage.addChild(destination, dragger);
stage.mouseMoveOutside = true;
stage.update();
thanks
I am not exactly sure what you are asking. The demo you showed works fine (looks like it came from this codepen), and it is not clear what you are trying to add. This demo was made directly in code, not with Animate CC - which is really good for building assets, animations, and display list structure, but you should write application code around what gets exported.
There are plenty of documentation and examples online for Drag and Drop, in the EaselJS GitHub, and EaselJS docs:
DragAndDrop demo in GitHub
Live demo on EaselJS demos page
Documentation on pressMove
Tutorial on Mouse Events which includes Drag and Drop
I recommend narrowing down what you are trying to do, show what code or approaches you have tried so far, and posting specific questions here.
Lastly, here is the first part of an ongoing series for working with Animate CC: http://blog.gskinner.com/archives/2015/04/introduction-to-the-flash-cc-html5-canvas-document.html
Cheers.
How can I get the screen size using with addon SDK ?
var w = screen.width/2;
gives me an error : Message: ReferenceError: screen is not defined
You can use the window you have associated to your add-on; it's probably safer, because it will work even if the last visible window is closed but firefox is still opened (e.g. on OS X):
const { window: { screen }} = require("sdk/addon/window");
console.log(screen.width);
This will work:
var screen = require('sdk/window/utils').getMostRecentBrowserWindow().screen;
console.log(screen.width);
If you want multi monitor support I have a script but you have to understand it. It uses XPCOM, and it needs a range. This script only checks along the x axis, you should also check along the y axis.
So this is the script here that will detect all monitors in the x plane IF it falls in the y plane of 0-20 coordintates of primary screen, I don't recommend this method.
var sm = Cc['#mozilla.org/gfx/screenmanager;1'].getService(Ci.nsIScreenManager);
function getScreens() {
var screen = null;
var screens = [];
var screenManager = sm;
var min = 0;
var max = 0;
for (x = 0; x < 15000; x += 600) {
var s = screenManager.screenForRect(x, 20, 10, 10);
if (s != screen) {
screen = s;
var left = {},
top = {},
width = {},
height = {};
screenManager.primaryScreen.GetRect(left, top, width, height);
screens.push({
width: width.value,
height: height.value,
min: min,
max: min + width.value
});
min += width.value;
}
}
return screens;
}
var screens = getScreens();
console.log('screens:', screens);
This is the method I recommend
I needed to detect all monitor dimensons and had to resort to jsctypes, if you need that its here: https://github.com/Noitidart/NativeShot/blob/master/modules/workers/MainWorker.js#L853-L1523
That code is extremely long, thats because its getting all monitors and the taking screenshots of them. So you will want to extract just the monitors part. If you need help with it I can do it for you.
Is it possible to be able to drag and drop objects other than just circles and rectangles around a page using Raphael js?
I want to add in paths and images which you can then move around but its proving tricky.
I would like to work this out with Raphael because of its support with touch interfaces.
Here is the code
<script>
window.onload = function () {
var R = Raphael(0, 0, "100%", "100%"),
r = R.circle(100, 100, 50).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5}),
g = R.circle(210, 100, 50).attr({fill: "hsb(.3, 1, 1)", stroke: "none", opacity: .5}),
b = R.circle(320, 100, 50).attr({fill: "hsb(.6, 1, 1)", stroke: "#fff", "fill-opacity": 0, "stroke-width": 0.8, opacity: .5}),
p = R.path("M 250 250 l 0 -50 l -50 0 l 0 -50 l -50 0 l 0 50 l -50 0 l 0 50 z") .attr({fill: "hsb(.8, 1, 1)", stroke: "none", opacity: .5});
var start = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
this.animate({r: 70, opacity: .25}, 500, ">");
},
move = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
this.animate({r: 50, opacity: .5}, 500, ">");
};
R.set(r, g, b, p).drag(move, start, up);
};
</script>
The key here (that I found) is to convert the x and y deltas into translate values, which the path object understands.
http://www.nathancolgate.com/post/2946823151/drag-and-drop-paths-in-raphael-js
Effectively the same approach:
var paper = Raphael(10, 50, 320, 200);
var tri = paper.path("M0 0L0 20L25 10L0 0Z").attr("fill", "#ff0");
var rex = paper.rect(10, 20, 50, 50).attr("fill", "#ff0");
var start = function () {
this.odx = 0;
this.ody = 0;
this.animate({"fill-opacity": 0.2}, 500);
},
move = function (dx, dy) {
this.translate(dx - this.odx, dy - this.ody);
this.odx = dx;
this.ody = dy;
},
up = function () {
this.animate({"fill-opacity": 1}, 500);
};
tri.drag(move, start, up);
rex.drag(move, start, up);
As translate is being deprecated in Raphael, I've modified Nathan's answer to work with transform:
var paper = Raphael(10, 50, 320, 200);
var tri = paper.path("M0 0L0 20L25 10L0 0Z").attr("fill", "#ff0");
var start = function () {
this.lastdx ? this.odx += this.lastdx : this.odx = 0;
this.lastdy ? this.ody += this.lastdy : this.ody = 0;
this.animate({"fill-opacity": 0.2}, 500);
},
move = function (dx, dy) {
this.transform("T"+(dx+this.odx)+","+(dy+this.ody));
this.lastdx = dx;
this.lastdy = dy;
},
up = function () {
this.animate({"fill-opacity": 1}, 500);
};
tri.drag(move, start, up);
I'm relatively new to Raphael and came up with this through trial and error, so someone out there might have an explanation of why it works or a cleaner way of doing it ;)
I experimented with this a little while ago, and got it working using the following approach:
Add an initially hidden, styled, absolutely positioned div with a transparent background and suitable border styling to your page, and using jQuery/UI make it draggable.
Add a click event to each of the Rapahel/SVG elements you wish to be draggable, and in this event add code to resize and reposition the div over the element which has just been clicked and then make it visible.
Add code to the div which updates the position of the Raphael element when it is dragged.
I extended this to add resizing capabilities, and this also worked well, but going forward it would be great to see drag, drop and resize capabilities (ideally properly integrated into the library rather than using jQuery) built into Raphael, as these features would open up a whole bunch of possibilities for in-browser designers using pure Raphael.
Try this for non-circles. Circles attributes are different than images, text, etc, I think.
var start = function () {
this.ox = this.attr("x");
this.oy = this.attr("y");
this.animate({r: 70, opacity: .25}, 500, ">");
},
move = function (dx, dy) {
this.attr({x: this.ox + dx, y: this.oy + dy});
},
up = function () {
this.animate({r: 50, opacity: .5}, 500, ">");
};
I would recommend you raphael.draggable library, that makes the trick for you. I used it with a map application that allows the user to use zoom over the map and then drag it.
I had a problem with this library in IE8 because in the function events refering to mousedown, mousemove, etc. IE drops an exception, telling the user that event is null. You can solve it by replacing the event by e and adding e = e || event in the raphael.draggable.js script. This fix doesn't affect other browsers.
So, the method mousemove in the startDragger is:
function startDragger() {
document.onmousemove = function(e) {
e = e || event
if (paper.draggable.current()) {
var transX = e.clientX - lastDragX;
var transY = e.clientY - lastDragY;
paper.draggable.current().translate(transX, transY);
lastDragX = e.clientX;
lastDragY = e.clientY;
}
};
}
And the link:
https://github.com/mephraim/raphael.draggable
Hope this could help you.
it's not that hard if you understand the usual dragging functions Chris Butler gave you.
I use this:
var start = function () {
//storing original coordinates
this.xSource = this.attrs.path[0][1];
this.ySource = this.attrs.path[0][2];
this.xDest = this.attrs.path[1][1];
this.yDest = this.attrs.path[1][2];
this.attr({opacity: 0.5});
},
move = function (dx, dy) {
//move will be called with dx and dy
var xS = this.xSource+dx;
var xD = this.xDest+dx;
var yS = this.ySource+dy;
var yD = this.yDest+dy;
this.attr({path: "M"+ xS +" "+ yS +"L"+ xD +" "+yD});
},
drag = function(){
this.node.drag(this.move,this.start,this.up);
};
You can also know which sort of figure you're dragging in the functions with this.type, so that you can make these functions work for all sort of figures.
In case anyone is still looking for a solution, here's a plugin that scales, rotates and drags all shapes including paths.
https://github.com/ElbertF/Raphael.FreeTransform