With the latest changes to Google Maps, the UI for getting a HTML snippet for embedding a photosphere into another web page has gone missing.
So, given a photosphere such as the one that can be found here, how can I embed it on a webpage using Google Maps API?
I tried two approaches:
With the approach described at https://developers.google.com/photo-sphere/web/ I wasn't able to find the panoid in the URL. I tried other random pieces of the URL to see if it would work, but it didn't.
With the approach described at https://developers.google.com/maps/documentation/javascript/examples/streetview-simple I specified the coordinates of the aforementioned photosphere, but the service returns a photosphere which is not the one I want. I want the one I authored myself.
At First:
the custom panoramas will not be published immediately, it will take some time until they will be available via the API
Your 2nd approach works for me, maybe the accuracy wasn't sufficient.
When I go to your google+-profile the location will be -23.55, -46.631, which will return a different panorama. But when I click on the map in the photo-details I get a more precise result in the page that will be opened:
-23.550201666666666,-46.63147500000002
When I use this location I get the desired panorama, the panoid is
PB0KYqVf9S0AAAQY__M_XQ
function init() {
var goo = google.maps,
map = new goo.Map(document.getElementById('map'), {
center : {lat: -23.5502017, lng: -46.631475},
zoom : 14,
noClear : true,
disableDefaultUI : true,
streetViewControl : true
}),
form = map.getDiv().querySelector('form'),
input = document.getElementById('latlng'),
desc = document.getElementById('desc'),
pano = document.getElementById('pano'),
pid = document.getElementById('pid'),
sv = new google.maps.StreetViewService();
map.setStreetView(new goo.StreetViewPanorama(pano,{
disableDefaultUI:true
}));
input.value=map.getCenter().toUrlValue();
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM]
.push(form);
map.controls[google.maps.ControlPosition.TOP_LEFT]
.push(pano);
map.controls[google.maps.ControlPosition.TOP_CENTER]
.push(desc);
google.maps.event.addListener(map,'get_pano',function(e){
sv.getPanorama({location: e.latlng, radius: 50}, function(data,status){
map.getDiv().className=status;
if (status === goo.StreetViewStatus.OK) {
map.getStreetView().setPano(data.location.pano);
pid.value=data.location.pano;
desc.innerHTML=data.location.description;
}
else{
desc.innerHTML='no streetview available';
pid.value='';
}
google.maps.event.trigger(map,'resize');
});
});
google.maps.event.addListener(map,'click',function(e){
input.value=e.latLng.toUrlValue();
google.maps.event.trigger(form,'submit');
});
google.maps.event.addDomListener(form,'submit',function(e){
if(e)e.preventDefault();
var ll=input.value.split(','),
r=[85,180],p=['lat','lng'],f,latlng={},err=false;
if(ll.length===2){
for(var i=0;i<ll.length;++i){
f=parseFloat(ll[i]);
if(Math.abs(f)<=r[i]){
latlng[p[i]]=f;
}
else{
err=true;
}
}
}
else{
err=true;
}
if(err){
alert('invalid coordinates')
}
else{
google.maps.event.trigger(map,'get_pano',{latlng:latlng})
}
return false;
});
google.maps.event.trigger(form,'submit');
}
html, body,#map {
height: 100%;
margin: 0;
padding: 0;
}
#pano{
height:100px;
width:150px;
}
#pid,#pano{
display:none;
}
#map>form{
display:none;
}
#pid{
background:Chartreuse;
}
#map.OK #pid,#map.OK #pano,#map.OK #desc{
display:block;
}
#desc{
background:tomato !important;
}
#map.OK #desc{
background:rgba(0,255,0, .8) !important;
}
#map form,#desc{
text-align:center;
padding:6px;
background:rgba(255,255,255, .8);
border:1px solid #000;
border-radius:4px;
}
#desc{
background:rgba(255,0,0, .8);
}
#map form,#pano{
margin:4px;
}
<div id="map">
<form>
<input id="latlng" placeholder="latitude,longitude"><br/><input type="submit"><br/>
<input id="pid" readonly>
<div id="pano"></div>
<div id="desc"></div>
</form>
</div>
<script async defer
src="https://maps.googleapis.com/maps/api/js?v=3&callback=init">
</script>
Related
is there a way to change a background-image on conditions?
Im trying to build a weatherapp and I will change the background of a div.
Like:
Weather api returns:
rainy -> change background image to rain.jpg
snow -> change background image to snow.jpg
sunny -> change background to sunny.jpg
etc.
I've tried multiple ways already but nothing worked.
<template>
<div :class="{background_image}"></div>
</template>
<script>
export default {
// ...
data() {
return {
backgroundImage: 'snow'
},
computed:{
background_image : function () {
switch(this.backgroundImage) {
case 'snow':
return 'bg-snow';
case 'rainy':
return 'bg-rainy';
case 'sunny':
return 'bg-sunny';
default:
return 'bg-default';
}
}
},
methods: {
apiCall() {
//api call update background image according to the response
this.backgroundImage = response ; // response contains sunny text
}
},
// ...
}
</script>
<style>
.bg-sunny{
background-image: url('sunny.jpg');
}
.bg-snow{
background-image: url('snow.jpg');
}
.bg-rainy{
background-image: url('rainy.jpg');
}
.bg-default{
background-image: url('default.jpg');
}
</style>
You can achieve this behavior by looking up the image in an object, where you have defined your key and the corresponding image value. In addition, you need to tell webpack to require that media file. That require tells webpack to treat this file as a request.
<template>
<div :style="{ backgroundImage: `url(${weatherTypes[getWeatherType()]})` }"></div>
</template>
<script>
export default {
// ...
data() {
return {
weatherTypes: {
snow: require('some/path/snow.png'),
sun: require('some/path/sun.png'),
// ...
}
}
},
methods: {
getWeatherType() { return 'snow'; },
},
// ...
}
</script>
Reproduction link
I want to have the data come back in the array and change colors according to if its "resolved" "working" or "open" the current code is working but is only ever one color, console log shows its coming back as resolved but my guess is its just showing the last in the array and not looping through, i tried creating a for loop in the computed and no change. I have a feeling its some small dumb detail i'm overlooking. The main function is working as i want it to, it's just the css im struggling with. Any help would be appreciated, i've found a ton of v-bind information for onclick but not any for dynamic values in an array.
<template>
<div
class="card-content has-background-dark has-text-light"
id="ev-card"
v-for="item in p3data.slice(0, 19)"
:key="item.p3data"
:class="cardColor"
>
</div>
</template>
<script>
data() {
return {
p3data: [],
status: "",
};
},
computed: {
cardColor: function() {
var color = "";
if (this.status == "Resolved") {
color = "green";
} else if (this.status == "Working") {
color = "yellow";
} else if (this.status == "Open") {
color = "red";
} else {
color = "red";
}
return color;
}
},
created() {
var p3 = "some url";
axios.get(p3).then(response => {
// pulls the info from the api to display in an array
this.p3data = response.data;
// console.log(response.data);
// shows the parent arrays length
var updateInfo = response.data;
for (var item of updateInfo) {
var updateData = item.updates;
var uLength = updateData.length;
uLength = uLength - 1;
for (var i = 0; i < updateData.length; i++) {
// console.log(utem)
if (updateData[i].message === "") {
updateData[i].message = item.message;
continue;
} else {
}
}
item.message = updateData[uLength].message;
item.updatekind = updateData[uLength].updatekind;
if (item.updatekind == 3) {
item.updatekind = "Resolved";
} else if (item.updatekind == 2) {
item.updatekind = "Working";
} else if (item.updatekind == 1) {
item.updatekind = "Open";
} else {
item.updatekind = "Open";
}
}
this.status = item.updatekind;
</script>
<style>
.red {
border: 4px solid hsl(0, 94%, 51%);
}
.yellow {
border: 4px solid hsl(54, 76%, 54%);
}
.green {
border: 4px solid hsl(115, 81%, 35%);
}
</style>
the problem is that your computed property, cardColor, changes only based on the value of this.status, which is a single variable specific to this component. In your code, after you do the axios call, loop through all the items and after that you do this.status = item.updatekind which sets status with item.updatekind, where item is the last element in the loop. And that's the status value that is used to set the cardColor property.
What you need is to calculate the cardColor for each one of your items. There are a few ways to do so, I think the most straightforward for you would be to do it in the existing code, here:
if (item.updatekind == 3) {
item.updatekind = "Resolved";
item.cardColor = "green";
} else if (item.updatekind == 2) {
item.updatekind = "Working";
item.cardColor = "yellow";
} else {
item.updatekind = "Open";
item.cardColor = "red";
}
and then in your template you can do
<template>
<div
class="card-content has-background-dark has-text-light"
id="ev-card"
v-for="item in p3data.slice(0, 19)"
:key="item.p3data"
:class="item.cardColor"
>
</div>
</template>
If you don't want to change the code in the promise, you can use conditional classes as well.
<template>
<div
class="card-content has-background-dark has-text-light"
id="ev-card"
v-for="item in p3data.slice(0, 19)"
:key="item.p3data"
:class="{
'green': item.updatekind === 'Resolved',
'yellow': item.updatekind === 'Working',
'red': item.updatekind === 'Open'
}"
></div>
</template>
I guess it just depends on your personal preferences.
Thanks,
I don't know how vue works nor what are you trying to achieve. Correct me if I'm wrong, but you are trying to have several cards with different colors right? If so, it seems like you are saving just one value in status, what I think it may work it would be having the cardColor function as a property of the item. And have something like :class="item.cardColor()" which would return its class based in the current state.
I'm looking to add a react element with H.ui.Control. Is this possible? and how might it be done?
// sudo code of what I did
componentDidMount() {
...
let button = new H.ui.Control(this.myButtonControl);
button.setPosition('top-left');
this._ui.addControl('button-control', button);
...
}
myButtonControl() {
return <button className="H_btn">Hello World</button>
}
A new <div class="H_ctl"></div>, appears where the control was suppose to be, but not the button.
While it's not exactly what I wanted to do, I did find a solution. I created a generic class that extends H.ui.Control, in this case ButtonGroupControl.
class ButtonGroupControl extends H.ui.Control {
constructor(buttons: []) {
super();
this._buttons = buttons;
this.addClass('H_grp');
}
renderInternal(el, doc) {
this._buttons.forEach((button, i) => {
let btn = doc.createElement('button');
btn.className = 'H_btn';
btn.innerText = this._buttons[i].label;
btn.onclick = this._buttons[i].callback;
el.appendChild(btn);
})
super.renderInternal(el, doc);
}
}
export default ButtonGroupControl;
Then, inside my map component, I created passed array of items into the control, like so:
const mapToolsControl: ButtonGroupControl = new ButtonGroupControl([
{
label: 'Add Field',
callback: () => {
console.log('callback: adding field');
}
},
{
label: 'Remove Field',
callback: () => {
console.log('callback: remove field');
}
}
]);
Lastly, I added the control to the map like:
this._map.addControl('map-tools-control', mapToolsControl);
This results in the following (it's a link because I don't have enough points to embed yet):
Screenshot of Result
Here is what i have done (adding two buttons to the map)
var U_I = new H.ui.UI(map);
var container = new H.ui.Control();
container.addClass('here-ctrl here-ctrl-group');
var button = new H.ui.base.Element('button', 'here-ctrl-icon map_control');
container.addChild(button);
button.addEventListener('click', function() { alert(1); });
var button = new H.ui.base.Element('button', 'here-ctrl-icon map_center');
container.addChild(button);
button.addEventListener('click', function() { alert(2); });
container.setAlignment('top-right');
U_I.addControl('myControls', container );
U_I.addControl('ScaleBar', new H.ui.ScaleBar() );
the rendering is made by css (here is an extract)
button.here-ctrl-icon {
width: 25px;
height: 25px;
margin: 2px 0 0 2px;
}
.map_control { background: url("images/map_control.png") no-repeat scroll 0 0 transparent; }
.map_center { background: url("images/map_center.png") no-repeat scroll 0 0 transparent; }
H.ui.base.Button(); is not working ... it creates a div
It is not possible to add attributes to button such as alt or title thru the api.
I still have to deal with the addEventListener ... (not working !)
the result :
my new nice controls
I have an view in Polymer whereby users can scan a QR code and the data will appear as a heading below the video preview. This is the code.
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="shared-styles.html">
<script type="text/javascript" src="../js/instascan.min.js"></script>
<dom-module id="my-view1">
<template>
<style>
:host {
display: block;
text-align: center;
}
#preview {
width: 100% !important;
height: auto !important;
border-radius: 2px;
}
</style>
<!-- Video preview of camera for QR code scanning -->
<video id="preview"></video>
<!-- List of QR code items scanned-->
<h1>{{bucketItems}}</h1>
</template>
<script>
class MyView1 extends Polymer.Element {
static get is() { return 'my-view1'; }
static get properties() {
return {
bucketItems: {
type: String,
reflectToAttribute: true
},
}
}
// Once page has loaded
connectedCallback() {
super.connectedCallback();
// List of items in bucket (contains scanned ingredients)
var itemsBucket = [];
// Scan QR Code using Instascanner
let scanner = new Instascan.Scanner({ video: this.$.preview });
scanner.addListener('scan', function (content) {
// Access the QR code content using "content"
if (!itemsBucket.includes(content)) {
// Only add items once to the bucket
itemsBucket.push(content);
}
this.bucketItems = itemsBucket.toString();
console.log(this.bucketItems);
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
scanner.start(cameras[0]);
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
}
}
window.customElements.define(MyView1.is, MyView1);
</script>
</dom-module>
When I console.log(this.bucketItems) I can see the list of items they have scanned but the data is not visible in the h1 tag. How do I bind it correctly. I am new to polymer and just beginning to learn data bindings.
This problem is the context of your callback is not bound to the Polymer object, so it uses the outer context.
You could switch to arrow functions to automatically bind the Polymer object, use :
scanner.addListener('scan', content=> {
instead of:
scanner.addListener('scan', function (content) {
DEMO
How to write this type of code in loop? Actually I don't want to write the same same line again and again, Is their any way to compress this code? can we write this code in loop?
function showCandidates()
{document.getElementById("cand9").style.display="block";
document.getElementById("cand10").style.display="block";
document.getElementById("cand11").style.display="block";
document.getElementById("cand12").style.display="block";
document.getElementById("cand13").style.display="block";
document.getElementById("cand14").style.display="block";
document.getElementById("cand15").style.display="block";
document.getElementById("hide_cand").style.display="block";
document.getElementById("view_cand").style.display="none";
}
function hideCandidates()
{document.getElementById("cand9").style.display="none";
document.getElementById("cand10").style.display="none";
document.getElementById("cand11").style.display="none";
document.getElementById("cand12").style.display="none";
document.getElementById("cand13").style.display="none";
document.getElementById("cand14").style.display="none";
document.getElementById("cand15").style.display="none";
document.getElementById("hide_cand").style.display="none";
document.getElementById("view_cand").style.display="block";
}
I suggest this way:
var show_ids = ["cand9", "cand10", "cand11"] // ... and so on
funciton showCandidates() {
for (var index in show_ids) {
var id = show_ids[index];
document.getElementById(id).style.display="none";
}
}
similar for hideCandidates
You should assign to your html elements a class for example
<div class="hideable" >content </div>
Then either you use JQuery or plain javascript to get all the elements that have the "hideable class attribute:
document.getElementsByClassName('hideable')
or
>$(".hideable")
Since your the two previous methods will return an array, you will have to loop through the array and apply the appropriate style attribute.
Firstly, this can be all encapsulated into one function. The function can take a parameter to assign to the display property. And obviously use some if statement in there to deal with the view_cand elements' display.
I would look into using jquery for this though, it makes selecting DOM elements (especially sets of DOM elements) a damn site easier.
I'd write the code for you here but I don't know anything about the elements you're selecting or the structure to your DOM.
Something like this?
for(i=0;i<candNumber;i++){
id= "cand" + i;
document.getElementById(id).style.display="block";
}
Try this .It'll hide/show ( the wayas you requested) by parameter given to function.
setVisibilityByClass("visible"/"invisible") - shows/hides by changing class
setVisibility("block"/"none") - shows/hides by changing styles directly
CHOOSE ONLY ONE.
css classes:
.vissible{ display: block; } .invissible{ display: none; }
Js functions:
function setVisibility(val) {
var not = new Array;
not["none"] = "block";
not["block"] = "none";
for (i = 9; i <= 15; i++){
document.getElementById("cand" + i).style.display = val;
}
document.getElementById("hide_cand").style.display = val;
document.getElementById("view_cand").style.display = not[val];
}
function setVisibilityByClass(val) {
var not = new Array;
not["invissible"] = "vissible";
not["vissible"] = "invissible";
for (i = 9; i <= 15; i++){
document.getElementById("cand" + i).setAttribute("class", val);
}
document.getElementById("hide_cand").setAttribute("class", val);
document.getElementById("view_cand").setAttribute("class", not[val]);
}
I hope this helps:
(function() {
"use strict";
var candidates = {
idx: 0,
getElement: function(id) { return document.getElementById(id); },
toggle: function(elmnts, obj) {
var idx = candidates.idx,
getElement = function(id) { return candidates.getElement(id); };
if (elmnts.length) {
while ( idx < elmnts.length ) {
getElement(elmnts[idx]).style.display = obj.display;
idx++;
}
}
}
};
var idsToHide = [
"cand9", "cand10", "cand11", "cand12",
"cand13", "cand14", "cand15", "hide_cand"
];
var idsToShow = [
"cand9", "cand10", "cand11", "cand12",
"cand13", "cand14", "cand15", "hide_cand"
];
function showCandidates() {
candidates.toggle(idsToShow, {
display: "block"
});
candidates.toggle(["view_cand"], { display: "none" });
}
function hideCandidates() {
candidates.toggle(idsToHide, {
display: "none"
});
candidates.toggle(["view_cand"], { display: "block" });
}
})();
Easy to do with jQuery:
$(document).ready(function(){
$("#candidates").toggle(function (){
$(this).text('Hide Candidates');
$.each($('.candidate'), function() {
$(this).show();
});
}, function() {
$(this).text('Show Candidates');
$.each($('.candidate'), function() {
$(this).hide();
});
});
});
HTML:
Show Candidates
<div class='candidate' id='1'>
<h1>Hello</h1>
</div>
<div class='candidate' id='2'>
<h1>Hello</h1>
</div>
<div class='candidate' id='3'>
<h1>Hello</h1>
</div>
CSS:
.candidate { display: none }
Here's a JS fiddle: http://jsfiddle.net/vbh5T/
If you don't want to use jQuery then please ignore my answer.
(1) First of all, doing these kinds of lookups is best done with jquery. Apart from being easier (see code below), it also allows you pre-calculate the set of elements to act on. This matters, because lookups by ID scan the whole document tree. Accordingly, the more elements in the page, the slower it is to recalculate the set of elements to act on.
(2) Rather than setting individual properties, it is much better to use a css class.
<style>
.invisible {display:none !important;}
</style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8"> // <![CDATA[
$(document).ready(function(){
var hide = function(i) {i.addClass('invisible');};
var show = function(i) {i.removeClass('invisible');};
var candidates = $("#cand9, #cand10 /* etc. [...] */");
/* or, if you rejig this to set a class on all candidate elements:
var candidates = $(".candidate"); */
var hide_cand = $("#hide_cand");
var view_cand = $("#view_cand");
function showCandidates()
{
show(candidates);
show(view_cand);
hide(hide_cand);
}
});
// ]]>
</script>
I leave the corresponding hideCandidates as an exercise for the reader.