Creating a bubble map from custom GeoJson with Highcharts / Highmaps - highcharts

I'm trying to use Highmaps with a custom GeoJson, in order to have bubbles appear on my map.
I got error #22 so I followed the instructions here (there's also an example of what I'm trying to achieve)
I installed proj4 in my Angular app (and proj4js as well, but I got the warning : proj4js#10.0.0: please use 'proj4' instead, proj4js is not maintained). The installations seemed to work without any problem.
However, now I still get an error #21 from Highmaps, and I can't figure out what is wrong.
Can somebody help me ?

After hunting down obscure Google results, here is what I did to stop getting this error :
I added this in my GeoJson :
"type": "FeatureCollection",
"hc-transform": { // this part
"default": {
"crs": "a string defined like in Proj4 examples... I'm still struggling with it, to be honest"
}
},
...
At the beginning of my Angular component file :
var proj4 = require('proj4');
And inside my Angular component :
ngOnChanges() { // it doesn't matter where you put it,
if (!window['proj4']) { // as long as it happens before any Highmaps-related work
window['proj4'] = proj4.default;
}
}
This solution was inspired by this result : https://gist.github.com/jon-a-nygaard/9437aad5d03c11c8c65604e4e7fba34b
Maybe this will help somebody in the future. Cheers !

Related

Cannot read property 'navigate' of undefined while using custom cell-renderers in ag-grid

I'm using ag-grid to render a table in my angular 7.2.1 app. The custom cell renderer is just to render an edit button in the rows that will redirect to a different page.
I've done this before in a different app on a different Angular version a while ago, but for some reason the same code in this Angular 7 app is resulting in this. I think I may be missing something really simple.
I've created a minimalist reproduction of the error I'm seeing in this stackblitz - https://stackblitz.com/edit/angular-v98mjs
If you click on the Edit button, you will see this error in the console.
ERROR Error: Cannot read property 'navigate' of undefined
ag-grid versions:-
I'm using the following version for ag-grid:-
"ag-grid-angular": "^20.2.0", "ag-grid-community": "^20.2.0",
Please look at the stackblitz code in the link above for the code.
You needed to define onEdit with Arrow Function
onEdit = (row): void => {
console.log('row is being edited', {row})
this.router.navigate(['/new-url', { id: row.incidentId }], {
relativeTo: this.route.parent
});
};
More example such thing: ag-grid server side infinite scrolling accessing props
Have a look at the updated plunk: https://stackblitz.com/edit/angular-oppxte
Without arrow function, inside onEdit function of AppComponent was not able to get reference of this.router, and hence, you were getting the error.
Cannot read property 'navigate' of undefined
I have also introduced RootComponent and NewComponent for better modularity in the example. Hope it will be clear with that.

array.prototype.foreach called on null or undefined highcharts

I am working on Highcharts highmaps rich information on click chart.First time load the information by json array and its working fine.But when I am filter data using filters and load chart again it`s give me same error array.prototype.foreach called on null or undefined highcharts at below lines.What is solution for this?
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
var points = mapChart.getSelectedPoints();
Below link I am using as reference:
http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/demo/rich-info/
I will answer this question in case someone else bumps into this problem in the future (even though I saw your problem is solved in github).
I encountered this issue with Highcharts when resizing the website (having 2 pie charts and one bar graph). I managed to solve it by wrapping the initialization of the graphs in a document.ready:
$(() => {
controller.initializePieHighChart();
controller.initializeBarHighChart();
});

if the original JS has many functions, how dart to initiate them?

after several rounds of research, I found there is no clear answer about the situation like below:
I have a js file called 'AAA.js', and there is simple code in side like this:
var AAA = {
listenForMenuLayer: function () {
console.log("menu initiated");
$('.nav-menu').on('click', function() { console.log("menu clicked")});
}
init: function(){
this.listenForMenuLayer();
}
};
And in the dart, I wrote like below (using 'dart:js'):
js.context['AAA'].callMethod('init');
Then, when I run it, everything looks fine, the "menu initiated" shows properly, which means the 'listenForMenuLayer' is initiated, but when click on the '.nav-menu', there is nothing happened. (I check many times, there is no spelling error or else)
My question is: Can Dart accept this kind of initiating of external JS event? or we should re-write those JS events at all, please advise, many thanks.
Updates:
I found that if we write the js code like above, the jquery will not be initiated properly, which means all the features begin with '$' will not be functional.
guys, I update it to using 'package:js/js.dart';
#JS('AAA.init')
external void aInit();
then some where, just simply call after including:
aInit();

Firefox WebExtention won't load

So, I tried to load my add-on using the about:debugging page in Firefox. But, it simply wouldn't load. Is there somewhere where an error would be logged that I could find it?
Here is my manifest.JSON code:
{
"description": "Adds a stickfigure",
"manifest_version": 2,
"name": "StickMan",
"version": "1.0",
"icons": {
"48": "icons/StickMan-48.png"
},
"applications": {
"gecko": {
"id": "extention#stick.man",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["StickManUpdate.js"]
},
"browser_action": {
"default_icon": {
"48": "icons/StickManButton.png"
},
"default_title": "Call StickMan",
},
}
I hope that this helps other frustrated add-on creators.
Thanks in advance
The lack of loading issue is that you have multiple syntax errors in the JSON of your manifest.json file. In your manifest.json file the lines at the end of the file:
"default_title": "Call StickMan",
},
}
Should not have the extra , (which would indicate you are going to have another property in the Object):
"default_title": "Call StickMan"
}
}
If you were using the Firefox Developer Edition, the fact that you had these errors would have been obvious:
However, even if you are running Firefox 47.0.1 and had merely used the Browser Console (keyboard shortcut: Ctrl-Shift-J), as suggested in the comments, you would have seen the error:
A promise chain failed to handle a rejection. Did you forget to '.catch', or did you forget to 'return'?
See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
Date: Sun Jul 17 2016 11:11:22 GMT-0700 (Pacific Standard Time)
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Full Stack: readJSON/</<#resource://gre/modules/Extension.jsm:628:19
NetUtil_asyncFetch/<.onStopRequest#resource://gre/modules/NetUtil.jsm:128:17
While a bit cryptic, it still shows the line number of the first issue:
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
The error produced in the Browser Console of Firefox Developer Edition is a bit easier to parse as to what the issue is:
SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Stack trace:
readJSON/</<#resource://gre/modules/Extension.jsm:859:19
NetUtil_asyncFetch/<.onStopRequest#resource://gre/modules/NetUtil.jsm:128:17
WebExtensions Development:
The WebExtensions API is currently in development. If you are developing a WebExtension, you should be using either Firefox Nightly, or Firefox Developer Edition in order to test your code.
More on your code:
Syntax error:
In addition to the above syntax errors, you have more issues. I did not attempt to resolve all of them, but did get sucked into fixing enough so that the add-on was functional. The next reported error, a syntax error, is in your StickManUpdate.js file on the code:
browser.tabs.sendMessage(
message: "End";
);
You have multiple issues here. Please see the tabs.sendMessage() documentation. You are missing the required tabId parameter. In addition, you appear to be mixing-up the difference between having an Object being passed as a parameter containing properties which are the information passed to the method versus a list of parameters which are other native types passed to a method. Note: It is not uncommon for there to be both a list of parameters of various native or non-native types and an Object containing properties which are data passed to the method.
Assuming browserAction is defined:
You use methods of browserAction in multiple locations where it should be browser.browserAction. browserAction by itself is not defined. Alternately, you could use browserAction as a shortcut by defining it like: var browserAction = browser.browserAction;.
Use of browserAction.getTitle() as if it is synchronous when in reality it is asynchronous:
You make a call to browserAction.getTitle() to get the value of the title. The value of the title is only available in the callback function, which you do not supply. This implies a lack of understanding of asynchronous programming. You might want to review some questions on that subject like:
Why isn't a global variable set immediately after defining a callback/listener function (asynchronous messaging, port.on)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
How do I return the response from an asynchronous call?
Wrong parameter type supplied to browserAction.setTitle():
This appears to, again, be confusion as to the difference between parameters of other native types and a parameter that is an Object (which may be an Object literal) which contains properties which are the information passed to the method. Admittedly, WebExtensions appear to almost arbitrarily mix using actual parameters and Objects with the properties functioning as parameters when passing information to methods. It appears that being careful as to which is being used in a particular method will be required.
Not having various functions specify the ID for the tab:
In multiple calls to various methods, you do not pass the tabId when you should. You are adding your StickMan canvas to a single tab per mouse click. You should be passing the tab ID for calls to multiple methods.
Assigning to document.body.innerHTML in stickman.js:
In general, assigning to innerHTML at any time should be avoided, if possible. It is a bad idea under most circumstances. In most instances, it may cause the entire DOM to be re-evaluated. For doing what you desire, adding HTML in text format to the DOM at the end of the HTML for an element, there is a specific function which is better/faster: insertAdjacentHTML(). Your code:
document.body.innerHTML+= '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>';
Could be written as:
document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
However, it is still a bad idea to use insertAdjacentHTML() here. There is a significant stigma attached to using either insertAdjacentHTML() or assigning to innerHTML. Using either will result in your add-on receiving additional scrutiny when submitted to AMO for distribution. This is mostly because there are real security issues with using either methodology for changing the DOM. The security issues are when what is being added is text that is dynamically generated from input/data which is not hard coded into your add-on. In addition, you are already mixing adding the element as text and performing changes to it using other JavaScript (e.g. assigning to canvas.style.position). You really should use one or the other. In this case, it is better to construct canvas entirely in JavaScript. It is, after all, only 4 lines to do the same thing you were doing in the two you were using for the innerHTML assignment and the getElementById() to find the canvas element.
Personally, I like using insertAdjacentHTML() in many instances with complex structures. It is generally faster to use it for inserting larget amounts of HTML. It also allows you to keep what is being inserted represented as text. Such text may be much easier to visualize the structure being added rather than figuring out what a large chunk of DOM generated using document.createElement() and setAttribute() actually looks like. However, along with the other drawbacks mentioned above, using insertAdjacentHTML() may not lend itself as easily to writing modular code.
Issues with how you insert you content script and canvas:
Every time the user clicks on your browserAction button you insert another copy of your content script into the tab. This leads to issues of errors being generated due to the consumed content scripts getting the message sent by your call to browser.tabs.sendMessage() and not being able to find the canvas. The correct solution to this is to only chrome.tabs.executeScript() the first time the button is clicked in a tab and then send a message to the content script each subsequent time the button is clicked in that tab causing the same canvas to be re-inserted into the DOM. An easy way to track if you have already loaded the StickMan into a particular tab is to use setTitle() to have the title for your button be different after the first run in that tab.
Other issues:
Note: Your code structure in stickman.js is a bit convoluted. You might want to address this.
All together
manifest.json:
{
"description": "Adds a stickfigure",
"manifest_version": 2,
"name": "StickMan",
"version": "1.0",
"icons": {
"48": "icons/StickMan-48.png"
},
"applications": {
"gecko": {
"id": "extention#stick.man",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["StickManUpdate.js"]
},
"browser_action": {
"default_icon": {
"48": "icons/StickManButton.png"
},
"default_title": "Call StickMan",
"browser_style": true
}
}
StickManUpdate.js:
browser.browserAction.onClicked.addListener(function(tab) {
browser.browserAction.getTitle({tabId:tab.id},function(title){
if(title === 'Call StickMan') {
chrome.tabs.executeScript(tab.id, {
file: "/content_scripts/stickman.js"
});
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
} else if (title === 'Call StickMan again') {
browser.tabs.sendMessage(tab.id,"Draw");
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
}else {
browser.tabs.sendMessage(tab.id,"End");
browser.browserAction.setTitle({title:'Call StickMan again',tabId:tab.id});
}
});
});
stickman.js:
var running = true;
//document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
var canvas = document.createElement("canvas");
canvas.setAttribute("width",100);
canvas.setAttribute("height",200);
//var canvas = document.getElementById('StickManCanvas0000000');
canvas.style.position = 'fixed';
canvas.style.left = '0px';
canvas.style.top = (window.innerHeight-200)+'px';
canvas.style.backgroundColor = 'rgba(0, 0, 0, 0)';
canvas.style.border = '1px dashed red';
var ctx = canvas.getContext('2d');
var pos = {
x:0,
headX:50,
headY:20,
bodyX:50,
bodyY:150,
leftArmX:25,
leftArmY:90,
rightArmX:75,
rightArmY:90,
leftLegX:30,
leftLegY:200,
rightLegX:70,
rightLegY:200,
};
var setPos = function(x, y) {
canvas.style.left = x+'px';
canvas.style.top = (window.innerHeight-y-200)+'px';
};
var drawMan = function(time) {
setPos(pos.x, 0);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.moveTo(pos.headX, pos.headY);
ctx.lineTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.rightLegX, pos.rightLegY);
ctx.moveTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.leftLegX, pos.leftLegY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.rightArmX, pos.rightArmY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.leftArmX, pos.leftArmY);
ctx.stroke();
ctx.fillStyle = '#888888';
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.fill();
if(running) {
window.requestAnimationFrame(drawMan);
}
};
drawMan();
document.body.appendChild(canvas);
browser.runtime.onMessage.addListener(function(m) {
if(m === 'End' && running === true) {
running = false;
document.body.removeChild(canvas);
} else if(m === 'Draw' && running === false) {
running = true;
document.body.appendChild(canvas);
}
});
Functionality demo [Note1: You must navigate to an actual webpage. Note2: The tooltips that pop up to tell you what the title is of your browser_action button are not captured with the program I used to create the following .gif. Note3: I added the browser_style property to the browser_action in your manifest.json file. It is new in Firefox 48. Without it, Firefox will issue a warning in the Browser Console when the add-on is loaded.]:

Google Places Autocomplete with Jquery Mobile not working on mobile/touch device

As title suggests I am building a mobile website with JQuery Mobile (1.3.0) and am trying to implement Google Places Autocomplete (API v3) to aid user input of location data.
The autocomplete functions correctly on desktop device, but not when used on a mobile device (I have only tested on iOS 6).
When used on mobile device the dropdown list of relevant locations do appear, but simply disappear when you press one without loading the selection on the map.
I have looked around and seen some solutions that sight the z-index of
.pac-container
as the culprit (see: http://osdir.com/ml/google-maps-js-api-v3/2012-01/msg00823.html).
I have implemented these fixes but to no avail, and I am not convinced that z-index is the problem because I can see that the selected item does change to it's :hover state/colour when pressed on mobile.
Please if anyone has suggestions I am all ears, need any more details let me know.
Saravanan's answer is a bit overkill. To fix the conflict with FastClick and PAC, add the needsclick class to both the pac-item and all its children.
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');
Thanks Daniel. But the solution I have given has some performance impact.
I have modifed the FastClick library little bit to accomplish that.
First I have added a param to FastClick constructor, where defaultElCls will be the elements which should not implement fastclick.
function FastClick(layer, defaultElCls) {
'use strict';
var oldOnClick, self = this;
this.defaultElCls = defaultElCls;
Then modify needsClick method:
FastClick.prototype.needsClick = function(target) {
'use strict';
var nodeName = target.nodeName.toLowerCase();
if (nodeName === 'button' || nodeName === 'input') {
// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
// Don't send a synthetic click to disabled inputs (issue #62)
if ((this.deviceIsIOS && target.type === 'file') || target.disabled) {
return true;
}
} else if (nodeName === 'label' || nodeName === 'video') {
return true;
}
return ((/\bneedsclick\b/).test(target.className) || (new RegExp(this.defaultElCls).test(target.className)));
};
Then pass pac-item to the FastClick constructor
new FastClick(document.body, "pac-item");
Hope this will be taken care by FastClick library as well :)
I've also encountered this bug, and determined fastclick to be the culprit. I was originally going to go with Devin Smith's answer, but epegzz's warning about MutationEvents being deprecated led me to MutationObservers, and since I haven't seen a fix involving them I thought I'd share my solution.
var observer_config = { attributes: false, childList: true, subTree: false, characterData: false }
var observer = new MutationObserver( function(mutations) {
var self = this;
mutations.forEach(function(mutation){
// look for the container being added to the DOM
var pac_container_added = $(mutation.addedNodes).hasClass('pac-container');
// if it is, begin observing it
if (pac_container_added){
var pac_container = mutation.addedNodes[0];
self.observe(pac_container, observer_config);
}
// look for pac-items being added (as children of pac_container)
// This will not resolve if the observer on pac-container has not been created
var pac_item_added = $(mutation.addedNodes).hasClass('pac-item');
// when pac items are added, add the needsclick class
if (pac_item_added) {
$('.pac-item, .pac-item span').addClass('needsclick')
}
});
});
observer.observe(document.body, observer_config);
It is more complex than I'd like it to be because we can't just add observer.observe('pac_container') in the top level, since its added asynchronously. Luckily, the solution for that problem is also MutationObservers.
We add another observer to pac_container when it is created. That way, it detects the pac-items being added, and when they are, we add the needsclick class.
This is my first time using MutationObservers, so feedback/improvements would be appreciated. As you can see, I used both jquery, but it should be pretty easy to pull it out.
There is a patch for fastclick that makes it work well with google places autocomplete. See This answer :)
After much hair pulling I have found the problem to be the "FastClick" library I added to my project.
As #Saravanan Shanmugam points out in this comment https://stackoverflow.com/a/16932543/1177832
FastClick seems to interfere with autocomplete. Also see above link for the workaround he has added to get the two to play nice.

Resources