google maps v3 duplicate markers - using an array to manage markers but still get duplicates - arrays

I'm not getting it: I have an array to manage my markers I add to a map. When I update the collection, the markers duplicate even though my markers array still only has the correct number of them in it.
I'm sure this is a really simple and stupid mistake on my part - but I'm not seeing it.
m.viewMarkers = function(data){
//ajax call to get latLng, returns an object with 4 markers
showMarkers();
}
function showMarkers(){
g.currentMarkers = []; // setting up my marker array
$.each(g.markersCollection, function(i,item){ // jquery-iterate over the object from the ajax call
g.currentMarkers.push( // adding markers to the array but purposely not drawing them on the map just yet
new google.maps.Marker({
position : new google.maps.LatLng(item.lat, item.lng)
});
);
});
$.each(g.currentMarkers, function(i,item){
if( g.map.getBounds().contains( item.getPosition() ) ){ // checking if this marker is within the viewport
item.setMap(g.map);
}
else {
item.setMap(null); // i don't want to have invisible markers slowing down my map
}
});
console.log(g.currentMarkers.length); // tells me it's 4, just as expected
}
google.maps.event.addListener(g.map, 'dragend', function() {
m.viewMarkers();
});
To me this looks like all is well, but the map keeps drawing 4 new markers on every dragend.... eeek!

Modify your showMarkers() function to this:
function showMarkers(){
//Removing old markers from the Map,if they are exist
if(g.currentMarkers && g.currentMarkers.length !== 0){
$.each(g.currentMarkers, function(i,item){
item.setMap(null);
});
}
g.currentMarkers = []; // setting up my marker array
$.each(g.markersCollection, function(i,item){
var expectedPosition = new google.maps.LatLng(item.lat, item.lng);
//No need to add marker on the Map if it will not visible on viewport,
//so we check the position, before adding
if(g.map.getBounds().contains(expectedPosition)){
g.currentMarkers.push(new google.maps.Marker({
position : expectedPosition
}) );
}
});
}

You can also compare new markers with your stored markers using some of following code (to display stored markers rather than new response marker):
var latlng1,latlng2;
for (var i=0; i< storedmarker.length; i++){
//Removing old markers from the Map,if they are exist with storedmarkers
latlng1 = storedmarker[i].getPosition();
for (var j=0; j< newmarkers.length; j++) {
latlng2 = newmarkers[j].getPosition();
if(latlng1.equals(latlng2)){
newmarkers[j].setMap(null);
}
}
//Set Marker
storedmarker[i].setMap(map);
}

Related

React google maps API how to make the marker icon fixed size

I've a google map with some markers, but when I zoom in and out the marker icon size changes, is there any way to make that size fixed?
const [markers,setMarkers] = useState([])
function generaMarker(elementolo,index){
var mark = <Marker draggable={modify===true?true:false} onDragEnd={(e)=>modify===true?handleSpostamentoMarker(e,index):null} onClick={(e)=>eliminate===true?deleteMarker(e,index):handleClickEl(elementolo)} label={elementolo.Nome} title={elementolo.Nome} icon={{url:getIcon(elementolo),s : new window.google.maps.Size(50,50),labelOrigin: new window.google.maps.Point(25,60)
}} position={new window.google.maps.LatLng(elementolo.Posizione.Lat,elementolo.Posizione.Lng)}/>
var nonDarmele = markers;
nonDarmele.push(mark);
setMarkers(nonDarmele)
return mark;
}
I use this function to render the markers and memorize them in the arrsy
if I write setMarkers((prev)=>[...prev,mark]) it crashes for the re renders even if the markers array is not rendered
I've tried also using a listener to the map zoom changes for setting new Marker icon sizes but I get that setIcon() method doesen't exists
function handleMarkerSize(map){
var zoom = map.getZoom()
var markerWidth = (zoom/9)*20;
var markerHeight = (zoom/9)*34;
//scaledSize: new window.google.maps.Size(50,50)
markers.forEach((mark)=>{
console.log("ooo",mark)
mark.props.icon = {
url: mark.props.icon.url,
scaledSize: new window.google.maps.Size(markerWidth,markerHeight),
labelOrigin: new window.google.maps.Point(25,60)
}
})
}
I'm using #react-google-maps/api
The map and markers visualization works fine, after rendering all the Markers there is no re render (only if in the function generaMarker() I use setMarkers with prev, and that make it crash)
Thanks for your help

Highlight text as you type in textarea Reactjs

