<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AChart_data</id>
	<title>Module:Chart data - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AChart_data"/>
	<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Chart_data&amp;action=history"/>
	<updated>2026-04-27T06:17:29Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=Module:Chart_data&amp;diff=34039&amp;oldid=prev</id>
		<title>Alex: Created page with &quot;-- &lt;nowiki&gt; ---@class chart local chart = {}  ---@class dataSet local dataSet = {}  local libraryUtil = require( &#039;Module:libraryUtil&#039; ) local rgba = require( &#039;Module:Rgba&#039; ) local isEmpty = require( &#039;Module:Paramtest&#039; ).is_empty local arr = require( &#039;Module:Array&#039; )  ---@alias xyData table&lt;string, number&gt; ---@alias xyDataSet xyData[] ---@alias dataArr number[] ---@alias options_t table&lt;string, string|number|options_t&gt;  ---@param val any ---@param default any ---@return a...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Chart_data&amp;diff=34039&amp;oldid=prev"/>
		<updated>2024-10-15T17:22:05Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;-- &amp;lt;nowiki&amp;gt; ---@class chart local chart = {}  ---@class dataSet local dataSet = {}  local libraryUtil = require( &amp;#039;Module:libraryUtil&amp;#039; ) local rgba = require( &amp;#039;Module:Rgba&amp;#039; ) local isEmpty = require( &amp;#039;Module:Paramtest&amp;#039; ).is_empty local arr = require( &amp;#039;Module:Array&amp;#039; )  ---@alias xyData table&amp;lt;string, number&amp;gt; ---@alias xyDataSet xyData[] ---@alias dataArr number[] ---@alias options_t table&amp;lt;string, string|number|options_t&amp;gt;  ---@param val any ---@param default any ---@return a...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- &amp;lt;nowiki&amp;gt;&lt;br /&gt;
---@class chart&lt;br /&gt;
local chart = {}&lt;br /&gt;
&lt;br /&gt;
---@class dataSet&lt;br /&gt;
local dataSet = {}&lt;br /&gt;
&lt;br /&gt;
local libraryUtil = require( &amp;#039;Module:libraryUtil&amp;#039; )&lt;br /&gt;
local rgba = require( &amp;#039;Module:Rgba&amp;#039; )&lt;br /&gt;
local isEmpty = require( &amp;#039;Module:Paramtest&amp;#039; ).is_empty&lt;br /&gt;
local arr = require( &amp;#039;Module:Array&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
---@alias xyData table&amp;lt;string, number&amp;gt;&lt;br /&gt;
---@alias xyDataSet xyData[]&lt;br /&gt;
---@alias dataArr number[]&lt;br /&gt;
---@alias options_t table&amp;lt;string, string|number|options_t&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---@param val any&lt;br /&gt;
---@param default any&lt;br /&gt;
---@return any&lt;br /&gt;
local function default( val, default )&lt;br /&gt;
    if val == nil or (type( val ) == &amp;#039;string&amp;#039; and isEmpty( val )) then&lt;br /&gt;
        return default&lt;br /&gt;
    else&lt;br /&gt;
        return val&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param obj chart | dataSet&lt;br /&gt;
---@param options options_t&lt;br /&gt;
local function defaultOptions( obj, options )&lt;br /&gt;
     local function _setOptions( tbl, options )&lt;br /&gt;
        for k, v in pairs( options ) do&lt;br /&gt;
            if type( v ) == &amp;#039;table&amp;#039; and type( tbl[k] ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
                _setOptions( tbl[k], v )&lt;br /&gt;
            else&lt;br /&gt;
                tbl[k] = default( tbl[k], v )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    _setOptions( obj, options )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function stripNonChartJsVariables( tbl )&lt;br /&gt;
    local stripVarNames = {&lt;br /&gt;
        colorPallet = true,&lt;br /&gt;
        backgroundAlpha = true,&lt;br /&gt;
        hoverLightenValue = true,&lt;br /&gt;
        hoverSaturateValue = true,&lt;br /&gt;
        hoverAlpha = true,&lt;br /&gt;
        widthVal = true,&lt;br /&gt;
        heightVal = true,&lt;br /&gt;
        flippedXY = true&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    local function _strip( tbl )&lt;br /&gt;
        for k, v in pairs( tbl ) do&lt;br /&gt;
            if stripVarNames[k] then&lt;br /&gt;
                tbl[k] = nil&lt;br /&gt;
            elseif type( v ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
                _strip( v )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    _strip( tbl )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param tbl table&lt;br /&gt;
---@param seen table | nil @Only for internal use&lt;br /&gt;
local function stripInvalidValues( tbl, seen )&lt;br /&gt;
    seen = seen or {}&lt;br /&gt;
    seen[tbl] = true&lt;br /&gt;
&lt;br /&gt;
    for k, v in pairs( tbl ) do&lt;br /&gt;
        if type( k ) == &amp;#039;table&amp;#039; or type( k ) == &amp;#039;function&amp;#039; then&lt;br /&gt;
            tbl[k] = nil&lt;br /&gt;
        elseif type( v ) == &amp;#039;function&amp;#039; then&lt;br /&gt;
            tbl[k] = nil&lt;br /&gt;
        elseif seen[v] then&lt;br /&gt;
            tbl[k] = nil&lt;br /&gt;
        elseif type( v ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
            local mt = getmetatable( v )&lt;br /&gt;
            if mt and mt.__tostring then&lt;br /&gt;
                tbl[k] = tostring( v )&lt;br /&gt;
            else&lt;br /&gt;
                stripInvalidValues( v, seen )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    setmetatable( tbl, nil )&lt;br /&gt;
    stripNonChartJsVariables( tbl )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- =====================&lt;br /&gt;
--      Chart class&lt;br /&gt;
-- =====================&lt;br /&gt;
local checkChartClass = libraryUtil.makeCheckClassFunction( &amp;#039;Module:Chart data&amp;#039; , &amp;#039;chart&amp;#039;, chart, &amp;#039;chart object&amp;#039; )&lt;br /&gt;
chart.rgba = rgba&lt;br /&gt;
chart.colorPallets = {&lt;br /&gt;
    qualitative = {&lt;br /&gt;
        name = &amp;#039;qualitative&amp;#039;,&lt;br /&gt;
        rgba.new( 166,206,227 ),&lt;br /&gt;
        rgba.new( 31,120,180 ),&lt;br /&gt;
        rgba.new( 178,223,138 ),&lt;br /&gt;
        rgba.new( 51,160,44 ),&lt;br /&gt;
        rgba.new( 251,154,153 ),&lt;br /&gt;
        rgba.new( 227,26,28 ),&lt;br /&gt;
        rgba.new( 253,191,111 ),&lt;br /&gt;
        rgba.new( 255,127,0 ),&lt;br /&gt;
        rgba.new( 202,178,214 ),&lt;br /&gt;
        rgba.new( 106,61,154 )&lt;br /&gt;
    },&lt;br /&gt;
    blue = {&lt;br /&gt;
        name = &amp;#039;blue&amp;#039;,&lt;br /&gt;
        rgba.new( 208,209,230 ),&lt;br /&gt;
        rgba.new( 166,189,219 ),&lt;br /&gt;
        rgba.new( 103,169,207 ),&lt;br /&gt;
        rgba.new( 54,144,192 ),&lt;br /&gt;
        rgba.new( 2,129,138 ),&lt;br /&gt;
        rgba.new( 1,108,89 ),&lt;br /&gt;
        rgba.new( 1,70,54 )&lt;br /&gt;
    },&lt;br /&gt;
    green = {&lt;br /&gt;
        name = &amp;#039;green&amp;#039;,&lt;br /&gt;
        rgba.new( 217,240,163 ),&lt;br /&gt;
        rgba.new( 173,221,142 ),&lt;br /&gt;
        rgba.new( 120,198,121 ),&lt;br /&gt;
        rgba.new( 65,171,93 ),&lt;br /&gt;
        rgba.new( 35,132,67 ),&lt;br /&gt;
        rgba.new( 0,104,55 ),&lt;br /&gt;
        rgba.new( 0,69,41 )&lt;br /&gt;
    },&lt;br /&gt;
    blueGreen = {&lt;br /&gt;
        name = &amp;#039;blueGreen&amp;#039;,&lt;br /&gt;
        rgba.new( 204,236,230 ),&lt;br /&gt;
        rgba.new( 153,216,201 ),&lt;br /&gt;
        rgba.new( 102,194,164 ),&lt;br /&gt;
        rgba.new( 65,174,118 ),&lt;br /&gt;
        rgba.new( 35,139,69 ),&lt;br /&gt;
        rgba.new( 0,109,44 ),&lt;br /&gt;
        rgba.new( 0,68,27 )&lt;br /&gt;
    },&lt;br /&gt;
    orange = {&lt;br /&gt;
        name = &amp;#039;orange&amp;#039;,&lt;br /&gt;
        rgba.new( 254,227,145 ),&lt;br /&gt;
        rgba.new( 254,196,79 ),&lt;br /&gt;
        rgba.new( 254,153,41 ),&lt;br /&gt;
        rgba.new( 236,112,20 ),&lt;br /&gt;
        rgba.new( 204,76,2 ),&lt;br /&gt;
        rgba.new( 153,52,4 ),&lt;br /&gt;
        rgba.new( 102,37,6 )&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local colorPalletMt = {&lt;br /&gt;
    __index = function ( self, i )  -- Use the next color pallet if one pallet is too small for all the lines&lt;br /&gt;
        local pallet = next( chart.colorPallets, self.name ) or next( chart.colorPallets )&lt;br /&gt;
        pallet = chart.colorPallets[ pallet ]&lt;br /&gt;
        return pallet[ i - #self ]&lt;br /&gt;
    end,&lt;br /&gt;
    __tostring = function ( t ) return t.name end&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
for _, set in pairs( chart.colorPallets ) do&lt;br /&gt;
    if type( set ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
        setmetatable( set, colorPalletMt )&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function chart.main( frame )&lt;br /&gt;
    return chart._main( (frame:getParent() or frame).args )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param args options_t&lt;br /&gt;
---@return string&lt;br /&gt;
function chart._main( args )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data._main&amp;#039;, 1, args, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    local data = args&lt;br /&gt;
&lt;br /&gt;
    if not data.isChartObj then&lt;br /&gt;
        local moduleName = args.dataModule or args[1]&lt;br /&gt;
        local funcName = args[&amp;#039;function&amp;#039;] or args[2]&lt;br /&gt;
&lt;br /&gt;
        if isEmpty( moduleName ) then&lt;br /&gt;
            error( &amp;#039;Data module was not provided or is empty&amp;#039; )&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        if moduleName:find( &amp;#039;[Mm]odule:&amp;#039; ) == nil then&lt;br /&gt;
            moduleName = &amp;#039;Module:&amp;#039; .. moduleName&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        if funcName then&lt;br /&gt;
            data = require( moduleName )[ funcName ]( args )&lt;br /&gt;
&lt;br /&gt;
            assert( type( data )==&amp;#039;table&amp;#039;, string.format(&lt;br /&gt;
                &amp;quot;Error: function &amp;#039;%s&amp;#039; from module &amp;#039;%s&amp;#039; returned an invalid type (table expected, got %s)&amp;quot;,&lt;br /&gt;
                funcName, moduleName, type( data ) ) )&lt;br /&gt;
&lt;br /&gt;
            if data.isChartObj and not data.isFinished then&lt;br /&gt;
                data:finish()&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            data = mw.loadData( moduleName )&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local width = args.width or data.width or &amp;#039;60vw&amp;#039;&lt;br /&gt;
    local height = args.height or data.height or &amp;#039;60vh&amp;#039;&lt;br /&gt;
    local minWidth = args.minWidth or args.min_width or data.minWidth or &amp;#039;400px&amp;#039;&lt;br /&gt;
    local minHeight = args.minHeight or args.min_height or data.minHeight or &amp;#039;400px&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    return string.format(&lt;br /&gt;
        &amp;#039;&amp;lt;div class=&amp;quot;rsw-chartjs rsw-chartjs-config&amp;quot; style=&amp;quot;position:relative; margin:1em 0; width:%s; height:%s; min-width:%s; min-height:%s;%s&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;%s&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;,&lt;br /&gt;
        width,&lt;br /&gt;
        height,&lt;br /&gt;
        minWidth,&lt;br /&gt;
        minHeight,&lt;br /&gt;
        data.resizable and &amp;#039; resize:both; overflow:hidden; padding:0 5px 5px 0;&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
        mw.text.jsonEncode( data )&lt;br /&gt;
    )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param ys number[]&lt;br /&gt;
---@param xs number[] | nil&lt;br /&gt;
---@return xyDataSet&lt;br /&gt;
function chart.convertToXYFormat( ys, xs )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.convertToXYFormat&amp;#039;, 1, ys, &amp;#039;table&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.convertToXYFormat&amp;#039;, 2, xs, &amp;#039;table&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    xs = xs or {}&lt;br /&gt;
    local ret = {}&lt;br /&gt;
&lt;br /&gt;
    for i,v in ipairs( ys ) do&lt;br /&gt;
        table.insert( ret, { x=(xs[i] or i), y=v } )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param func function&lt;br /&gt;
---@param start_x number&lt;br /&gt;
---@param end_x number&lt;br /&gt;
---@param step number&lt;br /&gt;
---@return xyDataSet&lt;br /&gt;
function chart.generateXYFromFunc( func, start_x, end_x, step )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.generateXYFromFunc&amp;#039;, 1, func, &amp;#039;function&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.generateXYFromFunc&amp;#039;, 2, start_x, &amp;#039;number&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.generateXYFromFunc&amp;#039;, 3, end_x, &amp;#039;number&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.generateXYFromFunc&amp;#039;, 4, step, &amp;#039;number&amp;#039;,  true )&lt;br /&gt;
&lt;br /&gt;
    step = step or 1&lt;br /&gt;
    local ret = {}&lt;br /&gt;
&lt;br /&gt;
    for i = start_x, end_x, step do&lt;br /&gt;
        table.insert( ret, { x=i, y=func( i ) } )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param low_chance number&lt;br /&gt;
---@param high_chance number&lt;br /&gt;
---@param start_level number&lt;br /&gt;
---@param end_level number&lt;br /&gt;
---@return xyDataSet&lt;br /&gt;
function chart.jagexInterpolation( low_chance, high_chance, start_level, end_level )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.jagexInterpolation&amp;#039;, 1, low_chance, &amp;#039;number&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.jagexInterpolation&amp;#039;, 2, high_chance, &amp;#039;number&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.jagexInterpolation&amp;#039;, 3, start_level, &amp;#039;number&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.jagexInterpolation&amp;#039;, 4, end_level, &amp;#039;number&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    local function interpolate( x )&lt;br /&gt;
        return math.floor( ( (99-x)*low_chance + (x-1)*high_chance ) / 98 )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return chart.generateXYFromFunc( interpolate, start_level, end_level )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param setup options_t&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart.newChart( setup )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.newChart&amp;#039;, 1, setup, &amp;#039;table&amp;#039;, true )&lt;br /&gt;
    local obj = setup or {}&lt;br /&gt;
&lt;br /&gt;
    if obj.type == &amp;#039;bar&amp;#039; then&lt;br /&gt;
        defaultOptions( obj, {&lt;br /&gt;
            options = {&lt;br /&gt;
                fill = true,&lt;br /&gt;
                backgroundAlpha = 0.4,&lt;br /&gt;
                hoverLightenValue = 0.95,&lt;br /&gt;
                hoverAlpha = 0.5,&lt;br /&gt;
                hoverSaturateValue = 1,&lt;br /&gt;
                scales = {&lt;br /&gt;
                    x = { -- This is used for horizontal bar graphs&lt;br /&gt;
                        ticks = {&lt;br /&gt;
                            beginAtZero = true&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    y = {&lt;br /&gt;
                        ticks = {&lt;br /&gt;
                            beginAtZero = true&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        } )&lt;br /&gt;
    elseif obj.type == &amp;#039;bubble&amp;#039; then&lt;br /&gt;
        defaultOptions( obj, {&lt;br /&gt;
            options = {&lt;br /&gt;
                fill = true,&lt;br /&gt;
                backgroundAlpha = 0.4,&lt;br /&gt;
                hoverLightenValue = 0.95,&lt;br /&gt;
                hoverAlpha = 0.5,&lt;br /&gt;
                hoverSaturateValue = 1&lt;br /&gt;
            }&lt;br /&gt;
        } )&lt;br /&gt;
    elseif obj.type == &amp;#039;radar&amp;#039; then&lt;br /&gt;
        defaultOptions( obj, {&lt;br /&gt;
            options = {&lt;br /&gt;
                scale = {&lt;br /&gt;
                    ticks = {&lt;br /&gt;
                        showLabelBackdrop = false,&lt;br /&gt;
                        z = 1&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        } )&lt;br /&gt;
    elseif obj.type == &amp;#039;pie&amp;#039; or obj.type == &amp;#039;doughnut&amp;#039; then&lt;br /&gt;
        defaultOptions( obj, {&lt;br /&gt;
            options = {&lt;br /&gt;
                fill = true,&lt;br /&gt;
                backgroundAlpha = 0.8,&lt;br /&gt;
                hoverLightenValue = 0.95,&lt;br /&gt;
                hoverAlpha = 0.9,&lt;br /&gt;
                hoverSaturateValue = 1&lt;br /&gt;
            }&lt;br /&gt;
        } )&lt;br /&gt;
    elseif obj.type == &amp;#039;polarArea&amp;#039; then&lt;br /&gt;
        defaultOptions( obj, {&lt;br /&gt;
            options = {&lt;br /&gt;
                fill = true,&lt;br /&gt;
                backgroundAlpha = 0.5,&lt;br /&gt;
                hoverLightenValue = 0.95,&lt;br /&gt;
                hoverAlpha = 0.6,&lt;br /&gt;
                hoverSaturateValue = 1,&lt;br /&gt;
                scale = {&lt;br /&gt;
                    ticks = {&lt;br /&gt;
                        showLabelBackdrop = false,&lt;br /&gt;
                        z = 1&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        } )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    defaultOptions( obj, {&lt;br /&gt;
        isChartObj = true,&lt;br /&gt;
        type = &amp;#039;scatter&amp;#039;,&lt;br /&gt;
        widthVal = &amp;#039;60vw&amp;#039;,&lt;br /&gt;
        heightVal = &amp;#039;60vh&amp;#039;,&lt;br /&gt;
        minWidth = 400,&lt;br /&gt;
        resizable = true,&lt;br /&gt;
        data = {&lt;br /&gt;
            datasets = {}&lt;br /&gt;
        },&lt;br /&gt;
        options = {&lt;br /&gt;
            fill = false,&lt;br /&gt;
            colorPallet = chart.colorPallets.qualitative,&lt;br /&gt;
            backgroundAlpha = 0.3,&lt;br /&gt;
            hoverLightenValue = 0.95,&lt;br /&gt;
            hoverAlpha = 0.5,&lt;br /&gt;
            hoverSaturateValue = 1,&lt;br /&gt;
            maintainAspectRatio = false,&lt;br /&gt;
            title = {&lt;br /&gt;
                font = {&lt;br /&gt;
                    size = 18&lt;br /&gt;
                }&lt;br /&gt;
            },&lt;br /&gt;
            tooltips = {&lt;br /&gt;
                intersect = false&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    } )&lt;br /&gt;
&lt;br /&gt;
    setmetatable( obj, chart )&lt;br /&gt;
&lt;br /&gt;
    obj:setDimensions( obj.widthVal, obj.heightVal, obj.minWidth, obj.minHeight, obj.resizable )&lt;br /&gt;
&lt;br /&gt;
    return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@vararg xyDataSet | dataArr&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:addDataSets( ... )&lt;br /&gt;
    checkChartClass( self, &amp;#039;addDataSets&amp;#039; )&lt;br /&gt;
    local sets = { ... }&lt;br /&gt;
&lt;br /&gt;
    for i, set in ipairs( sets ) do&lt;br /&gt;
        libraryUtil.checkType( &amp;#039;chart.addDataSets&amp;#039;, i, set, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
        if not arr.contains( self.data.datasets, set, false ) then&lt;br /&gt;
            table.insert( self.data.datasets, set )&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param labels string&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:addDataLabels( labels )&lt;br /&gt;
    checkChartClass( self, &amp;#039;addDataLabels&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;Module:Chart_data.addDataLabels&amp;#039;, 1, labels, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    self.data.labels = default( self.data.labels, {} )&lt;br /&gt;
&lt;br /&gt;
    for _, label in ipairs( labels ) do&lt;br /&gt;
        table.insert( self.data.labels, label )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param width number | string&lt;br /&gt;
---@param height number | string | nil&lt;br /&gt;
---@param minWidth number | string | nil&lt;br /&gt;
---@param minHeight number | string | nil&lt;br /&gt;
---@param resizable boolean | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setDimensions( width, height, minWidth, minHeight, resizable )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setDimensions&amp;#039; )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;chart.setDimensions&amp;#039;, 1, width, {&amp;#039;number&amp;#039;, &amp;#039;string&amp;#039;} )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;chart.setDimensions&amp;#039;, 2, height, {&amp;#039;number&amp;#039;, &amp;#039;string&amp;#039;, &amp;#039;nil&amp;#039;} )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;chart.setDimensions&amp;#039;, 3, minWidth, {&amp;#039;number&amp;#039;, &amp;#039;string&amp;#039;, &amp;#039;nil&amp;#039;} )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;chart.setDimensions&amp;#039;, 4, minHeight, {&amp;#039;number&amp;#039;, &amp;#039;string&amp;#039;, &amp;#039;nil&amp;#039;} )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setDimensions&amp;#039;, 5, resizable, &amp;#039;boolean&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if type( width ) == &amp;#039;number&amp;#039; then&lt;br /&gt;
        self.widthVal = width&lt;br /&gt;
        self.width = width .. &amp;#039;px&amp;#039;&lt;br /&gt;
    elseif type( width ) == &amp;#039;string&amp;#039; then&lt;br /&gt;
        self.width = width&lt;br /&gt;
        self.widthVal = tonumber( width:match( &amp;#039;%d+&amp;#039; ) )&lt;br /&gt;
&lt;br /&gt;
        if type( self.widthVal ) ~= &amp;#039;number&amp;#039; then&lt;br /&gt;
            error( &amp;quot;bad argument #1 to &amp;#039;chart.setDimensions&amp;#039; (input doesn&amp;#039;t contain a number)&amp;quot;, 2 )&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        self.widthVal = nil&lt;br /&gt;
        self.width = &amp;#039;&amp;#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if type( height ) == &amp;#039;number&amp;#039; then&lt;br /&gt;
        self.heightVal = height&lt;br /&gt;
        self.height = height .. &amp;#039;px&amp;#039;&lt;br /&gt;
    elseif type( height ) == &amp;#039;string&amp;#039; then&lt;br /&gt;
        self.height = height&lt;br /&gt;
        self.heightVal = tonumber( height:match( &amp;#039;%d+&amp;#039; ) )&lt;br /&gt;
&lt;br /&gt;
        if type( self.heightVal ) ~= &amp;#039;number&amp;#039; then&lt;br /&gt;
            error( &amp;quot;bad argument #2 to &amp;#039;chart.setDimensions&amp;#039; (input doesn&amp;#039;t contain a number)&amp;quot;, 2 )&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        self.heightVal = nil&lt;br /&gt;
        self.height = &amp;#039;&amp;#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if type( minWidth ) == &amp;#039;number&amp;#039; then&lt;br /&gt;
        self.minWidth = minWidth .. &amp;#039;px&amp;#039;&lt;br /&gt;
    elseif type( minWidth ) == &amp;#039;string&amp;#039; then&lt;br /&gt;
        self.minWidth = minWidth&lt;br /&gt;
    else&lt;br /&gt;
        self.minWidth = nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if type( minHeight ) == &amp;#039;number&amp;#039; then&lt;br /&gt;
        self.minHeight = minHeight .. &amp;#039;px&amp;#039;&lt;br /&gt;
    elseif type( minHeight ) == &amp;#039;string&amp;#039; then&lt;br /&gt;
        self.minHeight = minHeight&lt;br /&gt;
    else&lt;br /&gt;
        self.minHeight = nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    self.resizable = default( resizable, self.resizable )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;pie&amp;#039;, &amp;#039;doughnut&amp;#039;, &amp;#039;radar&amp;#039;, &amp;#039;polarArea&amp;#039;}, self.type ) then&lt;br /&gt;
        self.height = self.width&lt;br /&gt;
        self.minHeight = self.minWidth&lt;br /&gt;
        self.options.aspectRatio = 1&lt;br /&gt;
    else&lt;br /&gt;
        if self.widthVal and self.heightVal then&lt;br /&gt;
            self.options.aspectRatio = self.widthVal / self.heightVal&lt;br /&gt;
        elseif self.widthVal then&lt;br /&gt;
            self.height = self.width&lt;br /&gt;
            self.options.aspectRatio = 1&lt;br /&gt;
        else&lt;br /&gt;
            self.options.aspectRatio = 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param text string | table | nil&lt;br /&gt;
---@param position string | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setTitle( text, position )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setTitle&amp;#039; )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;chart.setTitle&amp;#039;, 1, text, {&amp;#039;string&amp;#039;, &amp;#039;table&amp;#039;, &amp;#039;nil&amp;#039;} )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setTitle&amp;#039;, 1, position, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    self:setOptions{&lt;br /&gt;
        title = {&lt;br /&gt;
            display = text and true or false,&lt;br /&gt;
            text = text,&lt;br /&gt;
            position = position or &amp;#039;top&amp;#039;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param label string | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setXLabel( label )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setXLabel&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setXLabel&amp;#039;, 1, label, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;line&amp;#039;, &amp;#039;bar&amp;#039;, &amp;#039;bubble&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                x = {&lt;br /&gt;
                    scaleLabel = {&lt;br /&gt;
                        display = label and true or false,&lt;br /&gt;
                        labelString = label&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param label string | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setYLabel( label )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setYLabel&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYLabel&amp;#039;, 1, label, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;line&amp;#039;, &amp;#039;bar&amp;#039;, &amp;#039;bubble&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                y = {&lt;br /&gt;
                    scaleLabel = {&lt;br /&gt;
                        display = label and true or false,&lt;br /&gt;
                        labelString = label&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param min number | nil&lt;br /&gt;
---@param max number | nil&lt;br /&gt;
---@param step number | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setXLimits( min, max, step )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setXLimits&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setXLimits&amp;#039;, 1, min, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setXLimits&amp;#039;, 2, max, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setXLimits&amp;#039;, 3, step, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;bubble&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                x = {&lt;br /&gt;
                    min  = min,&lt;br /&gt;
                    max = max,&lt;br /&gt;
                    ticks = {&lt;br /&gt;
                        stepSize = step&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param min number | nil&lt;br /&gt;
---@param max number | nil&lt;br /&gt;
---@param step number | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setYLimits( min, max, step )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setYLimits&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYLimits&amp;#039;, 1, min, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYLimits&amp;#039;, 2, max, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYLimits&amp;#039;, 3, step, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;line&amp;#039;, &amp;#039;bar&amp;#039;, &amp;#039;bubble&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                y = {&lt;br /&gt;
                    min  = min,&lt;br /&gt;
                    max = max,&lt;br /&gt;
                    ticks = {&lt;br /&gt;
                        stepSize = step&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param format string&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setYFormat( format )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setYFormat&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYFormat&amp;#039;, 1, format, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    self:setOptions{&lt;br /&gt;
        scales = {&lt;br /&gt;
            y = {&lt;br /&gt;
                ticks = {&lt;br /&gt;
                    format = format&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param min number | nil&lt;br /&gt;
---@param max number | nil&lt;br /&gt;
---@param step number | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setRadialLimits( min, max, step )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setRadialLimits&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setRadialLimits&amp;#039;, 1, min, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setRadialLimits&amp;#039;, 2, max, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setRadialLimits&amp;#039;, 3, step, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;radar&amp;#039;, &amp;#039;polarArea&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scale = {&lt;br /&gt;
                min  = min,&lt;br /&gt;
                max = max,&lt;br /&gt;
                ticks = {&lt;br /&gt;
                    stepSize = step&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param type string | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setXAxisType( type )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setXAxisType&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setXAxisType&amp;#039;, 1, type, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;bar&amp;#039;, &amp;#039;bubble&amp;#039;, &amp;#039;line&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                x = {&lt;br /&gt;
                    type = type&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param type string | nil&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setYAxisType( type )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setYAxisType&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setYAxisType&amp;#039;, 1, type, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    if arr.contains( {&amp;#039;bar&amp;#039;, &amp;#039;bubble&amp;#039;, &amp;#039;line&amp;#039;, &amp;#039;scatter&amp;#039;}, self.type ) then&lt;br /&gt;
        self:setOptions{&lt;br /&gt;
            scales = {&lt;br /&gt;
                y = {&lt;br /&gt;
                    type = type&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param val boolean&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:showLegend( val )&lt;br /&gt;
    checkChartClass( self, &amp;#039;showLegend&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.showLegend&amp;#039;, 1, val, &amp;#039;boolean&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    self:setOptions{&lt;br /&gt;
        legend = {&lt;br /&gt;
            display = val&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param format string&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setTooltipFormat( format )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setTooltipFormat&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setTooltipFormat&amp;#039;, 1, format, &amp;#039;string&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    self:setOptions{&lt;br /&gt;
        tooltips = {&lt;br /&gt;
        	format = format&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param count number&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setDatasetsPerGroup( count )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setDatasetsPerGroup&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setDatasetsPerGroup&amp;#039;, 1, label, &amp;#039;number&amp;#039;, true )&lt;br /&gt;
&lt;br /&gt;
    self:setOptions{&lt;br /&gt;
        datasetsPerGroup = count&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:flipXY()&lt;br /&gt;
    checkChartClass( self, &amp;#039;flipXY&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    if self.type == &amp;#039;bar&amp;#039; then&lt;br /&gt;
        self:setXAxisType( &amp;#039;linear&amp;#039; )&lt;br /&gt;
            :setYAxisType( &amp;#039;category&amp;#039; )&lt;br /&gt;
            :setOptions{&lt;br /&gt;
                scales = {&lt;br /&gt;
                    x = {&lt;br /&gt;
                        offset = false,&lt;br /&gt;
                        gridLines = {&lt;br /&gt;
                            offsetGridLines = false&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        self.flippedXY = true&lt;br /&gt;
&lt;br /&gt;
        for _, v in ipairs( self.data.datasets ) do&lt;br /&gt;
            v.indexAxis = &amp;#039;y&amp;#039;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param options options_t&lt;br /&gt;
---@return chart&lt;br /&gt;
function chart:setOptions( options )&lt;br /&gt;
    checkChartClass( self, &amp;#039;setOptions&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.setOptions&amp;#039;, 1, options, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    local function _setOptions( tbl, options )&lt;br /&gt;
        for k, v in pairs( options ) do&lt;br /&gt;
            if type( v ) == &amp;#039;table&amp;#039; and type( tbl[k] ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
                _setOptions( tbl[k], v )&lt;br /&gt;
            else&lt;br /&gt;
                tbl[k] = v&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    _setOptions( self.options, options )&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@return string | table&lt;br /&gt;
function chart:finish()&lt;br /&gt;
    checkChartClass( self, &amp;#039;finish&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    for i, set in ipairs( self.data.datasets ) do&lt;br /&gt;
        if (self.options.colorPallet or set.colorPallet) and&lt;br /&gt;
            self.options.backgroundAlpha and&lt;br /&gt;
            self.options.hoverLightenValue and&lt;br /&gt;
            self.options.hoverSaturateValue and&lt;br /&gt;
            self.options.hoverAlpha&lt;br /&gt;
        then&lt;br /&gt;
            if arr.contains( {&amp;#039;bar&amp;#039;, &amp;#039;pie&amp;#039;, &amp;#039;doughnut&amp;#039;, &amp;#039;polarArea&amp;#039;}, self.type ) then&lt;br /&gt;
                if set.color and not set.colorPallet then&lt;br /&gt;
                    set.borderColor = tostring( set.color )&lt;br /&gt;
                    set.hoverBorderColor = tostring( set.color:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                              :saturate( self.options.hoverSaturateValue ) )&lt;br /&gt;
&lt;br /&gt;
                    set.backgroundColor = tostring( set.color:fade( self.options.backgroundAlpha ) )&lt;br /&gt;
                    set.hoverBackgroundColor = tostring( set.color:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                                  :saturate( self.options.hoverSaturateValue )&lt;br /&gt;
                                                                  :fade( self.options.hoverAlpha ) )&lt;br /&gt;
                else&lt;br /&gt;
                    set.borderColor = {}&lt;br /&gt;
                    set.hoverBorderColor = {}&lt;br /&gt;
                    set.backgroundColor = {}&lt;br /&gt;
                    set.hoverBackgroundColor = {}&lt;br /&gt;
&lt;br /&gt;
                    local pallet = default( set.colorPallet, self.options.colorPallet )&lt;br /&gt;
&lt;br /&gt;
                    for j = 1, #set.data do&lt;br /&gt;
                        table.insert( set.borderColor, tostring( pallet[j] ) )&lt;br /&gt;
                        table.insert( set.hoverBorderColor,&lt;br /&gt;
                                      tostring( pallet[j]:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                         :saturate( self.options.hoverSaturateValue ) ) )&lt;br /&gt;
&lt;br /&gt;
                        table.insert( set.backgroundColor, tostring( pallet[j]:fade( self.options.backgroundAlpha ) ) )&lt;br /&gt;
                        table.insert( set.hoverBackgroundColor,&lt;br /&gt;
                                      tostring( pallet[j]:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                         :saturate( self.options.hoverSaturateValue )&lt;br /&gt;
                                                         :fade( self.options.hoverAlpha ) ) )&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            else&lt;br /&gt;
                local pallet = default( set.colorPallet, self.options.colorPallet )&lt;br /&gt;
                set.borderColor = default( set.borderColor, pallet[i] )&lt;br /&gt;
&lt;br /&gt;
                if not set.hoverBorderColor then&lt;br /&gt;
                    set.hoverBorderColor = set.borderColor:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                          :saturate( self.options.hoverSaturateValue )&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                set.backgroundColor =&lt;br /&gt;
                    default( set.backgroundColor, self.options.colorPallet[i]:fade( self.options.backgroundAlpha ) )&lt;br /&gt;
&lt;br /&gt;
                if not set.hoverBackgroundColor then&lt;br /&gt;
                    set.hoverBackgroundColor = set.backgroundColor:lighten( self.options.hoverLightenValue )&lt;br /&gt;
                                                                  :saturate( self.options.hoverSaturateValue )&lt;br /&gt;
                                                                  :fade( self.options.hoverAlpha )&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                set.fill = default( default( set.fill, self.options.fill ), false )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    stripInvalidValues( self )&lt;br /&gt;
    self.isFinished =  true&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@return string&lt;br /&gt;
function chart:tostring()&lt;br /&gt;
    checkChartClass( self, &amp;#039;tostring&amp;#039; )&lt;br /&gt;
    self:finish()&lt;br /&gt;
    return chart._main( self )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function chart:debug()&lt;br /&gt;
    checkChartClass( self, &amp;#039;debug&amp;#039; )&lt;br /&gt;
    local temp = colorPalletMt.__index  -- By design this makes the color pallet tables behave like they are infinitely long,&lt;br /&gt;
                                        -- so we have to turn this off first&lt;br /&gt;
    local temp2 = chart.__tostring  -- Prevent chart from being turned into a json&lt;br /&gt;
    colorPalletMt.__index = nil&lt;br /&gt;
    chart.__tostring = nil&lt;br /&gt;
    mw.logObject( self )&lt;br /&gt;
    colorPalletMt.__index = temp&lt;br /&gt;
    chart.__tostring = temp2&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
chart.__index = chart&lt;br /&gt;
chart.__tostring = chart.tostring&lt;br /&gt;
chart.__concat = function( x, y )&lt;br /&gt;
    return tostring( x ) .. tostring( y )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- =======================&lt;br /&gt;
--      DataSet class&lt;br /&gt;
-- =======================&lt;br /&gt;
local checkDataSetClass = libraryUtil.makeCheckClassFunction( &amp;#039;Module:Chart data&amp;#039; , &amp;#039;dataSet&amp;#039;, dataSet, &amp;#039;dataSet object&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
---@param setup options_t&lt;br /&gt;
---@return dataSet&lt;br /&gt;
function chart:newDataSet( setup )&lt;br /&gt;
    checkChartClass( self, &amp;#039;newDataSet&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;chart.newDataSet&amp;#039;, 1, setup, &amp;#039;table&amp;#039;, true )&lt;br /&gt;
    local obj = setup or {}&lt;br /&gt;
&lt;br /&gt;
    if self.type == &amp;#039;scatter&amp;#039;  then&lt;br /&gt;
        obj.showLine = default( obj.showLine, true )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if self.type == &amp;#039;bar&amp;#039; then&lt;br /&gt;
        obj.borderWidth = default( obj.borderWidth, 1 )&lt;br /&gt;
&lt;br /&gt;
        if self.flippedXY then&lt;br /&gt;
            obj.indexAxis = &amp;#039;y&amp;#039;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    obj.data = default( obj.data, {} )&lt;br /&gt;
    obj.clip = 5&lt;br /&gt;
    obj.parent = self&lt;br /&gt;
&lt;br /&gt;
    self:addDataSets( obj )&lt;br /&gt;
&lt;br /&gt;
    return setmetatable( obj, dataSet )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param data xyDataSet | dataArr&lt;br /&gt;
---@return dataSet&lt;br /&gt;
function dataSet:addData( data )&lt;br /&gt;
    checkDataSetClass( self, &amp;#039;addData&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;dataSet.addData&amp;#039;, 1, data, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    for _, v in ipairs( data ) do&lt;br /&gt;
        table.insert( self.data, v )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param data xyData | number&lt;br /&gt;
---@return dataSet&lt;br /&gt;
function dataSet:addDataPoint( data )&lt;br /&gt;
    checkDataSetClass( self, &amp;#039;addDataPoint&amp;#039; )&lt;br /&gt;
    libraryUtil.checkTypeMulti( &amp;#039;dataSet.addDataPoint&amp;#039;, 1, data, {&amp;#039;table&amp;#039;, &amp;#039;number&amp;#039;} )&lt;br /&gt;
    table.insert( self.data, data )&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@param options options_t&lt;br /&gt;
---@return dataSet&lt;br /&gt;
function dataSet:setOptions( options )&lt;br /&gt;
    checkDataSetClass( self, &amp;#039;setOptions&amp;#039; )&lt;br /&gt;
    libraryUtil.checkType( &amp;#039;dataSet.setOptions&amp;#039;, 1, options, &amp;#039;table&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
    local function _setOptions( tbl, options )&lt;br /&gt;
        for k, v in pairs( options ) do&lt;br /&gt;
            if type( v ) == &amp;#039;table&amp;#039; and type( tbl[k] ) == &amp;#039;table&amp;#039; then&lt;br /&gt;
                _setOptions( tbl[k], v )&lt;br /&gt;
            else&lt;br /&gt;
                tbl[k] = v&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    _setOptions( self, options )&lt;br /&gt;
&lt;br /&gt;
    return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---@return chart&lt;br /&gt;
function dataSet:done()&lt;br /&gt;
    checkDataSetClass( self, &amp;#039;done&amp;#039; )&lt;br /&gt;
    return self.parent&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
dataSet.__index = dataSet&lt;br /&gt;
&lt;br /&gt;
return chart&lt;br /&gt;
-- &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
</feed>