Module:Gradient

From blackwiki
Jump to navigation Jump to search
g = {};

convert = require( "Module:BaseConvert" );
math_mod = require( "Module:Math" );

function hexToDec( val )
    return convert.convert( { n = val, base = 10, from = 16, precision = 0, width = 3 } );    
end

function decToHex( val )
    return convert.convert( { n = val, base = 16, precision = 0, width = 2 } );
end

function getTriplet( hex_code )
    local v1, v2, v3;
    
    v1 = hexToDec( hex_code:sub(1,2) );
    v2 = hexToDec( hex_code:sub(3,4) );
    v3 = hexToDec( hex_code:sub(5,6) );
    
    return v1, v2, v3;
end

function makeTriplet( v1, v2, v3 )
    local val = {
        decToHex( v1 ),
        decToHex( v2 ),
        decToHex( v3 )
        }
    
    return table.concat( val );
end

function g.export_gradient( frame )
    local result = {};
    local index = 1;
    local pos, color;
    local v1,v2,v3;
    
    while true do
        pos = frame.args[index];
        color = frame.args[index + 1];
        index = index + 2;
        
        if color == nil or pos == nil then
            break;
        end
        pos = tonumber( pos );
        color = color:match( "^%s*(.-)%s*$" );
        
        if color:sub(1,1) == '#' then
            color = color:sub(2);
        end
        v1, v2, v3 = getTriplet( color );
        
        table.insert( result, pos .. ': ' .. v1 .. ', ' .. v2 .. ', ' .. v3 .. '; ' );
    end
    
    return table.concat( result );
end
    
function importGradient( gradientString )
    local pattern_table = {};
    
    gradientString = gradientString:gsub( ' ', '' );
    for pos, v1, v2, v3 in string.gmatch( gradientString , "([-%d%.]*):(%d+),(%d+),(%d+);") do    
        table.insert( pattern_table, { tonumber(pos), tonumber(v1), tonumber(v2), tonumber(v3) } );
    end
    
    comp = function( a, b ) return a[1] < b[1]; end
    table.sort( pattern_table, comp );
    
    return pattern_table;
end

function getGradientValue( value, gradient_table )
    local last_pos = nil;
    local last_item = nil;
    
    for _, v in ipairs( gradient_table ) do
        if v[1] >= value then
            if last_item == nil then
                return v[2], v[3], v[4];
            else
                local shift = (value - last_item[1]) / (v[1] - last_item[1]);
                return shift*v[2] + (1-shift)*last_item[2], 
                    shift*v[3] + (1-shift)*last_item[3], 
                    shift*v[4] + (1-shift)*last_item[4]
            end
        end
        last_item = v;
    end
    
    return last_item[2], last_item[3], last_item[4];
end        

function g.gradient_value( frame )
    local gradient = frame.args.gradient;
    local value = tonumber( frame.args[1] or frame.args.value );
    local v1, v2, v3;
    
    if gradient == nil then 
        return '';
    end
    
    gradient = importGradient( gradient );
    v1, v2, v3 = getGradientValue( value, gradient );
    
    return makeTriplet( v1, v2, v3 );
end

function g.gradient_test( frame )
    local gradient = frame.args.gradient;   
    local step = frame.args.step;
    local row_break = tonumber( frame.args.cells_per_row or 20 );
    
    if gradient == nil then 
        return '';
    end
    
    gradient = importGradient( gradient );

    local min_value = nil;
    local max_value = nil;
    for _, v in ipairs( gradient ) do
        if min_value == nil or min_value > v[1] then
            min_value = v[1];
        end
        if max_value == nil or max_value < v[1] then
            max_value = v[1];
        end 
    end
        
    if step == nil then 
        step = (max_value - min_value)/30;
        step = math_mod._round( step, math.max( math_mod._precision( max_value ), math_mod._precision( min_value ) ) + 1 );
    end    
        
    local result = "{| class=wikitable \n";
    local v1, v2, v3, color;
    local count = 0;
    for i = min_value,max_value+step/2,step do
        v1, v2, v3 = getGradientValue( i, gradient );
        color = makeTriplet( v1, v2, v3 );
        result = result .. '| style="background-color:#' .. color .. '; width:2em; text-align:center;" | ' .. i ..
            '<br \><span style="color:#FFFFFF">' .. i .. '</span>\n';
        count = count + 1;
        if count == row_break then
            result = result .. '|- \n';
            count = 0;
        end        
    end
    
    result = result .. "|}"
    return result;
end

return g;