Skip to content

Gradient color for (line)charts #510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Doomic opened this issue Sep 23, 2016 · 5 comments
Open

Gradient color for (line)charts #510

Doomic opened this issue Sep 23, 2016 · 5 comments

Comments

@Doomic
Copy link

Doomic commented Sep 23, 2016

This issue will be an extention to #240 but i also find some results that may help.

ChartJs
ChartJs supports that that linecolors and backgroundcolors (and perhaps more color object) are a gradient. This can be done by getting the ctx and call createLinearGradient function, push the result in the color object you want and there is a gradient line/background.

gradient = ctx.createLinearGradient(0, 0, 250, 0);
gradient.addColorStop(0, 'rgba(243, 103, 101,0.5)');
gradient.addColorStop(1, 'rgba(0, 89, 179,0.5)');
dataset.backgroundColor: gradient;

AngularChart
Angular-chart can't give you the ctx (correct me if i am wrong). However just find the canvas with javascript and get the context(2d) will give the ctx. (just like you are used to in ChartJs)
Then a made the gradient and put it in the color scope and/or the datasetoverride.
However, this will not result in a gradient line or background. an other color will there (i believe it is the color for the latest draw object to the canvas).

Example
http://jsbin.com/duforuyumu/1/edit?html,js,output

Solution
After searching i found the problem. It is inside the angular.merge function. (this function is used inside the getDataSets function and the getDataSet function)
this merge function (deep copy) loops trough all attributes and if the attribute is an object; this object will be merged again. This looks like a good way of dealing with merging objects.
jQuery does also include a extend function with deep copy possibility. After implimenting this function insteed of the angular.merge the issues is fixed.

//angular.merge(dataset, datasetOverride[i]);
$.extend(true, dataset, datasetOverride[i]);

Search deeper
This means jquery merge the object a little bit different. I got the source code of both functions and find out that jquery first determent if the object is a "normal" object.

var normalObject = {};
var gradient = ctx.createLinearGradient(0, 0, 250, 0);

typeof normalObject -> "object"
typeof gradient -> "object"

toString.call(normalObject) -> "[object Object]"
toString.call(gradient) -> "[object CanvasGradient]"

as you can see... both are objects. however not both are a "normal" object.
Angular will try to loop trough the gradient attributes (but there are none). And jquery will copy (link) the gradient to the result (like a string or number just will be linked).

Final
I understand that this merge function is from angular. So the team there should fix this problem... I will make an issue there as well. But for now, angular-chart can be fixed with a jquery extend.

@Doomic
Copy link
Author

Doomic commented Sep 23, 2016

issue on angular github page
angular/angular.js#15180

@jtblin
Copy link
Owner

jtblin commented Sep 24, 2016

Great investigation @Doomic. Hopefully they can fix that in angular, I'd rather not have to roll my own merge function.

@Doomic
Copy link
Author

Doomic commented Sep 25, 2016

If you don't mind. I leave the "fight" where to fix up to you. (personally i agree with you and this should be fixed in angular.)

if they doen't want to fix there code, here is the code they use, but with the improvement. you could use it for the merge situations

/**
* @ngdoc function
* @name angular.merge
* @module ng
* @kind function
*
* @description
* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
*
* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
* objects, performing a deep copy.
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
* @returns {Object} Reference to `dst`.
*/
function merge(dst) {
  return baseExtend(dst, slice.call(arguments, 1), true);
}

function baseExtend(dst, objs, deep) {
  var h = dst.$$hashKey;

  for (var i = 0, ii = objs.length; i < ii; ++i) {
    var obj = objs[i];
    if (!isObject(obj) && !isFunction(obj)) continue;
    var keys = Object.keys(obj);
    for (var j = 0, jj = keys.length; j < jj; j++) {
      var key = keys[j];
      var src = obj[key];

      if (deep && isObject(src)) {
        if (isDate(src)) {
          dst[key] = new Date(src.valueOf());
        } else if (isRegExp(src)) {
          dst[key] = new RegExp(src);
        } else if (src.nodeName) {
          dst[key] = src.cloneNode(true);
        } else if (isElement(src)) {
          dst[key] = src.clone();
        } else if (toString.call(src) != "[object Object]") { 
          dst[key] = src;
        } else {
          if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
          baseExtend(dst[key], [src], true);
        }
      } else {
        dst[key] = src;
      }
    }
  }

  setHashKey(dst, h);
  return dst;
}

@rootux
Copy link
Contributor

rootux commented Apr 9, 2017

Hey. I want to use gradient color and come to this thread.
Did anyone was able to solve this?

@Narretz
Copy link

Narretz commented Jun 6, 2017

We've decided that this will not be fixed in AngularJS. Please use https://lodash.com/docs/4.17.4#merge or a similar function instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants