Layer control using leaftejs and vuejs - leaflet

Everyone I am a junior developer at NESAC(ISRO).
I am working on a project with vue JS and leaflet JS. So my task is:-
Using Leaflet JS, I have to render a map on the screen.
Set markers at "n" specific locations on the renderd map.
Create a sidebar with a checkbox of various entities such as cities, restaurants, parks etc.
Develop a Vue app such that, I create my different components on the components folder, so that all my components go through App.vue file and gets renderd at the index.html, i.e. my browser.
And, now I have to make a Layer control function such that each of my entities gets different reactions. Eg. If I click the restaurant checkbox at the sidebar, then all my restaurant leaflet markers should be shown on the screen, but each entity should have different reactivity.
Github Link.

You can use npm package for that - Vue2Leaflet
Here is docu: https://vue2-leaflet.netlify.app
And simple Map with Vue.js and leaflet:
<template>
<div style="height: 350px;">
<div class="info" style="height: 15%">
<span>Center: {{ center }}</span>
<span>Zoom: {{ zoom }}</span>
<span>Bounds: {{ bounds }}</span>
</div>
<l-map
style="height: 80%; width: 100%"
:zoom="zoom"
:center="center"
#update:zoom="zoomUpdated"
#update:center="centerUpdated"
#update:bounds="boundsUpdated"
>
<l-tile-layer :url="url"></l-tile-layer>
</l-map>
</div>
</template>
<script>
import {LMap, LTileLayer} from 'vue2-leaflet';
export default {
components: {
LMap,
LTileLayer,
},
data () {
return {
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
zoom: 3,
center: [47.413220, -1.219482],
bounds: null
};
},
methods: {
zoomUpdated (zoom) {
this.zoom = zoom;
},
centerUpdated (center) {
this.center = center;
},
boundsUpdated (bounds) {
this.bounds = bounds;
}
}
}
</script>
It's just a wrapper for a leaflet and you have complete access to all the leaflet functions through:
mounted() {
this.$nextTick(() => {
this.map = this.$refs.map.mapObject;
});
}
I think that can be a good start for you.

Related

How to show feeds in the same page after applying filters in ionic

i am creating an Listing ionic application where i am displaying feeds from an API in the home page. It also has some filter options which is an actionsheet with options such as near by, populer and so on. What i want to do is when user click one of the filter for example populer, i want to do display the new feeds on the same page. How can i do so ??
My code base is as below
home.ts
constructor(....){
this.getFeeds();
}
//make api call to get the feeds
getFeeds(){
const data = localStorage.getItem('userToken');
this.userPostData.api_token= data;
this.authService.postData(this.userPostData,'feeds').then((result)=>{
this.responseData = result;
})
}
//Feeds by location
//Actionsheet
filters() {
let actionSheet = this.actionSheetCtrl.create({
title: 'Sort Events by',
buttons: [
{
text: 'Location',
icon:'pin',
handler: () => {
//Make api call to feeds based on location
}
},
{
text: 'Popularity',
icon:'people',
handler: () => {
//Make api call to feeds based on location
}
}
]
});
actionSheet.present();
}
And my home.html is
<ion-card *ngFor="let item of responseData?.feed" tappable (click)="viewDetail(item.id)">
<div class="event-image-holder search-list">
<img src="http://localhost:8000/{{item.photo_url}}"/>
<div class="event-attendee-count">
<ion-icon name="people"></ion-icon> {{item.attendees.length}} are going
</div>
</div>
<ion-card-content>
<div class="event-info">
<div class="event-time">
<!-- 04 Feb -->
{{item.gmt_date_set | date:'dd MMM'}}
</div>
<div class="event-descp">
<h2>{{item.title}}</h2>
<p>
{{item.club.name}}
</p>
</div>
</div>
</ion-card-content>
</ion-card>
After some research here and there tutorials from youtube and udemy, i found that when ever you change the data of the variable it automatically change on the view page.
So in my case if i override the data of this.responseData it will automatically updated on the view page with out much doing.

How to fix overlapping Google Chart legend

This has been something I've been working on for hours now and I can't seem to find a solution that works. I have a page (ASP.NET Core) that has bootstrap tabs on it. Each tab displays a different chart. I've read various answers and tried so many different things from this and other sites but I'm sure what I'm doing wrong.
This is a proof of concept page I'm making and from what I understand I need to stall the loading of the chart until the nav-tab is selected. That is what I am unsure of how to do.
My View:
<html>
<head>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
#Html.Partial("~/Views/Shared/Chart_ByMonth.cshtml")
#Html.Partial("~/Views/Shared/Chart_ByMonthAndQuarter.cshtml")
#Html.Partial("~/Views/Shared/Chart_ByLeaseAdmin.cshtml")
#Html.Partial("~/Views/Shared/Chart_Fourth.cshtml")
<script type="text/javascript">
// Load the Visualization API and the corechart package.
google.charts.load('current', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawMonthChart);
google.charts.setOnLoadCallback(drawMonthAndQuarterChart);
google.charts.setOnLoadCallback(drawLeaseAdminChart);
google.charts.setOnLoadCallback(drawFourthChart);
</script>
<body>
<ul class="nav nav-tabs" id="tabs">
<li class="active" id="tab_1"><a data-toggle="tab" href="#home">By Month</a></li>
<li id="tab_2"><a data-toggle="tab" href="#menu1">By Month & Quarter</a></li>
<li id="tab_3"><a data-toggle="tab" href="#menu2">By Lease Admin</a></li>
<li id="tab_4"><a data-toggle="tab" href="#menu3">Fourth Chart</a></li>
</ul>
<div class="tab-content">
<div id="home" class="tab-pane fade in active">
<h3>By Month</h3>
<select>
<option selected>January</option>
<option>February</option>
<option>March</option>
<option>April</option>
<option>May</option>
<option>June</option>
<option>July</option>
<option>August</option>
<option>September</option>
<option>October</option>
<option>November</option>
<option>December</option>
</select>
<select>
<option>2016</option>
<option>2017</option>
</select>
<button type="submit" class="btn btn-success">Submit</button>
<div id="chart_month_div" style="padding-top: 20px;"></div>
</div>
.....
</div>
</body>
The partial view for that chart is just hard-coded data, again a proof of concept page:
<script type="text/javascript">
function drawMonthAndQuarterChart() {
// Create the data table.
var data = google.visualization.arrayToDataTable([
['Type', 'Cash', 'Credit', { role: 'annotation' }],
['January', 10, 24, ''],
['February', 16, 22, ''],
['March', 28, 19, '']
]);
// Set chart options
var options = {
width: 1200,
height: 400,
legend: { position: 'top', maxLines: 3 },
bar: { groupWidth: '75%' },
isStacked: true,
hAxis: {
minValue: 0,
title: 'Approvals for the month & quarter'
}
};
// Instantiate and draw our chart, passing in some options.
var chartMonthandquarter = new google.visualization.BarChart(document.getElementById('chart_monthandquarter_div'));
chartMonthandquarter.draw(data, options);
}
The charts all load fine when tabs are selected. The legend is overlapped with itself on all but the initially shown chart. I've tried defaulting the chart divs to be hidden and having an onclick event for each tab that overrides the styling, I've tried doing events where a tab is active, nothing seems to work and I've just been banging my head against the wall.
I suspect it has something to do with the fact that I'm calling
google.charts.setOnLoadCallback(drawMonthAndQuarterChart);
google.charts.setOnLoadCallback(drawLeaseAdminChart);
google.charts.setOnLoadCallback(drawFourthChart);
and since the charts are already drawn right on page creation, there's no way to redraw them. What I am not sure how to do is successfully get the charts to draw only when a new tab is active or something similar.
as you've gathered,
the problem is a result of drawing the chart while the tab is hidden
need to wait until the tab is shown before drawing for the first time
as such, only draw the first chart using the callback...
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawMonthChart);
once the callback fires, you don't have to call it again,
you can draw as many charts as needed afterwards
then wait for the tabs to be clicked before drawing the next chart...
here, a switch statement is used on the href attribute,
to determine which tab was clicked,
then draw its chart...
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
switch ($(e.target).attr('href')) {
case '#home':
drawMonthChart();
break;
case '#menu1':
drawMonthAndQuarterChart();
break;
case '#menu2':
drawLeaseAdminChart();
break;
case '#menu3':
drawFourthChart();
break;
}
});

Vue.js page transition fade effect with vue-router

