Constructor method in class not being called - javascript

I want to create a class Pixel that will store the position and colors of a given pixel.
Here is my code so far:
<canvas id="kartina" width="500" height="500"></canvas>
<input type="text" id="textField" size="80">
<script>
//pass in coordinates and Canvas context
function Pixel(x,y,ctx){
//assign coordinate properties
this.x=x;
this.y=y;
//get an array with the color data for the pixel
this.pixelData=function(){
return ctx.getImageData(x,y,1,1).data;
};
//assign color properties
this.r=this.pixelData[0];
this.g=this.pixelData[1];
this.b=this.pixelData[2];
//define toString method
this.toString=function(){
var pixelToString= "x: "+this.x+
", y: "+this.y+
", R: "+this.r+
", G: "+this.g+
", B: "+this.b;
return pixelToString;
};
}
//test the class
var canvas=document.getElementById("kartina");
var ctx=canvas.getContext("2d");
var pixel=new Pixel(100,100,ctx);
textField.value=pixel.toString();
</script>
The output from toString() is:
x: 100, y: 100, R: undefined, G: undefined, B: undefined
So I know that the coordinate properties are being assigned correctly, but the pixelData initialization function is not being executed when new Pixel() constructs the instance. I want the object's constructor to call this initialization function; I thought this was the way to do it. How do I set up the constructor here?

Since pixelData is a function, you need to invoke it to get your desired results:
//assign color properties
this.r=this.pixelData()[0];
this.g=this.pixelData()[1];
this.b=this.pixelData()[2];
Or better yet:
var pData = this.pixelData();
this.r=pData[0];
this.g=pData[1];
this.b=pData[2];

You are referencing your this.pixelData() function as if it were an array using [] square brackets.
The function never gets called at all because you are treating it as an array instead of calling the function and then treating the result as an array.
Change this:
this.r=this.pixelData[0];
this.g=this.pixelData[1];
this.b=this.pixelData[2];
To this:
this.r=this.pixelData()[0];
this.g=this.pixelData()[1];
this.b=this.pixelData()[2];
Or to avoid calling it three times:
//assign color properties
var pixelData = this.pixelData()
this.r = pixelData[0];
this.g = pixelData[1];
this.b = pixelData[2];

Related

How can d3.transform be used in d3 v4?