I need to perform a behavior in FrontEnd but I don't know how to do it: Inside the textarea I have to put a background on certain keywords like "+project", "#context", while the user types, as if it were a markup text similar to testing tools for Regex.
Its not the complete solution, but you can adapt this example:
https://jsfiddle.net/julmot/hdyLpy37/
It uses the markjs library:
https://markjs.io/
Here is the javascript code:
// Create an instance of mark.js and pass an argument containing
// the DOM object of the context (where to search for matches)
var markInstance = new Mark(document.querySelector(".context"));
// Cache DOM elements
var keywordInput = document.querySelector("input[name='keyword']");
var optionInputs = document.querySelectorAll("input[name='opt[]']");
function performMark() {
// Read the keyword
var keyword = keywordInput.value;
// Determine selected options
var options = {};
[].forEach.call(optionInputs, function(opt) {
options[opt.value] = opt.checked;
});
// Remove previous marked elements and mark
// the new keyword inside the context
markInstance.unmark({
done: function(){
markInstance.mark(keyword, options);
}
});
};
// Listen to input and option changes
keywordInput.addEventListener("input", performMark);
for (var i = 0; i < optionInputs.length; i++) {
optionInputs[i].addEventListener("change", performMark);
}

How to use ranges saved to React state - Microsoft Word javascript API?

I am using the Microsoft Word Javascript API. I have used the .search() function to retrieve an array of ranges and then have saved them to state.definitions in my App.js React component state. This part works. When I try to print out the state using console.log(JSON.stringify(this.state.definitions)), I see the ranges that I just saved.
In a separate function, I want to retrieve those ranges and highlight them in a new color. This part does not work. I don't get any errors, but I don't see any highlight changes in the document.
Interestingly, if I try to highlight the ranges BEFORE saving them to state, it works. This makes me think that the ranges that I am retrieving from state are not actually the ranges understood by Word.
Any help would be much appreciated.
var flattenedTerms contains an array of range items that were retrieved from Word a few lines above. This code successfully changes the font
for (var i = 0; i < flattenedTerms.length; i++) {
console.log('flattenedTerms: ', flattenedTerms[i]);
flattenedTerms[i].font.color = 'purple';
flattenedTerms[i].font.highlightColor = 'pink';
flattenedTerms[i].font.bold = true;
}
return context.sync().then(function () {
return resolve(flattenedTerms);
})
})
Now the flattenedTerms array, which contains the range items, has been saved to state.definitions using this.setState. This fails to change the font. All of the console.logs do print.
highlightDefinedTerms = () => {
var self = this;
return Word.run(
function (context) {
var definitions = self.state.definitions;
console.log('Highlighting ', definitions.length, ' terms.');
for (var i = 0; i < definitions.length; i++) {
console.log('Highlighting definition: ', JSON.stringify(definitions[i]));
definitions[i].font.color = 'blue';
definitions[i].font.highlightColor = 'red';
definitions[i].font.bold = true;
}
return context.sync();
}
)
}
You need to pass a first parameter to “Word.run” to specify the object whose context you want to resume.
Word.run(self.state.definitions, function(context) ...)

How to add legends in Amserial charts

I am using Amcharts in my AngularJS Application to create a simple bar chart.The following is my code in the controller:
let empChart;
let empBarGraph;
let empLine;
const writeemp = data => {
const {
total,
employees,
} = data;
empChart.dataProvider = e;
empChart.write('emp');
empChart.validateData();
};
AmCharts.handleLoad();
var configChart = function () {
empChart = new AmCharts.AmSerialChart();
empChart.categoryField = "state";
empChart.labelRotation = 90;
var yAxis = new AmCharts.ValueAxis();
yAxis.position = "left";
empChart.addValueAxis(yAxis);
empBarGraph = new AmCharts.AmGraph();
empBarGraph.valueField = "count";
empBarGraph.type = "column";
empBarGraph.fillAlphas = 1;
empBarGraph.lineColor = "#f0ab00";
empBarGraph.valueAxis = yAxis;
empChart.addGraph(empBarGraph);
empChart.write('empChart');
$http.get(hostNameService.getHostName()+"/dashboard/employees/statecount")
.then(response => writeemp(response.data));
}
Code in html:
<div class='panel-body'>
<div id="empChart"></div>
</div>
This would return me the values of State on x-axis and count on y-axis. I wanted to filter the chart based on the value of state and was not sure how to create the legends for this chart. could anyone suggest me on how to use legends. I want to create legends for the state value that is being returned.
You can add a legend using the OO-based syntax by creating a legend object through new AmCharts.AmLegend() and adding it to the class by calling the chart's addLegend method:
var legend = new AmCharts.AmLegend();
empChart.addLegend(legend);
If you want the legend to show values upon hovering over a column, you need to add a ChartCursor to your chart:
var cursor = new AmCharts.ChartCursor();
empChart.addChartCursor(cursor);
You can change what the legend displays upon column rollover by setting the valueText property. It allows for the same [shortcodes] used in fields like balloonText and labelText, e.g. legend.valueText = "[[category]]: [[value]]". You can also use set its valueFunction if you need to customize the text it returns dynamically like in your previous questions. All of the properties available in the legend object can be found in the AmLegend API documentation.
Updated:
Legends work off of graph objects only, so there isn't an out of the box method that allows you to represent each column as a legend item that toggles the other columns' visibility unless you're willing to reorganize your dataset and use different graph objects for each state. A workaround for this is to use the the legend's custom data array and add some event handling so that clicking on the custom data items adds/removes a toggle by unsetting your count valueField in the dataProvider.
The following annotated code accomplishes what you're trying to do:
//create the legend but disable it until the dataProvider is populated,
//since you're retrieving your data using AJAX
var legend = new AmCharts.AmLegend();
legend.enabled = false;
chart.addLegend(legend);
chart.toggleLegend = false;
// Callback that handles clicks on the custom data entry markers and labels
var handleLegendClick = function(legendEvent) {
//Set a custom flag so that the dataUpdated event doesn't fire infinitely
legendEvent.chart.toggleLegend = true;
// The following toggles the markers on and off.
// The only way to "hide" a column is to unset the valueField at the data index,
// so a temporary "storedCount" property is added to the dataProvider that stores the
// original value so that the value can be restored when the legend marker is toggled
// back on
if (undefined !== legendEvent.dataItem.hidden && legendEvent.dataItem.hidden) {
legendEvent.dataItem.hidden = false;
legendEvent.chart.dataProvider[legendEvent.dataItem.stateIdx].count = legendEvent.chart.dataProvider[legendEvent.dataItem.stateIdx].storedCount; //restore the value
} else {
// toggle the marker off
legendEvent.dataItem.hidden = true;
legendEvent.chart.dataProvider[legendEvent.dataItem.stateIdx].storedCount = legendEvent.chart.dataProvider[legendEvent.dataItem.stateIdx].count; //store the value
legendEvent.chart.dataProvider[legendEvent.dataItem.stateIdx].count = undefined; //set to undefined to hide the column
}
legendEvent.chart.validateData(); //redraw the chart
}
chart.addListener('dataUpdated', function(e) {
var legendDataItems; //used to store the legend's custom data array.
if (e.chart.toggleLegend === true) {
//is the user toggling a legend marker? stop here as the dataProvider will get updated in handleLegendClick
e.chart.toggleLegend = false;
return;
}
// if we're at this point, the data provider was updated.
// reconstruct the data array.
// initialize by grabbing the state, setting a color and stoing the index
// for toggline the columns later
legendDataItems = e.chart.dataProvider.map(function(dataElement, idx) {
return {
'title': dataElement.state,
'color': graph.lineColor,
'stateIdx': idx //used in toggling
}
});
// if the legend is not enabled, then we're setting this up for the first time.
// turn it on and attach the event handlers
if (e.chart.legend.enabled === false) {
e.chart.legend.enabled = true;
e.chart.legend.switchable = true;
e.chart.legend.addListener('clickMarker', handleLegendClick);
e.chart.legend.addListener('clickLabel', handleLegendClick);
}
// update the legend custom data and redraw the chart
e.chart.legend.data = legendDataItems;
e.chart.validateNow();
});
Here's a fiddle that illustrates this: http://jsfiddle.net/g254sdq5/1/

mapstraction.removeMarker() function not working properly, it didn't remove marker on map

mapstraction.removeMarker didn't remove the marker on map
It doesn't throws any exception.bt its not removed on mapstraction map.
`mapstraction.removeMarker(markers[j]);
//I will get all markers from mapstraction map, then i want to remove all
removeAllMarkers(mapstraction.markers);
//some of them are not removed
function removeAllMarkers(markers){
for(var j=0; j<markers.length; j++){
try{
mapstraction.removeMarker(markers[j]);
}catch(err){
}
}
}

Resources