Module:CineMol/svg
Jump to navigation
Jump to search
-- This is a port of CineMol to lua
-- CineMol https://github.com/moltools/CineMol was written by David Meijer, Marnix H. Medema & Justin J. J. van der Hooft and is MIT licensed
-- Please consider any edits made to this page as dual licensed MIT & CC-BY-SA 4.0
local p = {}
local Point2D = require( 'Module:CineMol/geometry' ).Point2D
local checkType = require( 'Module:CineMol/geometry' ).checkType
local Color = require( 'Module:CineMol/style' ).Color
local Fill = require( 'Module:CineMol/style' ).Fill
function p.Circle2D(reference, center, radius)
checkType( 'Circle2D', 1, reference, 'string' )
checkType( 'Circle2D', 2, center, 'Point2D' )
checkType( 'Circle2D', 3, radius, 'number' )
local obj = {
_TYPE = 'Shape2D',
reference = reference,
center = center,
radius = radius
}
function obj:to_svg()
return string.format('<circle class="%s" cx="%.3f" cy="%.3f" r="%.3f"/>', self.reference, self.center.x, self.center.y, self.center.radius )
end
return obj
end
function p.Line2D(reference, start, endp)
checkType( 'Line2D', 1, reference, 'string' )
checkType( 'Line2D', 2, start, 'Point2D' )
checkType( 'Line2D', 3, endp, 'Point2D' )
local obj = {
_TYPE = 'Shape2D',
reference = reference,
start = start,
endp = endp
}
function obj:to_svg()
return string.format(
'<line class="%s" x1="%.3f" y1="%.3f" x2="%.3f" y2="%.2f"/>',
self.reference, self.start.x, self.start.y, self.endp.x, self.endp.y
)
end
return obj
end
function p.Polygon2D(reference, points)
checkType( 'Line2D', 1, reference, 'string' )
checkType( 'Line2D', 2, points, 'table' )
assert( #points == 0 or points[1]._TYPE == 'Point2D', 'Wrong type for arg 2' )
local obj = {
_TYPE = 'Shape2D',
reference = reference,
points = points
}
function obj:to_svg()
local pointList = ''
for _,pt in ipairs(points) do
pointList = pointList .. string.format( "%.3f,%.3f ", pt.x, pt.y )
end
if string.sub( pointList, -1 ) == ' ' then
pointList = string.sub( pointList, 1, -2 )
end
return string.format(
'<polygon class="%s" points="%s"/>',
self.reference,
pointList
)
end
return obj
end
-- This is a bit different than CineMol.
function p.ViewBox( minx, miny, width, height )
checkType( 'ViewBox', 1, minx, 'number' )
checkType( 'ViewBox', 2, miny, 'number' )
checkType( 'ViewBox', 3, width, 'number' )
checkType( 'ViewBox', 4, height, 'number' )
local obj = {
_TYPE = 'ViewBox',
miny = miny,
minx = minx,
width = width,
height = height
}
function obj:to_value()
return string.format("%.3f %.3f %.3f %.3f", minx, miny, width, height )
end
return obj
end
-- This is different then in CineMol
function p.Svg(view_box, window, background_color, fills, objects)
checkType( 'Svg', 1, view_box, 'ViewBox' )
fills = fills == nil and {} or fills
objects = objects == nil and {} or objects
local obj = {
_TYPE = 'Svg',
view_box = view_box,
-- We maybe ignore this and handle our own sizing.
window = window,
background_color = background_color,
fills = fills,
objects = objects
}
function obj:header()
local x = self.view_box.min_x
local y = self.view_box.min_y
local background = ""
if self.background_color ~= nil then
background =
"<rect " ..
string.format('x="%.3f" y="%.3f" ', x, y ) ..
'width="100%" ' ..
'height="100%" ' ..
string.format( 'fill="%s"', self.background_color.to_hex() ) ..
"/>"
end
return background
end
-- We do not return surounding <svg> tag
function obj:to_svg()
local header = self:header()
local styles, definitions = {}, {}
for i,fill in ipairs(self.fills) do
local style, definition = fill:to_svg()
assert( style ~= 'nil' )
styles[#styles+1] = style
if definition ~= nil then
definitions[#definitions+1] = definition
end
end
local styles_str = table.concat( styles, "\n" )
local definitions_str = table.concat( definitions, "\n" )
local objects_str = ""
for i,object in ipairs( objects ) do
objects_str = objects_str .. object:to_svg() .. "\n"
end
return header .. "\n<defs>\n<style>\n" .. styles_str .. "\n</style>\n" .. definitions_str .. "\n</defs>\n" .. objects_str
end
function obj:to_mw_svg()
return mw.svg.new()
:setAttribute( 'viewBox', self.view_box:to_value() )
:setContent( self:to_svg() )
end
return obj
end
return p