I want to limit the clickable area of all the icons from a KML file, and I'm a little stumped about how to make that happen. The icons are all the same typical-style pointer, and I'd like to limit the clickable area to the circle encompassed by the top of the pointer. The icon is 19x32, so I think I want a circle centered 9px from the top, 9px from the left, with a radius of 9px. If geoxml3 will do that, I figure that would be specified in the parser object, though maybe it would be in the IconStyle in the KML file. If in fact that would be in the parser object I haven't found the right syntax. It is apparently not:
var blues = new geoXML3.parser({map: map, singleInfoWindow: true, zoom: false, markerOptions: {shape: {type:circle, coords: [9px,9px,9px]}}});
blues.parse('allbluesdance.kml');
The markerOptions option to GeoXml3 is exactly a Google Maps Javascript API v3 markerOptions object.
Your icon is 49x32 pixels, the center of the circle is defined from the top left, so you probably want 24,9 for the center and a radius of 9:
var blues = new geoXML3.parser({
map: map,
singleInfoWindow: true,
suppressDirections: true,
markerOptions: {
shape: {
type: 'circle',
coords: [24,9,9]
}
},
zoom: false
});
From the documentation on Complex Icons:
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var shape = {
coords: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
The HTML area circle shape, looks like what you have should work if you remove the "px" (the documentation says an array of numbers), except that it is off to the left of the icon.
working example
Related
I am building a Warehouse map in 2D with fabricjs where I am displaying their racking systems as a series of rectangles.
As a first "layer/group", i add all bays as groups containing a rectangle and text, both positioned at the same (x,y). They also have both an angle set to fit their orientation in the space.
As a second "layer/group", i add groups containing a circle and text, representing the bay's number of issues. The (x,y) also fits the bays. This way, all my issues are always on top of the bays and the center of the group fits the rotated corner of the bay.
On the first paint, all is well aligned. Once they're shown on the page, the user can create new issues, so I am trying to position the issue group fitting the original (x,y), but since it can all be panned and zoomed, I am having a hard time positioning it where it should be.
I've been looking at their explanations about transforms, but I can't figure who the boss should be and thinking that having nested groups may also be why I am all mixed up.
By doing:
const gMatrix = matchingBay.group.calcTransformMatrix(false);
const targetToCanvas = fabric.util.transformPoint(matchingBay.aCoords.tl, gMatrix);
I am on the bay, but on the "group" corner, which is not what I am looking for. (x,y) will be one of the corners of the rectangle in the group, that may have been rotated.
By specifying the original (x,y) in this code will get me way off the actual painting zone.
So, my question is, how do I get the transformed (x,y) so I can add my issue group at those coordinates?
[EDIT]
As the suggestion of spring, it made me realize I can use the rotated rectangle's transforms to find its coordinates, so I tried:
const rect = matchingBay.getObjects()[BAY_RECTANGLE_INX];
const gMatrix = rect.calcTransformMatrix();
const targetToCanvas = fabric.util.transformPoint(rect.aCoords.bl, gMatrix);
Bottom left corner is where I wish to add the new Circle. After rotation, the bottom left is now the bottom right. But I am still off. As shown, the red circle should be on the corner. It looks like the rotation has not been applied.
qrDecompose gives me something that seems right:
{angle: -90, scaleX: 1, scaleY: -1, skewX: 0, skewY: 0, translateX: 6099.626027314769, translateY: 4785.016008065199 }
I realized that I was not thinking it the right way. Since I have the rectangle already in hands, I just had to get its own transformation and resolve the corner by my own, the following fixed my issue:
{
[...]
const rect = matchingBay.getObjects()[BAY_RECTANGLE_INX];
const gMatrix = rect.calcTransformMatrix();
const decomposed = fabric.util.qrDecompose(gMatrix);
const trans = fabric.util.transformPoint(new fabric.Point((decomposed.scaleX * -rect.width) / 2, (decomposed.scaleY * rect.height) / 2), gMatrix);
const top = trans.y;
const left = trans.x;
[...]
}
Since the matrix is bringing the center point of the rectangle, I can get the corner by substracting its width and height and then transforming the coordinates to find out where the matrix puts it.
djvanderlaan's d3.js Planetarium first defines a "sun" circle at the center of the SVG area:
svg.append("circle").attr("r", 20).attr("cx", w/2)
.attr("cy", h/2).attr("class", "sun")
and then defines two orbits around the sun (with code slightly rearranged for clarity here):
var planets = [
{ R: 300, r: 5, speed: 5, phi0: 90},
{ R: 150, r: 10, speed: 2, phi0: 190}
];
var container = svg.append("g")
.attr("transform", "translate(" + w/2 + "," + h/2 + ")")
container.selectAll("g.planet").data(planets).enter().append("g")
.attr("class", "planet")
.each(function(d, i) {
d3.select(this).append("circle").attr("class", "orbit")
.attr("r", d.R)
d3.select(this).append("circle").attr("r", d.r).attr("cx",d.R)
.attr("cy", 0).attr("class", "planet");
});
The first circle in each group--the "orbit" circle--is never given center coordinates cx and cy. That's not just in the source code; I looked at the "orbit" circles in the inspectors in three browsers, and there is no cx or cy for the orbit circles. However, these circles are centered on the center of the SVG area, i.e. on x=w/2, y=h/2. How does the browser know where to place these circles? Does it inherit cx and cy from the enclosing g element? From the "sun"?
Yes, all svg elements inherit the transform and scale of their parent svg:g elements. You can use this to set a local center, as done here, or to play with scale and rotate with fine precision (since setting these all with the transform attribute can sometimes lead to unexpected results).
Often, people place their circle elements inside a parent g and position the g without ever setting cx/cy because a circle defaults to centering on the center of its parent. This isn't the case with svg:rect elements, which have to be offset to "center" them.
So, I'm using snap.svg and I'd like to dynamically rotate an object over time. Something like this:
function rotateObject()
{
myObject.rotation += value;
}
The problem is I don't know how to access the rotation values for my display objects (or if they even exist!) So given something simple, let's say a circle declared like this:
snap = Snap(800,600);
circle = snap.circle(400,300,50);
I know I can access the x and y values like so:
circle.attr("cx");
circle.attr("cy");
What I need help with is:
Is there a rotation property of some sort that I can use to rotate this object?
If not, how do I rotate an object with snap.svg?
Better rotate objects using Snap.Matrix()
The way suggested by Ian, works for me perfectly while I used Chrome version < 36.0
When I updated Chrome to 36.0.1985.125 I saw bug with text rotation.
So, the soulution was using
var matrix = new Snap.Matrix();
matrix.rotate(-90, x, y);
Paper.text(x, y, 'Text').attr({
fontWeight: 'bold',
fill: '#434343',
transform: matrix
});
instead of
Paper.text(x, y, 'Text').attr({
fontWeight: 'bold',
fill: '#434343',
transform: 'r-90'
});
Maybe it will be useful for somebody.
Ideally you will control the rotation yourself, (rather than figuring it out from the attributes which is possible, but fiddlier). Animation can be easier, depending on what you need. Here is an example showing some basic animation with a rect (as circle rotation is just itself if around the centre)...
s = Snap(400, 620);
var myRect = s.rect(100, 100, 100, 200).attr({
fill : 'white',
stroke : 'black'
});
var myRotate = 45;
// if you wanted to rotate manually using your own adjust variable then this
// myRect.transform("r" + myRotate);
// but simpler in most cases to use the animate method
myRect.animate( { transform: "r" + myRotate + ",150,200" }, 1000 ); //rotate around centre of 150,200
Fiddle at http://jsfiddle.net/XG7ks/6/
Really it would probably be best to get a basic grounding on transformations with SVG (and translate, rotate, scale) just for it to make a bit more sense. You can 'see' the resultant transform with myRect.attr('transform') but I would probably leave that just at first.
I have 3 sprites. Left edge, right edge, and repeating center which has 1 pixel width but is scaled up. The problem is that the scaled sprite fades out the farther away it is from the center:
I've tried using CCTexture's setAliasTexParameters but the result doesn't look good:
How do I get the antialiased looks in the first picture but without the fade out problem?
You could try this on the sprite:
// These parameters set the texture properties:
// minifying filter - linear interpolation,
// magnification filter - linear interpolation,
// texture repeat in S direction,
// texture repeat in T direction (*)
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[sprite.texture setTexParams:¶ms];
// This explicitly sets the contentSize of the sprite to (10, 200),
// but also sets the "window to the texture" to this rectangle:
[sprite setTextureRect:CGRectMake(0, 0, 10, 200)];
You have to tweak these settings, but hope you get it.
You don't have to scale the sprite.
(*) For S and T check this: Difference between U V and S T texture coordinates
http://jsfiddle.net/jBgqW/
I've painted the background with fillRect and fillStyle set to rgb(255,0,0) but when I iterate through the pixels and set some random color and value of the alpha pixel to 0 everything becomes white. I've assumed that when the pixel is transparent it should blend with the previously painted background color or does it always default to white.
I hope that it's just my wrong way of using the canvas.
Can anyone explain why the background isn't red in this case and how do i use the alpha pixel properly? I would like to know if this has something to do with the alpha premultiplication.
When using globalAlpha, the pixel colors are calculated with the current rgba values and the new values.
However, in this case you're setting the values manually and therefore doing no calculations. You're just setting the rgba values yourself, which means that the alpha channel is not used for calculating but is just altered without further use. The previous color (red) is basically overwritten in a 'brute force' way - instead of rgba(255, 0, 0, 255), it's now just rgba(128, 53, 82, 0). The original red color has simply been thrown away.
As a result, an alpha of 0 represents complete transparency, so you see the colors of the parent element.
This can be confirmed if you change the body background color: http://jsfiddle.net/jBgqW/2/.
This is somewhat thread necromancy, but I've just faced this problem and have a solution to it, if not for the original poster then for people like me coming from google.
As noted, putImageData directly replaces pixels rather than alpha blends, but that also means it preserves your alpha data. You can then redraw that image with alpha blending using drawImage.
To give an example, lets says we have a canvas that is 200 by 100 pixels and a 100 by 100 imageData object.
// our canvas
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
// our imageData, created in whatever fashion, with alpha as appropriate...
var data = /* ... */
// lets make the right half of our canvas blue
ctx.fillStyle="blue";
ctx.rect(100, 0, 100, 100);
ctx.fill();
// now draw our image data to the left (white) half, pixels are replaced
ctx.putImageData(data, 0, 0, 100, 100);
// now the magic, draw the canvas to itself with clipping
ctx.drawImage(canvas, 100, 0, 100, 100, 100, 0, 100, 100);
Voila. The right half of the image is now your image data blended with the blue background, rendered with hardware assistance.