Bootstrap tabs and Echarts - twitter-bootstrap-3

am having an issue with displaying my Echarts on the second tab. The chart is only displayed on the first tab but on navigation to the second tab it doesn't display
<ul class="nav nav-tabs" style="margin-bottom: 15px;">
<li class="active">
Campaigns
</li>
<li>
Subscribers
</li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="campaign">
<div id="pieChart" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
</div>
<div class="tab-pane fade" id="subscribers">
<div id="barChart" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
</div>
</div>
then hereis the js that displays the chart
var myChart = echarts.init(document.getElementById('pieChart'));
myChart.setTheme({color:['#6CC66C','#418BCA','#ff6600']});
pieChartOption = option = {
title : {
text: 'Campaign Analysis',
subtext: 'Jackpot',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient : 'vertical',
x : 'left',
data:['Sent','Pending','Not Delivered']
},
toolbox: {
show : true,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
magicType : {
show: true,
type: ['pie', 'funnel'],
option: {
funnel: {
x: '25%',
width: '50%',
funnelAlign: 'left',
max: 1548
}
}
},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : true,
series : [
{
name:'Access Source',
type:'pie',
radius : '55%',
center: ['50%', '60%'],
data:[
{value:{{ $no}}, name:'Sent'},
{value:135, name:'Pending'},
{value:155, name:'Not Delivered'}
]
}
]
};
myChart.setOption(pieChartOption);
/*######################### BARCHART ##################################*/
var myBarChart = echarts.init(document.getElementById('barChart'));
var barChartOption = {
title: {
text: '某地区蒸发量和降水量',
subtext: '纯属虚构'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['2014', '2015']
},
toolbox: {
show: true,
feature: {
mark: {
show: true
},
dataView: {
show: true,
readOnly: false
},
magicType: {
show: true,
type: ['line', 'bar']
},
restore: {
show: true
},
saveAsImage: {
show: true
}
}
},
calculable: true,
xAxis: [{
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
}],
yAxis: [{
type: 'value'
}],
series: [{
name: '2014',
type: 'bar',
data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
}, {
name: '2015',
type: 'bar',
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
}]
};
myBarChart.setOption(barChartOption);
/*######################### BARCHART ##################################*/
$(function() {
$( "#tabs" ).tabs({
select: function(event, ui) {
console.log('Calling chart.invalidateSize()');
chart.invalidateSize();
}
});
What cud be the solution to this?
});

ECharts documentation has mentioned
Sometimes charts may be placed in multiple tabs. Those in hidden labels may fail to initialize due to the ignorance of container width and height. So resize should be called manually to get the correct width and height when switching to the corresponding tabs, or specify width/heigth in opts explicitly.
So every time you switch to a new tab, just call the resize function on the chart instance:
chartInstance.resize()

The answer is a little late and I am not sure if you found a solution, but the resolution to this would be a combination of echarts setOption and Bootstrap's Tab event.
Like-
$('#myTabItem').on('shown.bs.tab', function (e) {
myChart.setOption(options);
})
The above code will reload the chart mychart using echarts setOption callback as soon as the Bootstrap Tab is shown. More info on Bootstrap Tab events can be found here.

Related

How to remove active classes from all buttons before making another one active?

I'm new to vue, I still don't understand everything, tell me. I have buttons that I display through v-for, I need to get the active class of only one button when pressed, all the others need to be turned off, tell me, preferably visually, how can I do it better?
I am using the method activeBtn, but this doesn't turn off the active class from the previous buttons
activeBtn(event, index) {
this.buttons[index].isActive = !this.buttons[index].isActive;
<script>
data() {
return {
buttons: [
{
label: "A",
isActive: false,
type: "border-left",
name: "BorderLeftComonent",
},
{
label: "A",
isActive: false,
type: "text-balloon",
name: "TextBalloonComponent"
},
{
label: "A",
isActive: false,
type: "dashed",
name: "DashedComponent"
},
],
};
},
methods: {
activeBtn(event, index) {
this.buttons[index].isActive = !this.buttons[index].isActive;
}
</script>
<template>
<div id="btn-box">
<button
v-for="(button, index) in buttons"
:key="index"
:class="button.isActive ? 'on' : 'off'"
#click="component = button.name, activeBtn($event, index)">
<div :class="`btn btn-${button.type}`">{{ button.label }}</div>
</button>
</div>
</template>
Since you only want to get one active button at any one point, it doesn't make sense to manage the active state inside each button.
Instead, you should manage it at group level by storing the currently selected button's id. A button would then be active when its id matches the currently selected id.
Here's an example:
new Vue({
el: '#app',
data: () => ({
buttons: [
{
id: "button-1",
label: "A",
type: "border-left",
name: "BorderLeftComonent"
},
{
id: "button-2",
label: "A",
type: "text-balloon",
name: "TextBalloonComponent"
},
{
id: "button-3",
label: "A",
type: "dashed",
name: "DashedComponent"
}
],
activeButtonId: "button-1"
}),
methods: {
activate(id) {
this.activeButtonId = id;
}
}
})
.on {
background-color: red
}
.off {
background-color: blue
}
.on, .off {
color: white
}
<script src="https://unpkg.com/vue#2/dist/vue.min.js"></script>
<div id="app">
<div>
<button
v-for="{id, type, label} in buttons"
:key="id"
:class="activeButtonId === id ? 'on' : 'off'"
#click="activate(id)"
>
<div :class="`btn btn-${type}`" v-text="label" />
</button>
</div>
</div>

Google Maps showing grey box in Vue modal

I have a <b-modal> from VueBootstrap, inside of which I'm trying to render a <GmapMap> (https://www.npmjs.com/package/gmap-vue)
It's rendering a grey box inside the modal, but outside the modal it renders the map just fine.
All the searching I've done leads to the same solution which I'm finding in some places is google.maps.event.trigger(map, 'resize') which is not working. Apparently, it's no longer part of the API [Source: https://stackoverflow.com/questions/13059034/how-to-use-google-maps-event-triggermap-resize]
<template>
<div class="text-center">
<h1>{{ title }}</h1>
<div class="row d-flex justify-content-center">
<div class="col-md-8">
<GmapMap
ref="topMapRef"
class="gmap"
:center="{ lat: 42, lng: 42 }"
:zoom="7"
map-type-id="terrain"
/>
<b-table
bordered
dark
fixed
hover
show-empty
striped
:busy.sync="isBusy"
:items="items"
:fields="fields"
>
<template v-slot:cell(actions)="row">
<b-button
size="sm"
#click="info(row.item, row.index, $event.target)"
>
Map
</b-button>
</template>
</b-table>
<b-modal
:id="mapModal.id"
:title="mapModal.title"
#hide="resetInfoModal"
ok-only
>
<GmapMap
ref="modalMapRef"
class="gmap"
:center="{ lat: 42, lng: 42 }"
:zoom="7"
map-type-id="terrain"
/>
</b-modal>
</div>
</div>
</div>
</template>
<script>
// import axios from "axios";
import { gmapApi } from 'gmap-vue';
export default {
name: "RenderList",
props: {
title: String,
},
computed: {
google() {
return gmapApi();
},
},
updated() {
console.log(this.$refs.modalMapRef);
console.log(window.google.maps);
this.$refs.modalMapRef.$mapPromise.then((map) => {
map.setCenter(new window.google.maps.LatLng(54, -2));
map.setZoom(2);
window.google.maps.event.trigger(map, 'resize');
})
},
data: function () {
return {
items: [
{ id: 1, lat: 42, long: 42 },
{ id: 2, lat: 42, long: 42 },
{ id: 3, lat: 42, long: 42 },
],
isBusy: false,
fields: [
{
key: "id",
sortable: true,
class: "text-left",
},
{
key: "text",
sortable: true,
class: "text-left",
},
"lat",
"long",
{
key: "actions",
label: "Actions"
}
],
mapModal: {
id: "map-modal",
title: "",
item: ""
}
}
},
methods: {
// dataProvider() {
// this.isBusy = true;
// let promise = axios.get(process.env.VUE_APP_LIST_DATA_SERVICE);
// return promise.then((response) => {
// this.isBusy = false
// return response.data;
// }).catch(error => {
// this.isBusy = false;
// console.log(error);
// return [];
// })
// },
info(item, index, button) {
this.mapModal.title = `Label: ${item.id}`;
this.mapModal.item = item;
this.$root.$emit("bv::show::modal", this.mapModal.id, button);
},
resetInfoModal() {
this.mapModal.title = "";
this.mapModal.content = "";
},
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1 {
margin-bottom: 60px;
}
.gmap {
width: 100%;
height: 300px;
margin-bottom: 60px;
}
</style>
Does anyone know how to get the map to display properly in the modal?
Surely, I'm not the first to try this?
Had this problem, in my case it was solved by providing the following options to google maps:
mapOptions: {
center: { lat: 10.365365, lng: -66.96667 },
clickableIcons: false,
streetViewControl: false,
panControlOptions: false,
gestureHandling: 'cooperative',
mapTypeControl: false,
zoomControlOptions: {
style: 'SMALL'
},
zoom: 14
}
However you can probably make-do with just center and zoom.
Edit: Try using your own google maps components, follow this tutorial:
https://v2.vuejs.org/v2/cookbook/practical-use-of-scoped-slots.html#Base-Example
You can use the package described in the tutorial to load the map, dont be scared by the big red "deprecated" warning on the npm package page.
However for production, you should use the package referenced by the author, which is the one backed by google:
https://googlemaps.github.io/js-api-loader/index.html
The only big difference between the two:
The 'google' object is not returned by the non-deprecated loader, it is instead attached to the window. See my answer here for clarification:
'google' is not defined Using Google Maps JavaScript API Loader
Happy coding!

Adding img attribute to options in b-select component

I would like to add HTML img attribute to the b-form-select component of boostrap-vue inside to load img with each option?
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: null, text: 'Please select some item' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Default Selected Option' },
{ value: 'c', text: 'This is another option' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
It seems bootstrap-vue and bootstrap have different implementations on select components. And bootstrap-vue doesn't support thumbnails and it uses native select and options elements which makes impossible to set background image. Instead you can emulate dropdown component like select as below :
Template
<template>
<div class="hello">
<div class="back"></div>
<b-dropdown :text="selected ? selected.text : 'Please select some item'">
<b-dropdown-item
:disabled="option.disabled"
#click="select(option)"
v-for="option in options"
:key="option.value"
>
<div>
<img :src="option.src">
{{option.text}}
</div>
</b-dropdown-item>>
</b-dropdown>
</div>
</template>
Component
export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
selected: null,
options: [
{
value: null,
text: "Please select some item",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "a",
text: "This is First option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "b",
text: "Default Selected Option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "c",
text: "This is another option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "d",
text: "This one is disabled",
disabled: true,
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
}
]
};
},
methods: {
select(option) {
console.log(option);
this.selected = option;
}
}
};
Sandbox
Just like Bootstraps's custom select component BootstrapVue's <b-form-select> is based on <select>, which by HTML5 standards does not support complex HTML content in <option> elements.
If you need complex content (i.e. images, etc) in the options, you would need to create a custom component (probably based on <b-dropdpwn>) that allows you to use custom HTML5 in the "options" (dropdown items) and emulate the native select features.

How do I pass custom options into chartjs

I'm trying to be able to add notes to my charts but i'm stuck on how I would pass my individual photon object into my chartOptions variable to be used in the tooltips label function?
<template>
<swiper-slide v-for="(photon,key) in $store.state.photons" :key='key'>
<line-chart width="80vw" :dataset="dataset" :library="chartOptions" class="animated slideInLeft delay-0.01s"
v-else :data="photon.data.rbChannel" ytitle="R/B Channel" :download="true"></line-chart>
<line-chart width="80vw" :dataset="dataset" :library="chartOptions" class="animated slideInRight delay-0.01s"
v-else :data="photon.data.tempF" ytitle="Temperature F" :colors="['#ff0000']" :download="true"></line-chart>
</swiper-slide>
</template>
chartOptions variable
chartOptions: {
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
console.log(data.labels[tooltipItem.index])
console.log(tooltipItem)
return data.labels[tooltipItem.index]
}
}
},
height: '400px',
pan: {
enabled: false,
mode: 'xy',
},
zoom: {
enabled: true,
mode: 'x',
},
drag: true,
gridLines: {
zeroLineColor: "rgba(0,255,0,1)"
}
}

