Module:Sandbox/Con-struct (t)/Test1/svg-graphs
Jump to navigation
Jump to search
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
Lua
Documentation for this module may be created at Module:Sandbox/Con-struct (t)/Test1/svg-graphs/doc
Code
-- GraphLineMarker (), create style sheets for line and marker --
--[[
1: graph number
2: sign, if line required
3: sign, if marker required
4: color of border
5: fill color of graph, if available
6: color inside of marker; 'x' means nothing
]]
local function GraphLineMarkerStyle (iGraph, bShowLine, bShowMarker, sColor, sGraphColorFill, sMarkerColorFill)
local sReturn = ''
local sGraphColor, sFill, sFillMarker, sMarker
if bShowLine then
sGraphColor = sColor
else
sGraphColor = 'none'
end
if sGraphColorFill then
sFill = ' fill: ' .. sGraphColorFill .. ';\n'
else
sFill = ''
end
if bShowMarker then sMarker =
' marker-start:url(#graph' .. iGraph .. 'markerstretch); marker-mid:url(#graph' .. iGraph .. 'markerstretch); marker-end:url(#graph' .. iGraph .. 'markerstretch);\n'
else
sMarker = ''
end
sReturn = sReturn ..
' .graph' .. iGraph .. 'lineblank { /*-- look of graph ' .. iGraph .. ' --*/\n' ..
' stroke: ' .. sGraphColor .. ';\n' ..
' }\n' ..
' .graph' .. iGraph .. 'line {\n' ..
' stroke: ' .. sGraphColor .. ';\n' ..
sFill ..
sMarker ..
' }\n'
if bShowMarker then
if not sMarkerColorFill then
sMarkerColorFill = sColor
end
sReturn = sReturn ..
' .graph' .. iGraph .. 'marker { /*-- look of marker ' .. iGraph .. ' --*/\n' ..
' stroke: ' .. sColor .. ';\n' ..
' fill: ' .. sMarkerColorFill .. ';\n' ..
' }\n'
end
return sReturn
end
---- GraphUseLine () workaround for constant line thickness on stretched graphs, one line: ----
--[[1: id number, text
2: delta, px
3: direction
4: href of graph
5: extra attributes
]]
local function GraphUseLine (sID, dDelta, sDirection, sHref, sExtraAttributes)
local sTranslate
if sDirection == "y" then
sTranslate = '0, ' .. dDelta
else
sTranslate = dDelta .. ', 0'
end
if sExtraAttributes then
sExtraAttributes = ' ' .. sExtraAttributes
else
sExtraAttributes = ""
end
gsDebug = gsDebug .. 'svg-line.GraphUseLine(): sID: ' .. sID .. ', dDelta: ' .. dDelta .. ', sDirection: ' .. sDirection .. '\n'
return
' <use id="graphuse' .. sID .. '-line' ..
'" transform="translate(' .. sTranslate .. ')"' .. sExtraAttributes ..
' xlink:href="#' .. sHref .. '"/>\n'
end
---- GraphUseLines (), workaround for constant line thickness on stretched graphs, many lines for one graph ----
--[[1: line number
2: defined line thickness (dlt), px, e. g. 0.6
3: required width (rw), %, e. g. 180% means two required lines; ToDo: remove?
4: relation of line thickness width/height or height/width, <= 1
5: direction "x" or "y"
6: href of graph
- the line thickness must be reduced (rlt) before to: rlt = dlt / rw * 100, e. g. 0.33
- the line must be placed
- at outside of real line thickness, = real line width / 2
- minus real line thickness / 2
-> delta = rlt * (1 - rw/100) / 2
- for lapping: 0.49 but not 0.50
]]
local function GraphUseLines (iID, dLineThickness, dWidthRequired, dThicknessRelation, sDirection, sHref)
local sReturn = ""
local sExtraAttribute = 'class="graph' .. iID
if not dLineThickness then dLineThickness = 1 end
if not dThicknessRelation then dThicknessRelation = 1 end
if not sHref then sHref = 'graphs' end
if dThicknessRelation > 1.3 then
sReturn =
GraphUseLine (iID .. 'p2', round ( 0.49 * dLineThickness * (1 - 1/dThicknessRelation), 3), sDirection, sHref, sExtraAttribute .. 'lineblank"') ..
GraphUseLine (iID .. 'm2', round (-0.49 * dLineThickness * (1 - 1/dThicknessRelation), 3), sDirection, sHref, sExtraAttribute .. 'lineblank"')
end
if dThicknessRelation > 2.3 then
sReturn = sReturn ..
GraphUseLine (iID .. 'p3', round ( 0.48 * dLineThickness * (1 - 3/dThicknessRelation), 3), sDirection, sHref, sExtraAttribute .. 'lineblank"') ..
GraphUseLine (iID .. 'm3', round (-0.48 * dLineThickness * (1 - 3/dThicknessRelation), 3), sDirection, sHref, sExtraAttribute .. 'lineblank"')
end
sReturn = sReturn ..
GraphUseLine (iID .. '-1', 0, 'x', sHref, sExtraAttribute .. 'line"') -- none movement of one line
gsDebug = gsDebug .. 'svg-line.GraphUseLines(): iID: ' .. iID .. ', dLineThickness: ' .. dLineThickness .. ', dThicknessRelation: ' .. dThicknessRelation .. '\n'
return sReturn
end
-------- global functions --------
---- svgChartValuePair (), create a pair of values ----
function svgChartValuePair (sX, sY, iXLen, iXLenInteger, iYLenInteger)
if iserror () then return '' end
local iLen
if sX == nil or sY == nil then return nil end
iLen = iXLenInteger - lenInteger (sX)
--gsDebug = gsDebug .. " lenInteger: " .. lenInteger (sX) .. ", iLen: " .. iLen .. ", string.sub. " .. string.sub ("abcdefg", 1, iLen) .. ", " .. sX .. ", \n"
sX = string.sub (" ", 1, iLen) .. sX -- first formatting spaces for the first value
sX = string.sub (sX .. " ", 1, iXLen) -- following formatting spaces for the first value, left side of the string
iLen = iYLenInteger - lenInteger (sY)
sY = string.sub (" ", 1, iLen) .. sY -- first formatting spaces for the 2nd value
return ' ' .. sX .. ' ' .. sY .. '\n'
end
-------- public SVG Chart functions --------
function LineMarkerStyles (dChartElementSize, dGraphWidth, dGraphStretchWidth, dGraphStretchHeight, tsGraphValues, tsGraphLine, tsGraphMarker, tsGraphColor, tsGraphFill, tsGraphMarkerFill)
if iserror () then return '' end
local sReturn, i
sReturn =
' .graphgeneral { /*-- general look of graphs and markers, e.g. in legend --*/\n' ..
' stroke-width: ' .. LineWidth (dChartElementSize, dGraphWidth) .. ';\n' ..
' fill: none;\n' ..
' stroke-linejoin: round;\n' ..
' stroke-linecap: round;\n' ..
' }\n' ..
' .graphgeneralstretch { /*-- general look of graphs and markers on a stretched chart --*/\n' .. -- because vector-effect="non-scaling-stroke" don't work currently
' stroke-width: ' .. LineWidth (dChartElementSize, dGraphWidth, dGraphStretchWidth, dGraphStretchHeight) .. ';\n' ..
' fill: none;\n' ..
' stroke-linejoin: round;\n' ..
' stroke-linecap: round;\n' ..
' }\n'
for i = 1, MAXCHARTNUMBER do
if tsGraphValues[i] or tsGraphMarker[i] then sReturn = sReturn ..
GraphLineMarkerStyle (i, tsGraphLine[i] ~= 'none', tsGraphMarker[i], tsGraphColor[i], tsGraphFill[i], tsGraphMarkerFill[i])
end
end
return sReturn
end
---- svgGraphLine (), code for the graph lines ----
function svgGraphLine (iGraphNumber, sColor)
if iserror () then return '' end
return
' <!-- graph ' .. iGraphNumber .. ' -->\n' ..
' <use id="graphuse' .. iGraphNumber .. '" transform="translate(0, 0)" class="graph' .. iGraphNumber .. 'line" xlink:href="#graph' .. iGraphNumber .. '-line"/>\n'
end
---- svgGraphFill (), code for filled graph areas ----
function svgGraphFill (iGraphNumber, sColor)
if iserror () then return '' end
return
' <!-- graphfill ' .. iGraphNumber .. ' -->\n' ..
' <use id="graphfilluse' .. iGraphNumber .. '" transform="translate(0, 0)" class="graph' .. iGraphNumber .. 'line" xlink:href="#graph' .. iGraphNumber .. '-fill"/>\n'
end
---- svgChartValues (), formatted output of the pairs of values for a chart, 2 values per line ----
function svgChartValues (iChartNumber, tsX, tsY, iXLenMax, iXIntegerLen, iYIntegerLen)
if iserror () then return '' end
-- local sX, sY
local sReturn = ""
local i, sPair
i = 1
--gsDebug = gsDebug .. " svgChartValues (), tiXIntegerLen: " .. tiXIntegerLen[iChartNumber] .. ", tiXLenMax: " .. tiXLenMax[iChartNumber] .. "\n"
while true do
-- sPair = svgChartValuePair (tsX[i], tsY[i], tiXLenMax[iChartNumber], tiXIntegerLen[iChartNumber], tiYIntegerLen[iChartNumber])
sPair = svgChartValuePair (tsX[i], tsY[i], iXLenMax, iXIntegerLen, iYIntegerLen)
if sPair == nil then break end
sReturn = sReturn .. sPair
i = i + 1
end
return sReturn
end
-- --
function svgGraphsDefs (dYMin, tsX, tsY, tsGraphValues, tsGraphFill, tsXFirst, tsXLast, tsGraphText, dGraph1WidthPx, iXLenMax, iXIntegerLen, iYIntegerLen)
if iserror () then return '' end
local i, bGraphsOther, sStroke, sHeadFill, sHeadLine, sGraphEnd, sGraphText, sReturnFill, sReturnLine
sReturnLine = ''
sReturnFill = ''
bGraphsOther = false
for i = MAXCHARTNUMBER, 1, -1 do
-- charts --
sStroke = ''
if tsGraphValues[i] and tsX[i] and tsY[i] then
-- sReturnLine = sReturnLine .. svgGraph (i, 0)
-- graph no. 1 --
if i == 1 then
sHeadLine = '<g id="graph1">\n'
sHeadFill = '<g id="graph1-fill">\n'
sStroke = 'stroke-width="' .. dGraph1WidthPx .. '" '
-- all the other graphs --
else if not bGraphsOther then -- 1x instructions for all graphs without graph 1
sHeadLine = '<g id="graphs">\n'
sHeadFill = '<g id="graphs-fill">\n'
bGraphsOther = true
else -- all the graphs without graph 1
sHeadLine = ''
sHeadFill = ''
end end
-- comment --
if tsGraphText[i] then
sGraphText = tsGraphText[i]
else
sGraphText = 'graph ' .. i
end
if i == 1 or (i == 2 and bGraphsOther) then -- to times a </g> end: for 1st graph and summary of all other graphs
sGraphEnd = '</g>\n'
else
sGraphEnd = ''
end
-- complete svg instructions for every graph --
sReturnLine = sReturnLine ..
-- todo stroke-width="0.98
sHeadLine ..
' <!-- ' .. sGraphText .. ' -->\n' ..
' <polyline id="graph' .. i .. '-line" ' .. sStroke .. 'fill="none" points="\n' ..
svgChartValues (i, tsX[i], tsY[i], iXLenMax, iXIntegerLen, iYIntegerLen) ..
' "/>\n' ..
sGraphEnd
end
-- fill the graph area if wanted --
if tsGraphFill[i] and tsGraphValues[i] then
-- todo stroke-width="0.98
sReturnFill = sReturnFill ..
sHeadFill ..
' <!-- ' .. sGraphText .. ' -->\n' ..
' <polyline id="graphfill' .. i .. '-fill" stroke="none" points="\n' ..
svgChartValuePair (tsXFirst[i], dYMin, iXLenMax, iXIntegerLen, iYIntegerLen) ..
svgChartValues (i, tsX[i], tsY[i], iXLenMax, iXIntegerLen, iYIntegerLen) ..
svgChartValuePair (tsXLast[i], dYMin, iXLenMax, iXIntegerLen, iYIntegerLen) ..
' "/>\n' ..
'</g>\n'
end
end
return
'<!--====== graph data with origin values, you can manually copy or attach the values here ======-->\n' ..
'<!-- modify displacement "translate" -->\n' ..
sReturnFill .. sReturnLine
end
---- GraphUse (), workaround for constant line thickness on stretched graphs: ----
--[[in case that the function vector-effect="non-scaling-stroke" is sometimes implemented in the rsvg lib
and that lib is impemented in wikicommons, this workaround should be dropped by
- remove of the defs command for the lines, implementing vector-effect="non-scaling-stroke" there and
- propper scaling of the defined line thicknesses
- remove all other factors of {{{GraphStretchWidth|100}}}|{{{GraphStretchHeight|100}}}
1: line number
dLineWidthPx
2: DiagramSize, px
3: href of graphs
4: GraphStretchWidth, %
5: GraphStretchHeight, %
6: alternate line thicknes, %
]]
local function svgGraphUse (iID, dLineWidthPx, iDiagramSize, dGraphStretchWidth, dGraphStretchHeight, dThicknessAlternate)
-- local sReturn = ' <!-- graph ' .. iID .. ' -->\n'
local sHref
local sReturn = ' <!-- graph ' .. iID .. ' -->\n'
--[[ if iID == 1 then
sHref = 'graph' .. iID
else
sHref = 'graph' .. iID .. '-line'
end ]]
sHref = 'graph' .. iID .. '-line'
if dGraphStretchWidth > dGraphStretchHeight then
sReturn = sReturn ..
GraphUseLines (iID, dLineWidthPx, dGraphStretchWidth , dGraphStretchWidth / dGraphStretchHeight, 'y', sHref) -- /LineWidth must have the same stroke-width expression as in def "graphgeneral"
else
sReturn = sReturn ..
GraphUseLines (iID, dLineWidthPx, dGraphStretchHeight, dGraphStretchHeight / dGraphStretchWidth, 'x', sHref) -- /LineWidth must have the same stroke-width expression as in def "graphgeneral"
end
gsDebug = gsDebug .. 'svg-line.svgGraphUse(): iID: ' .. iID .. ', dGraphStretchWidth: ' .. dGraphStretchWidth .. ', dGraphStretchHeight: ' .. dGraphStretchHeight .. '\n'
return sReturn
end
-- function GraphUseLines (iID, dLineThickness, dWidthRequired, dThicknessRelation, sDirection, sHref)
---- svg generation with backward order, required for some visibilities ----
function svgGraphsUse (dXMin, dYMin, dLineWidthPx, dImageSize, tsGraphValues, tsGraphFill, dGraphStretchWidth, dGraphStretchHeight, svgGraphFill)
if iserror () then return '' end
local i, sReturnLine
local sReturnFill = ''
sReturnLine = ' \n' ..
'<g class="graphgeneralstretch" transform="scale(' ..
round ( dGraphStretchWidth / 100, 1) .. ', ' ..
round (-1 * dGraphStretchHeight / 100, 1) .. ') translate(' .. -1 * dXMin .. ', ' .. -1 * dYMin .. ')">\n'
for i = MAXCHARTNUMBER, 1, -1 do
-- chart lines --
if tsGraphValues[i] then
sReturnLine = sReturnLine ..
--todo svgGraphUse (i, iDiagramSize, dGraphStretchWidth, dGraphStretchHeight, dThicknessAlternate) (i, gtsX[i], gtsY[i]) ..
svgGraphUse (i, dLineWidthPx, dImageSize, dGraphStretchWidth, dGraphStretchHeight, dLineWidthPx)
end
-- fill the chart area if wanted --
if tsGraphFill[i] and tsGraphValues[i] then
if sReturnFill == '' then
sReturnFill = ' \n' ..
'<g class="graphgeneralstretch" transform="scale(' ..
round ( dGraphStretchWidth / 100, 1) .. ', ' ..
round (-1 * dGraphStretchHeight / 100, 1) .. ') translate(' .. -1 * dXMin .. ', ' .. -1 * dYMin .. ')">\n'
end
--sReturnFill = sReturnFill .. ' ' .. i .. ', \n'
sReturnFill = sReturnFill ..
svgGraphFill (i, tsGraphFill[i])
if i == 1 then end
end
end
-- finalize svg instructions --
if sReturnFill ~= '' then sReturnFill = sReturnFill .. '</g>\n' end
if sReturnLine then sReturnLine = sReturnLine .. '</g>\n' end
gsDebug = gsDebug .. 'svg-line.svgGraphs(): dLineWidth: ' .. dLineWidthPx .. ', dImageSize: ' .. dImageSize .. '\n'
return sReturnFill .. sReturnLine
end