maps.google API max 256 visible markers - google-maps-markers

Breaks my head everytime I think about a solution:
I can process (placing) more than 256 markers using google.maps.Map(), each with an eventListener (InfoWindow), but I can only make max 256 markers visible.I toggle markers with a few buttons.If I go over 256, the markers will be visible but not clickable anymore (breaks the functionality) and a reload of the page is neccessary.
var arrayLength = points.length;
for (var i = 0; i < arrayLength; i++) {
var marker = addMarker(points[i], map);
marker.setMap(map);
}
function addMarker(point, map) {
var infowindow = new google.maps.InfoWindow();
var iconColor = (point.type == 'circle') ? "/images/circle.png" : "/images/pointer_" + point.clr.replace("#","") + ".png";
var size = (point.type == 'circle') ? '20' : '10';
var goldStar = {
url: iconColor,
scaledSize: new google.maps.Size(size,15)
};
var marker = new google.maps.Marker({
position: point.latlng,
title: "" + point.crDate + "",
icon: goldStar,
visible: false,
});
google.maps.event.addListener(marker, "click", function() {
infowindow.close();
infowindow.setContent(
'<div style="cursor:pointer;text-decoration:underline;" onClick="window.opener.getQIDData('
+ point.qid
+ ',\'\','
+ point.t
+',\''
+ point.afd
+ '\')">'
+ point.crDate
+ '<br>'
+ point.afd
+ '<br>'
+ point.pers
+ '<br>'
+ point.qid
+'</div>' );
infowindow.open(map, marker);
});
return marker;
}
var markerGroups = {
"l-m": [],
"o-m": [],
"o-m2": [],
"r-m": [],
"r-b": [],
"r-bb": [],
"p-2": [],
"p-3": [],
"a-i": [],
"a-b": [],
"a-bl": [],
"a-on": [],
"a-old": [],
"a-youri": [],
"sms": [],
"l-1": [],
"l-2": []
};
// 'type' is the selected (pressed) button, corresponding to the markerGroups
function toggleGroup(type) {
var count = 0;
// buttons with .selected have no points visible (counter-intuitive, sorry ;-))
$("." + type).toggleClass("selected");
for (var group in markerGroups) {
if (!$("." + group).hasClass("selected")) {
count = (count + markerGroups[group].length);
}
}
// clear all markers before putting new on screen if count > 256
if (count > 256) {
for (var group in markerGroups) {
markerGroups[group].forEach(marker => marker.setVisible(false));
$("." + group).addClass("selected");
}
}
for (var group in markerGroups) {
var state = ($("." + group).hasClass("selected"))
? false
: true;
if (type == group) {
markerGroups[group].forEach(marker => marker.setVisible(state));
}
}
}

This
scaledSize: new google.maps.Size(size,15)
broke the code. Has nothing to do with maximum eventlisteners.
Making more than 256 markers visible with scaled images is impossible.
Thank you for reading.

Related

Solving Vuetify "v-menu" appears as fixed if parent component is inside a scrolling container