In d3.js v4 the d3.transform method has been removed, without any hint about how to replace it.
Does anyone know how to replace the following d3.js v3 code?
d3.transform(String).translate;
Edit 2016-10-07: For a more general approach see addendum below.
According to the changelog it is gone. There is a function in transform/decompose.js, though, which does the calculations for internal use. Sadly, it is not exposed for external use.
That said, this is easily done even without putting any D3 to use:
function getTranslation(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, "transform", transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// As per definition values e and f are the ones for the translation.
return [matrix.e, matrix.f];
}
console.log(getTranslation("translate(20,30)")) // simple case: should return [20,30]
console.log(getTranslation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"))
This creates a dummy g element for calculation purposes using standard DOM methods and sets its transform attribute to the string containing your transformations. It then calls .consolidate() of the SVGTransformList interface to consolidate the possibly long list of transformation to a single SVGTransform of type SVG_TRANSFORM_MATRIX which contains the boiled down version of all transformations in its matrix property. This SVGMatrix per definition holds the values for the translation in its properties e and f.
Using this function getTranslation() you could rewrite your D3 v3 statement
d3.transform(transformString).translate;
as
getTranslation(transformString);
Addendum
Because this answer has gained some interest over time, I decided to put together a more general method capable of returning not only the translation but the values of all transformation definitions of a transform string. The basic approach is the same as laid out in my original post above plus the calculations taken from transform/decompose.js. This function will return an object having properties for all transformation definitions much like the former d3.transform() did.
function getTransformation(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, "transform", transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// Below calculations are taken and adapted from the private function
// transform/decompose.js of D3's module d3-interpolate.
var {a, b, c, d, e, f} = matrix; // ES6, if this doesn't work, use below assignment
// var a=matrix.a, b=matrix.b, c=matrix.c, d=matrix.d, e=matrix.e, f=matrix.f; // ES5
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * 180 / Math.PI,
skewX: Math.atan(skewX) * 180 / Math.PI,
scaleX: scaleX,
scaleY: scaleY
};
}
console.log(getTransformation("translate(20,30)"));
console.log(getTransformation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"));
If you pull in d3 v4 through npm, you can import the src/transform/parse file directly and call parseSvg:
// using es2015 modules syntax
import { parseSvg } from "d3-interpolate/src/transform/parse";
parseSvg("translate(20, 20)");
On elements which have the d3.js zoom listener on them -- usually the <g> element appended to the svg element -- you can use this call to get the transformation attributes outside of the zoom function:
var self = this;
var t = d3.zoomTransform(self.svg.node());
// t = {k: 1, x: 0, y: 0} or your current transformation values
This returns the same values as when calling d3.event.transform within the zoom event function itself.
Calling d3.event.transform outside the zoom event function will error:
Uncaught TypeError: Cannot read property 'transform' of null
I have to use d3.zoomTransform to allow panning and zooming from buttons outside the graph.
I found a little bit simpler solution than that.
selection.node().transform.baseVal[0].matrix
In this matrix you have cordinates e and f witch are equivalent to x, y. (e === x, f === y). No need to implement your very own funtion for that.
baseVal is a list of transformations of the element. You can't use that for the object without previus transformation! (the list will be empty) Or if you done many tranformation to the object the last position will be under the last element of baseVal list.
I am a little late to the party, but I had some code that was beneficial to me, I hope it helps you out too.
The code above by #altocumulus is quite thorough and works like a charm. However it didn't quite meet my needs since I was doing the calculations by hand and needed to alter some transform properties as painlessly as possible.
This might not be the solution for everyone, but it was perfect for me.
function _getTokenizedTransformAttributeValue(transformStr) {
var cleanedUpTransformAttrArr = transformStr.split(')', ).slice(0,-1);
return cleanedUpTransformAttrArr.reduce(function(retObj, item) {
var transformPair = item.split('(');
retObj[transformPair[0]] = transformPair[1].split(',');
return retObj;
}, {});
}
function _getStringFromTokenizedTransformAttributeObj(transformAttributeObj) {
return Object.keys(transformAttributeObj).reduce(function(finalStr, key) {
// wrap the transformAttributeObj[key] in array brackets to ensure we have an array
// join will flatten the array first and then do the join so [[x,y]].join(',') -> "x,y"
return finalStr += key + "(" + [transformAttributeObj[key]].join(',') + ")";
}, '');
}
The really great thing with the first function is that I can manually alter a specific property (e.g. rotation), and not have to worry about how it affects translate or anything else (when rotating around a point), whereas when I rely on the built-in or even d3.transform methods they consolidate all the properties into one value.
Why is this cool?
Imagine a some HTML
<g class="tick-label tick-label--is-rotated" transform="translate(542.8228777985075,0) rotate(60, 50.324859619140625, 011.402383210764288)" style="visibility: inherit;"></g>
Using d3.transfrom I get:
In object form
jr {rotate: 59.99999999999999, translate: [577.8600589984691, -37.88141544673796], scale: [1, 1], skew: 0, toString: function}
In string form
"translate(577.8600589984691,-37.88141544673796)rotate(59.99999999999999)skewX(0)scale(1,1)"
Which is correct mathematically, but makes it hard for me to simply remove the angle of rotation and the translation that had to be introduced to rotate this element around a given point.
Using my _getTokenizedTransformAttributeValue function
In object form
{translate: ["542.8228777985075", "0"], rotate: ["60", " 50.324859619140625", " 011.402383210764288"]}
In string form using the function _getStringFromTokenizedTransformAttributeObj
"translate(542.8228777985075,0)rotate(60, 50.324859619140625, 011.402383210764288)"
Which is perfect because now when you remove the rotation, your element can go back to where it was
Granted, the code could be cleaner and the function names more concise, but I really wanted to get this out there so others could benefit from it.
I found a way do achieve something similar by using this:
d3.select(this).node().getBBox();
this will give you access to the x/y position and width/height
You can see an example here: https://bl.ocks.org/mbostock/1160929

How to edit objects attributes from array using parallel/multithreading Hamsters.js Javascript lib

When using Hamster.js we have to define the parameter array as
params = {"array":my_array}
my_array is formed by elements with many attributes and I need to change the attributes x and y.
In the function I pass to Hamster.js I defined:
function map_node_hamster() {
params.array.forEach(function (d) {
d.x = some_calculation_here;
d.y = other_calculation_here;
}
}
but after calling the hamster.run() function, the elements of my original array stay intact.
As I need performance, I thought Hamsters could just change the values that my array is pointing. I actually do not know much about Javascript and how it manages arrays.
I'm calling the run function like this:
console.log("Before hamster:");
console.log(network.nodes);
p = {'array': network.nodes, "w": w, "h":h};
hamsters.run(p, map_node_hamster, function(output){console.log(output); return output;}, hamsters.maxThreads, true);
console.log("After hamster:");
console.log(network.nodes);
And the elements of network.nodes are intact after hamsters.run().
How could I change elements of array inside run function? Or.. How would be the right way to do the changes?
As the vector nodes is large, copying, sorting, and things like this will decrease performance and maybe it will be worst than single thread/non-parallel version.
It seems like the answer is to create an index array and change nodes in the callback function (output).
Despite the behavior of my "d3 graphic representation of network" is really not what I expected... maybe the code is actually right in the sense of answering my question (how to change objects from array in parallel computing with Hamsters.js). That is:
p = {'array': network.indexes,
"nodes": network.nodes,
"w": w,
"h": h};
hamsters.run(p, map_node_hamster, function (output) {
output.forEach(function (d) {
network.nodes[d.i].x = d.xy[0];
network.nodes[d.i].y = d.xy[1];
});
return output;
}, cores, true);
And... changing the function to work like this:
function map_node_hamster() {
pfor (var i = 0; i < params.array.length; i++) {
var result;
var d = params.nodes[params.array[i]];
var d = params.nodes[params.array[i]];
result = {x: d.x calculation, y: d.y calculation};
rtn.data.push({"i": params.array[i], "xy": [result.x, result.y]});
}
}

How to extract properties from html Canvas CanvasGradient and CanvasPattern objects

Given: an html canvas context:
Example code: http://jsfiddle.net/m1erickson/wJ67M/
This code creates a CanvasGradient object in the gradient variable.
var gradient=context.createLinearGradient(0,0,300,150);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'white');
This code creates a CanvasGradient object in the gradient variable.
var gradient=context.createRadialGradient(150,150,30, 150,150,100);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'white');
This code creates a CanvasPattern object in the pattern variable.
var pattern=context.createPattern(myImage,'repeat');
Is there a programatic way of extracting the properties from these objects after they are created (not by referring back to the JS code that created them)?
Wanted:
The linear gradients line segment (0,0,300,150) and its colorstops (0,red,1,white).
The radial gradients circles (150,150,30, 150,150,100) and its colorstops (0,red,1,white).
The patterns image and repeat properties.
Thanks for any thoughts!
The canvas specs does not grant access to the inner gradient or pattern properties, just like, as you also know, one cannot get access to the transform matrix.
So the only solution is to inject CanvasRenderingContext2D, CanvasGradient and CanvasPattern prototypes to store, in the created objects, the values used to create them.
So for the Canvas, you can write something like :
// save native linear gradient function
var nativeCreateLinearGradient = CanvasRenderingContext2D.prototype.createLinearGradient ;
// redefine createLinearGradient with a function that stores creation data
// new properties : gradientType, x0, y0, x1, y1, colorStops
CanvasRenderingContext2D.prototype.createLinearGradient = function(x0, y0, x1, y1) {
// actually create the gradient
var newGradient = nativeCreateLinearGradient.apply(this,arguments);
// store creation data
newGradient.gradientType = 0 ; // 0 for linear, 1 for radial
newGradient.x0 = x0; newGradient.y0 = y0;
newGradient.x1 = x1; newGradient.y1 = y1;
newGradient.colorStops = [];
return newGradient;
};
And for the Gradient :
var dummyContext = document.createElement('canvas').getContext('2d');
var nativeAddColorStop = CanvasGradient.prototype.addColorStop;
CanvasGradient.prototype.addColorStop = function (offset, color) {
// evaluate offset (to avoid reference issues)
offset = +offset;
// evaluate color (to avoid reference issues)
dummyContext.fillStyle = color;
color = dummyContext.fillStyle ;
// store color stop
this.colorStops.push([offset, color]);
// build the real gradient
nativeAddColorStop.call(this, offset, color);
return this;
};
You can do this in a very similar way for the radial gradient, and for the pattern you might want to copy the image, which type is CanvasImageSource )

