79420634

Date: 2025-02-07 11:09:07
Score: 0.5
Natty:
Report link

I've had to switch the library to ramani-maps which is still a wrapper for maplibre-gl but more complete.

About the map filtering was easy to implement. I've also uploaded the extension on github gist under the MIT License


fun Style.filterLayersByDate(date: LocalDate) {
    val dateRange = DateRange.fromDate(date)
    for (layer in this.layers) {
        when (layer) {
            is LineLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            is FillLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            is CircleLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            is SymbolLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            is HeatmapLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            is FillExtrusionLayer -> {
                if (!originalFilters.containsKey(layer.id)) {
                    originalFilters[layer.id] = layer.filter
                }
                layer.resetFilter()
                layer.setFilter(constrainExpressionFilterByDateRange(originalFilters[layer.id], dateRange))
            }

            else -> null
        }
    }
}


private fun constrainExpressionFilterByDateRange(
    filter: Expression? = null,
    dateRange: DateRange,
    variablePrefix: String = "maplibre_gl_dates"
): Expression {
    val startDecimalYearVariable = "${variablePrefix}__startDecimalYear"
    val startISODateVariable = "${variablePrefix}__startISODate"
    val endDecimalYearVariable = "${variablePrefix}__endDecimalYear"
    val endISODateVariable = "${variablePrefix}__endISODate"

    val dateConstraints = Expression.all(
        Expression.any(
            Expression.all(
                Expression.has("start_decdate"),
                Expression.lt(
                    Expression.get("start_decdate"),
                    Expression.`var`(endDecimalYearVariable)
                )
            ),
            Expression.all(
                Expression.not(Expression.has("start_decdate")),
                Expression.has("start_date"),
                Expression.lt(
                    Expression.get("start_date"),
                    Expression.`var`(startISODateVariable)
                )
            ),
            Expression.all(
                Expression.not(Expression.has("start_decdate")),
                Expression.not(Expression.has("start_date"))
            )
        ),
        Expression.any(
            Expression.all(
                Expression.has("end_decdate"),
                Expression.gte(
                    Expression.get("end_decdate"),
                    Expression.`var`(startDecimalYearVariable)
                )
            ),
            Expression.all(
                Expression.not(Expression.has("end_decdate")),
                Expression.has("end_date"),
                Expression.gte(
                    Expression.get("end_date"),
                    Expression.`var`(startISODateVariable)
                )
            ),
            Expression.all(
                Expression.not(Expression.has("end_decdate")),
                Expression.not(Expression.has("end_date"))
            )
        )
    )

    val finalExpression = if (filter != null) {
        Expression.all(dateConstraints, filter)
    } else {
        dateConstraints
    }

    return Expression.let(
        Expression.literal(startDecimalYearVariable), Expression.literal(dateRange.startDecimalYear),
        Expression.let(
            Expression.literal(startISODateVariable), Expression.literal(dateRange.startISODate),
            Expression.let(
                Expression.literal(endDecimalYearVariable), Expression.literal(dateRange.endDecimalYear),
                Expression.let(
                    Expression.literal(endISODateVariable), Expression.literal(dateRange.endISODate),
                    finalExpression
                )
            )
        )
    )
}

fun Layer.resetFilter() {
    originalFilters[this.id]?.let { originalFilter ->
        when (this) {
            is LineLayer -> setFilter(originalFilter)
            is FillLayer -> setFilter(originalFilter)
            is CircleLayer -> setFilter(originalFilter)
            is SymbolLayer -> setFilter(originalFilter)
            is HeatmapLayer -> setFilter(originalFilter)
            is FillExtrusionLayer -> setFilter(originalFilter)
            else -> {}
        }
    }
}
Reasons:
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Marcel