How do I transition an object's attribute in d3? - javascript

I would like to apply a transition, not on a d3 selection, but on a js Object.
Something like
var node = {
x : 0,
y : 0,
radius : 100
};
d3.transition(node).duration(200).attr('radius', 200);
Any suggestions please?

Related

echarts - Ability to add texture stripes on map

I generate a map with echarts.
I'm able to pickup 0 values to colorize them in gray using visualMap property combined with inRange min, max, outOfRange options.
The wanted result is almost there (see the screenshots) !
But I'd like to display elements with 0 values with stripes / pattern - now in gray on the screenshot. How can I achieve this with echarts ?
Example of wanted pattern :
I had a look on following documentation - and tried some code with no success :
https://echarts.apache.org/en/option.html#visualMap
https://echarts.apache.org/en/option.html#aria.decal
https://echarts.apache.org/examples/en/editor.html?c=pie-pattern
My visualMap configuration part is as follow :
visualMap : {
type: 'continuous',
left : 'right',
top : 'center',
min : 469,
max : 144464,
inRange : {
color : colors
},
outOfRange: {
color:'#f4f4f4'
},
text : [ 'Haute', 'Faible' ],
calculable : true
},
Additional need : I'd also be happy to be able to see outOfRange in legend.
(also reported here : https://github.com/apache/echarts/issues/14874)
In order to use a pattern fill you need to use a canvas object as a color source. Here is a code example I use to create dynamic, two-colored, striped patterns:
function DashedPattern(color1, color2, canvasId) {
var c = document.createElement('canvas');
c.id = canvasId;
c.width = 120;
c.height = 120;
c.style.border = "0px none";
c.hidden = "true";
var body = document.getElementsByTagName("body")[0];
body.appendChild(c);
var ctx = c.getContext("2d");
ctx.strokeStyle = color1;
ctx.fillStyle = color2;
ctx.lineWidth = "2";
var patternSpread = 5;
ctx.beginPath();
for (i = 1; i <= c.width / patternSpread; i++) {
ctx.moveTo(i * patternSpread, 0);
ctx.lineTo(0, i * patternSpread);
}
for (i = 1; i < c.height / patternSpread; i++) {
ctx.moveTo(c.width, i * patternSpread);
ctx.lineTo(i * patternSpread, c.height);
}
ctx.fillRect(0, 0, c.width, c.height);
ctx.stroke();
return c;
}
var c = DashedPattern(p.itemStyle.areaColor, p.itemStyle.secondColor, patternId);
var newColor = { image: c, repeat: 'repeat' };
p.itemStyle.areaColor = newColor;
Of course, if you only use pre-defined static patterns you can just create pattern images and load them into canvas instead of dynamic generation.
The drawback of patterns in echarts is that they are bitmaps and don't look as nice as the rest of the map.
Here is the example of the map I have using patterns:
As you can see the stripes align nicely between areas but when zoomed in the bitmap edginess is clearly visible. Probably this can be reduced by playing with pattern size.
Actually version 5.0+ of echart implement decal feature.
We borrowed the concept of decal from computer graphics to avoid confusing with pattern, which ECharts already used. The difference between a decal and a pattern in ECharts is that, a decal is a parametric configuration that generates repeating images while a pattern takes an image to repeat.
More information and samples regarding this new feature on following links :
https://github.com/apache/echarts/issues/13263
https://echarts.apache.org/examples/en/editor.html?c=doc-example/aria-decal
https://echarts.apache.org/en/option.html#series-bar.itemStyle.decal
Because decal feature does not rely on image there is no pixel effect, unlike using pattern !

SnapSvg moving image onclick

So i am tryingout Snap svg
Right now i have the following code:
var chatSvg = Snap("#chatSvg");
var c = chatSvg.image('assets/figures/naked.jpg', 10, 10);
chatSvg.click(function (event) {
c.x = event.x;
c.y = event.y;
});
However once the properties x and y is changed the image does not move.
Can anyone tell me what im doing wrong?
You change attributes in Snap using the attr() method, which will change the SVG attributes at the lower level for you.
So for example, it would look like
c.attr({ x: event.x, y: event.y })
Its also worth noting that the x, y coords get passed correctly into the click function, so its generally preferred to use this, so you could change the func to...
chatSvg.click( function( event, x, y ) {
c.attr({ x: x, y: y })
});

How to find the offset for a polygon Fabric.js

I am making a polygon from lines.
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
On click, I capture mouse position. After, I add that point to array of points.
roofPoints.push(new Point(x, y));
function Point(x, y) {
this.x = x;
this.y = y;
}
When all points are set I do this:
var roof = new fabric.Polyline(roofPoints, {
fill : 'purple',
});
The problem with this is that while I set points I am drawing lines for the polygon like so:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
So basically I'm making a counter of a polygon and when I'm done drawing the counter, I just create a polygon. But the problem is that when I create polygon it doesn't fit in the counter it just moves away from the counter. I have tried to find how to correctly offset it.
roof.set({
left : left,
top : top,
});
I was trying to get left upper point of a bounding rectangle for the polygon and to set it so it places correctly. But that din't work. This how it looks
And a fiddle How it looks
Ok so I checked coords of created polygon and saw that it has recalculated them somehow and that's why it was offset. For example:
PointBefore
58 | 193
PointAfter
-189 | -52
This is how it changes, so to make the correct offset all I did was get it before I create the polygon and set top and left after it has been created.
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
var roof = new fabric.Polyline(roofPoints, {
fill: 'purple'
});
roof.set({
left: left,
top: top
});
return roof;
And a fiddle that works.
This script doesn't work on 1.4.13 and 1.5.0 fabricjs versions. Cannot confirm on previus versions.
EDIT: Fixed the problem, also in later versions:
Change this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
into this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}));