Raphael.js newbie question: how to create a rectangular and lines as ONE object?

In raphael, if I want to render the following shape:
I have to do something like:
var paper = Raphael("notepad", 320, 200);
var rect = paper.rect(...);
var line1 = paper.path(...);
var line2 = paper.path(...);
which create three elements: rect, line1, line2.
BUT, I would like to treat the rendered shape as one object in other js code insteand of three. In Raphael, how can I create this shape which returns me just one object not three?
You want to create a set.
Creates array-like object to keep and operate couple of elements at once. Warning: it doesn't create any elements for itself in the page.
var st = paper.set();
st.push(
paper.circle(10, 10, 5),
paper.circle(30, 10, 5)
);
st.attr({fill: "red"});
Your code would look something like this:
var paper = Raphael("notepad", 320, 200),
st = paper.set();
st.push(
paper.rect(...),
paper.path(...),
paper.path(...)
);
// use st elsewhere
Edit
How can I access individual element in the set then?
You can grab references to the objects before you add them to the set:
var paper = Raphael("notepad", 320, 200),
st = paper.set(),
rect1 = paper.rect(...),
path1 = paper.path(...),
path2 = paper.path(...);
st.push(rect1, path1, path2);
I'm not 100% sure, but since the docs say that a set is "array-like," then you should also be able to access elements in the set using array index notation:
var i, elt;
for (i=0; i<st.length; i++)
{
elt = st[i];
// do stuff with elt
}