There is a long standing issue with the v-menu component in Vuetify:
by default the popup is physically "detached" from the activator and created as a child of v-app, thus avoiding being clipped if some of the parent DOM nodes has overflow: hidden style; however, this leads to the issue that the popup behaves as "position: fixed" when the activator is inside a scrolling container - that is, it does not scroll with the activator and looks visually disconnected, just "hanging" over the page.
the Vuetify maintainers admit the fact and suggest using the "attach" prop - however, 9 times out of 10 when using "attach" the position of the popup is computed wrong.
After 2 hours of debugging I finally gave up on using the "attach" prop and decided to simply track the scrolling position of the parent container where the activator resides and take it into account when computing the position of the popup. I am sharing my solution to the issue below and hoping that it will be included in the mainstream Vuetify.
Here is the patch file which solves the above issue plus a few others. Create a folder named patches inside your project and save the patch file as patches/vuetify#2.6.4.patch. Then add a new script to the scripts group in your package.json
"scripts":
{
....
"prepare": "custompatch"
}
Then run npm -i -D custompatch (to install the patcher for your CI/CD) and npx custompatch (to actually patch Vuetify in your dev environment).
Index: \vuetify\lib\components\VDialog\VDialog.js
===================================================================
--- \vuetify\lib\components\VDialog\VDialog.js
+++ \vuetify\lib\components\VDialog\VDialog.js
## -43,17 +43,21 ##
transition: {
type: [String, Boolean],
default: 'dialog-transition'
},
- width: [String, Number]
+ width: [String, Number],
+ zIndex: {
+ type: [String, Number],
+ default: 200
+ }
},
data() {
return {
activatedBy: null,
animate: false,
animateTimeout: -1,
- stackMinZIndex: 200,
+ stackMinZIndex: this.zIndex || 200,
previousActiveElement: null
};
},
Index: \vuetify\lib\components\VMenu\VMenu.js
===================================================================
--- \vuetify\lib\components\VMenu\VMenu.js
+++ \vuetify\lib\components\VMenu\VMenu.js
## -120,10 +120,10 ##
return {
maxHeight: this.calculatedMaxHeight,
minWidth: this.calculatedMinWidth,
maxWidth: this.calculatedMaxWidth,
- top: this.calculatedTop,
- left: this.calculatedLeft,
+ top: `calc(${this.calculatedTop} - ${this.scrollY}px + ${this.originalScrollY}px)`,
+ left: `calc(${this.calculatedLeft} - ${this.scrollX}px + ${this.originalScrollX}px)`,
transformOrigin: this.origin,
zIndex: this.zIndex || this.activeZIndex
};
}
Index: \vuetify\lib\components\VSelect\VSelect.js
===================================================================
--- \vuetify\lib\components\VSelect\VSelect.js
+++ \vuetify\lib\components\VSelect\VSelect.js
## -678,12 +678,17 ##
},
onScroll() {
if (!this.isMenuActive) {
- requestAnimationFrame(() => this.getContent().scrollTop = 0);
+ requestAnimationFrame(() =>
+ {
+ const content = this.getContent();
+ if (content) content.scrollTop = 0;
+ });
} else {
if (this.lastItem > this.computedItems.length) return;
- const showMoreItems = this.getContent().scrollHeight - (this.getContent().scrollTop + this.getContent().clientHeight) < 200;
+ const content = this.getContent();
+ const showMoreItems = content ? this.getContent().scrollHeight - (this.getContent().scrollTop + this.getContent().clientHeight) < 200 : false;
if (showMoreItems) {
this.lastItem += 20;
}
Index: \vuetify\lib\components\VSlideGroup\VSlideGroup.js
===================================================================
--- \vuetify\lib\components\VSlideGroup\VSlideGroup.js
+++ \vuetify\lib\components\VSlideGroup\VSlideGroup.js
## -181,9 +181,9 ##
},
methods: {
onScroll() {
- this.$refs.wrapper.scrollLeft = 0;
+ if (this.$refs.wrapper) this.$refs.wrapper.scrollLeft = 0; // TMCDOS
},
onFocusin(e) {
if (!this.isOverflowing) return; // Focused element is likely to be the root of an item, so a
Index: \vuetify\lib\components\VTextField\VTextField.js
===================================================================
--- \vuetify\lib\components\VTextField\VTextField.js
+++ \vuetify\lib\components\VTextField\VTextField.js
## -441,8 +441,9 ##
this.$refs.input.focus();
},
onFocus(e) {
+ this.onResize();
if (!this.$refs.input) return;
const root = attachedRoot(this.$el);
if (!root) return;
Index: \vuetify\lib\directives\click-outside\index.js
===================================================================
--- \vuetify\lib\directives\click-outside\index.js
+++ \vuetify\lib\directives\click-outside\index.js
## -35,10 +35,11 ##
}
function directive(e, el, binding, vnode) {
const handler = typeof binding.value === 'function' ? binding.value : binding.value.handler;
+ const target = e.target;
el._clickOutside.lastMousedownWasOutside && checkEvent(e, el, binding) && setTimeout(() => {
- checkIsActive(e, binding) && handler && handler(e);
+ checkIsActive({...e, target}, binding) && handler && handler({...e, target});
}, 0);
}
function handleShadow(el, callback) {
Index: \vuetify\lib\directives\ripple\index.js
===================================================================
--- \vuetify\lib\directives\ripple\index.js
+++ \vuetify\lib\directives\ripple\index.js
## -119,9 +119,9 ##
el.style.position = el.dataset.previousPosition;
delete el.dataset.previousPosition;
}
- animation.parentNode && el.removeChild(animation.parentNode);
+ animation.parentNode && /* el */animation.parentNode.parentNode.removeChild(animation.parentNode);
}, 300);
}, delay);
}
Index: \vuetify\lib\mixins\detachable\index.js
===================================================================
--- \vuetify\lib\mixins\detachable\index.js
+++ \vuetify\lib\mixins\detachable\index.js
## -28,13 +28,23 ##
},
contentClass: {
type: String,
default: ''
+ },
+ scroller:
+ {
+ default: null,
+ validator: validateAttachTarget
}
},
data: () => ({
activatorNode: null,
- hasDetached: false
+ hasDetached: false,
+ scrollingNode: null,
+ scrollX: 0,
+ scrollY: 0,
+ originalScrollX: 0,
+ originalScrollY: 0
}),
watch: {
attach() {
this.hasDetached = false;
## -42,10 +52,38 ##
},
hasContent() {
this.$nextTick(this.initDetach);
+ },
+ isActive(val)
+ {
+ if (val)
+ {
+ if (typeof this.scroller === 'string') {
+ // CSS selector
+ this.scrollingNode = document.querySelector(this.scroller);
+ } else if (this.scroller && typeof this.scroller === 'object') {
+ // DOM Element
+ this.scrollingNode = this.scroller;
+ }
+ if (this.scrollingNode)
+ {
+ this.originalScrollX = this.scrollingNode.scrollLeft;
+ this.originalScrollY = this.scrollingNode.scrollTop;
+ this.scrollX = this.originalScrollX;
+ this.scrollY = this.originalScrollY;
+ this.scrollingNode.addEventListener('scroll', this.setScrollOffset, {passive: true});
+ }
+ }
+ else
+ {
+ if (this.scrollingNode)
+ {
+ this.scrollingNode.removeEventListener('scroll', this.setScrollOffset, {passive: true});
+ }
+ this.scrollingNode = null;
+ }
}
-
},
beforeMount() {
this.$nextTick(() => {
## -95,8 +133,12 ##
} else {
removeActivator(activator);
}
}
+ if (this.scrollingNode)
+ {
+ this.scrollingNode.removeEventListener('scroll', this.setScrollOffset, {passive: true});
+ }
},
methods: {
getScopeIdAttrs() {
## -132,9 +174,13 ##
}
target.appendChild(this.$refs.content);
this.hasDetached = true;
+ },
+ setScrollOffset(event)
+ {
+ this.scrollX = event.target.scrollLeft;
+ this.scrollY = event.target.scrollTop;
}
-
}
});
//# sourceMappingURL=index.js.map
\ No newline at end of file
Index: \vuetify\lib\mixins\menuable\index.js
===================================================================
--- \vuetify\lib\mixins\menuable\index.js
+++ \vuetify\lib\mixins\menuable\index.js
## -96,9 +96,9 ##
computed: {
computedLeft() {
const a = this.dimensions.activator;
const c = this.dimensions.content;
- const activatorLeft = (this.attach !== false ? a.offsetLeft : a.left) || 0;
+ const activatorLeft = (this.attach !== false ? this.getActivatorLeft() : a.left) || 0;
const minWidth = Math.max(a.width, c.width);
let left = 0;
left += activatorLeft;
if (this.left || this.$vuetify.rtl && !this.right) left -= minWidth - a.width;
## -117,9 +117,9 ##
const a = this.dimensions.activator;
const c = this.dimensions.content;
let top = 0;
if (this.top) top += a.height - c.height;
- if (this.attach !== false) top += a.offsetTop;else top += a.top + this.pageYOffset;
+ if (this.attach !== false) top += this.getActivatorTop(); else top += a.top + this.pageYOffset;
if (this.offsetY) top += this.top ? -a.height : a.height;
if (this.nudgeTop) top -= parseInt(this.nudgeTop);
if (this.nudgeBottom) top += parseInt(this.nudgeBottom);
return top;
## -130,10 +130,13 ##
},
absoluteYOffset() {
return this.pageYOffset - this.relativeYOffset;
+ },
+
+ windowContainer() {
+ return typeof this.attach === 'string' ? document.querySelector(this.attach) || document.body : typeof this.attach === 'object' ? this.attach : document.body;
}
-
},
watch: {
disabled(val) {
val && this.callDeactivate();
## -274,19 +277,19 ##
},
getInnerHeight() {
if (!this.hasWindow) return 0;
- return window.innerHeight || document.documentElement.clientHeight;
+ return this.attach !== false ? this.windowContainer.clientHeight : window.innerHeight || document.documentElement.clientHeight;
},
getOffsetLeft() {
if (!this.hasWindow) return 0;
- return window.pageXOffset || document.documentElement.scrollLeft;
+ return this.attach !== false ? this.windowContainer.scrollLeft : window.pageXOffset || document.documentElement.scrollLeft;
},
getOffsetTop() {
if (!this.hasWindow) return 0;
- return window.pageYOffset || document.documentElement.scrollTop;
+ return this.attach !== false ? this.windowContainer.scrollTop : window.pageYOffset || document.documentElement.scrollTop;
},
getRoundedBoundedClientRect(el) {
const rect = el.getBoundingClientRect();
## -368,19 +371,38 ##
this.sneakPeek(() => {
if (this.$refs.content) {
if (this.$refs.content.offsetParent) {
const offsetRect = this.getRoundedBoundedClientRect(this.$refs.content.offsetParent);
- this.relativeYOffset = window.pageYOffset + offsetRect.top;
+ this.relativeYOffset = (this.attach !== false ? this.windowContainer.scrollTop : window.pageYOffset) + offsetRect.top;
dimensions.activator.top -= this.relativeYOffset;
- dimensions.activator.left -= window.pageXOffset + offsetRect.left;
+ dimensions.activator.left -= (this.attach !== false ? this.windowContainer.scrollLeft : window.pageXOffset) + offsetRect.left;
}
dimensions.content = this.measure(this.$refs.content);
}
this.dimensions = dimensions;
});
+ },
+
+ getActivatorTop() {
+ let result = 0;
+ let elem = this.getActivator();
+ while (elem && elem !== this.windowContainer && this.windowContainer.contains(elem)) {
+ result += elem.offsetTop;
+ elem = elem.offsetParent;
+ }
+ return result;
+ },
+
+ getActivatorLeft() {
+ let result = 0;
+ let elem = this.getActivator();
+ while (elem && elem !== this.windowContainer && this.windowContainer.contains(elem)) {
+ result += elem.offsetLeft;
+ elem = elem.offsetParent;
+ }
+ return result;
}
-
}
});
//# sourceMappingURL=index.js.map
\ No newline at end of file

