getBoundingClientRect of SVG Path not working - javascript

I am making a library for Google Geo Charts on click zooming (API != zoom)
I need to get the width or height of the svg paths so I can filter them and store their coordinates in an array object. I was able to store alaska and hawaii g elements coords but with the continental US I have to go one level deeper to path and am having a hard time realizing where I am going wrong.
I am getting undefined on the continental nodeList.
google.visualization.events.addOneTimeListener(chart, 'ready', function (e){
google.visualization.events.addListener(chart, 'select', function (e){
var selection = chart.getSelection(),
selectedState = '',
nodes = document.querySelectorAll("g[clip-path]")[0].childNodes[0],
continental = nodes.childNodes[0],
alaska = nodes.childNodes[1],
hawaii = nodes.childNodes[2],
stateCoords = {},
nl = null,
zoomX = null,
zoomY = null;
//////////////////////////////
//Get Coordinates of States//
/////////////////////////////
getCoords(alaska);
getCoords(hawaii);
// getCoords(continental);
console.log(stateCoords);
function getCoords(nodeList){
function getZoom(nodeList, s){
nl = nodeList.getBoundingClientRect();
zoomY = nl.top + (nl.height/2);
zoomX = nl.left + (nl.width/2);
stateCoords[s] = [zoomX, zoomY];
}
if (nodeList == alaska) {
getZoom(nodeList, 1);
}
else if (nodeList == hawaii){
getZoom(nodeList, 11);
}
else {
console.log('continental');
var nodeListLength = nodeList.childNodes.length,
i = 0,
s = 0;
for (i; i < nodeListLength; i++) {
console.log(nodeList.childNodes[i]);
var pathBound = nodeList.childNodes[i].getBoundingClientRect();
if (pathBound.height > 3 && s != 1 && s!= 11) {
getZoom(nodeList[i], s);
s++;
} else { s++; }
}
}
}

Related

how can identify inside / outside / center stroke in PSD using javascript for photoshop

i want to identify and size in pixel of inside / outside / center of PSD layer's Stroke
here i have some code for identify stroke of layer but i can't find which types of stroke is on layer
function hasLayerFX(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
return executeActionGet(ref).hasKey(stringIDToTypeID('layerEffects'));
};
var doc = app.activeDocument;
var layers = app.activeDocument.layers;
for (var x = 0; x < layers.length; x++) {
doc.activeLayer = doc.layers[x];
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var desc = executeActionGet(ref);
var results = hasLayerFX();
if(results == true){
var stork = executeActionGet(ref).getObjectValue(stringIDToTypeID('layerEffects')).hasKey(stringIDToTypeID('frameFX'));
if(stork == true){
alert("This layer contains stork");
}
}
}
frameFX is an object descriptor, just like layerEffects. So when you're sure that layer has a stroke (using hasKey) you simply get these values from your layer descriptor. To know what values to look for I use Jaroslav Bereza's Action Manager Humanizer
var doc = app.activeDocument,
layers = doc.layers;
for (var x = 0; x < layers.length; x++)
{
doc.activeLayer = doc.layers[x];
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var desc = executeActionGet(ref);
if (hasStroke(desc))
{
var strokeValues = getStrokeValues(desc);
alert("Layer " + doc.layers[x].name + " has a " + strokeValues.type + " stroke with " + strokeValues.value + "px size");
}
}
function hasStroke(d)
{
if (!d.hasKey(stringIDToTypeID('layerEffects'))) return false
if (!d.getObjectValue(stringIDToTypeID('layerEffects')).hasKey(stringIDToTypeID('frameFX'))) return false
return true
}; // end of hasStroke()
function getStrokeValues(d) {
var temp = d.getObjectValue(stringIDToTypeID('layerEffects')).getObjectValue(stringIDToTypeID('frameFX'));
// possible values of the 'style' are insetFrame, centeredFrame and outsetFrame
return {
type: typeIDToStringID(temp.getEnumerationValue(stringIDToTypeID("style"))),
value: temp.getInteger(stringIDToTypeID("size"))
}
}; // end of getStrokeValues()

check if a lat long is within an extent using open layers 3

I have a UK county shape file (Multipolygon) using EPSG:4326 in my geoserver. I'm using open layers 3 to load this shape file in my application as below :
source = new ol.source.XYZ({url: '/gmaps?zoom={z}&x={x}&y={y}&Layers=UKCounties', crossOrigin: "anonymous"});
countiesLayer = new ol.layer.Tile({source: source});
map.addLayer(countiesLayer);
This works well. I have a requirement to get users current location which is done as
var coordinate = geolocation.getPosition();
I'm able to retrieve the correct lat & long here. Ex : Lat = 53.797534899999995, Lng = -1.5449. now I need to check which of the counties (polygon) these points are in using open layers 3 & Javascript.
Using Geoserver WFS, I'm able to get the bounding box of each of the counties as
$.each(features, function(index, eachFeature) {
var bbox = eachFeature.properties.bbox;
if (bbox != null) {
var bottomLeft = ([bbox[0], bbox[1]]);
var topRight = ([bbox[2], bbox[3]]);
var extent = new ol.extent.boundingExtent([bottomLeft, topRight]);
if (ol.extent.containsXY(extent1,lat,long)) {
alert("got the feature");
}
}
});
The issue is my code doesn't print the alert statement.I've also tried using
if (ol.extent.containsXY(extent,long,lat))
and
var XY = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857');
if (ol.extent.containsXY(extent,XY[0],XY[1]))
if (ol.extent.containsXY(extent,XY[1],XY[0]))
But none of these print the alert. Is there anything wrong in this?
Before answering your question, I did not know the method of "ol.extent.containsXY".
I used my poor logic! I detected a feature if in a polygon by follwing :
transform feature and container(polygon) to coordinate [lon, lat]
detect the container if contain the feature
extent array rule [minLon, minLat, maxLon, maxLat]
code snippet: (my destinationPro:'EPSG:3857', sourcePro:'EPSG:4326')
QyGIS.prototype.isInner = function(featureExtent, containerExtent) {
var featureLonLat = ol.proj.transformExtent(featureExtent, destinationPro, sourcePro);
var containerLonLat = ol.proj.transformExtent(containerExtent, destinationPro, sourcePro);
// in my condition, the feature is a point, so featureLonLat[0] = featureLonLat[2], featureLonLat[1] = featureLonLat[3]. what's more extent have four value in a array so the loop length is 4
for (var i = 0; i < featureLonLat.length; i++) {
/* actually:
featureLonLat[0] < containerLonLat[0] || featureLonLat[0] > containerLonLat[2]
featureLonLat[1] < containerLonLat[1] || featureLonLat[1] > containerLonLat[3]
featureLonLat[2] < containerLonLat[0] || featureLonLat[2] > containerLonLat[2]
featureLonLat[3] < containerLonLat[1] || featureLonLat[3] > containerLonLat[3]
*/
if (featureLonLat[i] < containerLonLat[i % 2] || featureLonLat[i] > containerLonLat[i % 2 + 2]) {
return false;
}
}
return true;
};
QyGIS.prototype.getInnerFeatures = function(layerName, extent) {
var self = this;
var layer = self.getLayer(layerName);
if (layer) {
var source = layer.getSource();
var features = source.getFeatures();
for (var i = 0; i < features.length; i++) {
var curFeatureExtent = features[i].getGeometry().getExtent();
if (self.isInner(curFeatureExtent, extent)) {
console.log(features[i].get('name') + 'in area');
}
}
}
};
At last, sorry for my poor english if my answer confuse you .
I had to use
var XY = ol.extent.applyTransform(extent, ol.proj.getTransform("EPSG:3857", "EPSG:4326"));
instead of
var XY = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857');
and it works.

What should i do in order to print level also in Breadth first search Algo.

What can be done in the below algo in order to print values level wise in binary tree.
BinarySearchTree.prototype.breadthFirstTraversal = function() {
console.log("Breadth First Traversal");
var q = []
q.push(this.root);//You don't need to write the root here, it will be written in the loop
while (q.length > 0)
{
var n = q.shift();
console.log(n.value); //Only write the value when you dequeue it
if (n.left !=null)
{
q.push(n.left);//enqueue the left child
}
if (n.right !=null)
{
q.push(n.right);//enque the right child
}
}
};
Just wanted to add this since it doesn't require the storage of the level of each corresponding node as in the solution above so it doesn't require you to add a property to your object. If you think about it the queue will have, at most, two different levels in it. So you only need one global marker to let you know if you are dealing with a new level and a flag to let you know if you should mark the new right or left node being pushed.
BinarySearchTree.prototype.breadthFirstTraversal = function() {
console.log("Breadth First Traversal");
var q = new Array();
q.push(this.root);
var printArray = [];
var printArray.push(this.root.value);
var newlevel = false;
var marker = 1;
var level = 0;
while(q.length > 0){
if(marker==1){
console.log("level: " + level);
console.log(printArray);
newlevel = true;
}
var n = q.shift();
printArray.shift();
marker -= 1;
//console.log(n.value);
if(n.left != null){
q.push(n.left);
printArray.push(n.left.value);
if(newlevel){
marker = q.length;
level+=1;
newlevel = false;
}
}
if(n.right != null){
q.push(n.right);
printArray.push(n.right.value);
if(newlevel){
marker = q.length;
level+=1;
newlevel = false;
}
}
}
};
Store level for each node, and print them only when level changes:
BinarySearchTree.prototype.breadthFirstTraversal = function() {
console.log("Breadth First Traversal");
var q = [];
var prevLevel = -1; // monitor level switch
var byLevel = []; // store node values for printing
this.root.level = 0; // set root level
q.push(this.root);//You don't need to write the root here, it will be written in the loop
byLevel.push(this.root.value);
while (q.length > 0)
{
var n = q.shift();
// Next level, print and reset
if (n.level > prevLevel) {
console.log(byLevel);
byLevel = [];
prevLevel = n.level;
}
if (n.left !=null)
{
n.left.level = n.level + 1;
q.push(n.left);//enqueue the left child
byLevel.push(n.left.value);
}
if (n.right !=null)
{
n.right.level = n.level + 1;
q.push(n.right);//enque the right child
byLevel.push(n.right.value);
}
}
if (byLevel.length > 0) {
console.log(byLevel);
}
};

How to update position of markers with real time gps coordinates?

I've got real time gps positions for a few cars and I want to create a map with updating markers. My code works but it doesn't "update" the markers, instead it adds new objects with new coordinates to the leaflet map. After few minutes my map is full of markers. What I'm doing wrong? Here is my basic concept.
var intervalV = document.getElementById("intervalValue").value * 1000;
document.getElementById("setIntervalButton").onclick = startData;
function startData() {
DataInterval = window.setInterval(getNewData, intervalV);
};
function getNewData() {
$.getJSON(server, {
fun : "GetGpsData",
userId : "user",
sessionId : $("#sessionId").val()
}, fillMap);
}
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var positions = json.devicesData[i].positions.length;
var devicepostiion;
if (json.devicesData[i].connected == false
) {
var devicepostion = L.marker([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon], {
icon : offlineCarIcon
}, {
draggable : false
}).addTo(map);
} else {
devicepostion = new L.marker(, {
icon : onlineCarIcon
});
devicepostion.addTo(map).setLatLng([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon]).update();
}
}
}
};
If your goal is to update markers with a new visual appearance and location if they already exist on the map...then you should be using .setIcon and .setLatLng on the existing marker instead of making a new one.
Your current code makes new markers in both cases.
Here your code updated to work as you want. As #snkashis pointed out, you do not need to create a new marker each time
var devicePosition = -1;
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (devicePosition === -1) {
var devicePosition = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition.setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition !== -1) {
devicePosition.setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
If you have multiple markers, you need to update each one accordingly to their id, I suggest to find (or add, if you create the APIs) an unique ID in json.devicesData[i].
Let's suppose the uniqueId of each marker is called, well, uniqueId, then your code can be something like this:
var devicePosition = {};
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
var uniqueId = data.uniqueId;
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (!devicePosition[uniqueId]) {
var devicePosition[uniqueId] = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition[uniqueId].setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition[uniqueId]) {
devicePosition[uniqueId].setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}

2D Javascript Array TypeError

[EDIT] Full application available at: http://bit.ly/1CGZzym
I'm receiving the error:
Uncaught TypeError: Cannot set property '0' of undefined
with the following code. I believe it is due to my not declaring the child array of the 2D array properly but I am really confused as to where I should be declaring this. Any ideas would be excellent.
// Create an array for the tiles we're about to draw
var tileArray = []
is declared out side of the function.
I assume it is because I am trying to create child elements within each [col] so I guess I need to declare each col number somewhere but nothing I attempt seems to be working.
function drawGrid()
{
// Draw diamond grid
var col = 0;
var row = 0;
topTileX = (viewWidth/2);
topTileY = 0;
var nextX = 0;
var nextY = 0;
var getCols = 0;
while (topTileX > -1)
{
tileArray[col][row] = new DiamondTile(topTileX, topTileY, tileWidth, true, col, row);
tileArray[col][row].draw();
while (tileArray[col][row].xPos + tileArray[col][row].tileWidth < (viewWidth) + tileWidth)
{
col++;
nextX = tileArray[col-1][row].xPos + tileArray[col-1][row].tileWidth / 2;
nextY = tileArray[col-1][row].yPos + tileArray[col-1][row].tileHeight / 2;
tileArray[col][row] = new DiamondTile(nextX, nextY, tileWidth, true, col, row);
tileArray[col][row].draw();
if (col == getCols)
{
break;
}
}
row++;
getCols = col;
col = 0;
topTileX = topTileX - tileWidth/2;
topTileY = topTileY + tileHeight/2;
}
};
For the purpose of demonstration, the DiamondTile function is as follows:
function DiamondTile(xPos,yPos,width,interactive,myCol,myRow)
{
// Set x and y position for this sprite
this.xPos = xPos;
this.yPos = yPos;
this.myRow = myRow;
this.myCol = myCol;
// Used for AI pathfinding
this.isObstacle = false;
this.isStart = false;
this.isEnd = false;
this.gValue = 0;
this.hValue = 0;
this.fCost = 0;
this.tileWidth = width;
this.tileHeight = this.tileWidth/2;
var self = this;
// Create sprite
this.spriteObj = new PIXI.Sprite(grass);
this.spriteObj.interactive = interactive;
this.spriteObj.anchor = new PIXI.Point(0.5,0);
this.spriteObj.hitArea = new PIXI.Polygon([
new PIXI.Point(0,0),
new PIXI.Point(100,50),
new PIXI.Point(0,100),
new PIXI.Point(-100,50)
]);
this.spriteObj.mouseover = function()
{
if (self.spriteObj.tint == 0xFFFFFF)
{
self.spriteObj.tint = 0xA7E846;
}
text2.setText(self.myCol + "," + self.myRow + " Start: " + self.isStart);
}
this.spriteObj.mouseout = function()
{
if (self.spriteObj.tint == 0xA7E846)
{
self.spriteObj.tint = 0xFFFFFF;
}
}
this.spriteObj.click = function()
{
if (startStage === true)
{
startStage = false;
self.isStart = true;
self.spriteObj.tint = 0x1AFF00;
text.setText("Now select an end point");
endStage = true;
return true;
}
if (endStage === true)
{
endStage = false;
self.isEnd = true;
self.spriteObj.tint = 0xFF0000;
text.setText("Now place some obstacles");
obsStage = true;
return true;
}
if (obsStage ===true)
{
self.isObstacle = true;
self.spriteObj.tint = 0x3B3B3B;
text.setText("Press 'C' to calculate path");
return true;
}
}
};
That is a multi-dimensional array and you have not initialized the first dimension array correctly. In the while loop you have to initialize the first dimension to be able to access a second dimension element with an index:
while (topTileX > -1)
{
if (tileArray[col] == null)
tileArray[col] = [];
tileArray[col][row] = new DiamondTile(topTileX, topTileY, tileWidth, true, col, row);
tileArray[col][row].draw();
// omitted other code for brevity
}
Javascript arrays are dynamic and it's enough to initialize the first dimension array elements in this case. You don't have to initialize the individual items in the second dimension.
Update: here is a fiddle with working code http://jsfiddle.net/0qbq0fts/2/
In addition your semantics is wrong. By the book, the first dimension of a 2-dimensional array should be rows, and the second dimension should be columns.
You have to explicit create the elements representing the second dimension, e.g.:
function make2DArray(rows, cols) {
var r = Array(rows);
for (var i = 0; i < rows; ++i) {
r[i] = Array(cols);
}
return r;
}
If you don't know in advance how many columns, just use this:
function make2DArray(rows) {
var r = Array(rows);
for (var i = 0; i < rows; ++i) {
r[i] = [];
}
return r;
}
The individual rows can each have independent lengths, and will grow as you add values to them.
Similarly, if you just need to add a new (empty) row, you can just do:
tileArray.push([]);
This should probably me a comment, but SO has crashed on my side. JavaScript might be throwing an exception on your stated line, but the problem may be with the 'DiamondTile' function.

Categories