anychart ganttResource how to change range/zoom on the fly - anychart

I use anychart.ganttResource ()
Currently, I limit the timeline of my data by setting a range outside of Gantt, which controls the period I get data from - and I have chart.zoomTo ("week", 2, "firstDate"). This works fine, but now my client want to be able to "zoom" in the chart.
I can see that this is possible using maps, but I can not find anything similar in Gantt. Ideally I would like a slider which could control the zoom or something like zoomOnMouseWheel, but I don't know if this is posible at all.

Zooming with mouseWheel events is possible with some code tricks. I have prepared an example for you, please check it.
anychart.onDocumentReady(function (){
// data tree settings
var treeData = anychart.data.tree(data, "as-table");
// chart type
var chart = anychart.ganttResource();
// chart position
chart.bounds(0, 0, "100%", "100%");
// chart data
chart.data(treeData);
// data tree width
chart.splitterPosition(170);
var dataGrid = chart.dataGrid();
// settings for first column
dataGrid.column(0).width(30).title().text("#");
// settings for the second column
dataGrid.column(1).width(140).format(function(item) {
return item.get("name");
}).title().text("Person");
// chart container
chart.container("container").draw();
//zooming feature
var zoomingCoef = 1;
var isPreviousNegative = true;
//mouse wheel listener
$("#container").on('wheel', function(e){
e.preventDefault();
e.stopImmediatePropagation();
//define the zoomingCoef
if(e.originalEvent.deltaY > 0 ^ isPreviousNegative) {
zoomingCoef -= e.originalEvent.deltaY/10;
} else {
zoomingCoef =1;
}
//zoomIn or zoomOut
if(e.originalEvent.deltaY < 0) {
chart.zoomIn(zoomingCoef);
isPreviousNegative = true;
} else {
chart.zoomOut(zoomingCoef);
isPreviousNegative = false;
}
});
});
// data
var data = [
{
"id": "1",
"name": "Phase 1 - Strategic Plan",
"periods": [
{"id": "1_1", "start": 1171468800000, "end": 1171987200000, "fill": "green"}]
},
{
"id": "2",
"name": "Self-Assessment",
"periods": [
{"id": "2_1", "start": 1173024000000, "end": 1173715200000, "fill": "yellow"}]
},
{
"id": "3",
"name": "Define business vision",
"periods": [
{"id": "3_1", "start": 1169740800000, "end": 1170172800000, "fill": "green"}]
},
{
"id": "4",
"name": "Identify available skills, information and support",
"periods": [
{"id": "4_1", "start": 1171814400000, "end": 1172419200000, "fill": "green"}]
},
{
"id": "5",
"name": "Decide whether to proceed",
"periods": [
{"id": "5_1", "start": 1171296000000, "end": 1171382400000, "fill": "green"}]
},
{
"id": "6",
"name": "Define the Opportunity",
"periods": [
{"id": "6_1", "start": 1173628800000, "end": 1174320000000, "fill": "green"}]
}
];
html, body, #container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
<link href="https://cdn.anychart.com/releases/8.1.0/css/anychart-ui.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="https://cdn.anychart.com/releases/8.1.0/js/anychart-bundle.min.js"></script>
<div id="container"></div>

Related

Amchart's Serial Chart page gets freezed when used in Ionic

I am using Amchart's serial chart in ionic framework. I have rendered the serial chart using
var chart = AmCharts.makeChart("chartdiv",
{
"type": "serial",
"categoryField": "Name",
"rotate": true,
"angle": 30,
"depth3D": 40,
"startDuration": 1,
"fontSize": 10,
"theme": "default",
"precision": 4,
"creditsPosition": "bottom-right",
"responsive": {
"enabled": true
},
"categoryAxis": {
"gridPosition": "middle",
"title": "Name",
"inside": true
},
"graphs": [
{
"balloonText": "[[title]] of [[Name]]:[[value]]",
"fillAlphas": 1,
"id": "AmGraph-1",
"title": "X",
"type": "column",
"valueField": "X"
},
{
"balloonText": "[[title]] of [[Name]]:[[value]]",
"fillAlphas": 1,
"id": "AmGraph-2",
"title": "Y",
"type": "column",
"valueField": "Y"
},
{
"balloonText": "[[title]] of [[Name]]:[[value]]",
"fillAlphas": 1,
"id": "AmGraph-3",
"title": "Z",
"type": "column",
"valueField": "Z"
}
],
"valueAxes": [
{
"id": "ValueAxis-1",
"title": "Amount"
}
],
"titles": [
{
"id": "Title-1",
"text": "SUMMARY"
}
],
"legend": {
"enabled": true,
"useGraphSettings": true,
"position": "bottom"
},
"dataProvider": $scope.data,
"listeners": [{
"event": "clickGraphItem",
"method": function (event) {
$scope.SelectedX = event.item.category;
$scope.SelectedContext = event.item.dataContext;
$scope.LoadDetailsData($scope.SelectedX, $scope.SelectedContext.Period);
}
}]
}
);
chart.addListener("dataUpdated", zoomChart);
zoomChart();
function zoomChart() {
chart.zoomToIndexes(0, chart.dataProvider.length - (chart.dataProvider.length - 3));
}
I am opening IonicModal on click of graph items and creating another chart. When I close the IonicModal, page which contains the above chart gets freezed untill I press hardware back button.
I am using pie charts few places but not facing this issue on those pages. It seems there is some issue with the serial chart only.
Using IonicModal from template URL option to open Modal -
$ionicModal.fromTemplateUrl('template.html', { scope: $scope })
.then(function (modal) {
$scope.sortModal = modal;
});
$scope.sortShow = function () {
//alert('inside show');
$timeout(function () {
$scope.sortModal.show();
$scope.LoadDetailsChart(); //creating next chart data
}, 0);
};
$scope.sortClose = function () {
$scope.sortModal.hide();
};
$scope.$on('$destroy', function () {
$scope.sortModal.remove();
});
I just need to add paneventenabled property as false here. As per amcharts docs,
This setting affects touch-screen devices only. If a chart is on a page, and panEventsEnabled are set to true, the page won't move if the user touches the chart first. If a chart is big enough and occupies all the screen of your touch device, the user won’t be able to move the page at all. That's why the default value is "false". If you think that selecting/panning the chart or moving/pinching the map is a primary purpose of your users, you should set panEventsEnabled to true.

Dynamic form using AngularJS, multiple values binding

I am looking for a best approach to convert a static form to an angular dynamic form. I am not sure how to bind multiple values to the same answer.
The static page is available at: https://jsfiddle.net/hvuq5h46/
<div ng-repeat="i in items">
<select ng-model="i.answer" ng-options="o.id as o.title for o in i.answersAvailable" ng-visible="y.TYPE = 'SINGLE'"></select>
<input type="checkbox" ng-model="i.answer" ng-visible="y.TYPE = 'MULTIPLE'" />
</div>
The JSON file
[
{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [
{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
Things would be much simpler if you can use a multiple select, but I understand it might be difficult for user to interact (consider something like md-select, which transforms multiple select into a list of checkbox for you)
Multiple select:
<select multiple
ng-model="i.answer"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"></select>
Anyway it is completely ok to use HTML checkbox. To do that we would need to bind checkbox model into the data as usual, and then update the answer array simultaneously.
ng-model="o.selected"
ng-change="updateAnswer(i)"
Also, we'll need to copy existing data to model during init.
ng-init="initMultiple(i)"
Working code:
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.items = [{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
$scope.initMultiple = function(item) {
item.answersAvailable.forEach(function(option) {
option.selected = item.answer.indexOf(option.id) != -1;
});
}
$scope.updateAnswer = function(item) {
item.answer = item.answersAvailable.filter(function(option) {
return option.selected;
})
.map(function(option) {
return option.id;
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<div ng-repeat="i in items">
<select ng-model="i.answer[0]"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'SINGLE'"></select>
<label ng-repeat="o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"
ng-init="initMultiple(i)">
<input type="checkbox"
ng-model="o.selected"
ng-change="updateAnswer(i)" /> {{o.title}}
</label>
<div>{{i.answer}}</div>
</div>
</div>
Based on my experience, I will make a separation as two Angular models (or usually called services) for the form questions and another one which will collect the answers and eventually will be passed to the backend for further processing. This will provide me a flexibility to maintain both logic and presentation.
var myModule = angular.module('myModule', []);
myModule.factory('QuestionsFormService', function() {
var _question1;
var _question2;
var _question3;
function init(data){
//questions initiation
}
return init;
});
var myModule = angular.module('myModule', []);
myModule.factory('FormDataService', function() {
var _dataAnswer = {}
function init(){
//data initialization
}
function insertData(key, value){
_dataAnswer[key] = value
}
return init;
});
From the example of service models above, you need to make these available to your presentation through the Angular controller with Dependency Injection.
myModule.controller("MyCtrl", function($scope, FormDataService, QuestionsFormService) {
$scope.form_questions = QuestionsFormService.init();
$scope.form_answers = FormDataService.init()
//further logic to make these available on your view on your convenience
});
What you write on the HTML page as an Angular view is already close enough. You only need to change the binding to two models as I propose above. Thank you.

How can I change the attribute in dataset of Fusionchart?

Hi I am implementing a chart in my Angularjs Application, You can see this plunker http://jsfiddle.net/fusioncharts/73xgmacm/ The thing which I want to achieve is to change the value attribute to profit. How can I do this ? I want to display profit not values.
Regards
After 2 days I finally find out the answer. The thing is You cannot change the Fusionchart attribute value but you can change the attribute of your API once you fetched. I used a loop after I fetched the API and replace the 'profit' attribute with value in this way I made the chart. Yes The thing which i had been ignoring was the use of 'variable' instead of scope. If you see this example you would understand Example Here. I am sharing my code May be it helps someone else too.
Give below is my json array which i called tps.json
[
{
"index": "1",
"variantoption": "fan-green",
"company": "sk fans",
"quantity": "650",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "2",
"variantoption": "fan-white",
"company": "al ahmed fans",
"quantity": "450",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "3",
"variantoption": "fan-purple",
"company": "asia fans",
"quantity": "350",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "4",
"variantoption": "fan-yellow",
"company": "falcon fans",
"quantity": "250",
"profit": "78296",
"loss": "8457",
"year": "2016"
}
]
and here is my controller
$http.get('js/tps.json').success(function (data) {
var chartdata = data;
var arrLength = chartdata.length;
console.log(arrLength);
for (var i = 0; i < arrLength; i++) {
if (chartdata[i]['profit'] && chartdata[i]['index']) {
chartdata[i].value = chartdata[i].profit;
delete chartdata[i].profit;
chartdata[i].label = chartdata[i].index;
delete chartdata[i].index;
console.log(chartdata);
}
}
console.log(chartdata);
FusionCharts.ready(function () {
var tps = new FusionCharts({
type: 'column2d',
renderAt: 'chart-container',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Monthly",
"xaxisname": "Month",
"yaxisname": "Revenue",
"numberprefix": "$",
"showvalues": "1",
"animation": "1"
},
"data" : chartdata
}
});
tps.render();
});
}
);
}
-Stay foolish stay hungry

mapbox-gl.js with PGRestAPI vector tile(pbf)

I have own vector tile from PGRestAPI, url like below
"http://192.168.1.4:3001/services/postgis/cleantech2/geom/vector-tiles/{z}/{x}/{y}.pbf"
and I try use mapbox-gl.js to render the map, but nothing display.
I am doing wrong? thx
var style = {
"version": 8,
"sources": {
"countries": {
"type": "vector",
"tiles": ["http://192.168.1.4:3001/services/postgis/cleantech2/geom/vector-tiles/{z}/{x}/{y}.pbf"],
"maxzoom": 6
}
},
"glyphs": location.origin+location.pathname+"font/{fontstack}/{range}.pbf",
"layers": [{
"id": "background",
"type": "background",
"paint": {
"background-color": "#ddeeff"
}
},{
"id": "country-glow-outer",
"type": "line",
"source": "countries",
"source-layer": "country",
"layout": {
"line-join":"round"
}
}]
};
var init_lat = 1.3552799//42.299228067198634;
var init_lng = 103.6945413;//-83.69717033229782;
mapboxgl.accessToken = 'mapbox-token';
var map = new mapboxgl.Map({
container: 'map',
style: style,
center: [init_lng,init_lat],
zoom: 15
});
edit 1:
after debug mapbox-gl-js code, now can see several circles. I modify the style, the source-layer name from pbf must be correct.
but not display all the points, it seems filtered?
var style = {
"version": 8,
"sources": {
"cleantech": {
"type": "vector",
// "url": "mapbox://map-id"
// "url": "http://tileserver.com/layer.json",
"tiles": ["http://192.168.1.4:3001/services/postgis/cleantech2/geom/vector-tiles/{z}/{x}/{y}.pbf"],
"maxzoom": 6
}
},
"glyphs": location.origin+location.pathname+"font/{fontstack}/{range}.pbf",
"layers": [{
"id": "cleantech2_geom_id",
"type": "circle",
'source': 'cleantech',
'layout': {
'visibility': 'visible'
},
'paint': {
'circle-radius': 8,
'circle-color': 'rgba(55,148,179,1)'
},
'source-layer': 'cleantech2_geom'
}]
};
edit 2:
change the maxzoom to 22, all data displayed. lets drink!

AngularJs filter is not working correctly

Please see the link
http://plnkr.co/edit/Cn0sNDGEkPOzV19ye8NW?p=preview
I have changed my JSON, then I can't able to filter the data.
var result = $filter('filter')(foo.results, {id:2426})[0];
if you limit on your JSON data
and you can make sure the data property value is num
maybe you can try this ...
var foo = {
"count": 70,
"language": "en",
"0": {
"id": "2420",
"name": "Medical Center"
},
"1": {
"id": "7840",
"name": "Conference Room"
},
"2": {
"id": "2426",
"name": "Deck 5 Starboard"
}
};
foo.results = [];
for(var property in foo){
if(property == parseInt(property, 10).toString()){
foo.results.push(foo[property]);
}
}
var result = $filter('filter')(foo.results, {id:2426})[0];
$scope.name = result.name;
wish help !!

Resources