Comme promis, voici ma version du Caire. Je l'ai scripté avec Lua, en utilisant lfs pour parcourir les répertoires. J'aime ces petits défis, car ils me permettent d'explorer des APIs que je voulais creuser depuis un certain temps...
lfs et LuaCairo sont tous deux multiplateformes, donc cela devrait fonctionner sur d'autres systèmes (testé sur WinXP Pro SP3 français).
J'ai fait une première version en dessinant les noms des fichiers au fur et à mesure que je marchais dans l'arbre. Avantage : pas de surcharge mémoire. Inconvénient : Je dois spécifier la taille de l'image au préalable, donc les listes risquent d'être coupées.
J'ai donc réalisé cette version, en parcourant d'abord l'arbre des répertoires, en le stockant dans une table Lua. Ensuite, connaissant le nombre de fichiers, je crée le canevas pour qu'il s'adapte (au moins verticalement) et je dessine les noms.
Vous pouvez facilement passer du rendu PNG au rendu SVG. Le problème avec ce dernier : Cairo le génère à bas niveau, en dessinant les lettres au lieu d'utiliser la capacité de texte de SVG. Au moins, cela garantit un rendu précis même sur des systèmes sans police. Mais les fichiers sont plus gros... Ce n'est pas vraiment un problème si vous le compressez après, pour avoir un fichier .svgz.
Ou il ne devrait pas être trop difficile de générer le SVG directement, j'ai utilisé Lua pour générer le SVG dans le passé.
-- LuaFileSystem <http://www.keplerproject.org/luafilesystem/>
require"lfs"
-- LuaCairo <http://www.dynaset.org/dogusanh/>
require"lcairo"
local CAIRO = cairo
local PI = math.pi
local TWO_PI = 2 * PI
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Graphviz"
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Tecgraf"
local dirToList = arg[1] or "C:/PrgCmdLine/tcc"
-- Ensure path ends with /
dirToList = string.gsub(dirToList, "([^/])$", "%1/")
print("Listing: " .. dirToList)
local fileNb = 0
--~ outputType = 'svg'
outputType = 'png'
-- dirToList must have a trailing slash
function ListDirectory(dirToList)
local dirListing = {}
for file in lfs.dir(dirToList) do
if file ~= ".." and file ~= "." then
local fileAttr = lfs.attributes(dirToList .. file)
if fileAttr.mode == "directory" then
dirListing[file] = ListDirectory(dirToList .. file .. '/')
else
dirListing[file] = ""
end
fileNb = fileNb + 1
end
end
return dirListing
end
--dofile[[../Lua/DumpObject.lua]] -- My own dump routine
local dirListing = ListDirectory(dirToList)
--~ print("\n" .. DumpObject(dirListing))
print("Found " .. fileNb .. " files")
--~ os.exit()
-- Constants to change to adjust aspect
local initialOffsetX = 20
local offsetY = 50
local offsetIncrementX = 20
local offsetIncrementY = 12
local iconOffset = 10
local width = 800 -- Still arbitrary
local titleHeight = width/50
local height = offsetIncrementY * (fileNb + 1) + titleHeight
local outfile = "CairoDirTree." .. outputType
local ctxSurface
if outputType == 'svg' then
ctxSurface = cairo.SvgSurface(outfile, width, height)
else
ctxSurface = cairo.ImageSurface(CAIRO.FORMAT_RGB24, width, height)
end
local ctx = cairo.Context(ctxSurface)
-- Display a file name
-- file is the file name to display
-- offsetX is the indentation
function DisplayFile(file, bIsDir, offsetX)
if bIsDir then
ctx:save()
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_source_rgb(0.5, 0.0, 0.7)
end
-- Display file name
ctx:move_to(offsetX, offsetY)
ctx:show_text(file)
if bIsDir then
ctx:new_sub_path() -- Position independent of latest move_to
-- Draw arc with absolute coordinates
ctx:arc(offsetX - iconOffset, offsetY - offsetIncrementY/3, offsetIncrementY/3, 0, TWO_PI)
-- Violet disk
ctx:set_source_rgb(0.7, 0.0, 0.7)
ctx:fill()
ctx:restore() -- Restore original settings
end
-- Increment line offset
offsetY = offsetY + offsetIncrementY
end
-- Erase background (white)
ctx:set_source_rgb(1.0, 1.0, 1.0)
ctx:paint()
--~ ctx:set_line_width(0.01)
-- Draw in dark blue
ctx:set_source_rgb(0.0, 0.0, 0.3)
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_font_size(titleHeight)
ctx:move_to(5, titleHeight)
-- Display title
ctx:show_text("Directory tree of " .. dirToList)
-- Select font for file names
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_NORMAL)
ctx:set_font_size(10)
offsetY = titleHeight * 2
-- Do the job
function DisplayDirectory(dirToList, offsetX)
for k, v in pairs(dirToList) do
--~ print(k, v)
if type(v) == "table" then
-- Sub-directory
DisplayFile(k, true, offsetX)
DisplayDirectory(v, offsetX + offsetIncrementX)
else
DisplayFile(k, false, offsetX)
end
end
end
DisplayDirectory(dirListing, initialOffsetX)
if outputType == 'svg' then
cairo.show_page(ctx)
else
--cairo.surface_write_to_png(ctxSurface, outfile)
ctxSurface:write_to_png(outfile)
end
ctx:destroy()
ctxSurface:destroy()
print("Found " .. fileNb .. " files")
Bien sûr, vous pouvez changer les styles. Je n'ai pas dessiné les lignes de connexion, je ne le voyais pas comme nécessaire. Je pourrais les ajouter optionnellement plus tard.
11 votes
Pourquoi cette question est-elle fermée ? Il existe des DSL de programmation pour dessiner des arbres : par exemple, des outils comme Graphviz qui peuvent résoudre ce problème de manière "programmatique".
5 votes
Je vais rouvrir le dossier (provisoirement) parce que si c'était un simple "comment montrer ce qui est à l'écran", il aurait demandé une capture d'écran. S'il veut le dessiner, c'est probablement pour un document de conception ou une présentation, donc il va programmer à un moment donné.
2 votes
Je suis d'accord. J'ai déjà eu besoin de ce même type de fonctionnalité et j'ai dû faire semblant avec Visio. J'en avais besoin pour la documentation de l'UE. C'était certainement lié au code.
7 votes
Très stupide, de fermer ceci comme hors-sujet. Moi aussi, j'ai trouvé un besoin de quelque chose SO aime censurer.
1 votes
Je suis désolé si ma question est hors sujet ici. Je comprends la raison pour laquelle. Merci à tous ceux qui ont répondu, cela a été utile. Pour clarifier, j'avais besoin d'un diagramme à inclure dans la documentation de l'arbre du projet. Les captures d'écran ne suffisent pas car l'arbre entier est plus long qu'un seul écran.
0 votes
De une question similaire sur Meta Stack Exchange essayez d'utiliser jsfiddle.net/WjAk9/7/embedded/résultat
0 votes
sudo snap install tree
ou visitez snapcraft.io/tree