Change canvas gradient object's properties

var i = 0;
var x = 960;
var y = 540;
var interval = window.setInterval(render, 100);
function render()
{
gradient = cxt.createRadialGradient(x, y, i, x, y, i+10);
gradient.addColorStop(0, "rgba(0,0,0,0)");//white inside
gradient.addColorStop(.4, "rgba(255,255,255,1)");//white inside
gradient.addColorStop(.6, "rgba(255,255,255,1)");//white inside
gradient.addColorStop(1, "rgba(0,0,0,0)");//fade to transparent black outside;
cxt.fillStyle= "#000000";
cxt.fillRect(0,0,WIDTH,HEIGHT);
cxt.fillStyle = gradient;
cxt.fillRect(0,0,WIDTH,HEIGHT);
cxt.fill();
cxt.drawImage(logo,0,0);
i+=5;
}
I'm trying to animate a feathered loop expanding.
This code is pretty inefficient, because I'm using the constructor to change as single property each loop. How can I change a single property that is passed as a parameter to the constructor?
From the Canvas specs...
interface CanvasGradient {
// opaque object
void addColorStop(in float offset, in DOMString color);
};
...and earlier it says about fillStyle and strokeStyle...
On getting, if the value is a color,
then the serialization of the color
must be returned. Otherwise, if it is
not a color but a CanvasGradient or
CanvasPattern, then the respective
object must be returned. (Such objects
are opaque and therefore only useful
for assigning to other attributes or
for comparison to other gradients or
patterns.)
Lastly, introspecting a gradient just reveals the addColorStop function.
So I think the constructor is the only place those values can be set; but are you sure the constructor is really slowing it down? If your animation is slow maybe it's something else. Have you timed it?

Categories

Resources