QML Chart interactive - charts

I have a pie chart created dynamically, that uses function createPieChart() described below. When a slice is clicked, I want to call a function to print out the label and value of that slice.
I am facing 2 problems:
Although I connect "clicked" or "pressed" or "released" signals, the slot is not reached. I am using qtcharts 2.0 (I cannot update right now).
I am able to connect "hovered" signal, but without passing any parameter, so I don't know what slice I am into.
These are the other functions:
function createPieChart(data){
pieserieschart.clear();
slices.splice(0, slices.length) //clear slices array
for (var prop in data) {
slices.unshift(pieserieschart.append(prop, data[prop]));
//I get "Cannot read property 'label' of undefined using this method
slices[0].hovered.connect(function(){mouseHoverSlice(slices[0].label));
//WORKS, but I want to pass the label of that slice (and the value if possible)
slices[0].hovered.connect(mouseHoverSlice);
//it is not working at all
slices[i].clicked.connect(sliceClicked);
}
function sliceClicked(){
console.log("Slice Clicked"); //I cannot see this printed
}
function mouseHoverSlice(info){
console.log("Slice hover: " + info);
}
Any idea of how to do it? Thanks!

After upgrade to QtCharts 2.2 I was able to solve it like this:
For pie & line & scatter plots, I used onClicked, which returns the slice/point. So you don't need to connect any signal when creating the slices or points dynamically.
For bar charts, I was able to connect the barset created
var barvalues = barserieschart.append("label",values)
barvalues.clicked.connect(barClicked)
...
ChartView {
PieSeries {id: pieserieschart; onClicked: sliceClicked(slice) }
BarSeries {id: barserieschart }
ScatterSeries{id: scatterserieschart; onClicked: scatterclicked(point)}
}

Related

Section Views displays based on checkbox selection, how to draw Google Charts with good legend?

So I have read you can't draw nice Google Charts when the div's are hidden, somehow the legend is way off.
Now I am trying some solutions I have found here, but none of them seems to work. I am using this as last part of my draw Chart function
var container = document.getElementById("chart1");
container.style.display = null;
var chart = new google.visualization.PieChart(container);
chart.draw(data, options);
and my Google Chart calls
// Section1
google.charts.setOnLoadCallback(drawA1);
google.charts.setOnLoadCallback(drawA2);
google.charts.setOnLoadCallback(drawA3);
google.charts.setOnLoadCallback(drawa4);
google.charts.setOnLoadCallback(drawA5);
//Section2
google.charts.setOnLoadCallback(drawB1);
google.charts.setOnLoadCallback(drawB2);
google.charts.setOnLoadCallback(drawB3);
google.charts.setOnLoadCallback(drawB4);
// Section3
google.charts.setOnLoadCallback(drawC1);
google.charts.setOnLoadCallback(drawC2);
google.charts.setOnLoadCallback(drawC3);
google.charts.setOnLoadCallback(drawC4);
google.charts.setOnLoadCallback(drawC5);
google.charts.setOnLoadCallback(drawC6);
On page load all sections are hidden and this is the function which show hides section views based on checkboxes selected
// Show / Hide Section Views
$("input[name='section_view[]']:checked").each(function ()
{
var inputValue = $(this).attr("value");
$("#section_view" + inputValue).toggle();
$("#menuItemSection" + inputValue).toggle();
});
What else can I try so the google charts are drawn as expected???
ps: I am trying out How to fix overlapping Google Chart legend for my situation, but no luck at the moment
first, setOnLoadCallback only needs to be called once per page load
but you can use the promise the load statement returns instead
in addition, the load statement will wait for the page to load before returning the promise
as such, google.charts.load can be used in place of --> $(document).ready (or similar method)
recommend replacing "on page load" function with google.charts.load
move all the page load stuff there
and when the promise is returned, you can start drawing charts without --> setOnLoadCallback
when section is made visible, use the toggle's complete option to know when toggle is done
(just provide a function)
then draw the chart
you can probably use inputValue to know which chart to draw
see following example...
// replace $(document).ready with the following
google.charts.load('current', {
packages: ['corechart']
}).then(function () { // <-- promise function returned
// move on page load stuff here
// move draw chart functions here...
$("input[name='section_view[]']:checked").each(function ()
{
var inputValue = $(this).attr("value");
$("#section_view" + inputValue).toggle(function () {
$("#menuItemSection" + inputValue).toggle(function () {
// draw chart
switch (inputValue) {
case 'A1':
drawA1();
break;
case 'B1':
drawB1();
break;
// etc...
}
});
});
});
});

leafeltjs (mapbox) z-index ordering not working

Another developer created our original map but I'm tasked with making some changes. One of these is making sure the activated marker is brought to the front when clicked on (where it is partially overlapped by other markers).
The developers have used mapbox 2.2.2.
I have looked at leafletjs's docs, have followed some instructions on other posted solutions (e.g. solution one and solution two). Neither of these makes any difference.
Examining the marker in Chrome's console I can see the value of options.zIndexOffset is being set (10000 in my test case). I've even set _zIndex to an artificially high value and can see that reflected in the marker's data structure. But visually nothing is changing.
This is how the map is set up initially. All features are from a single geojson feed:
L.mapbox.accessToken = '<access token here>';
var map = L.mapbox.map('map', 'map.id', {
}).setView([37.8, -96], 3);
var jsonFeed, jsonFeedURL;
var featureLayer = L.mapbox.featureLayer()
.addTo(map)
.setFilter(function (f) {
return false;
});
$.getJSON(jsonFeedURL, function (json) {
jsonFeed = json;
jsonFeedOld = json;
// Load all the map features from our json file
featureLayer.setGeoJSON(jsonFeed);
}).done(function(e) {
// Once the json feed has loaded via AJAX, check to see if
// we should show a default view
mapControl.activateInitialItem();
});
Below is a snippet of how I had tried setting values to change the z-index. When a visual marker on the featureLayer is clicked, 'activateMarker' is called:
featureLayer.on('click', function (e) {
mapControl.activateMarker(e);
});
The GEOjson feed has urls for the icons to show, and the active marker icon is switched to an alternative version (which is also larger). When the active feature is a single Point I've tried to set values for the marker (lines commented out, some of the various things I've tried!)
activateMarker: function (e) {
var marker = e.layer;
var feature = e.layer.feature;
this.resetMarkers();
if (feature.properties.hasOwnProperty('icon')) {
feature.properties.icon['oldIcon'] = feature.properties.icon['iconUrl'];
feature.properties.icon['iconUrl'] = feature.properties.icon['iconActive'];
feature.properties.icon['oldIconSize'] = feature.properties.icon['iconSize'];
feature.properties.icon['iconSize'] = feature.properties.icon['iconSizeActive'];
}
if (feature.geometry.type == 'Point') {
marker.setZIndexOffset(10001);
marker.addTo(featureLayer);
}
//featureLayer.setGeoJSON(jsonFeed);
}
Any advice would be greatly appreciated! I'm at the point where I don't know what else to try (and that's saying something).
What probably happens is that you just flush your markers with the last call to .setGeoJSON():
If the layer already has features, they are replaced with the new features.
You correctly adjust the GeoJSON data related to your icon, so that when re-created, your featureLayer can use the new values to show a new icon (depending on how you configured featureLayer).
But anything you changed directly on the marker is lost, as the marker is removed and replaced by a new one, re-built from the GeoJSON data.
The "cleanest" way would probably be to avoid re-creating all features at every click.
Another way could be to also change something else in your GeoJSON data that tells featureLayer to build your new marker (through the pointToLayer option) with a different zIndexOffset option.

sap.m.TileContainer scrollIntoView issue

I have an XML view that contains a TileContainer which is bound to a model that is used to create StandardTiles. The XML snippet is:
<TileContainer id="tilelist" tiles="{Applications}">
<tiles>
<StandardTile name="{ID}" icon="{Icon}" title="{Name}" press="doNavigation" info="{Description}"
number="{path : 'Number', formatter: 'linxas.com.fiori.launchpad.util.Formatter.formatUsingURL'}"
numberUnit="{NumberUnit}"/>
</tiles>
</TileContainer>
This is working perfectly, the correct tiles are getting displayed etc. When I click on a tile, there is navigation that occurs and I want to "remember" which tile was clicked (by index) so when returning I can scroll to that tile. This is done on the tile's press event handler (doNavigation function) and stores the index in sessionStorage. This is also working properly.
doNavigation : function (evt) {
if (sessionStorage && this.getView().byId('tilelist')) {
sessionStorage.setItem("selected_tile", this.getView().byId('tilelist').indexOfTile(evt.getSource()));
}
...
}
The proper value is stored. So when navigating back, within the onAfterRendering function of the page that contains the TileContainer I have the following code. It is attempting to see if there is a "selected_tile" value stored in sessionStorage, if so it calls scollIntoView passing in the tile index. The issue is that this code is executed, but doesn't work and I suspect it is because at the time of calling this function, the TileContainer's tiles aggregation is returning 0 length.
onAfterRendering : function (evt) {
var theList = this.getView().byId("tilelist");
if (sessionStorage && theList) {
var tile_index = sessionStorage.getItem("selected_tile");
console.log(tile_index + " of " + theList.getTiles().length);
if (tile_index) {
theList.scrollIntoView(+tile_index, true);
sessionStorage.removeItem("selected_tile");
}
}
}
My console output looks something like this (based on the tile that was clicked):
5 of 0
Any help would be appreciated. I assume that there is somewhere else that I need to execute this last bit of code as the TileContainer does not seem to be finished processing its tiles at this point, at least that is my assumption of why the tiles aggregation is 0.
Are you using Routing in your project?
If yes, you can try to register a method to handle the routePatternMatched event of the router. This method will be called after the onAfterRendering method - if the proper route pattern is matched.
To achieve this, just create the following:
onInit: function() {
sap.ui.core.UIComponent.getRouterFor(this).getRoute("NameOfYourCurrentRoute").attachPatternMatched(this._routePatternMatched, this);
},
_routePatternMatched: function(oEvent) {
//do your stuff here
},
Hopefully the TileList is ready at this point to navigate to the correct tile.

How to scroll on multiple AmCharts simultaneously?

I just started using AmCharts and have setup two line plots, one on top of the other, with their respective scrollbars.
Now, I want to "link" the scrollbars of both plots, so that if I move the scrollbar on the chart1, I'll get the same date range on the chart2. I imagine this shouldn't be too difficult with a listener, a get value function and a set value function, but I'm unable to find how to get the start/end values of the scrollbar so that I can play with them.
Any help would be appreciated.
thanks
There is a demo for this in the AmCharts Knowledge Base
https://www.amcharts.com/kbase/share-scrollbar-across-several-charts/
This is the code that is syncing the scrollbars, (I have added the annotations):
Create an array to populate with your charts
var charts = [];
Create how ever many charts you need
charts.push(AmCharts.makeChart("chartdiv", chartConfig));
charts.push(AmCharts.makeChart("chartdiv2", chartConfig2));
charts.push(AmCharts.makeChart("chartdiv3", chartConfig3));
Iterate over the charts, adding an event listener for "zoomed" which will share the event handler
for (var x in charts) {
charts[x].addListener("zoomed", syncZoom);
}
The event handler
function syncZoom(event) {
for (x in charts) {
if (charts[x].ignoreZoom) {
charts[x].ignoreZoom = false;
}
if (event.chart != charts[x]) {
charts[x].ignoreZoom = true;
charts[x].zoomToDates(event.startDate, event.endDate);
}
}
}

iScroll: Track Y Coordinate to addClass on Scroll

When I log myScroll.y and myScrollPagesY, I get this:
var myScroll;
function loaded() {
myScroll = new iScroll('wrapper', {
snap: 'div',
momentum: false});
console.log(myScroll.y);
console.log(myScroll.pagesY);
}
Output:
0
0, -422, -465
So, the default numerical value is 0, but while I scroll I don't see the number change in the console.
Do I have to somehow incorporate the iScroll refresh(); method to constantly update the Y coordinate?
How would I write an if statement that basically said:
if myScroll.y = a certain number then add the class "selected" to the nav button.
Basically, as you are scrolling down the page I want the nav bar at the top to highlight when you hit a new section.
Thanks in advance!
You can use the onScrollMove-event. Attach a method to this iScroll-property. The first argument is the scrollerobject. Now read the y-value.
function onScrollMove(scroller, e) {
//read scroller.y or scroller.currPageY, or whatever property you want to use :)
};