How to achieve a fade effect page transition between vue-router defined pages (components)?
Wrap <router-view></router-view> with <transition name="fade"></transition> and add these styles:
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
Detailed answer
Assuming you have created your application with vue-cli, e.g.:
vue init webpack fadetransition
cd fadetransition
npm install
Install the router:
npm i vue-router
If you are not developing your app using vue-cli, make sure to add the vue router the standard way:
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
You can use e.g.: https://unpkg.com/vue-router/dist/vue-router.js
The CLI has created a backbone application for you, which you can add components to.
1) Create page components
In Vue, components (UI elements) can be nested. A page in your app can be made with a regular Vue component that is considered as the root to other components in that page.
Go to src/ and create pages/ directory. These page-root components (individual pages) will be put in this directory, while the other components used in the actual pages can be put to the ready-made components/ directory.
Create two pages in files called src/pages/Page1.vue and src/pages/Page2.vue for starters. Their content will be (edit page numbers respectively):
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
2) Setup routing
Edit the generated src/main.js add the required imports:
import VueRouter from 'vue-router'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Add a global router usage:
Vue.use(VueRouter)
Add a router setup:
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
The last route just redirects the initial path / to /page1. Edit the app initiation:
new Vue({
router,
el: '#app',
render: h => h(App)
})
The whole src/main.js example is at the end of the answer.
3) Add a router view
Routing is set up by now, just a place where the page components will be rendered according to the router is missing. This is done by placing <router-view></router-view> somewhere in the templates, you will want to put it in the src/App.vue's <template> tag.
The whole src/App.vue example is at the end of the answer.
4) Add fade transition effect between page components
Wrap the <router-view></router-view> with a <transition name="fade"> element, e.g.:
<template>
<div id="app">
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
Vue will do the job here: it will create and insert appropriate CSS classes starting with the name specified through-out the effect's duration, e.g.: .fade-enter-active. Now define the effects in App.vue's section:
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
That's it. If you run the app now, e.g. with npm run dev, it will automatically display Page 1 with a fade-in effect. If you rewrite the URL to /page2, it will switch the pages with fade-out and fade-in effects.
Check out the documentation on routing and transitions for more information.
5) Optional: Add links to pages.
You can add links to particular pages with the <router-link> component, e.g.:
<router-link to="/page1">Page 1</router-link>
<router-link to="/page2">Page 2</router-link>
This automatically gives the links a router-link-active class in case they are active, but you can also specify custom classes if you are using e.g. Bootstrap:
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
Files for reference
src/main.js:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
/* eslint-disable no-new */
new Vue({
router,
el: '#app',
render: h => h(App)
})
src/App.vue:
<template>
<div id="app">
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
src/pages/Page1.vue:
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
src/pages/Page2.vue:
<template>
<h1>Page 2</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Plug and Play Solution
There is also a plug and play solution called vue-page-transition which offers you all sort of transitions. (fade, flip, zoom, overlay etc.)
1 - Install the npm package:
yarn add vue-page-transition
2 - register the plugin:
import Vue from 'vue'
import VuePageTransition from 'vue-page-transition'
Vue.use(VuePageTransition)
3 - wrap your router-view with the global animation:
<vue-page-transition name="fade-in-right">
<router-view/>
</vue-page-transition>
Learn more on GitHub:
https://github.com/Orlandster/vue-page-transition

Adding qTip2 tooltips to each node of a jsTree