Kendo Grid Sorting issues for numeric

I am using kendo grid to display data, but while sorting(ascending or descending) it's sorting perfectly for string values. But for numeric it's not sorting properly it's taking only first character to do sorting, not taking as string values even it's in numeric. How to solve this issue ?
You can use the gird column sortable.compare property to assign your own compare function.
Then what you are looking for is a Natural sort, like the one described here: http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 and implemented here: http://www.davekoelle.com/files/alphanum.js
Here is a demo using a case insensitive version of the natural sort:
https://dojo.telerik.com/eReHUReH
function AlphaNumericCaseInsensitive(a, b) {
if (!a || a.length < 1) return -1;
var anum = Number(a);
var bnum = Number(b);
if (!isNaN(anum) && !isNaN(bnum)) {
return anum - bnum;
}
function chunkify(t) {
var tz = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a ? a.toLowerCase() : "");
var bb = chunkify(b ? b.toLowerCase() : "");
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (!isNaN(c) && !isNaN(d)) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
}
var dataSource = new kendo.data.DataSource({
data: [
{ id: 1, item: "item101" },
{ id: 2, item: "item2" },
{ id: 3, item: "item11" },
{ id: 4, item: "item1" }
]
});
$("#grid").kendoGrid({
dataSource: dataSource,
sortable: true,
columns: [{
field: "item",
sortable: {
compare: function(a, b) {
return AlphaNumericCaseInsensitive(a.item, b.item);
}
}
}]
});

