diff --git a/README.md b/README.md index dc9327bf..2c0e4d70 100644 --- a/README.md +++ b/README.md @@ -7,23 +7,26 @@ ## Luxor -Luxor is a Julia package for drawing simple 2D vector graphics. Think of it as a high-level easier to use interface to [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. In Luxor, the emphasis is on simplicity and ease of use. +Luxor is a Julia package for drawing simple static 2D vector graphics. It provides basic drawing functions and utilities for working with shapes, polygons, clipping masks, PNG and SVG images, turtle graphics, and simple animations. !["luxor gallery"](docs/src/assets/figures/luxorgallery.svg) -Luxor is thoroughly procedural and static: your code issues a sequence of simple graphics 'commands' until you've completed a drawing, then the results are saved into a PDF, PNG, SVG, or EPS file. +The focus of Luxor is on simplicity and ease of use: it should be easier to use than plain [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. -Tutorials can be found in the documentation, which you find by clicking on the badges above: +For more complex and sophisticated graphics in 2D and 3D, [Makie.jl](https://docs.makie.org/stable/) is the best choice. + +Luxor is thoroughly procedural and static: your code issues a sequence of simple graphics ‘commands’ until you’ve completed a drawing, then the results are saved into a PDF, PNG, SVG, or EPS file. +Tutorials can be found in the documentation, which you find by clicking on the badges above: ![where is the documentation?](docs/src/assets/figures/where-is-the-documentation.png) “stable” describes the current release; “development” contains changes that are still in the master branch and may change before the next release. There are some Luxor-related videos on [YouTube](https://www.youtube.com/channel/UCfd52kTA5JpzOEItSqXLQxg), and some Luxor-related blog posts at [cormullion.github.io/](https://cormullion.github.io/). -Luxor is designed primarily for drawing static pictures. If you want to build animations, use [Javis.jl](https://github.com/Wikunia/Javis.jl/). +Luxor is designed primarily for drawing static pictures and simple animations. If you want to build complex or elaborate animations, use [Javis.jl](https://github.com/JuliaAnimators/Javis.jl) and [Makie](https://docs.makie.org/stable/). -Luxor isn't interactive: for building interactivity, look at [Pluto.jl](https://github.com/fonsp/Pluto.jl) and [Makie](https://github.com/JuliaPlots/Makie.jl). +Luxor isn't interactive: for building interactivity, look at [Pluto.jl](https://github.com/fonsp/Pluto.jl) and [Makie](https://docs.makie.org/stable/). [docs-development-img]: https://img.shields.io/badge/docs-development-blue [docs-development-url]: http://juliagraphics.github.io/Luxor.jl/dev/ diff --git a/data/gallery/graphdemo.jl b/data/gallery/graphdemo.jl new file mode 100644 index 00000000..5dd6a925 --- /dev/null +++ b/data/gallery/graphdemo.jl @@ -0,0 +1,621 @@ +module luxorgraphtools +export CanvasConfig +export PlottingArea +export lit_defaultcolorpalette +export lit_convert_x_imagecoor_to_cartesiancoor +export lit_convert_y_imagecoor_to_cartesiancoor +export lit_convert_xy_imagecoor_to_cartesiancoor +export lit_convert_x_cartesiancoor_to_imagecoor +export lit_convert_y_cartesiancoor_to_imagecoor +export lit_convert_xy_cartesiancoor_to_imagecoor +export lit_convert_cartesianpoint_to_imagepoint_noncenter +export lit_convert_cartesianpoint_to_imagepoint_center +export lit_convert_cartesianpoint_to_imagepoint_noncenter_as_center +export lit_cartesianpoint_noncenter +export lit_cartesianpoint_center +export lit_cartesianpoint_noncenter_as_center +export lit_RotationMatrix2D +export lit_ScaleMatrix2D +export lit_TranslationMatrix2D +export lit_CartTranslationMatrix2D +export lit_ReflectXaxisMatrix2D +export lit_ReflectYaxisMatrix2D +export lit_SetFakeCartesianSystem +export lit_FakeCartesianSystemMatrix2D +export lit_CalcPlottingArea +export lit_CalcInternalPlottingArea +export lit_ConvertInternalPlottingAreaToCartesian +export lit_calc_physical_y_in_graph +export lit_graphfuncplot +export lit_graphseriesplot +export lit_SetInternalPlottingAreaMatrix +export lit_create_graph_xticks +export lit_create_graph_yticks +export lit_create_graph_title +export lit_create_X_axis_title +export lit_create_Y_axis_title +export lit_convert_graph_xvalue_to_image_xcoor +export lit_convert_graph_xvalue_to_cart_xcoor +export lit_convert_graph_yvalue_to_image_ycoor +export lit_convert_graph_yvalue_to_cart_ycoor +export lit_graph_arrow_text_cart +export lit_graph_arrow_text_cart_NE +export lit_graph_arrow_text_cart_SE + + +using Luxor, Images + +struct CanvasConfig + width::Int64 + height::Int64 +end + +struct PlottingArea + # All coordinates below are Image Coordinates + xtopleft::Float64 + ytopleft::Float64 + xtopright::Float64 + ytopright::Float64 + xbotleft::Float64 + ybotleft::Float64 + xbotright::Float64 + ybotright::Float64 +end + +lit_defaultcolorpalette = [ + RGB{Float64}(0.0, 0.6056031611752245, 0.9786801175696073), + RGB{Float64}(0.8888735002725198, 0.43564919034818994, 0.2781229361419438), + RGB{Float64}(0.2422242978521988, 0.6432750931576305, 0.3044486515341153), + RGB{Float64}(0.7644401754934356, 0.4441117794687767, 0.8242975359232758), + RGB{Float64}(0.6755439572114057, 0.5556623322045815, 0.09423433626639477), + RGB{Float64}(4.821181644776295e-7, 0.6657589812923561, 0.6809969518707945), + RGB{Float64}(0.930767491919665, 0.3674771896571412, 0.5757699667547829), + RGB{Float64}(0.7769816661712932, 0.5097431319944513, 0.1464252569555497), + RGB{Float64}(3.8077343661790943e-7, 0.6642678029460116, 0.5529508754522481), + RGB{Float64}(0.558464964115081, 0.5934846564332882, 0.11748125233232104), + RGB{Float64}(5.947623898072685e-7, 0.6608785231434254, 0.7981787608414297), + RGB{Float64}(0.6096707676128648, 0.49918492100827777, 0.9117812665042642), + RGB{Float64}(0.3800016049820351, 0.5510532724353506, 0.9665056985227146), + RGB{Float64}(0.942181647954218, 0.37516423354097583, 0.4518168202944593), + RGB{Float64}(0.8684020893043971, 0.3959893639954845, 0.7135147524811879), + RGB{Float64}(0.42314674364630817, 0.6224954944199981, 0.19877060252130468) +] + +function lit_convert_x_imagecoor_to_cartesiancoor(canvasconfig::CanvasConfig, x) + local x_cart + x_cart = x + return x_cart +end + +function lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig::CanvasConfig, y) + local y_cart + y_cart = (canvasconfig.height - 1) - y + return y_cart +end + +function lit_convert_xy_imagecoor_to_cartesiancoor(canvasconfig::CanvasConfig, x, y) + return (lit_convert_x_imagecoor_to_cartesiancoor(canvasconfig, x), + lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, y) + ) +end + +function lit_convert_x_cartesiancoor_to_imagecoor(canvasconfig::CanvasConfig, x) + local x_image + x_image = x + return x_image +end + +function lit_convert_y_cartesiancoor_to_imagecoor(canvasconfig::CanvasConfig, y) + local y_image + y_image = (canvasconfig.height - 1) - y + return y_image +end + +function lit_convert_xy_cartesiancoor_to_imagecoor(canvasconfig::CanvasConfig, x, y) + return (lit_convert_x_cartesiancoor_to_imagecoor(canvasconfig, x), + lit_convert_y_cartesiancoor_to_imagecoor(canvasconfig, y) + ) +end + +function lit_convert_cartesianpoint_to_imagepoint_noncenter(canvasconfig::CanvasConfig, p) + return Point( + lit_convert_xy_cartesiancoor_to_imagecoor(canvasconfig, p[1], p[2])... + ) +end + +function lit_convert_cartesianpoint_to_imagepoint_center(canvasconfig::CanvasConfig, p) + return Point(p[1], -1 * p[2]) +end + +function lit_convert_cartesianpoint_to_imagepoint_noncenter_as_center(canvasconfig::CanvasConfig, p) + local xcenter = div(canvasconfig.width, 2) + local ycenter = div(canvasconfig.height, 2) + return Point(p[1] + xcenter, -1 * p[2] + ycenter) +end + +function lit_cartesianpoint_noncenter(canvasconfig::CanvasConfig, x, y) + return Point(lit_convert_xy_cartesiancoor_to_imagecoor(canvasconfig, x, y)...) +end + +function lit_cartesianpoint_center(canvasconfig, x, y) + return Point(x, -y) +end + +function lit_cartesianpoint_noncenter_as_center(canvasconfig::CanvasConfig, x, y) + local xcenter = div(canvasconfig.width, 2) + local ycenter = div(canvasconfig.height, 2) + return Point(x + xcenter, (-y) + ycenter) +end + +function lit_RotationMatrix2D(theta_radian) + local θ = Float64(theta_radian) + return [cos(θ) -sin(θ) 0.0 + sin(θ) cos(θ) 0.0 + 0.0 0.0 1.0] +end + +function lit_ScaleMatrix2D(ScaleX, ScaleY) + local scalex = Float64(ScaleX) + local scaley = Float64(ScaleY) + return [scalex 0.0 0.0 + 0.0 scaley 0.0 + 0.0 0.0 1.0] +end + +function lit_TranslationMatrix2D(TransX, TransY) + local transx = Float64(TransX) + local transy = Float64(TransY) + return [1.0 0.0 transx + 0.0 1.0 transy + 0.0 0.0 1.0] +end + +function lit_CartTranslationMatrix2D(TransX, TransY) + local transx = Float64(TransX) + local transy = -1.0 * Float64(TransY) + return [1.0 0.0 transx + 0.0 1.0 transy + 0.0 0.0 1.0] +end + +function lit_ReflectXaxisMatrix2D() + return [1.0 0.0 0.0 + 0.0 -1.0 0.0 + 0.0 0.0 1.0] +end + +function lit_ReflectYaxisMatrix2D() + return [-1.0 0.0 0.0 + 0.0 1.0 0.0 + 0.0 0.0 1.0] +end + +function lit_SetFakeCartesianSystem(canvasconfig::CanvasConfig) + local f_matrix = lit_ReflectXaxisMatrix2D() + local t_matrix = lit_TranslationMatrix2D(0.0, canvasconfig.height - 1) + + local total_matrix = t_matrix * f_matrix + local cm = juliatocairomatrix(total_matrix) + setmatrix(cm) +end + +function lit_FakeCartesianSystemMatrix2D(canvasconfig::CanvasConfig) + local f_matrix = lit_ReflectXaxisMatrix2D() + local t_matrix = lit_TranslationMatrix2D(0.0, canvasconfig.height - 1) + + local total_matrix = t_matrix * f_matrix + return total_matrix +end + +function lit_CalcPlottingArea(canvasconfig::CanvasConfig) + # All coordinates below are Image Coordinates + local xtopleft = round(65 / 600 * canvasconfig.width) + local ytopleft = round(30 / 400 * canvasconfig.height) + local xtopright = round(585 / 600 * canvasconfig.width) + local ytopright = round(30 / 400 * canvasconfig.height) + local xbotleft = round(65 / 600 * canvasconfig.width) + local ybotleft = round(355 / 400 * canvasconfig.height) + local xbotright = round(585 / 600 * canvasconfig.width) + local ybotright = round(355 / 400 * canvasconfig.height) + return PlottingArea(xtopleft, ytopleft, xtopright, ytopright, + xbotleft, ybotleft, xbotright, ybotright) +end + +function lit_CalcInternalPlottingArea(plottingarea::PlottingArea) + # All coordinates below are Image Coordinates + local xtopleft = plottingarea.xtopleft + 1.0 + local ytopleft = plottingarea.ytopleft + 1.0 + local xtopright = plottingarea.xtopright - 1.0 + local ytopright = plottingarea.ytopright + 1.0 + local xbotleft = plottingarea.xbotleft + 1.0 + local ybotleft = plottingarea.ybotleft - 1.0 + local xbotright = plottingarea.xbotright - 1.0 + local ybotright = plottingarea.ybotright - 1.0 + return PlottingArea(xtopleft, ytopleft, xtopright, ytopright, + xbotleft, ybotleft, xbotright, ybotright) +end + +function lit_ConvertInternalPlottingAreaToCartesian( + canvasconfig::CanvasConfig, + plottingarea::PlottingArea) + local xtopleft = plottingarea.xtopleft + local ytopleft = lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, plottingarea.ytopleft) + local xtopright = plottingarea.xtopright + local ytopright = lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, plottingarea.ytopright) + local xbotleft = plottingarea.xbotleft + local ybotleft = lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, plottingarea.ybotleft) + local xbotright = plottingarea.xbotright + local ybotright = lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, plottingarea.ybotright) + return PlottingArea(xtopleft, ytopleft, xtopright, ytopright, + xbotleft, ybotleft, xbotright, ybotright) +end + +function lit_calc_physical_y_in_graph(yval, ylimits, physicalheight) + local y_val_bot = ylimits[1] + local y_val_range = ylimits[2] - ylimits[1] + local y_ratio = (yval - y_val_bot) / y_val_range + local y = y_ratio * physicalheight + return y +end + +function lit_graphfuncplot(func, xlims, ylims, internalcartPA) + local x_val_range = xlims[2] - xlims[1] + local x_prev, x_val_prev, x_val + local y_prev, y_physical_prev, y, y_physical + local physicalheight = internalcartPA.ytopleft - internalcartPA.ybotleft + local physicalwidth = internalcartPA.xtopright - internalcartPA.xtopleft + box(Point(0, 0), Point(physicalwidth, physicalheight), :clip) + for x_pixel = 1:physicalwidth + x_prev = x_pixel - 1 + x_val_prev = xlims[1] + (x_prev / physicalwidth) * x_val_range + y_prev = func(x_val_prev) + y_physical_prev = lit_calc_physical_y_in_graph(y_prev, ylims, physicalheight) + + x_val = xlims[1] + (x_pixel / physicalwidth) * x_val_range + y = func(x_val) + y_physical = lit_calc_physical_y_in_graph(y, ylims, physicalheight) + + line(Point(x_prev, y_physical_prev), Point(x_pixel, y_physical), :stroke) + end + clipreset() +end + +function lit_graphseriesplot(x::AbstractArray, y::AbstractArray, xlims, ylims, internalcartPA) + local x_val_range = xlims[2] - xlims[1] + local y_val_range = ylims[2] - ylims[1] + local len_x = length(x) + local len_y = length(y) + local physicalheight = internalcartPA.ytopleft - internalcartPA.ybotleft + local physicalwidth = internalcartPA.xbotright - internalcartPA.xbotleft + # Sanity check: Make sure x and y have the same length + if len_x != len_y + println("Error in lit_graphseriesplot : len_x != len_y") + return nothing + end + box(Point(0, 0), Point(physicalwidth, physicalheight), :clip) + # Figure out points + mypoints = Point[] + + local count = 0 + while count < len_x + x_value = x[begin+count] + + x_proportion = (x_value - xlims[1]) / x_val_range + x_pixel = x_proportion * physicalwidth + + y_value = y[begin+count] + + y_proportion = (y_value - ylims[1]) / y_val_range + y_pixel = y_proportion * physicalheight + + # Push Point into mypoints + push!(mypoints, Point(x_pixel, y_pixel)) + # Increment countX + count += 1 + end + # Plot points + for count = 2:length(mypoints) + line(mypoints[count-1], mypoints[count], :stroke) + end + + # Finish plotting + clipreset() +end + +function lit_SetInternalPlottingAreaMatrix(canvasconfig, internalcartPA) + local matrix = lit_FakeCartesianSystemMatrix2D(canvasconfig) + local total_matrix = lit_CartTranslationMatrix2D(internalcartPA.xbotleft, internalcartPA.ybotleft) * matrix + local cm = juliatocairomatrix(total_matrix) + setmatrix(cm) +end + +function lit_create_graph_xticks(majortick::Integer, xlims, plottingarea; + font="Courier", fontsize=12, + ticklength=10, textoffset=25, debug=false) + local stepamount = (xlims[2] - xlims[1]) / (majortick + 2.0) + hstep = ((plottingarea.xbotright - 0.5) - (plottingarea.xbotleft + 0.5)) / (majortick + 2.0) + for loopcounter in 0:majortick+2 + p = Point((plottingarea.xbotleft + 0.5) + loopcounter * hstep, plottingarea.ybotleft) + line(p, Point(p[1], p[2] + ticklength), :stroke) + setfont(font, fontsize) + settext("$(round(xlims[1] + loopcounter * stepamount, digits=2))", p + (0, textoffset), halign="center", valign="bottom") + end +end + +function lit_create_graph_xticks(arr::Union{AbstractArray,StepRange{T,T} where T<:Number}, + xlims, plottingarea; font="Courier", fontsize=12, ticklength=10, textoffset=25, debug=false) + local physicalwidth = (plottingarea.xbotright - 0.5) - (plottingarea.xbotleft + 0.5) + local x_proportion + for tick in arr + x_proportion = (tick - xlims[1]) / (xlims[2] - xlims[1]) + if 0.0 <= x_proportion <= 1.0 + p = Point((plottingarea.xbotleft + 0.5) + x_proportion * physicalwidth, plottingarea.ybotleft) + line(p, Point(p[1], p[2] + ticklength), :stroke) + setfont(font, fontsize) + settext("$(round(tick, digits=2))", p + (0, textoffset), halign="center", valign="bottom") + else + if debug + println("Tick Point out of range of bottom axis") + end + end + end +end + +function lit_create_graph_yticks(majortick, ylims, plottingarea; + font="Courier", fontsize=12, + ticklength=10, textoffset=20, debug=false) + local stepamount = (ylims[2] - ylims[1]) / (majortick + 2.0) + vstep = ((plottingarea.ybotleft - 0.5) - (plottingarea.ytopleft + 0.5)) / (majortick + 2.0) + for loopcounter in 0:majortick+2 + p = Point(plottingarea.xbotleft, (plottingarea.ytopleft + 0.5) + loopcounter * vstep) + line(Point(p[1] - ticklength, p[2]), p, :stroke) + setfont(font, fontsize) + settext("$(round(ylims[2] - loopcounter * stepamount, digits=2))", p + (-1 * textoffset, 0), halign="right", valign="center") + end +end + +function lit_create_graph_yticks(arr::Union{AbstractArray,StepRange{T,T} where T<:Number}, + ylims, plottingarea; font="Courier", fontsize=12, ticklength=10, textoffset=25, debug=false) + local physicalheight = (plottingarea.ybotright - 0.5) - (plottingarea.ytopright + 0.5) + local y_proportion + for tick in arr + y_proportion = (tick - ylims[1]) / (ylims[2] - ylims[1]) + if 0.0 <= y_proportion <= 1.0 + p = Point(plottingarea.xbotleft, + (plottingarea.ybotleft - 0.5) - y_proportion * physicalheight) + line(Point(p[1] - ticklength, p[2]), p, :stroke) + setfont(font, fontsize) + settext("$(round(tick, digits=2))", p + (-1 * textoffset, 0), halign="right", valign="center") + else + if debug + println("Tick Point out of range of vertical axis") + end + end + end +end + +function lit_create_graph_title(canvasconfig, plottingarea, title; font="Times", fontsize=30, debug=false) + p = Point((plottingarea.xtopleft + plottingarea.xtopright) / 2.0, plottingarea.ytopleft / 2.0) + setfont(font, fontsize) + settext(title, p + (0, 0), halign="center", valign="center") +end + +function lit_create_X_axis_title(canvasconfig, plottingarea, title; font="Helvetica", fontsize=18, debug=false) + p = Point((plottingarea.xbotleft + plottingarea.xbotright) / 2.0, plottingarea.ybotleft) + setfont(font, fontsize) + settext(title, p + (0, (40 / 63) * (canvasconfig.height - plottingarea.ybotleft)), halign="center", valign="center") +end + +function lit_create_Y_axis_title(canvasconfig, plottingarea, title; font="Helvetica", fontsize=18, debug=false) + p = Point(plottingarea.xbotleft, (plottingarea.ytopleft + plottingarea.ybotleft) / 2.0) + setfont(font, fontsize) + settext(title, p + (-1 * (46 / 63) * plottingarea.xbotleft, 0), halign="center", valign="center", angle=90) +end + +function lit_convert_graph_xvalue_to_image_xcoor(xvalue, xlims, plottingarea) + local physicalwidth = (plottingarea.xbotright - 1) - (plottingarea.xbotleft + 1) + local x_proportion + x_proportion = (xvalue - xlims[1]) / (xlims[2] - xlims[1]) + return (plottingarea.xbotleft) + x_proportion * physicalwidth - 0.5 +end + +function lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, plottingarea) + local xcoor_image = lit_convert_graph_xvalue_to_image_xcoor(xvalue, xlims, plottingarea) + local xcoor_image2 = xcoor_image - plottingarea.xbotleft + return lit_convert_x_imagecoor_to_cartesiancoor(canvasconfig, xcoor_image2) +end + +function lit_convert_graph_yvalue_to_image_ycoor(yvalue, ylims, plottingarea) + local physicalheight = (plottingarea.ybotright - 1) - (plottingarea.ytopright + 1) + local y_proportion + y_proportion = (yvalue - ylims[1]) / (ylims[2] - ylims[1]) + return (plottingarea.ybotleft) - y_proportion * physicalheight - 0.5 +end + +function lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, plottingarea) + local ycoor_image = lit_convert_graph_yvalue_to_image_ycoor(yvalue, ylims, plottingarea) + return lit_convert_y_imagecoor_to_cartesiancoor(canvasconfig, ycoor_image) - (canvasconfig.height - plottingarea.ybotleft) +end + +function lit_graph_arrow_text_cart( + text, x, y; arrow_length=50, arrowgap=2, blankgap=5, + text_shiftup=1, headangle=pi / 10, + font="Courier", fontsize=12) + arrow(Point(x + arrow_length, y), Point(x + arrowgap, y), arrowheadlength=12, arrowheadangle=headangle, linewidth=2) + setfont(font, fontsize) + settext(text, Point(x, y) + (arrow_length + blankgap, text_shiftup), halign="left", valign="center") +end + +function lit_graph_arrow_text_cart_NE( + text, x, y; arrow_length=50, arrowgap=2, blankgap=5, + text_shiftup=1, headangle=pi / 10, horizontal_length=40, + font="Courier", fontsize=12) + local diagonal_length = arrow_length / 1.4142135623730951 + arrow(Point(x + diagonal_length, y + diagonal_length), Point(x + arrowgap, y), arrowheadlength=12, arrowheadangle=headangle, linewidth=2) + line(Point(x + diagonal_length, y + diagonal_length), + Point(x + diagonal_length + horizontal_length, y + diagonal_length), :stroke) + setfont(font, fontsize) + settext(text, Point(x, y) + + (diagonal_length + horizontal_length + blankgap, diagonal_length + text_shiftup), halign="left", valign="center") +end + +function lit_graph_arrow_text_cart_SE( + text, x, y; arrow_length=50, arrowgap=2, blankgap=5, + text_shiftup=1, headangle=pi / 10, horizontal_length=40, + font="Courier", fontsize=12) + local diagonal_length = arrow_length / 1.4142135623730951 + arrow(Point(x + diagonal_length, y - diagonal_length), Point(x + arrowgap, y), arrowheadlength=12, arrowheadangle=headangle, linewidth=2) + line(Point(x + diagonal_length, y - diagonal_length), + Point(x + diagonal_length + horizontal_length, y - diagonal_length), :stroke) + setfont(font, fontsize) + settext(text, Point(x, y) + + (diagonal_length + horizontal_length + blankgap, -1 * diagonal_length + text_shiftup), halign="left", valign="center") +end + +end + + + + + + + + + +""" + I originally used the font "Menlo Bold" but since it is not a popular font + I have changed it to "Courier" + + The Fonts used in this source code are + 1) Times + 2) Helvetica + 3) Courier +""" + +using .luxorgraphtools + +function plotfigure(fname) + println("running plotfigure()") + + widthheight = (840, 560) + Drawing(widthheight..., fname) + canvasconfig = CanvasConfig(widthheight...) + background("white") + sethue("red") + + # Start with coordinates transformation back to Normal + setmatrix([1, 0, 0, 1, 0, 0]) + + myplottingarea = lit_CalcPlottingArea(canvasconfig) + myinternalPA = lit_CalcInternalPlottingArea(myplottingarea) + myinternalcartPA = lit_ConvertInternalPlottingAreaToCartesian(canvasconfig, myinternalPA) + + sethue("grey30") + setline(1) + """ Draw the outline of the graph box """ + points = [Point(myplottingarea.xtopleft, myplottingarea.ytopleft), + Point(myplottingarea.xbotleft, myplottingarea.ybotleft), + Point(myplottingarea.xbotright, myplottingarea.ybotright)] + poly(points, :stroke, close=false) + setline(2) + + # Now prepare to plot sine, cosine and multi-trig graph + xlims = (0.0, 2.0 * pi) + ylims = (-1.1, 1.1) + + # Set the coordinates to Cartesian which is inside the + # Plotting Area of the graph + lit_SetInternalPlottingAreaMatrix(canvasconfig, myinternalcartPA) + + x = range(0, 2π, length=100) + y1 = sin.(x) + y2 = cos.(x) + y3 = -1 .* (sin.(2x) .+ cos.(π * x)) .* exp.(-0.2x) + + # Now plot Series Y1 + sethue(colorant"darkblue") + lit_graphseriesplot(x, y1, xlims, ylims, myinternalcartPA) + + # Now plot the Cosine series + sethue(colorant"purple") + # + # lit_graphseriesplot(x,y2,xlims,ylims,myinternalcartPA) + # + """ + Instead of using x and y2 series + We can just plot the cosine series using + the Cosine function directly + """ + lit_graphfuncplot(cos, xlims, ylims, myinternalcartPA) + + # Now plot Series Y3 + sethue(colorant"deeppink") + lit_graphseriesplot(x, y3, xlims, ylims, myinternalcartPA) + + # Now draw the arrows as you please + sethue(colorant"black") + """ Draw Arrow for Series Y1 """ + xvalue = 0.95 + xcoor = lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, myplottingarea) + yvalue = sin(xvalue) + ycoor = lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, myplottingarea) + lit_graph_arrow_text_cart("Series Y1", xcoor, ycoor, arrow_length=40) + + """ Draw Arrow for Series Y2 """ + xvalue = 1.0 + xcoor = lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, myplottingarea) + yvalue = cos(xvalue) + ycoor = lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, myplottingarea) + lit_graph_arrow_text_cart("Series Y2", xcoor, ycoor, arrow_length=40) + + """ Draw Arrow for Series Y3 """ + xvalue = 0.7 + xcoor = lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, myplottingarea) + yvalue = -1 * (sin(2 * xvalue) + cos(pi * xvalue)) * exp(-0.2 * xvalue) + ycoor = lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, myplottingarea) + lit_graph_arrow_text_cart("Series Y3", xcoor, ycoor) + + """ Draw Arrow for Sine Function """ + xvalue = 2.7 + xcoor = lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, myplottingarea) + yvalue = sin(xvalue) + ycoor = lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, myplottingarea) + lit_graph_arrow_text_cart_NE("Sine Function", xcoor, ycoor, arrow_length=40) + + """ Draw Arrow for Cosine Function """ + xvalue = 4.05 + xcoor = lit_convert_graph_xvalue_to_cart_xcoor(canvasconfig, xvalue, xlims, myplottingarea) + yvalue = cos(xvalue) + ycoor = lit_convert_graph_yvalue_to_cart_ycoor(canvasconfig, yvalue, ylims, myplottingarea) + lit_graph_arrow_text_cart_SE("Cosine Function", xcoor, ycoor, arrow_length=40, horizontal_length=10) + + # Set coordinates transformation back to Normal + setmatrix([1, 0, 0, 1, 0, 0]) + + # Now produce a tickline + """ X ticklines """ + sethue(colorant"darkblue") + lit_create_graph_xticks(0:1:10, xlims, myplottingarea) + + """ Y ticklines """ + sethue(colorant"midnightblue") + lit_create_graph_yticks(-1.1:0.1:1.1, ylims, myplottingarea) + + """ Graph Title """ + sethue(colorant"black") + lit_create_graph_title(canvasconfig, myplottingarea, "Trigonometry curves", font="Times") + + """ X-axis title """ + lit_create_X_axis_title(canvasconfig, myplottingarea, "X-axis : rotational angle in radians") + + """ Y-axis title """ + lit_create_Y_axis_title(canvasconfig, myplottingarea, "Y-axis : voltage in volts") + + # finish off the picture + finish() + preview() + # The end +end + +fname = dirname(dirname(pathof(Luxor))) * "/docs/src/assets/figures/graphdemo.svg" +plotfigure(fname) diff --git a/data/gallery/luxor-logo.jl b/data/gallery/luxor-logo.jl new file mode 100644 index 00000000..88aa8bab --- /dev/null +++ b/data/gallery/luxor-logo.jl @@ -0,0 +1,83 @@ +# luxor logo +# contibuted by cormullion + +using Luxor, Colors + +function set_gold_blend() + gblend = blend(O, 0, O, 220, "gold", "gold3") + setblend(gblend) +end + +function draw_scarab_legs(pos) + translate(pos) + # legs + @layer begin + for i in 1:2 + move(O) + rline.((polar(80, -π / 6), + polar(70, -π / 2), + polar(12, -5π / 6), + polar(60, -π / 4))) + + #middle leg + move(0, 40) + rline.(( + polar(120, -π / 6), + polar(40, π / 2))) + + #back leg + move(0, 100) + rline.(( + polar(130, -π / 6), + polar(110, π / 2))) + + # flip for other leg + transform([-1 0 0 1 0 0]) + end + end +end + +function draw_scarab_body() + @layer begin + squircle(Point(0, -25), 26, 75, action = :path) + squircle(Point(0, 0), 50, 70, action = :path) + squircle(Point(0, 40), 65, 90, action = :path) + end +end + +function draw(fname) + Drawing(380, 520, fname) + origin() + setline(20) + setlinecap("butt") + setlinejoin("round") + + width = currentdrawing().width/2 - 15 + height = currentdrawing().height/2 - 15 + + sethue("black") + squircle(O, width, height - 10, rt = 0.4, action = :fill) + set_gold_blend() + squircle(O, width, height - 10, rt = 0.4, action = :path) + + translate(0, 50) + draw_scarab_legs(O) + strokepath() + + draw_scarab_body() + fillpath() + + # julia dots === Ra egyptian sun deity + @layer begin + translate(0, -190) + circle(O, 48, action = :fill) + juliacircles(20) + end + + finish() + preview() +end + +fname = dirname(dirname(pathof(Luxor))) * "/docs/src/assets/figures/luxor-logo.svg" + +draw(fname) diff --git a/data/gallery/temple.jl b/data/gallery/temple.jl new file mode 100644 index 00000000..43d89c70 --- /dev/null +++ b/data/gallery/temple.jl @@ -0,0 +1,114 @@ +# temple.jl +# contibuted by kfung + +using Luxor +Drawing(1280, 720, "../assets/figures/temple.png") +origin() +setblend(blend(Point(0, -200), Point(0, 300), "#F38070", "#F3C3BC")) +box(O, 1280, 720, :fill) +sethue("#F7C5BC") +setopacity(0.3) +sun = Point(450, -225) +poly([sun, Point(400, 400), Point(640, 400), sun], :fill) +poly([sun, Point(-150, 400), Point(150, 400), sun], :fill) +poly([sun, Point(-640, 400), Point(-640, 0), sun], :fill) +poly([sun, Point(-640, -150), Point(-640, -450), sun], :fill) +poly([sun, Point(100, -360), Point(300, -360), sun], :fill) +poly([sun, Point(375, -400), Point(475, -400), sun], :fill) +poly([sun, Point(585, -400), Point(775, -400), sun], :fill) +poly([sun, Point(640, -265), Point(640, -175), sun], :fill) +poly([sun, Point(640, -100), Point(640, 125), sun], :fill) +sethue("#C02C20") +setopacity(1) +circle(450, -225, 40, :fill) +sethue("white") +setopacity(0.98) +ellipse(20, -275, 150, 75, :fill) +ellipse(-20, -240, 150, 50, :fill) +ellipse(60, -245, 150, 50, :fill) +ellipse(-450, -240, 150, 50, :fill) +ellipse(-350, -250, 150, 50, :fill) +ellipse(430, -90, 200, 10, :fill) +ellipse(470, -95, 200, 10, :fill) +setopacity(0.8) +ellipse(-450, -130, 200, 10, :fill) +ellipse(-490, -135, 200, 10, :fill) +setopacity(1) +sethue("#2E951A") +drawbezierpath(makebezierpath([Point(-780, 500), Point(-640, 100), Point(-560, -20), Point(-480, -80), Point(-400, -80), Point(-320, -20), Point(-240, 100), Point(-240, 500)]), :fill, close=false) +sethue("#37C61B") +drawbezierpath(makebezierpath([Point(-780, 500), Point(-640, 200), Point(-560, 100), Point(-480, 40), Point(-400, 30), Point(-320, 70), Point(-240, 150), Point(-240, 500)]), :fill, close=false) +sethue("#23AE34") +setopacity(1) +ellipse(530, 90, 100, 100, :fill) +ellipse(490, 150, 80, 80, :fill) +ellipse(570, 150, 80, 80, :fill) +sethue("#713D1D") +box(530, 220, 15, 290, :fill) +setline(15) +line(Point(530,180), Point(565, 125), action = :stroke) +line(Point(530,140), Point(495, 105), action = :stroke) +sethue("#E13705") +circle(480, 150, 8, :fill) +circle(560, 100, 8, :fill) +circle(510, 70, 8, :fill) +circle(580, 160, 8, :fill) +[circle(544+16*(i-1), 292, 8, :fill) for i in 1:3] +circle(552, 278, 8, :fill) +circle(512, 292, 8, :fill) +circle(496, 292, 8, :fill) +sethue("white") +setline(10) +line(Point(440, 300), Point(440, 250), action = :stroke) +poly([Point(410, 250), Point(395, 235), Point(410, 220), Point(465, 220), Point(465, 250)], :fill) +sethue("black") +fontsize(12) +fontface("Arial") +text("THIS WAY", Point(434, 241), halign=:center, valign = :center) +setopacity(1) +sethue("#2A3A4A") +box(0, 330, 1280, 60, :fill) +setline(20) +setopacity(1) +drawbezierpath(makebezierpath([Point(-570, 320), Point(-500, 270), Point(-400, 230), Point(-550, 200), Point(-360, 160), Point(-460, 110), Point(-342, 70), Point(-340, 70)]), action = :stroke, close=false) +circle(-340, 69, 10, :fill) +circle(-336, 67, 10, :fill) +setopacity(1) +sethue("white") +[box(-600+100*(i-1), 330, 50, 5, :fill) for i in 1:13] +sethue("#E7D1BC") +box(0, 240, 700, 120, :fill) +box(0, 150, 300, 120, :fill) +box(0, 40, 500, 120, :fill) +sethue("#EE766B") +[circle((-400+20*(i-1)), 180, 10, :fill) for i in 1:41] +[circle((-270+20*(i-1)), -20, 10, :fill) for i in 1:28] +sethue("#D14A3E") +poly([Point(-420, 180), Point(420, 180), Point(250, 70), Point(-250, 70), Point(-420, 180)], :fill) +poly([Point(-290, -20), Point(290, -20), Point(150, -120), Point(-150, -120), Point(-290, -20)], :fill) +circle(0, 58, 10, :fill) +circle(0, 45, 4, :fill) +sethue("#B71909") +poly([Point(0, 55), Point(140, 180), Point(-140, 180), Point(0, 55)], :fill) +sethue("#E7D1BC") +poly([Point(0, 70), Point(159, 210), Point(-159, 210), Point(0, 70)], :fill) +sethue("black") +[box(-180+120*(i-1), 30, 20, 40, :fill) for i in 1:4] +box(-300, 240, 20, 40, :fill) +box(-200, 240, 20, 40, :fill) +box(200, 240, 20, 40, :fill) +box(300, 240, 20, 40, :fill) +sethue("#C99A6F") +box(-130, 240, 10, 120, :fill) +box(130, 240, 10, 120, :fill) +poly([Point(0, 85), Point(91, 165), Point(-91, 165), Point(0, 85)], :fill) +sethue("black") +box(0, 258, 88, 84, :fill) +sethue("#C99A6F") +box(-20, 260, 38, 80, :fill) +box(20, 260, 38, 80, :fill) +sethue("black") +circle(-10, 260, 4, :fill) +circle(10, 260, 4, :fill) +finish() +preview() \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index dbecd2c2..d658476f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -22,7 +22,8 @@ makedocs( ], "Examples" => [ "Simple examples" => "example/examples.md", - "More examples" => "example/moreexamples.md" + "More examples" => "example/moreexamples.md", + "Gallery" => "example/gallery.md", ], "How to guides" => [ "Create drawings" => "howto/createdrawings.md", diff --git a/docs/src/assets/figures/graphdemo.svg b/docs/src/assets/figures/graphdemo.svg new file mode 100644 index 00000000..3b3dc73f --- /dev/null +++ b/docs/src/assets/figures/graphdemo.svg @@ -0,0 +1,2356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/figures/luxor-logo.svg b/docs/src/assets/figures/luxor-logo.svg new file mode 100644 index 00000000..84b26e58 --- /dev/null +++ b/docs/src/assets/figures/luxor-logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/example/gallery.md b/docs/src/example/gallery.md new file mode 100644 index 00000000..d6932e78 --- /dev/null +++ b/docs/src/example/gallery.md @@ -0,0 +1,27 @@ +# Gallery + +Here are some more examples of Luxor in action. Please send your contributions for inclusion here! + +## Luxor logo + +Contributed by @cormullion. + +![luxor logo](../assets/figures/luxor-logo.svg) + +Code is here: Luxor > data > gallery > luxor-logo.jl + +## A Japanese-style Temple scene + +Contributed by **kfung**, a student that participated in [Google Code-in](https://codein.withgoogle.com/about/) 2019 competition. + +![temple](../assets/figures/temple.png) + +Code is here: Luxor > data > gallery > temple.jl + +## A plot + +Contributed by @stevensiew. + +![graph](../assets/figures/graphdemo.svg) + +Code is here: Luxor > data > gallery > graphdemo.jl diff --git a/docs/src/example/moreexamples.md b/docs/src/example/moreexamples.md index 35c863f6..e77688f2 100644 --- a/docs/src/example/moreexamples.md +++ b/docs/src/example/moreexamples.md @@ -166,203 +166,3 @@ polygons. Most of the animations on [this YouTube channel](https://www.youtube.com/channel/UCfd52kTA5JpzOEItSqXLQxg) are made with Luxor. -## The Luxor logo - -```@example -using Luxor, Colors - -function set_gold_blend() - gblend = blend(O, 0, O, 250, "gold2", "gold3") - setblend(gblend) -end - -function draw_scarab_legs(pos) - translate(pos) - # legs - @layer begin - for i in 1:2 - move(O) - rline.((polar(80, -π/6), - polar(70, -π/2), - polar(12, -5π/6), - polar(60, -π/4))) - - #middle leg - move(0, 40) - rline.(( - polar(120, -π/6), - polar(40, π/2))) - - #back leg - move(0, 100) - rline.(( - polar(130, -π/6), - polar(110, π/2))) - - # flip for other leg - transform([-1 0 0 1 0 0]) - end - end -end - -function draw_scarab_body() - @layer begin - squircle(Point(0, -25), 26, 75, action=:path) - squircle(Point(0, 0), 50, 70, action=:path) - squircle(Point(0, 40), 65, 90, action=:path) - end -end - -function draw() - @drawsvg begin - setopacity(1.0) - setline(20) - setlinecap("butt") - setlinejoin("round") - width = 180 - height= 240 - - sethue("black") - squircle(O, width, height-5, rt=0.4, action=:fill) - - set_gold_blend() - squircle(O, width, height-5, rt=0.4, action=:path) - translate(0, 50) - draw_scarab_legs(O) - strokepath() - draw_scarab_body() - fillpath() - - # julia dots === Ra egyptian sun deity - @layer begin - translate(0, -190) - circle(O, 48, action=:fill) - juliacircles(20) - end - - clipreset() - end -end - -draw() -``` - -## A Japanese-style Temple scene - -This code was created by **kfung**, a student that participated in [Google Code-in](https://codein.withgoogle.com/about/) 2019 competition. - -```@example -using Luxor -Drawing(1280, 720, "../assets/figures/temple.png") -origin() -setblend(blend(Point(0, -200), Point(0, 300), "#F38070", "#F3C3BC")) -box(O, 1280, 720, :fill) -sethue("#F7C5BC") -setopacity(0.3) -sun = Point(450, -225) -poly([sun, Point(400, 400), Point(640, 400), sun], :fill) -poly([sun, Point(-150, 400), Point(150, 400), sun], :fill) -poly([sun, Point(-640, 400), Point(-640, 0), sun], :fill) -poly([sun, Point(-640, -150), Point(-640, -450), sun], :fill) -poly([sun, Point(100, -360), Point(300, -360), sun], :fill) -poly([sun, Point(375, -400), Point(475, -400), sun], :fill) -poly([sun, Point(585, -400), Point(775, -400), sun], :fill) -poly([sun, Point(640, -265), Point(640, -175), sun], :fill) -poly([sun, Point(640, -100), Point(640, 125), sun], :fill) -sethue("#C02C20") -setopacity(1) -circle(450, -225, 40, :fill) -sethue("white") -setopacity(0.98) -ellipse(20, -275, 150, 75, :fill) -ellipse(-20, -240, 150, 50, :fill) -ellipse(60, -245, 150, 50, :fill) -ellipse(-450, -240, 150, 50, :fill) -ellipse(-350, -250, 150, 50, :fill) -ellipse(430, -90, 200, 10, :fill) -ellipse(470, -95, 200, 10, :fill) -setopacity(0.8) -ellipse(-450, -130, 200, 10, :fill) -ellipse(-490, -135, 200, 10, :fill) -setopacity(1) -sethue("#2E951A") -drawbezierpath(makebezierpath([Point(-780, 500), Point(-640, 100), Point(-560, -20), Point(-480, -80), Point(-400, -80), Point(-320, -20), Point(-240, 100), Point(-240, 500)]), :fill, close=false) -sethue("#37C61B") -drawbezierpath(makebezierpath([Point(-780, 500), Point(-640, 200), Point(-560, 100), Point(-480, 40), Point(-400, 30), Point(-320, 70), Point(-240, 150), Point(-240, 500)]), :fill, close=false) -sethue("#23AE34") -setopacity(1) -ellipse(530, 90, 100, 100, :fill) -ellipse(490, 150, 80, 80, :fill) -ellipse(570, 150, 80, 80, :fill) -sethue("#713D1D") -box(530, 220, 15, 290, :fill) -setline(15) -line(Point(530,180), Point(565, 125), action = :stroke) -line(Point(530,140), Point(495, 105), action = :stroke) -sethue("#E13705") -circle(480, 150, 8, :fill) -circle(560, 100, 8, :fill) -circle(510, 70, 8, :fill) -circle(580, 160, 8, :fill) -[circle(544+16*(i-1), 292, 8, :fill) for i in 1:3] -circle(552, 278, 8, :fill) -circle(512, 292, 8, :fill) -circle(496, 292, 8, :fill) -sethue("white") -setline(10) -line(Point(440, 300), Point(440, 250), action = :stroke) -poly([Point(410, 250), Point(395, 235), Point(410, 220), Point(465, 220), Point(465, 250)], :fill) -sethue("black") -fontsize(12) -fontface("Arial") -text("THIS WAY", Point(434, 241), halign=:center, valign = :center) -setopacity(1) -sethue("#2A3A4A") -box(0, 330, 1280, 60, :fill) -setline(20) -setopacity(1) -drawbezierpath(makebezierpath([Point(-570, 320), Point(-500, 270), Point(-400, 230), Point(-550, 200), Point(-360, 160), Point(-460, 110), Point(-342, 70), Point(-340, 70)]), action = :stroke, close=false) -circle(-340, 69, 10, :fill) -circle(-336, 67, 10, :fill) -setopacity(1) -sethue("white") -[box(-600+100*(i-1), 330, 50, 5, :fill) for i in 1:13] -sethue("#E7D1BC") -box(0, 240, 700, 120, :fill) -box(0, 150, 300, 120, :fill) -box(0, 40, 500, 120, :fill) -sethue("#EE766B") -[circle((-400+20*(i-1)), 180, 10, :fill) for i in 1:41] -[circle((-270+20*(i-1)), -20, 10, :fill) for i in 1:28] -sethue("#D14A3E") -poly([Point(-420, 180), Point(420, 180), Point(250, 70), Point(-250, 70), Point(-420, 180)], :fill) -poly([Point(-290, -20), Point(290, -20), Point(150, -120), Point(-150, -120), Point(-290, -20)], :fill) -circle(0, 58, 10, :fill) -circle(0, 45, 4, :fill) -sethue("#B71909") -poly([Point(0, 55), Point(140, 180), Point(-140, 180), Point(0, 55)], :fill) -sethue("#E7D1BC") -poly([Point(0, 70), Point(159, 210), Point(-159, 210), Point(0, 70)], :fill) -sethue("black") -[box(-180+120*(i-1), 30, 20, 40, :fill) for i in 1:4] -box(-300, 240, 20, 40, :fill) -box(-200, 240, 20, 40, :fill) -box(200, 240, 20, 40, :fill) -box(300, 240, 20, 40, :fill) -sethue("#C99A6F") -box(-130, 240, 10, 120, :fill) -box(130, 240, 10, 120, :fill) -poly([Point(0, 85), Point(91, 165), Point(-91, 165), Point(0, 85)], :fill) -sethue("black") -box(0, 258, 88, 84, :fill) -sethue("#C99A6F") -box(-20, 260, 38, 80, :fill) -box(20, 260, 38, 80, :fill) -sethue("black") -circle(-10, 260, 4, :fill) -circle(10, 260, 4, :fill) -finish() -nothing # hide -``` - -![temple](../assets/figures/temple.png) diff --git a/docs/src/index.md b/docs/src/index.md index d36b83c9..41bc500a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -6,17 +6,22 @@ end # Introduction to Luxor -Luxor is a Julia package for drawing simple static vector graphics. It provides basic drawing functions and utilities for working with shapes, polygons, clipping masks, PNG and SVG images, turtle graphics, and simple animations. +Luxor is a Julia package for drawing simple static 2D vector graphics. It provides basic drawing functions and utilities for working with shapes, polygons, clipping masks, PNG and SVG images, turtle graphics, and simple animations. !["luxor gallery"](assets/figures/luxorgallery.svg) -The focus of Luxor is on simplicity and ease of use: it should be easier to use than plain [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. +The focus of Luxor is on simplicity and ease of use: it should be easier to use than plain [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. + +For more complex and sophisticated graphics in 2D and 3D, [Makie.jl](https://docs.makie.org/stable/) is the best choice. Luxor is thoroughly procedural and static: your code issues a sequence of simple graphics 'commands' until you've completed a drawing, then the results are saved into a PDF, PNG, SVG, or EPS file. There are some Luxor-related videos on [YouTube](https://www.youtube.com/channel/UCfd52kTA5JpzOEItSqXLQxg), and some Luxor-related blog posts at [cormullion.github.io/](https://cormullion.github.io/). -Luxor isn't interactive: for interactive graphics, look at [Pluto.jl](https://github.com/fonsp/Pluto.jl), [Makie](https://github.com/JuliaPlots/Makie.jl), and [Javis](https://github.com/wikunia/Javis.jl). +Luxor is designed primarily for drawing static pictures and simple animations. If you want to build complex or elaborate animations, use [Javis.jl](https://github.com/JuliaAnimators/Javis.jl) and [Makie](https://docs.makie.org/stable/). + +Luxor isn't interactive: for building interactivity, look at [Pluto.jl](https://github.com/fonsp/Pluto.jl) and [Makie](https://docs.makie.org/stable/). + Please submit issues and pull requests on [GitHub](https://github.com/JuliaGraphics/Luxor.jl). Original version by [cormullion](https://github.com/cormullion), much improved with contributions from the Julia community. diff --git a/src/colors_styles.jl b/src/colors_styles.jl index c85b6611..5ae97cb6 100644 --- a/src/colors_styles.jl +++ b/src/colors_styles.jl @@ -315,9 +315,11 @@ function mask(point::Point, focus::Point, width, height; end """ -get_current_hue() + get_current_hue() As set by eg `sethue()`. Return an RGB colorant. + +See also [`getcolor`](@ref), [`get_current_color`](@ref). """ function get_current_hue() (r, g, b, _) = _get_current_color() @@ -325,9 +327,11 @@ function get_current_hue() end """ -get_current_color() + get_current_color() + +Return an RGBA colorant, the current color, as set by `setcolor()` etc. -Return an RGBA colorant, the current color, as set by `setcolor` etc... +See also [`getcolor`](@ref), [`get_current_hue`](@ref). """ function get_current_color() (r, g, b, a) = _get_current_color() @@ -335,9 +339,11 @@ function get_current_color() end """ -getcolor() + getcolor() + +Return an RGBA colorant, the current color, as set by `setcolor()` etc. -Return an RGBA colorant, the current color, as set by `setcolor` etc... +Calls [`get_current_color`](@ref). See also [`get_current_hue`](@ref). """ function getcolor() Luxor.get_current_color()