Vue sending data to other components is one step behind

Sorry for my bad english this isn't my main language, also sorry for the markup!!
Hi im trying to send data from my parent component to the child components. The idea behind this, is so that i can use a specifik color for every component. This color is declared in the parent component in the routers array. But the data sended to the component was from the previous one, so it sends to color which was previously stored in routerColor.
<template>
<div class="flex" id="app">
<quick-acces>
</quick-acces>
<nav>
<router-link v-for="(router, index) in routers" class="nav-item" :to="{name:router.name, params: {routerColor}}" :style="{background: router.color}" #click.native="changeBorderColor(router.color)" v-bind:key="index">{{router.label}}</router-link>
</nav>
<main :style="{border: currentBorder}">
<router-view class="router-view">
</router-view>
</main>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
routers: [
{
name: 'ToDo',
link: '/to-do-list',
label: "To do list",
color: "#F9BE02"
},
{
name: 'Daily',
link: '/dailyplanner',
label: "Daily Planner",
color: "#F53240"
},
{
name: 'Projects',
link: '/projects',
label: "Projects",
color: "#02C8A7"
},
{
name: 'Steps',
link: '/function-steps',
label: "Steps",
color: "#2E302C"
},
{
name: 'Timer',
link: '/timer',
label: "Timer",
color: "#8FC33A"
},
{
name: 'Test',
link: '/test',
label: "Test",
color: "orange"
}
],
routerColor: "",
openTab: this.routers,
currentBorder: ""
}
},
methods: {
changeBorderColor: function(color){
this.routerColor = color
console.log(this.routerColor)
this.currentBorder = "3px solid" + color
},
I modified your code so I could make a snippet that runs.
I found that clicking the "orange" strip would update the color, but the border color did not show up until you clicked another color. I saw that you build the border color string without a space after "color", so when it built the string with "orange", it would be 3px solidorange, which does not work. Other colors were ok, because 3px solid#F9BE02 parses.
So I think your problem is just putting in a space after "color".
new Vue({
el: '#app',
data() {
return {
routers: [{
name: 'ToDo',
link: '/to-do-list',
label: "To do list",
color: "#F9BE02"
},
{
name: 'Daily',
link: '/dailyplanner',
label: "Daily Planner",
color: "#F53240"
},
{
name: 'Projects',
link: '/projects',
label: "Projects",
color: "#02C8A7"
},
{
name: 'Steps',
link: '/function-steps',
label: "Steps",
color: "#2E302C"
},
{
name: 'Timer',
link: '/timer',
label: "Timer",
color: "#8FC33A"
},
{
name: 'Test',
link: '/test',
label: "Test",
color: "orange"
}
],
routerColor: "",
openTab: this.routers,
currentBorder: ""
}
},
methods: {
changeBorderColor: function(color) {
this.routerColor = color
// I added a space after "solid"
this.currentBorder = "3px solid " + color
}
},
components: {
routerLink: {
props: {
to: Object
},
template: '<div>X{{to.params.routerColor}}</div>'
},
routerView: {
template: '<div>V</div>'
}
}
});
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div class="flex" id="app">
<router-link v-for="(router, index) in routers" class="nav-item" :to="{name:router.name, params: {routerColor}}" :style="{background: router.color}" #click.native="changeBorderColor(router.color)" v-bind:key="index">{{router.label}}</router-link>
<main :style="{border: currentBorder}">
<router-view class="router-view">
</router-view>
</main>
</div>