The new feature for StreetView API 3 is that there is a label (called description) over the links (arrows of possible movement direction) on panorama.
I can turn on/off the links by the StreetViewPanoramaOptions.linksControl option, but I've found no way to display links without the labels, like in API 2.
I tried to intercept link-change event and overwrite link definitions, but it seems that the StreetViewPanorama.getLinks() returns a copy of the list: there is no effect on panorama image when I change the result array.
Is it possible to do it?
Well, I tried again and find out that my original statement about the links being unmodifiable was incorrect. With the following code, I was able to erase all the labels:
this.displayInContainer = function( container ) {
validatePano = new google.maps.StreetViewPanorama(
document.getElementById(container),
this.currentPanoramaOptions);
var obj = this;
google.maps.event.addListener(validatePano, 'links_changed', function() {
var links = obj.panoObject.getLinks();
for(var i = 0; i < links.length; i++ ) {
links[i].description = "";
}
});
}
Related
Is it possible to set the background color for a row in slickgrid (based on data values) AND use pagination? For angular-slickgrid package.
I used getItemMetadata as suggested multiple other (old) posts - example SlickGrid: How to loop through each row and set color based on the condition?.
This code:
metadata(old_metadata_provider) {
return function(row) {
var item = this.getItem(row);
var ret = (old_metadata_provider(row) || {});
if (item) {
ret.cssClasses = (ret.cssClasses || '');
if ("attribute" in item) {
return { cssClasses: 'redRow' }; //redRow is in styles.css
}
}
return ret;
}
}
and the call is:
this.dataViewObj.getItemMetadata = this.metadata(this.dataViewObj.getItemMetadata);
It works correctly. However, when I turn pagination on, the color does not work as expected. I read that SlickGrid re-uses the same row elements when scrolling or paginating and will overwrite the styles associated with them. Is there another way to do it? Thanks for any help on this.
I tried adding the following code, after reading suggestion from ghiscoding, but the colors are still not working when pagination is enabled.
angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.dataViewObj = angularGrid.dataView;
this.gridObj = angularGrid.slickGrid;
this.checkRowBackgroundColor(); //where I call the metadata function from my previous post, if the dataView object is defined.
//I added this code:
var self = this;
this.dataViewObj.onPagingInfoChanged.subscribe(function (e, dataView, grid) {
self.gridObj.invalidate();
self.gridObj.render();
});
}
Try this approach:
angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.dataViewObj = angularGrid.dataView;
this.gridObj = angularGrid.slickGrid;
// check color change logic for the first time page load
this.checkRowBackgroundColor();
// use arrow function so that 'this' works properly
this.dataViewObj.onPagingInfoChanged.subscribe((e, dataView, grid) => {
// check your color change logic every time Paging Info Changed
this.checkRowBackgroundColor();
});
}
Inside your checkRowBackgroundColor:
checkRowBackgroundColor() {
// ... any of your logic
// get metadata
this.dataViewObj.getItemMetadata = this.metadata(this.dataViewObj.getItemMetadata);
// rerender the grid after getting new metadata
this.gridObj.invalidate();
this.gridObj.render();
}
Your problem should be solved now. As I have not tested on my local machine, I can not give guarantee. You can checkout original documentation of angular-slickgrid about this specific topic here: Dynamically Add CSS Classes to Item Rows
I am building a classified ads website (like craigslist) with: handlebars (hbs), nodejs and multer for uploading images.
I have already created my own CRUD.
Users could post their ads for free, introducing their info for each ad:
user name
email
ad title
ad description
ad city
ad category
ad images (more than one if user needs)
I have a view, list.hbs, where ads show its information:
When users clicks on ad pictures, it will open like a modal box / pop up:
Everything perfect until here.
I save pictures in my ad.model, through multer like this:
image: {
imgName:{
type:String
},
imgPath:{
type:[String]
}
}
As you can see, I store path's pictures in an array to my mongodb database (managed by mongoose).
I.e:
"image" : {
"imgPath" : [
"uploads/e3c97fb10dd4c602054bedce194464b6",
"uploads/302fe7e147932d2b868a79b1799ba3f9"
]
}
The problem is here. I 've been trying to change image after clicking in each picture and it is impossible to do it.
I have tried via , but it looks like hbs doesn't work properly and don't read variables from handlebars:
I even tried passing through helper via onclick = myfunction({{#imageHelper}}{{/imageHelper}}), but it doesn't work...
Anybody knows how to handle this in handlebars? How to add js code to this view?
Note: my modal box / pop up is made it with pure html / css, no js or jquery in there.
I can't believe my mistake, how I didn't noticed before!
If you reach this question, or any question linked to handlebars - multer - javascript DOM, please, don't forget that template variables inside an onclick element MUST be quoted.
Mistake / Error
I passed through onclick element this:
<img onclick="myFun({{ad.reference}},{{ad.image.imgPath}})" class="imgAd" id="{{ad.reference}}" src="{{ad.image.imgPath.[0]}}"/>
And to manage the src and change images clicking everywhere on the image, I tried to do this:
...
<script>
let i = 0;
//next prev image
function myFun(ref,str){
const arr = str.split(',');
const len = arr.length;
if(i < len - 1){
i = i + 1;
document.getElementById(ref).src = arr[i]
}
else {
i = 0;
document.getElementById(ref).src = arr[i]
}
}
</script>
(This script above, just for change next picture, and so on)
Remember: if you pass variables like that, not quoted, js will throw errors, because it receives a "variable" like parameter, not a string.
In this case onclick received this:
uploads/b5e01da1707382ed915f314c0c77266c //variable, not string
Correct way:
<img onclick="myFun('{{ad.reference}}','{{ad.image.imgPath}}')" class="imgAd" id="{{ad.reference}}" display="block" src="{{ad.image.imgPath.[0]}}"/>
I passed a string, not a variable:
After I quoted each handlebar variable, I passed as string.
"uploads/b5e01da1707382ed915f314c0c77266c"
Now, the script will works. I get a string that I need to transform in an array to handle it:
<script>
let i = 0;
//next prev image
function myFun(ref,str){
const arr = str.split(',');
const len = arr.length;
if(i < len - 1){
i = i + 1;
document.getElementById(ref).src = arr[i]
}
else {
i = 0;
document.getElementById(ref).src = arr[i]
}
}
</script>
With this, I was able to manage DOM in each ad, changing images after clicking with nodejs, hbs and multer.
When a user drags the little yellow man onto the screen, it transitions into a full screen street view. This is good. However, it also litters the screen with my map markers. This is bad.
The hard way of solving this is for me to loop through every possible marker I could have on the map, storing which were visible before street view was initiated, and then restoring them when street view is done. But I can't find a street view initiation event anywhere in the API documentation.
The better and easier solution would be to set some option like "Don't show my markers while in street view."
Edit: managed to find a way to monitor the state of street view. How to detect enter and exit streetView in Google Maps API v3
However, I'd still like to know if there's a way to just... not show markers when in street view.
Final edit:
I'm including the 'solution'. This is a simplified version of what I ended up writing, because the layers each touch various modules throughout the application, so they aren't as simply handled as is shown.
Final solution:
// Add listener for when we go into street view.
google.maps.event.addListener(map.getStreetView(), 'visible_changed', function() {
var setAllMap = function (mapObjects, state) {
for (var i = 0, len = mapObjects.length; i < len; i++) {
mapObjects[i].setMap(state);
}
};
// If street view was just activated
if (this.getVisible()) {
// hide everything
setAllMap(LayerOne, null);
setAllMap(LayerTwo, null);
setAllMap(LayerThree, null);
// If we're leaving street view
} else {
// show the marker layers that were on
setAllMap(LayerTwo, true);
setAllMap(LayerThree, true);
// If visibility state was true
if (LayerOne.getVisible()) {
setAllMap(LayerOne, true);
}
if (LayerTwo.getVisible()) {
setAllMap(LayerTwo, true);
}
if (LayerThree.getVisible()) {
setAllMap(LayerThree, true);
}
}
});
Using the listener in the answer you posted, see when street view is active and do setAllMap(null); to hide the markers. When it leaves street view, do setAllMap(map); to show the markers again.
Edit (from the Google Maps documentation):
function setAllMap(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
I was fiddling a bit with Here Maps and with some some of the examples Here Javascript API Explorer and Here Maps on GitHub.
I tried to see if there's already a way to just add a visual bearing attribute in addition to longitude and latitude and have something like a small tip appear to the marker. This feels like something that many would like to have, so just to check I haven't missed anything obvious...
Is there a way to add visual bearing information to markers?
If not, does anyone know if there's an example of using a custom marker to achieve this I just couldn't locate?
There is no bearing/heading control ready available within the API - you will have to create a custom map component of your own. The usual way of doing this would be to inject some HTML as a new DOM element within the map control.
Firstly define your custom HtmlControl as shown:
function extend(B, A) {
function I() {}
I.prototype = A.prototype;
B.prototype = new I();
B.prototype.constructor = B;
}
function HtmlControl (html, id) {
nokia.maps.map.component.Component.call(this);
this.init(html, id);
}
extend(HtmlControl,
nokia.maps.map.component.Component);
HtmlControl.prototype.init = function (html, id) {
that = this;
that.id = id
that.set("node", document.createElement("div"));
that.node.innerHTML = html;
};
HtmlControl.prototype.getId = function() {
return "HtmlControl." + this.id;
};
HtmlControl.prototype.attach = function(map) {
map.getUIContainer().appendChild(this.node);
};
HtmlControl.prototype.detach = function(display) {
map.getUIContainer().removeChild(this.node);
};
Then set up the map and add the custom component as shown:
htmlControl = new HtmlControl(
"<img id='compass' style='left:4em;top:1em;width:100px;height:100px' src='...'/>", "Compass");
map.components.add(htmlControl);
The source file for the <img> element will need to hold the compass image. This is most likely to be an image with due North pointing upwards since the map control is based on the Normalized Mercator projection
Alternatively look at using the Map Image API and investigate the ra parameter to rotate the map.
My site consists of a Leaflet map with the leaflet.markerclusters plugin. I am also using Flowplayer to play a video that opens in a JQuery Tools overlay using the selector id "#video1".
Currently, when I click on any marker on the map it fires my test video in an overlay. My goal is to create a click event unique to each individual marker in the cluster. Eventually, I would like every marker to have a click event that fires a video unique to that marker.
I am a beginner, and have been doing okay using these well documented libraries up until now. However, I don't have the skills to bridge this current gap. Would someone please give me a push in the right direction? Below is a link to my JS Fiddle. My issue begins on JavaScript line 2098.
var markers = new L.MarkerClusterGroup();
var addressPoints = [
[40.634902, -73.965054, "Video1"],
[40.660897, -73.961082, "Video2"],
[40.693353, -73.970413, "Video3"],
[40.693289, -73.966289, "Video4"],
[40.68973, -73.971007, "Video5"],
[40.718423, -73.957428, "Video6"],
[40.71817, -73.956918, "Video7"],
[40.681427, -73.993959, "Video8"]
];
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = new L.Marker(new L.LatLng(a[0], a[1]), {
title: title
});
marker.bindPopup(title);
markers.addLayer(marker);
}
map.addLayer(markers);
//assign video div ID to overlay
$('#video1').overlay({
load: false,
top: "center",
left: "center"
});
//bind marker click event to overylay
markers.on('click', function () {
$("#video1").data("overlay").load();
});
Thank you,
Joey
http://jsfiddle.net/Joey84/nM458/26/
You are headed in the right direction with the markers.on("click"... function. You just need to make a few edits. Just as you added the event listener to the entire "markers" layer, you can add it to individual markers in your for loop.
...
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = new L.Marker(new L.LatLng(a[0], a[1]), {
title: title
});
if (title=="Video1") {
marker.on('click', function () {
$("#video1").data("overlay").load();
});
}
marker.bindPopup(title);
markers.addLayer(marker);
}
...
Likewise - and probably the better solution - you can access details about the marker you clicked in the on("click"... you are currently using by passing a variable to the function. This would be useful if you have multiple videos and don't want to check with an if statement when creating markers.
markers.on('click', function (d) {
// Grab marker title and make it look like an ID
var marker_title = "#" + d.layer.options.title.toLowerCase();
// Make sure the jQuery object exists
if ( $(marker_title) ){
// Call up the video.
$(marker_title).data("overlay").load();
}
});
Note that I used toLowerCase() because your data has the title capitalized and the video id is all lowercase.
Here it is in action:
http://jsfiddle.net/nM458/44/