THREE.js & the order of transformations

I'm learning THREE.js right now, and I stucked with a probably noob problem.
I've a JSON object width dynamic update, it contains some data of 4 walls. The JSON struct:
{
...
walls: [{
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: 0
}, {
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: -(Math.PI/2)
}, {
start: {
x : 0,
y : 0,
z : 1200
},
length: 1200,
rotation: 0
}, {
start: {
x : 1200,
y : 0,
z : 0
},
length: 1200,
rotation: (Math.PI/2)
}],
...
}
I'm trying to position walls on canvas, It's OK when the wall has just a translation OR rotation, but there's a problem when the wall has both of them.
Here's my code (this._container is an instance of THREE.Mesh):
this._container.matrixAutoUpdate = false;
this._container.add(new THREE.AxisHelper(1000));
if(rotation) {
this._container.rotation.y = rotation;
this._container.updateMatrix();
}
if(translation) {
this._container.translateX((translation.x + (width/2)));
this._container.translateY((translation.y + (height/2)));
this._container.translateZ((translation.z));
this._container.updateMatrix();
}
If I apply rotation first then translate, it rotates the object's local axes too, and the translation will have wrong directions (http://robber.hu/webgl/1.png). If I apply translation first, than rotate, the Y axis moves to other position, and the rotation will be around wrong point (http://robber.hu/webgl/2.png).
I think there are two ways to solve this problem, but can't find the solutions:
Somehow using a "global translation", so the object translates on the scene's axis, and then use the first method
Change the object's "pivot" to left or right edge, and than use the second method
How can I implement it, or where can I find some docs/tutorial for this?
Solved.
The solution was that: Use three transformations insted of two. First, translate object to final position, second, rotate it, and finally, translate again via local X and y axis. Third translation moving the local axis from object's center to the corner.
R

raphaelJS 2.1 animate along path

I want to animate a path (actually a set of paths, but I'll get to that) along a curved path.
RaphaelJS 2 removed the animateAlong method, for reasons I haven't been able to discern. Digging into the Raphael documentation's gears demo as abstracted by Zevan, I have got this far:
//adding a custom attribute to Raphael
(function() {
Raphael.fn.addGuides = function() {
this.ca.guide = function(g) {
return {
guide: g
};
};
this.ca.along = function(percent) {
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "t" + [point.x, point.y]
};
return t;
};
};
})();
var paper = Raphael("container", 600, 600);
paper.addGuides();
// the paths
var circ1 = paper.circle(50, 150, 40);
var circ2 = paper.circle(150, 150, 40);
var circ3 = paper.circle(250, 150, 40);
var circ4 = paper.circle(350, 150, 40);
var arc1 = paper.path("M179,204c22.667-7,37,5,38,9").attr({'stroke-width': '2', 'stroke': 'red'});
// the animation
// works but not at the right place
circ3.attr({guide : arc1, along : 1})
.animate({along : 0}, 2000, "linear");
http://jsfiddle.net/hKGLG/4/
I want the third circle to animate along the red path. It is animating now, but at a distance from the red path equal to the third circle's original coordinates. The weird thing is that this happens whether the transform translate in the along object is relative (lowercase "t") or absolute (uppercase "T"). It also always animates in the same spot, even if I nudge it with a transform translation just before the animate call.
Any help very appreciated. I just got off the boat here in vector-land. Pointers are helpful--a working fiddle is even better.
You're just a hop, skip, and jump away from the functionality that you want. The confusion here concerns the interaction between transformations and object properties -- specifically, that transformations do not modify the original object properties. Translating simply adds to, rather than replaces, the original coordinates of your circles.
The solution is extremely straightforward. In your along method:
this.ca.along = function(percent) {
var box = this.getBBox( false ); // determine the fundamental location of the object before transformation occurs
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "...T" + [point.x - ( box.x + ( box.width / 2 ) ), point.y - ( box.y + ( box.height / 2 ) )] // subtract the center coordinates of the object from the translation offset at this point in the guide.
};
return t;
Obviously, there's some room for optimization here (i.e., it might make sense to create all your circles at 0,0 and then translate them to the display coordinates you want, avoiding a lot of iterative math). But it's functional... see here.
One other caveat: the ...T translation won't effect any other transforms that have already been applied to a given circle. This implementation is not guaranteed to play nicely with other transforms.

Categories

Resources