svg change polygon color onclick - svg

I have a SVG map of france in my webpage and every district is a polygon, I need that when I click a district the color change and stay that way until I click it again
this is my code
function init(evt) {
if ( window.svgDocument == null ) {
svgDoc = evt.target.ownerDocument;
}
function update(district){
$(this).find("path, polygon, circle").attr("fill", "#0d0");<- what is wrong
}
this is one of my polygons
<path id="14" d="M82.387,173.009L109.168,141h2.42l3.33-5.965l20.425,8.818l5.296,0.475l-
1.876,31.861l5.236,7.5v8.018 l-15.6-1.701l
0.273-3.599C128.127,186.407,99.635,180.95,82.387,173.009z" fill="#CCCCCC"
onclick="update('14')">
as you can see Im getting the onclick event the problem is I cant get the polygon to change color.
thanks in advance.

Check what this holds. A console.log(this) will make your life so much more easier
I'll answer 1. This will point to the window object when a function is called. So doing a $(this).attr will find the attributes in the window object and not in the object that you expect.
Since you're passing the object id in the function, you can use that to find the element in your document. You can do something like:
$('#'+ubicacion).attr("fill","blue")
Fiddle here.

Related

How to show image when a specific key is pressed in p5js?

I'm new to p5js :)
When users press a certain key between 1-0 on the keyboard, a certain sound plays and random image shows. I tried this...
function keyPressed() {
if (key === '2') {
songA.play()
image(imgB1, random(windowWidth), random(windowHeight), img.width/2, img.height/2);
}
But p5js only reads "image" in draw function. Then i tried keyisdown in the draw function and tried entering the keyCodes for each number, for instance 1 is 49 I believe, but it didn't work.
if (keyIsDown(49)) {
songA.play()
image(imgB1,random(windowWidth), random(windowHeight), img.width/2, img.height/2);
}}
I'm basically copying https://openprocessing.org/sketch/441971 from openprocessing which is similar to p5js but not really. Help?
Thanks!
Make sure your image is being preloaded in the setup() function
When you display the image, you are referencing "img" instead of imgB1, which means p5js doesn't know what size to display the image at, so I assume it defaults to 0. To fix this, just replace img with imgB1.

Fabric.js - Programmatically transforming group objects relative to a central image object

Using Fabric.js, I have an image object that acts like a background where other group objects (consisting of rectangle and text) can be placed over it.
I would like to be able to programmatically rotate the image (90 degrees clockwise or counter-clockwise) when user clicks the corresponding button, and then rotate all other group objects relative to the image.
I was able to get this to work with the Fabric.js group feature, but the performance progressively degraded over a few rotations even with just one group object.
Looking for alternatives, I changed to use the approach described in the tranformation example here: http://fabricjs.com/using-transformations. However, the group object is not placed in the expected position after rotation.
Would anyone have any pointers on what the problem might be?
Here's the relevant code that handles just one group object for simplicity:
private rotateObjects(rotationAngle: number): void
{
let groups = this.Canvas.getObjects().filter(x => x !== this.ActiveImage);
let imageTransform = this.ActiveImage.calcTransformMatrix();
let invertedImageTransform = fabric.util.invertTransform(imageTransform);
let annotationRelationship = fabric.util.multiplyTransformMatrices(invertedImageTransform, (groups[0]).calcTransformMatrix());
this.ActiveImage.rotate(rotationAngle);
let newTransform = fabric.util.multiplyTransformMatrices(this.ActiveImage.calcTransformMatrix(), annotationRelationship);
let options = fabric.util.qrDecompose(newTransform);
groups[0].set({
flipX: false,
flipY: false,
});
groups[0].setPositionByOrigin(new fabric.Point(options.translateX, options.translateY),
"center",
"center"
);
groups[0].set(options);
groups[0].setCoords();
this.Canvas.renderAll();
}
Here are screenshots of before and after rotation. Notice that the yellow group rectangle is not placed exactly over the words "Manny Bello".
Before rotation: https://imgur.com/RcS4ekZ
After rotation: https://imgur.com/nk8gStf

Passing angular interpolated ID to function

I have been trying to pass the ID of a SVG element generated by ng-repeat.
each one has a cx, cy, and an id:
$scope.circles = [
{cx:25, cy:40, id:1},
{cx:55, cy:40, id:2},
{cx:75, cy:40, id:3}];
These are interpolated in the HTML with this code:
<circle ng-repeat= "c in circles"
ng-attr-cx={{c.cx}}
ng-attr-cy={{c.cy}}
ng-attr-id={{c.id}}
r="6" stroke="black" stroke-width="3" fill="red"
ng-mouseover ="changeR(this)" />
There is a "base" SVG template in which these placed, and they appear in the appropriate locations.
When I examine the page elements, the ids are present. At the end of the SVG definition the ng-mouseover function should take the id, and allow for the modification of the circle... all of my attempts to pass the interpolated id attribute to the back end function seem to fail. I example I followed was here: fiddle, and it produced alerts in some permutations, but the id was either "undefined" or "[object Object]"...
My function in the back end is currently set up as
$scope.changeR= function (id){
alert(id);
var circleChange = document.getElementById(id);
circleChange.setAttribute("r", "20");
}
This produces an alert with "[object Object]", though I think I have stuck to the pattern in the fiddle, which works in the fiddle, bringing through the id as text in the alert window. When I pass the function the interpolated id numbers directly it works fine changing the radius like I wanted (I get the element by a hard coded ID and the radius changes on that one circle...)
How to I pass this ID to the back end so I can get the element and have it modify its own attributes effectively? If it is an issue of the page loading and somehow not registering the IDs in a timely way, why would the mouse-over event not be dealing with the fully loaded page?

How to call wxGrid's Render function - sequentially to achieve pagination?

Pagination can be accomplished by using sequential Render() calls from http://docs.wxwidgets.org/trunk/classwx_grid.html
I understand How - sequential pages can be got from top left and bottom right coordinates.
But I dont get what needs to be the wxDC in the Render() call . ?
I want to get the first three rows in the grid
BigGridFrame::BigGridFrame(long sizeGrid)
: wxFrame(NULL, wxID_ANY, wxT("Plugin Virtual Table"),
wxDefaultPosition, wxSize(500, 450))
{
m_grid = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_table = new BigGridTable(sizeGrid);
m_grid->SetTable(m_table, true);
//The above code gave me the table
//trying to get first three rows by render() function but it still gets the all of the grid values
**const wxGridCellCoords topLeft(0, 0);
const wxGridCellCoords bottomRight(3,4 );
wxClientDC clientDC(this); //this place I am not sure.. I couldnt find documentation
//m_grid->SelectBlock(topLeft, bottomRight, false);
m_grid->Render(clientDC, wxDefaultPosition, wxDefaultSize, topLeft, bottomRight, wxEXPAND);**
}
The DC is whatever you want to render the grid on, typically a wxMemoryDC to save the grid as a bitmap. This can't be used to partially render the grid on screen, which you appear to want to do, because it's just a static snapshot of the control.
I also have really no idea how can the code using this->Render() above compile considering that this is a wxFrame* and not a wxGrid*.
I misunderstood Render() function .
For pagination, I used the same logic used in
Changing Size of Grid when grid data is changed

How to update the fill color on existing svg elements with d3.js?

So i'm trying to make a map from an .svg file I produced with Illustrator because it's a map of the Netherlands with not so straightforward regions.
All the regions have their own #ID.
Now i'm trying to color each region according to their value in the dataset. I can force color on the regions by CSS ive done so on one region but thats obviously not good solution.
If I for example try to select(#id) and then change the .attr("fill","red"); it doesnt work.
How would I update region colors by id using d3.js according to the d[1] value in the dataset ?
Files: https://gist.github.com/gordonhatusupy/9466794
Live link: http://www.gordonjakob.me/regio_map/
The problem is that your Illustrator file already specifies fill colours on the individual <path> elements, and your id values are for parent <g> elements. Child elements inherit styles from parents, but only if the child doesn't have values of its own.
There are a couple things you could do to change it:
Change the Illustrator file so that the paths have no fill. Then they will inherit a fill colour set on the parent.
Select the paths directly, using d3.selectAll("g#id path") or d3.select("g#id").selectAll("path"); either version will select all <path> elements that are descendents of the <g> elment with id "id". Then you can set the fill attribute directly to over-write the value from Illustrator.
As discussed in the comments to the main question, if you want to take this a step further and actually join the data to the elements for future reference (e.g., in an event handler), the easiest way is to loop through your dataset, select each element, then use the .datum(newData) method to attach the data to each element:
dataset.forEach(function(d){ //d is of form [id,value]
d3.select("g#"+d[0]) //select the group matching the id
.datum(d) //attach this data for future reference
.selectAll("path, polygon") //grab the shapes
.datum(d) //attach the data directly to *each* shape for future reference
.attr("fill", colour(d[1]) ); //colour based on the data
});
http://jsfiddle.net/ybAj5/6/
If you want to be able to select all the top-level <g> elements in the future, I would suggest also giving them a class, so you can select them with, for example, d3.select("g.region"). For example:
dataset.forEach(function(d){ //d is of form [id,value]
d3.select("g#"+d[0]) //select the group matching the id
.datum(d) //attach this data for future reference
.classed("region", true) //add a class, without erasing any existing classes
.selectAll("path, polygon") //grab the shapes
.datum(d) //attach the data directly to *each* shape for future reference
.attr("fill", colour(d[1]) ); //colour based on the data
});
d3.selectAll("g.region")
.on("click", function(d,i) {
infoBox.html("<strong>" + d[0] + ": </strong>" + d[1] );
//print the associated data to the page
});
Example implementation: http://jsfiddle.net/ybAj5/7/
Although using dataset.forEach doesn't seem to be using the full capability of d3, it is actually much simpler than trying to attach the whole dataset at once -- especially since there is such variability in the structure of the regions, some of which have nested <g> elements:
//Option two: select all elements at once and create a datajoin
d3.selectAll("g[id]") //select only g elements that have id values
.datum(function(){
var id=d3.select(this).attr("id");
return [id, null]; })
//create an initial [id, value] dataset based on the id attribute,
//with null value for now
.data(dataset, function(d){return d[0];})
//use the first entry in [id,value] as the key
//to match the dataset with the placeholder data we just created for each
.selectAll("path, polygon") //grab the shapes
.datum(function(){
return d3.select(this.parentNode).datum() ||
d3.select(this.parentNode.parentNode).datum();
}) //use the parent's data if it exists, else the grandparent's data
.attr("fill", function(d){return d?colour(d[1]):"lightgray";});
//set the colour based on the data, if there is a valid data element
//else use gray.
This fiddle shows the above code in action, but again I would recommend using the forEach approach.

Resources