Skip to content

Instantly share code, notes, and snippets.

@Bombe
Last active September 26, 2018 18:44
Show Gist options
  • Save Bombe/6838a8992ac35b7522b3a714648f8c46 to your computer and use it in GitHub Desktop.
Save Bombe/6838a8992ac35b7522b3a714648f8c46 to your computer and use it in GitHub Desktop.
Creates an SVG-File with a calender for a whole year
import java.awt.*
import java.awt.SystemColor.*
import java.io.*
import java.nio.charset.*
import java.nio.file.*
import java.time.*
import java.time.DayOfWeek.*
import java.time.Month.*
import java.time.temporal.*
val year = 2021
val marginLeft = 4
val marginRight = 6
val marginTop = 4
val marginBottom = 4
val availableWidth = 297.0 - marginLeft - marginRight
val availableHeight = 210.0 - marginTop - marginBottom
val monthFields = generateSequence(LocalDate.of(year, 1, 1)!!) { date ->
date.plusDays(1).takeIf { it.year == year }
}
.groupBy { it.get(ChronoField.MONTH_OF_YEAR) }
.map { (month, days) ->
val dayOfWeekOnFirst = days.first().dayOfWeek!!
month to (1.rangeTo(dayOfWeekOnFirst.value).map { index ->
Cell(right = CellText("%02d".format(month), "rgb(0%,0%,100%"))
.takeIf { index == dayOfWeekOnFirst.value }
} +
days.map { day ->
val week = day.get(WeekFields.ISO.weekOfWeekBasedYear())
val dayOfWeek = day.dayOfWeek!!
val weekYear = day.get(WeekFields.ISO.weekBasedYear())
val leftCellText = when {
(day.dayOfMonth == 1) && (month == 1) -> CellText("%02d".format(week), "rgb(60%,60%,60%)")
dayOfWeek == WeekFields.ISO.firstDayOfWeek -> CellText("%02d".format(week), "rgb(60%,60%,60%)")
(weekYear != year) && ((day.dayOfMonth == 2) && (day.month == JANUARY)) -> CellText("%02d".format(weekYear % 100), "rgb(40%,40%,40%)")
(weekYear != year) && (dayOfWeek == WeekFields.ISO.firstDayOfWeek.plus(1)) -> CellText("%02d".format(weekYear % 100), "rgb(40%,40%,40%)")
else -> null
}
val rightCellText = CellText("%02d".format(day.dayOfMonth), when (dayOfWeek) {
SATURDAY -> "rgb(85%,0%,0%)"
SUNDAY -> "rgb(100%,0%,0%)"
else -> null
})
Cell(leftCellText, rightCellText)
})
}
val maxFields = monthFields.maxBy { it.second.size }!!.second.size
val svg = svg { svg ->
monthFields
.forEach { (month, days) ->
days.forEachIndexed { index, field ->
field?.run {
left?.run {
svg.text(marginLeft + availableWidth / 12 * (month - 1), marginTop + availableHeight / (maxFields + 1) * (index + 1), text, color)
}
svg.text(marginLeft + availableWidth / 12 * (month - 1) + 4, marginTop + availableHeight / (maxFields + 1) * (index + 1), right.text, right.color)
}
}
}
}
File("calender-$year.svg").writeText(svg.toString(), Charsets.UTF_8)
data class Cell(val left: CellText? = null, val right: CellText)
data class CellText(val text: String, val color: String? = null)
fun svg(body: (Svg) -> Unit) =
Svg().apply {
body(this)
}
class Svg {
private val texts: MutableList<Text> = mutableListOf()
fun text(x: Double, y: Double, text: String, color: String? = null) {
texts += Text(x, y, text, color)
}
override fun toString(): String {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" baseProfile=\"full\" width=\"297mm\" height=\"210mm\" viewBox=\"0 0 297 210\">" +
texts.joinToString(separator = "", transform = Any::toString) +
"</svg>"
}
}
class Text(private val x: Double, private val y: Double, private val text: String, private val color: String? = null) {
private val font = "MonoSpatial"
override fun toString() = "<text x=\"$x\" y=\"$y\" font-family=\"$font\" font-size=\"3.75\"${color?.let { " fill=\"$it\"" }
?: ""}>$text</text>"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment