Skip to content

Conversation

@etimberg
Copy link
Member

A lot of cleanup of the radial scale. I moved a lot of functionality into private functions.

Issues Fixed

  • When the scale was user for the polar area graph, the scale didn't use the full available area because it tried to fit the point labels (used for radar chart) even though non existed.
  • The point labels can now have multiple lines of text. Resolves Line Breaks on Radar Charts not working #3225

screen shot 2016-11-19 at 11 02 36 pm

Testing Done

  • Unit tests run
  • Tested the polar area and radar charts manually

Changed Behaviour

  • the getIndexAngle method no longer subtracts 90 degrees since we added it back almost all of the time.

@etimberg etimberg added this to the Version 2.5 milestone Nov 20, 2016
Copy link
Member

@simonbrunel simonbrunel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some code enhancement suggestions (not tested)

};
}

return size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (helpers.isArray(label)) {
    return {
        w: ...
        h: ...
    };
}

return {
  w: ...
  h: ...
};


// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be normalized with multiple var declarations and grouping uninitialized vars at the end.

Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
scale.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
}
determineReductions();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was to make eslint happy otherwise the function is too long and too complex

// Add quarter circle to make degree 0 mean top of circle
var angleRadians = scale.getIndexAngle(i);
var angle = helpers.toDegrees(angleRadians) % 360;
determineXLimits(angle);
Copy link
Member

@simonbrunel simonbrunel Nov 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the benefit to have functions for determineXLimits, determineYLimits and updateLimits, they are called only from that location. determineXLimits and determineYLimits could be refactored and updateLimits inlined:

function determineLimits(angle, pos, size, min, max) {
    if (angle == min || angle == max) {
        return {
            start: pos - (size / 2),
            end: pos + (size / 2)
        };
    }
    if (angle < min || angle > max) {
        return {
            start: pos - size - 5,
            end: pos
        };
    }
    return {
        start: pos,
        end: pos + size + 5
    };
}

var valueCount = getValueCount(scale);
for (i = 0; i < valueCount; i++) {
    // ... previous code ...
    var hlimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
    var vlimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);

    // update limits
    if (furthestLeft > hlimit.start) {
        furthestLeft = hlimit.start;
        furthestLeftAngle = angleRadians;
    }
    if (furthestRight < hlimit.end) {
        furthestRight = hlimit.end;
        furthestRightAngle = angleRadians;
    }
    // ... rest of the updateLimits method ...
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those functions came to make eslint happy otherwise it complains that fitWithPointLabels is too complex and has too many statements

Copy link
Member

@simonbrunel simonbrunel Nov 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think inner functions are a good approach to reduce code complexity, seems just a hack to trick eslint, but that makes the code more complex since these inner methods modify outer variables (also not good for performance to call useless functions in a loop).

determineLimits doesn't refer to outer scope variables, so can live outside fitWithPointLabels.

textAlign = 'right';
}

return textAlign;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (angle === 0 || angle === 180) {
    return 'center';
}
if (angle < 180) {
    return  'left';
}
return 'right';

}
}
ctx.closePath();
ctx.stroke();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid empty path drawing and i === 0 condition in the loop:

var count = getValueCount(scale);
if (count === 0) {
    return;
}

ctx.beginPath();

var pos = scale.getPointPosition(0, radius);
ctx.moveTo(pos.x, pos.y);

for (var i = 1; i < count; i++) {
    pos = scale.getPointPosition(i, radius);
    ctx.lineTo(pos.x, pos.y);
}

ctx.closePath();
ctx.stroke();

var pointLabelFontSize = helpers.getValueOrDefault(pointLabels.fontSize, globalDefaults.defaultFontSize);
var pointLabelFontStyle = helpers.getValueOrDefault(pointLabels.fontStyle, globalDefaults.defaultFontStyle);
var pointLabelFontFamily = helpers.getValueOrDefault(pointLabels.fontFamily, globalDefaults.defaultFontFamily);
var pointLabelFont = helpers.fontString(pointLabelFontSize, pointLabelFontStyle, pointLabelFontFamily);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite personal, but I'm not a huge fan of long variable names, especially when the scope is obvious: it makes the code harder to read.

function getPointLabelFontOptions(scale) {
    var options = scale.options.pointLabels;
    var size = helpers.getValueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
    var style = helpers.getValueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
    var family = helpers.getValueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);

    return {
        size: size,
        style: style,
        family: family,
        font: helpers.fontString(size, style, family);
    };

@etimberg
Copy link
Member Author

@simonbrunel I agree with your comments. i will make updates to the code to fix them

@etimberg etimberg force-pushed the improve-radial-scale branch from 0507f5d to e1606f8 Compare November 20, 2016 18:19
@etimberg
Copy link
Member Author

@chartjs/maintainers is this good to go?

Copy link
Member

@simonbrunel simonbrunel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

@etimberg etimberg merged commit 7e5e29e into master Nov 25, 2016
@etimberg etimberg deleted the improve-radial-scale branch November 25, 2016 12:19
exwm pushed a commit to exwm/Chart.js that referenced this pull request Apr 30, 2021
Clean up radial linear scale. It now supports multiple lines for point labels. Fixes chartjs#3225
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants