A global way to define colors for AMCharts
-
@craigweb I created a colors-page with this code:
<div ng-init="colorRed='#F44336'"></div> <div ng-init="colorRed2='#E57373'"></div> <div ng-init="colorOrange='#EF6C00'"></div> <div ng-init="colorOrange2='#FF9800'"></div>
And on the page with the AmCharts I used the
ma-ui-page-view
with the XID of the colors-page but it doesn't work. It only works if the ng-init definitions are on the same page where the chart is defined.But I would like to have one place where I can define 20+ colors to use it on different pages / charts and SVG. I learned that CSS would be the place to do it but I cannot get it to work with amcharts CSS reference.
-
@jonas said in A global way to define colors for AMCharts:
But I would like to have one place where I can define 20+ colors to use it on different pages / charts and SVG. I learned that CSS would be the place to do it but I cannot get it to work with amcharts CSS reference.
Just a quick thought, but have you added all of your css styles into a file that can be accessed by the user css styles under administration->ui settings->Miscellaneous settings->User stylesheet url?
That will always be loaded and will enable you to have your global css styles.Secondly, assuming you're using google chrome, using developer tools you can inspect the chart and select the html elements corresponding to the chart series in the amchart instance and 'create' styles for it. This can be done with the css styles window on the right hand side of the element window. This will allow you to ensure your naming conventions are correct for applying the styles you want - even copying and pasting them into your new global styles file so no concerns for misstypes etc...
-
@jonas
If you don't go the styles route which is probably better. You can store the colours in a JSON store. Then use the JSON component to retrieve them in each page. -
@mattfox Thanks for your input.
I use a global css stylesheet via the ui-settings.
But the css class of an AMChart line is always the same.amcharts-graph-stroke
oramcharts-graph-series-1
and we have 50+ charts and series-1 isn't always "blue" for example.And if I add
series-1-class="colorRed"
orseries-1-className="colorRed"
to the chart settings isn't working. But that's what I basically need. Add my own class to every series because I already defined all my colors in my stylesheet. -
Have you considered using the point default chart colour?
-
@craigweb There are often two different variants of one color. And predefined colors in the client industry. Room temperature, for example, is green. And outside temperature light green.
I have a look at your recommended JSON component way now.
-
Sounds like you need a chart profile configured in the graph options to set line colours. I've done something similar for highcharts that I've embedded into my dashboard. But am storing in a separate database.
I can look into coding something for you because I believe it will be beneficial for the mango community. I'll prob bastardise what jared has done from the watchlist page (it's good code!) and incorporate that into saving it as a profile in a json data file.
Let me know your thoughtsFox
-
@mattfox Hi!
We use a json component now and its working. But if you can build a better solution, we would definitely use it.For everyone who is looking for a solution:
Insert this in your page with the AMChart<ma-json-store xid="colours" item="myItem"></ma-json-store>
And our json with the xid "colours" is something like:
{ "Red": "#FF4040", "Orange": "#CD661D", "Grey": "#68838B" }
And in the AMChart we use
series-1-color="{{myItem.jsonData.Orange}}"
-
Nicely done Jonas, I'll throw together a UI directive to do this, shouldn't take tooo long.
However, what I'll do is make it so that the graphs save with the names series1, series2 etc
You can separate chart profiles with a non white space name. -
OK! As promised, here we are. I'm using 3.5.6 so I'm not entirely certain how well this will work. I've stuck to mango components to the best of my ability to allow the best compatibility sans the colour picker. If it doesn't work you may need to alter the HTML to use
<ma-color-picker
instead.
You'll need to set up a userModule file to incorporate this.
I've saved my files in/opt/mango/overrides/web/modules/mangoUI/web/dev/directives/chartProfile
the userModule.js is in/opt/mango/overrides/web/modules/mangoUI/web/dev
For the mangoUI settings, the url for the userModule.js file is:/modules/mangoUI/web/dev/userModule.js
The user module file contains this:
define(['angular', 'require','./directives/chartProfile/serialChartProfile.js'],function(angular, require,serialChartProfile) { 'use strict'; var userModule = angular.module('userModule', ['maUiApp']); try { userModule.directive('serialChartProfile', serialChartProfile); }catch(e){console.log(e);} return userModule; });//define
serialChartProfile.js
/* Date: 13/8/19 File:serialChartProfile.js Author: Matt 'Fox' Fox Desc: Directive that allows mangoUI users to create chart profiles for their dashboard pages. Name of the JSON store can be set as well as the names of each of the chart profiles. Credit goes to Will Geller and Jared Wiltshire for original codebase */ define(['angular', 'require'],function(angular, require) { 'use strict'; serialChartProfile.$inject = ['maJsonStore','$mdDialog','$mdColorPicker','$mdToast']; function serialChartProfile( JsonStore, $mdDialog, $mdColorPicker,$mdToast ) { console.log($mdColorPicker); var scope = { jsonStore: '<?',//has default option }; return { restrict: 'E', templateUrl:'/modules/mangoUI/web/dev/directives/chartProfile/chartProfile.html', designerInfo: { translation: 'ui.components.serialChartProfile', icon: 'show_chart', category: 'pointValuesAndCharts', attributes: { jsonStore: {type: 'text'} }, }, scope: scope, compile: function() { return linkFn; } }; function linkFn(scope, $element, attrs) { scope.profileStore={}; /* Default for ensuring we have a json store name */ var hasStoreName = !!attrs.jsonStore; if(!hasStoreName) { scope.jsonStore = "chartProfile1"; getChartProfiles(); } else { if( scope.jsonStore.length < 3 ) { scope.jsonStore = "chartProfile1"; getChartProfiles(); } else { getChartProfiles();} } scope.axisOptions = [ {name: 'left', translation: 'ui.app.left'}, {name: 'right', translation: 'ui.app.right'}, {name: 'left-2', translation: 'ui.app.farLeft'}, {name: 'right-2', translation: 'ui.app.farRight'} ]; function getChartProfiles() { JsonStore.get({ xid: scope.jsonStore }).$promise.then(function (item) { scope.profileStore = item.jsonData; scope.chartProfile = Object.keys(scope.profileStore)[0]; }, function () { //create prompt - no data scope.createProfile(); }).then(function() { }); } scope.saveToStore=function() { var item = new JsonStore(); item.jsonData = scope.profileStore; item.xid = scope.jsonStore; item.name = scope.jsonStore; item.readPermission = "user"; item.editPermission = "user"; var r = item.$save(); r.then(function(){$mdToast.show( $mdToast.simple() .textContent("Chart Profiles Saved") .position("top") .hideDelay(3000)); }, function myError(response) { console.log( response.statusText ); $mdToast.show( $mdToast.simple() .textContent(response.data) .position("top") .hideDelay(3000)); }); if (r.status) {} else {} }; scope.showColorPicker = function($event, object, propertyName, rebuild) { if (!object) return; this.$mdColorPicker.show({ value: object[propertyName] || tinycolor.random().toHexString(), defaultValue: '', random: false, clickOutsideToClose: true, hasBackdrop: true, skipHide: false, preserveScope: false, mdColorAlphaChannel: true, mdColorSpectrum: true, mdColorSliders: false, mdColorGenericPalette: true, mdColorMaterialPalette: false, mdColorHistory: false, mdColorDefaultTab: 0, $event: $event }).then(color => { object[propertyName] = color; }); }; scope.createProfile = function(ev) { // Appending dialog to document.body to cover sidenav in docs app var confirm = $mdDialog.prompt() .title('Create New Chart Profile') .textContent('Enter new profile name:') .placeholder('PowerUsage') .ariaLabel('PowerUsage') .initialValue('chartProfile1') .targetEvent(ev) .required(true) .ok('CREATE') .cancel('CANCEL'); $mdDialog.show(confirm).then(function(result) { scope.profileStore[ result ] = {}; scope.chartProfile = result; }, function() { //Do nothing and hide. }); }; scope.deleteProfile = function(ev) { // Appending dialog to document.body to cover sidenav in docs app var confirm = $mdDialog.confirm() .title('Delete Profile') .textContent('Are you sure you want to delete this profile?') .ariaLabel('Delete Chart Profile') .targetEvent(ev) .ok('Confirm Delete') .cancel('Cancel'); $mdDialog.show(confirm).then(function() { delete(scope.profileStore[scope.chartProfile]); scope.status = 'Profile Deleted, save settings to confirm'; }, function() { $scope.status = 'Operation cancelled'; }); }; } } return serialChartProfile; });//define
chartProfile.html
<main> <!-- <ma-json-store xid="jsonStore" name="jsonStore"></ma-json-store> --> <ma-button ng-click="createProfile()" label="Create Profile"></ma-button> <ma-button ng-click="saveToStore()" label="Save All Profiles"></ma-button> <ma-button ng-click="deleteProfile()" label="Delete Selected Profile"></ma-button> <md-select ng-model="chartProfile"> <md-option ng-repeat="(profile,vals) in profileStore" value="{{profile}}">{{profile}}</md-option> </md-select> <div class="md-padding"> <div ng-if="chartProfile.length>3"> <md-checkbox ng-model="profileStore[chartProfile].enabled.series1"><span>Configure Series 1:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series2"><span>Configure Series 2:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series3"><span>Configure Series 3:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series4"><span>Configure Series 4:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series5"><span>Configure Series 5:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series6"><span>Configure Series 6:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series7"><span>Configure Series 7:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series8"><span>Configure Series 8:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series9"><span>Configure Series 9:</span></md-checkbox> <md-checkbox ng-model="profileStore[chartProfile].enabled.series10"><span>Configure Series 10:</span></md-checkbox> {{chartProfile.enabled}} <div layout layout-align="start center" layout-wrap ng-repeat="(key,val) in profileStore[chartProfile].enabled" ng-if="val"> <strong flex="100" flex-gt-xs="30" flex-gt-md="15">Configure {{key}}</strong> <md-input-container flex> <label ma-tr="ui.app.lineColor"></label> <md-color-picker ng-model="profileStore[chartProfile][key].pointColor"></md-color-picker> </md-input-container> <!-- <md-input-container flex> <label ma-tr="ui.app.lineColor"></label> <input ng-model="profileStore[chartProfile][key].pointColor" ng-model-options="{debounce: 1000}"> </md-input-container> --> <md-input-container flex> <label ma-tr="ui.app.chartType"></label> <md-select ng-model="profileStore[chartProfile][key].type"> <md-option value=""><em ma-tr="ui.app.clear"></em></md-option> <md-option value="smoothedLine" ma-tr="ui.app.smooth"></md-option> <md-option value="line" ma-tr="ui.app.line"></md-option> <md-option value="step" ma-tr="ui.app.step"></md-option> <md-option value="column" ma-tr="ui.app.bar"></md-option> </md-select> </md-input-container> <md-input-container flex> <label ma-tr="ui.app.pointAxis"></label> <md-select ng-model="profileStore[chartProfile][key].axis"> <md-option value=""><em ma-tr="ui.app.clear"></em></md-option> <md-option ng-repeat="axis in axisOptions track by axis.name" ng-value="axis.name"> <span ma-tr="{{axis.translation}}"></span> </md-option> </md-select> </md-input-container> </div> <div> <md-checkbox ng-model="profileStore[chartProfile].configAxes"><span ma-tr="ui.app.configureAxes"></span></md-checkbox> </div> <div ng-if="profileStore[chartProfile].configAxes" ng-repeat="axis in axisOptions track by axis.name" layout="row" layout-align="start center" layout-wrap> <strong flex="100" flex-gt-xs="15" flex-gt-md="10" ma-tr="{{axis.translation}}"></strong> <div flex="100" flex-gt-xs="85" flex-gt-md="90" layout layout-align="start center" layout-wrap> <md-input-container flex="50" flex-gt-xs="33"> <label ma-tr="ui.app.axisTitle"></label> <input ma-empty-input="undefined" ng-model="profileStore[chartProfile].valueAxes[axis.name].title" ng-model-options="{debounce: 1000}" > </md-input-container> <div flex="50" flex-gt-xs="33" layout layout-align="start center"> <label ma-tr="ui.app.axisColor"></label> <md-color-picker ng-model="profileStore[chartProfile].valueAxes[axis.name].color" ></md-color-picker> <!-- <ma-color-picker ng-model="profileStore[chartProfile].valueAxes[axis.name].color" ></ma-color-picker> --> <!-- <md-input-container flex> <label ma-tr="ui.app.axisColor"></label> <input ma-empty-input="undefined" ng-model="profileStore[chartProfile].valueAxes[axis.name].color" ng-model-options="{debounce: 1000}" > </md-input-container> --> </div> <md-input-container flex="50" flex-gt-xs="33"> <label ma-tr="ui.app.stackType"></label> <md-select ma-empty-input="undefined" ng-model="profileStore[chartProfile].valueAxes[axis.name].stackType" > <md-option value=""><em ma-tr="ui.app.clear"></em></md-option> <md-option value="none" ma-tr="ui.app.none"></md-option> <md-option value="regular" ma-tr="ui.app.stacked"></md-option> <md-option value="100%">100% <span ma-tr="ui.app.stacked"></span></md-option> </md-select> </md-input-container> <md-input-container flex="50" flex-gt-xs="33"> <label ma-tr="ui.app.axisMinimum"></label> <input ma-empty-input="undefined" type="number" ng-model="profileStore[chartProfile].valueAxes[axis.name].minimum" ng-model-options="{debounce: 1000}" > </md-input-container> <md-input-container flex="50" flex-gt-xs="33"> <label ma-tr="ui.app.axisMaximum"></label> <input ma-empty-input="undefined" type="number" ng-model="profileStore[chartProfile].valueAxes[axis.name].maximum" ng-model-options="{debounce: 1000}" > </md-input-container> <md-input-container flex="50" flex-gt-xs="33"> <label ma-tr="ui.app.axisGridCount"></label> <input ma-empty-input="undefined" type="number" min="0" ng-model="profileStore[chartProfile].valueAxes[axis.name].gridCount" ng-model-options="{debounce: 1000}" > </md-input-container> </div> </div> </div> <style> .md-color-picker-input{color:black!important;}</style> </main>
<!-- json-store is optional; --> <serial-chart-profile [json-store='jsonStoreName'] ></serial-chart-profile>
Keep me informed, hopefully others can use this to make their chart templates for different statuses more dynamically!!
I won't lie, this may require further testing... and more comments!
Fox