Chartjs animate x-axis displaying data incorrectly in mac device

I am working with chartjs, I am trying to animate chart from right to left or left to right on load.
var canvas = document.getElementById('chart_canvas');
var ctx = canvas.getContext('2d');
// Generate random data to plot
var DATA_POINT_NUM = 10;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push(Math.random()*10);
data.labels.push(String.fromCharCode(65+i));
}
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
Example 1
The above code works fine on windows, but I'm facing issue on mac devices.While animating from left to right the data displays incorrectly means that the data moves to upward from x axis.How to fix this issue?
I am attaching screenshot.
Screenshot
Please change setTransform to transform.
Try the following code
var canvas = document.getElementById('chart_canvas');
var ctx = canvas.getContext('2d');
// Generate random data to plot
var DATA_POINT_NUM = 10;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push(Math.random()*10);
data.labels.push(String.fromCharCode(65+i));
}
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.transform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});

Performance issue when zooming (Leaflet 0.7.3)

I'm facing a performance problem with Leaflet (version 0.7.3). I'm working with an OSM map that I use to display a bunch of CircleMarkers linked by decorated Polylines (with arrow pattern every 25px). Loading take a little time but the main problem is that when I zoom the map I start facing severe lag (from the zoom level 16) and, beyond a certain limit (say 18 most of the time), browser just freeze and eventually crash (tested with chrome and firefox). I tried with a bunch of 1,000 linked markers, then I dropped to a set of around 100, but still the same concern... Of course, with 10 markers or less I don't have any problem.
Did you already face a similar trouble? How can I optimize Leaflet performances so that I can use an accurate zoom (beyond level 16) with more than 100 linked CircleMarkers ? I also wonder why performances are dropping so badly when zooming, while marker amount stay the same...
Thank you in advance for your answers,
Lenalys.
Cannot get the PolylineDecorator plugin to work on jsfiddle.
But here is the code that generate markers :
Map initialization :
var map;
function initializeMap(){
"use strict";
var layer;
var layer2;
function layerUrl(key, layer) {
return "http://wxs.ign.fr/" + key
+ "/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&"
+ "LAYER=" + layer + "&STYLE=normal&TILEMATRIXSET=PM&"
+ "TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg";
}
layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',
{
attribution: '© OpenStreetMap contributors',
maxZoom: 18
});
layer2 = L.tileLayer(
layerUrl(IGN_AMBIENTE_KEY, "GEOGRAPHICALGRIDSYSTEMS.MAPS"),
{attribution: '© IGN'}
);
var baseMaps = {
"Terrestre": layer,
"Bathymetrique": layer2
};
map = L.map('map', {
layers: [layer],
zoom: 8,
center: [42.152796, 9.139150],
zoomControl: false
});
L.control.layers(baseMaps).addTo(map);
//add zoom control with your options
L.control.zoom({
position:'topright' //topleft
}).addTo(map);
L.control.scale({
position:'bottomleft',
imperial : false
}).addTo(map);
}
Data Sample :
var jsonData ={"12":[{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.42362","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 15:37:12"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.42365","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 16:42:16"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.4236933333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 17:47:21"},
{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.4237383333333","temperature":null,"pulse":null,"battery":"20","date_time":"2015-03-17 19:57:23"}],
"13":[{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.61683","longitude":"9.4804633333333","temperature":"17.45","pulse":null,"battery":"80","date_time":"2015-04-08 07:45:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.538858333333","longitude":"9.48169","temperature":"14.37","pulse":null,"battery":"80","date_time":"2015-04-08 08:00:29"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.458748333333","longitude":"9.500225","temperature":"14.46","pulse":null,"battery":"80","date_time":"2015-04-08 08:15:49"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.3302","longitude":"9.5374583333333","temperature":"15.19","pulse":null,"battery":"80","date_time":"2015-04-08 08:31:05"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.170133333333","longitude":"9.5272116666667","temperature":"15.48","pulse":null,"battery":"80","date_time":"2015-04-08 08:46:20"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07959","longitude":"9.47688","temperature":"15.97","pulse":null,"battery":"80","date_time":"2015-04-08 09:01:31"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.076163333333","longitude":"9.4828633333333","temperature":"20.42","pulse":null,"battery":"80","date_time":"2015-04-08 09:16:59"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07194","longitude":"9.4908866666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:32:17"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072583333333","longitude":"9.4901516666667","temperature":"17.36","pulse":null,"battery":"80","date_time":"2015-04-08 09:47:32"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07238","longitude":"9.4904266666667","temperature":"19.38","pulse":null,"battery":"80","date_time":"2015-04-08 10:02:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072298333333","longitude":"9.4904983333333","temperature":"17.46","pulse":null,"battery":"80","date_time":"2015-04-08 10:17:55"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.095093333333","longitude":"9.5148383333333","temperature":"17.47","pulse":null,"battery":"80","date_time":"2015-04-08 10:33:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112881666667","longitude":"9.5133133333333","temperature":"19.3","pulse":null,"battery":"80","date_time":"2015-04-08 10:48:23"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112875","longitude":"9.513285","temperature":"22.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:03:57"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.141096666667","longitude":"9.5078216666667","temperature":"23.73","pulse":null,"battery":"80","date_time":"2015-04-08 11:19:12"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.282186666667","longitude":"9.5505183333333","temperature":"18.97","pulse":null,"battery":"80","date_time":"2015-04-08 11:34:28"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.405126666667","longitude":"9.531145","temperature":"20.71","pulse":null,"battery":"80","date_time":"2015-04-08 11:49:42"},
{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.482063333333","longitude":"9.480665","temperature":"21.7","pulse":null,"battery":"80","date_time":"2015-04-08 12:05:07"}]}
var oJSON = JSON.parse(jsonData);
var colors = [
"#400080",
"#008000",
"#EC7600",
"#E40341",
"#0D5E5E",
"#919191",
"#FF3C9D",
"#A70A0E",
"#00BFBF",
"#7171FF"
];
var classes = [
"color1",
"color2",
"color3",
"color4",
"color5",
"color6",
"color7",
"color8",
"color9",
"color10"
];
var lastMarkers = [];
var layers = new Array();
var polyline;
var decorator;
window.graphicsDevices = [];
var offsetLatitude = 0.003333;
var offsetLongitude = 0.011666;
Marker instanciation :
function printGPSOnMap(oJSON){
var nbKeys = 0;
for (var key in oJSON) {
nbKeys++;
var classe = classes[(key-1)%classes.length];
var color = colors[(key-1)%colors.length];
var positionInfo = [];
if (oJSON.hasOwnProperty(key)) {
var aInfo = oJSON[key];
var marker;
var latlngs = Array();
var startMarker = lastMarkers[key];
if(startMarker !== undefined && startMarker != null) {
var myIcon = L.divIcon({className: "myCircle "+classe, iconSize : [ 20, 20 ] });
startMarker.setIcon(myIcon);
latlngs.push(startMarker.getLatLng());
}
for(var i = 0; i < aInfo.length; i++) {
var oInfos = aInfo[i];
var sIdIndividual = oInfos["id_individual"];
var sLongitude = oInfos["longitude"];
var sLatitude = oInfos["latitude"];
var sTemperature = oInfos["temperature"];
var sPulse = oInfos["pulse"];
var sBattery = oInfos["battery"];
var sDatetime = oInfos["date_time"];
var sIndividualName = oInfos["individual_name"];
var id_device = oInfos["id_stm_device"];
var popupMsg = "...";
latlngs.push(L.marker([sLatitude,sLongitude]).getLatLng());
marker = new MyCustomMarker([sLatitude,sLongitude], {
icon : L.divIcon({
className : "myCircle "+classe + ((i == aInfo.length-1) ? ' myCircleEnd' : ''),
iconSize : [ 20, 20 ]
})
});
marker.bindPopup(popupMsg, {
showOnMouseOver: true
});
marker.bindLabel(key, {
noHide: true,
direction: 'middle',
offset: [offset[0], offset[1]]
});
positionInfo.push(marker);
}
lastMarkers[key] = marker;
}
if(latlngs.length > 1)
{
polyline = L.polyline(latlngs, {className: classe, weight: 2,opacity: 0.4}).addTo(map);
decorator = L.polylineDecorator(polyline, {
patterns: [
// define a pattern of 10px-wide arrows, repeated every 20px on the line
{offset: 0, repeat: '25px', symbol: new L.Symbol.arrowHead({pixelSize: 10, pathOptions: {fillOpacity:
0.76, color: color, weight: 1}})}
]}).addTo(map);
}
if(!window.graphicsDevices.hasOwnProperty(key))
window.graphicsDevices[key] = [];
for(var i = 0; i < positionInfo.length; i++) {
window.graphicsDevices[key].push(positionInfo[i]);
positionInfo[i].addTo(map);
if(latlngs.length > 1){
window.graphicsDevices[key].push(polyline);
polyline.addTo(map);
window.graphicsDevices[key].push(decorator);
decorator.addTo(map);
}
}
}//foreach key
}
Code for the custom marker :
var MyCustomMarker = L.Marker.extend({
bindPopup: function(htmlContent, options) {
if (options && options.showOnMouseOver) {
// call the super method
L.Marker.prototype.bindPopup.apply(this, [htmlContent, options]);
// unbind the click event
this.off("click", this.openPopup, this);
// bind to mouse over
this.on("mouseover", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.fromElement || e.originalEvent.relatedTarget;
var parent = this._getParent(target, "leaflet-popup");
// check to see if the element is a popup, and if it is this marker's popup
if (parent == this._popup._container)
return true;
// show the popup
this.openPopup();
}, this);
// and mouse out
this.on("mouseout", function(e) {
// get the element that the mouse hovered onto
var target = e.originalEvent.toElement || e.originalEvent.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup")) {
L.DomEvent.on(this._popup._container, "mouseout", this._popupMouseOut, this);
return true;
}
// hide the popup
this.closePopup();
}, this);
}
},
_popupMouseOut: function(e) {
// detach the event
L.DomEvent.off(this._popup, "mouseout", this._popupMouseOut, this);
// get the element that the mouse hovered onto
var target = e.toElement || e.relatedTarget;
// check to see if the element is a popup
if (this._getParent(target, "leaflet-popup"))
return true;
// check to see if the marker was hovered back onto
if (target == this._icon)
return true;
// hide the popup
this.closePopup();
},
_getParent: function(element, className) {
var parent = null;
if(element != null) parent = element.parentNode;
while (parent != null) {
if (parent.className && L.DomUtil.hasClass(parent, className))
return parent;
parent = parent.parentNode;
}
return false;
}
});
Have you gauged performance in canvas mode?
Use L_PREFER_CANVAS = true before initializing your leaflet map container.Might be able to help you possibly.

SlickGrid dropdown box editor not working

I have am trying to implement something along the lines of
Slickgrid, column with a drop down select list?
my code is;
slick.editors.js ;
(function ($) {
// register namespace
$.extend(true, window, {
"Slick": {
"Editors": {
"Text": TextEditor,
"Integer": IntegerEditor,
"Date": DateEditor,
"YesNoSelect": YesNoSelectEditor,
"Checkbox": CheckboxEditor,
"PercentComplete": PercentCompleteEditor,
"LongText": LongTextEditor,
"SelectOption": SelectCellEditor
}
}
});
with the function defined futher down,
function SelectCellEditor(args) {
var $select;
var defaultValue;
var scope = this;
this.init = function () {
if (args.column.options) {
opt_values = args.column.options.split(',');
} else {
opt_values = "yes,no".split(',');
}
option_str = ""
for (i in opt_values) {
v = opt_values[i];
option_str += "<OPTION value='" + v + "'>" + v + "</OPTION>";
}
$select = $("<SELECT tabIndex='0' class='editor-select'>" + option_str + "</SELECT>");
$select.appendTo(args.container);
$select.focus();
};
this.destroy = function () {
$select.remove();
};
this.focus = function () {
$select.focus();
};
this.loadValue = function (item) {
defaultValue = item[args.column.field];
$select.val(defaultValue);
};
this.serializeValue = function () {
if (args.column.options) {
return $select.val();
} else {
return ($select.val() == "yes");
}
};
this.applyValue = function (item, state) {
item[args.column.field] = state;
};
this.isValueChanged = function () {
return ($select.val() != defaultValue);
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
this.init();
}
Then in my CSHTML
var columns = [
{ id: "color", name: "Color", field: "color", options: "Red,Green,Blue,Black,White", editor: Slick.Editors.SelectOption },
{ id: "lock", name: "Lock", field: "lock", options: "Locked,Unlocked", editor: Slick.Editors.SelectOption },
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
$(function () {
var data = [];
for (var i = 0; i < 20; i++) {
data[i] = {
color: "Red",
lock: "Locked"
};
}
the grid shows and the colour is shown as if its a regular text in a cell, but no dropdown?.
The drop-down will appear only when you are editing that cell. Adding editable: true to your grid options should work I think.

Resources