I am creating a tree structure using thymeleaf in a recursive way to generate the html ul and li elements. Afterwards, I transform this list into a tree using jsTree. Until there, everything is fine. Afterwards, I want to add a tooltip with html content to each element of the tree. I am trying it with qTip2 but for some reason it is only showing an empty tooltip on the root nodes (platform.projectname and platform.projectname2) and nothing at all in the children.
Has anyone done this before? Any advice will be appreciated.
HTML/Thymeleaf container for the tree:
<div id="jstree_demo_div">
<div th:fragment="submenu" th:remove="tag">
<ul>
<li th:each="node : ${nodelist}">
<span th:text="${node.path}" class="treeelement">Town hall</span>
<div class="tooltip">
Logging configuration:
<br/><br/>
<select>
<option value="trace">Trace</option>
<option value="debug">Debug</option>
<option value="info">Info</option>
<option value="warn">Warn</option>
<option value="error">Error</option>
</select>
</div>
<div th:with="nodelist = ${node.children}" th:include="this::submenu" th:remove="tag"></div>
</li>
</ul>
</div>
</div>
JavaScript:
// jsTree
$(function () {
// 6 create an instance when the DOM is ready
$('#jstree_demo_div').jstree();
// 7 bind to events triggered on the tree
$('#jstree_demo_div').on("changed.jstree", function (e, data) {
console.log(data.selected);
});
// 8 interact with the tree - either way is OK
$('button').on('click', function () {
$('#jstree_demo_div').jstree(true).select_node('child_node_1');
$('#jstree_demo_div').jstree('select_node', 'child_node_1');
$.jstree.reference('#jstree_demo_div').select_node('child_node_1');
});
});
// qTip2
$(function(){
$('.treeelement').each(function(){
$(this).qtip({
content: {
text: $(this).next('.tooltip')
},
show: 'click',
hide: {
fixed: true,
delay: 2000
}
});
});
});
I made it work I guess, check this: JS Fiddle.
Try to:
move your qtip binding into loaded jsTree event to be sure it is loaded before you start binding qtip;
bind to jstree-ancor class the jsTree node has
you do not need to iterate with each
The reason for your tooltip having no text is that when building the tree jsTree rebuilds your <li> elements leaving out your .tooltip divs.
I found a way which suits better my needs, here is a JSFiddle example.
First I register the method nodeSelected to be executed when a node is selected, then I create and show the tooltip. This allows me to assign a specific ID to <select>.
$('#jstree_demo_div').on("changed.jstree", function (e, data) {
nodeSelected(data);
})
...
function nodeSelected(data){
console.log(data.selected);
// Using getElementById since JQuery does not work well with dots in identifiers
$(document.getElementById(data.selected + '_anchor')).qtip({
content: {
text: 'Logging configuration:<br/><br/><select><option value="TRACE">Trace</option><option value="DEBUG">Debug</option><option value="INFO">Info</option></select></div>
},
show: 'click',
hide: {
fixed: true,
delay: 1000
}
});
$(document.getElementById(data.selected + '_anchor')).qtip("show");
}

Leaflet breaks on load

I am facing issue with leaflet library. When I try to load map, images are loaded more then once. I am using leaflet with angular, grunt and browserify. I suspect it can be because of order of loading libraries and async execution, but I am not sure. There is no js error messages, leaflet just breaks.
This is my grunt file:
var $ = require('jquery');
window.jQuery = $;
//require boostrap.js for bootstrap components
var angular = require('angular');
require('ui.bootstrap');
require('showErrors');
require('leaflet');
require('leaflet-directive');
angular.module('common', [
require('angular-resource')
]);
var requires = [
'ngRoute',
'leaflet-directive',
'common',
'ui.bootstrap',
'ui.bootstrap.showErrors'
];
require('./common');
angular.module('app', requires).config(function($routeProvider) {
customRouteProvider.when('/common', {templateUrl: 'js/common/1.html'});
customRouteProvider.otherwise({redirectTo: '/'});
});
Html code:
<div ng-controller="mapController">
<div id="map" style="height: 440px; border: 1px solid #AAA;"></div>
</div>
mapController:
module.exports = function ($scope, leafletData) {
var map = L.map( 'map', {
center: [20.0, 5.0],
minZoom: 2,
zoom: 2
});
L.tileLayer( 'http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors | Tiles Courtesy of MapQuest <img src="http://developer.mapquest.com/content/osm/mq_logo.png" width="16" height="16">',
subdomains: ['otile1','otile2','otile3','otile4']
}).addTo( map );
}
But when I execute the code leaflet breaks and my map looks like:
I tried also with angular-leaflet-directive with standard and it still breaks. Did anyone face this issue before? Any suggestions?
in your file Html code
test with change style div: height: 80vh;
<div ng-controller="mapController">
<div id="map" style="height: 80vh; border: 1px solid #AAA;"></div>
</div>
And check the initialization the component life cycle:
Angular 6 is ngOnInit.
Ionic is ionViewDidEnter.
The idea is that booklet loading is done after initialization of the component.
This problem often occurs due to resizing of any parent container while the map is already initialized.
This my solution in Angular 12 link
If you are having this issue on Vue3 you need to import the CSS:
<script>
import "leaflet/dist/leaflet.css";