从 geojson 数据创建动态数量的传单图层组
Create dynamic number of leaflet layergroups from geojson data
简介
我在 R 中非常敏捷,但我的 java 技能是不存在的。因此,我愿意任由你摆布来回答这个问题,希望不要太复杂,问题(否则我将很难找出答案 ;-))。
运行 下面的代码要求您从 github 下载三个传单插件(代码注释中的链接)。它们应该放在文件夹 ./script
中,相对于您 运行 代码所在的位置。
样本数据
我有 excel-张多条路线。为了简单起见,我已经使用以下代码读入了一个文件,所以我不必在线共享 excel-文件:
# read excel file
bestand <- "./data/CBM_Schuttorf_Buren.xlsx"
bladen <- readxl::excel_sheets(bestand)
xldata <- lapply(bladen, function(x) {
readxl::read_excel(path = bestand, sheet = x,
col_types = c(rep(c("numeric", "text"), 2), rep("numeric", 2)))
})
names(xldata) <- bladen
这将产生以下对象,您需要使用该对象继续代码
bladen <- c("A1L", "A1R")
xldata <- list(A1L = structure(list(route = c(1, 1, 2, 2, 2, 3, 3, 3),
routeType = c("stremming", "stremming", "omleiding", "omleiding",
"omleiding", "omleiding", "omleiding", "omleiding"), punt = c(1,
2, 1, 2, 3, 1, 2, 3), puntType = c("start", "eind", "start",
"via", "eind", "start", "via", "eind"), lat = c(52.341823,
52.284989, 52.340234, 52.193045, 52.302415, 52.349596, 52.193045,
52.302415), lon = c(7.254037, 6.74575, 7.271095, 7.102321,
6.715246, 7.258845, 7.102321, 6.715246)), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -8L)), A1R = structure(list(
route = c(1, 1, 2, 2, 2, 3, 3, 3), routeType = c("stremming",
"stremming", "omleiding", "omleiding", "omleiding", "omleiding",
"omleiding", "omleiding"), punt = c(1, 2, 1, 2, 3, 1, 2,
3), puntType = c("start", "eind", "start", "via", "eind",
"start", "via", "eind"), lat = c(52.284267, 52.341886, 52.303024,
52.19279, 52.354846, 52.303024, 52.19279, 52.339145), lon = c(6.754951,
7.251379, 6.713831, 7.104181, 7.258402, 6.713831, 7.104181,
7.285606)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA,
-8L)))
我的问题
示例数据是一个简化的问题。只有两个列表条目,A1L 和 A1R。在我的生产数据中会有更多条目。
结果,我想要的是下面代码的动态版本。在这里,我在各处对图层组 A1L 和 A1R 进行了硬编码。但是虽然这可以作为概念验证,但在生产中是行不通的。
如前所述,我需要几个传单插件的功能,所以我非常依赖 htmlwidgets::onRender()
- 功能来获取我需要的东西。这也是我的致命弱点,因为我是 javascript 中的一个完整的 n00b。
期望输出
我愿意接受所有可以复制下面代码结果的建议,而无需对 filtering/Layergroups..
进行硬编码
注意:折线末端的箭头仅在传单显示在浏览器中时显示。他们 not 在 rstudio 查看器中显示(我很沮丧地发现了一个;-))
我的代码
library(tidyverse)
library(readxl)
library(osrm)
library(leaflet)
library(geojsonsf)
# below commented out, xldata is already provided
# # read excel file
# bestand <- "./data/myfile.xlsx"
# bladen <- readxl::excel_sheets(bestand)
# xldata <- lapply(bladen, function(x) {
# readxl::read_excel(path = bestand, sheet = x,
# col_types = c(rep(c("numeric", "text"), 2), rep("numeric", 2)))
# })
# names(xldata) <- bladen
# split individual routes (will become polylines later on)
routes <- lapply(xldata, function(x) split(x, f = x$route))
# create real routes, using osm routing
df <-
dplyr::bind_rows(
lapply(seq.int(routes), function(i) {
dplyr::bind_rows(
lapply(seq.int(lengths(routes)[i]), function(j) {
temp <- osrmRoute(loc = as.data.frame(routes[[i]][[j]][, c("lon", "lat")]),
overview = "full", returnclass = "sf") %>%
mutate(naam = paste0(bladen[i], "_", routes[[i]][[j]][1,2], routes[[i]][[j]][1,1])) %>%
mutate(groep = bladen[i]) %>%
mutate(groepVol = paste0("groups.",bladen[i])) %>%
mutate(type = ifelse(grepl("stremming", naam), "stremming", "omleiding"))
}))
})
)
df
# get boundaries for map
grens <- sf::st_bbox(df) %>% as.vector()
# create named list of geojson routes
plotdata <- lapply(split(df, f = df$naam), sf_geojson)
# PLUGIN SECTION
# from: https://github.com/slutske22/leaflet-arrowheads
arrowHead <- htmlDependency(
"leaflet-arrowheads",
"0.1.2",
src = normalizePath(".\script"),
#src = "./script",
script = "leaflet-arrowheads.js"
)
# from https://github.com/makinacorpus/Leaflet.GeometryUtil
geometryutil <- htmlDependency(
"leaflet.geometryutil",
"0.1.2",
src = normalizePath(".\script"),
#src = "./script",
script = "leaflet.geometryutil.js"
)
registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}
# plot the map and layers
leaflet() %>%
#register plugins
registerPlugin(arrowHead) %>%
registerPlugin(geometryutil) %>%
# add basemap
addProviderTiles(providers$CartoDB.Positron) %>%
# set map boundaries
fitBounds( grens[1], grens[2], grens[3], grens[4]) %>%
onRender("function(el, x, data) {
// funciton to define line color based on
// feature.properties.type
function getColor(d) {
return d == 'stremming' ? 'red' :
d == 'omleiding' ? 'seagreen' :
'black';
}
// funciton to define line dash based on
// feature.properties.type
function getDash(d) {
return d == 'stremming' ? '20' :
d == 'omleiding' ? '' :
'';
}
// function to set style of polylines
function newstyle(feature) {
return {
color: getColor(feature.properties.type),
weight: 10,
opacity: 1,
dashArray: getDash(feature.properties.type),
fillOpacity: 0.7
};
}
///////////////////////////////////////
//would like to make the code below this dynamic
//based on the groep-property in the JSON object
//so A1L and A1R groups (and thereby the filtering)
//are read in directly from the data object df
///////////////////////////////////////
// filtering
function A1L(feature) {if (feature.properties.groep === 'A1L') return true}
function A1R(feature) {if (feature.properties.groep === 'A1R') return true}
// crteation of layergroups
var groups = {
A1L: new L.LayerGroup(),
A1R: new L.LayerGroup()
};
// create layers and add to groups
var A1L = L.geoJSON(data, {
filter: A1L,
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
.addTo(groups.A1L);
var A1R = L.geoJSON(data, {
filter: A1R,
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
.addTo(groups.A1R);
var baseLayers = {
'A1L': A1L,
'A1R': A1R
};
var layerControl = L.control.layers(baseLayers, null, {collapsed: false}).addTo(this);
baseLayers['A1L'].addTo(this);
}", data = sf_geojson(df))
到目前为止我尝试了什么
我找到了可能是解决方案的东西 ,但我缺乏 java 技能来:
- 看看这是否确实是要走的路,如果是的话:
- 如何在我的代码中实现这一点。
经过 >1 天的无果而终,我终于找到了 an answer 我可以一起工作。
它现在可以正常工作了,这是我对任何寻找这种可能性的人的回答(我在过去 24 小时内发现了一些 ;-))
# plot the map and layers
leaflet() %>%
#register plugins
registerPlugin(arrowHead) %>%
registerPlugin(geometryutil) %>%
registerPlugin(groupedlayercontrol) %>%
# add basemap
addProviderTiles(providers$CartoDB.Positron) %>%
# set map boundaries
fitBounds( grens[1], grens[2], grens[3], grens[4]) %>%
onRender("function(el, x, data) {
// read data from the named list passd to onRender
// data.name_from_list
var routes = data.routes;
var groups = data.groups;
var types = groups;
// function to define line color based on
// feature.properties.type
function getColor(d) {
return d == 'stremming' ? 'red' :
d == 'omleiding' ? 'seagreen' :
'black';
}
// funciton to define line dash based on
// feature.properties.type
function getDash(d) {
return d == 'stremming' ? '20' :
d == 'omleiding' ? '' :
'';
}
// function to set style of polylines
function newstyle(feature) {
return {
color: getColor(feature.properties.type),
weight: 10,
opacity: 1,
dashArray: getDash(feature.properties.type),
fillOpacity: 0.7
};
}
// layerControl optioesn for groupedOverlays
var options = {
exclusiveGroups: ['Stremming'],
groupCheckboxes: false,
collapsed: false
};
// add empty layercontrol
var layerControl = L.control.groupedLayers(null, null, options).addTo(this);
// iterate over types, filter by that type, and format the layer for that feature type
types.forEach(function(type) {
var layer = L.geoJson(routes, {
filter: function(feature, layer) {
return feature.properties.groep == type;
},
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
// all done with the layer, add it to the control
layerControl.addOverlay(layer, type, 'Stremming');
});
}", data = list(routes = sf_geojson(df), groups = bladen))
简介
我在 R 中非常敏捷,但我的 java 技能是不存在的。因此,我愿意任由你摆布来回答这个问题,希望不要太复杂,问题(否则我将很难找出答案 ;-))。
运行 下面的代码要求您从 github 下载三个传单插件(代码注释中的链接)。它们应该放在文件夹 ./script
中,相对于您 运行 代码所在的位置。
样本数据
我有 excel-张多条路线。为了简单起见,我已经使用以下代码读入了一个文件,所以我不必在线共享 excel-文件:
# read excel file
bestand <- "./data/CBM_Schuttorf_Buren.xlsx"
bladen <- readxl::excel_sheets(bestand)
xldata <- lapply(bladen, function(x) {
readxl::read_excel(path = bestand, sheet = x,
col_types = c(rep(c("numeric", "text"), 2), rep("numeric", 2)))
})
names(xldata) <- bladen
这将产生以下对象,您需要使用该对象继续代码
bladen <- c("A1L", "A1R")
xldata <- list(A1L = structure(list(route = c(1, 1, 2, 2, 2, 3, 3, 3),
routeType = c("stremming", "stremming", "omleiding", "omleiding",
"omleiding", "omleiding", "omleiding", "omleiding"), punt = c(1,
2, 1, 2, 3, 1, 2, 3), puntType = c("start", "eind", "start",
"via", "eind", "start", "via", "eind"), lat = c(52.341823,
52.284989, 52.340234, 52.193045, 52.302415, 52.349596, 52.193045,
52.302415), lon = c(7.254037, 6.74575, 7.271095, 7.102321,
6.715246, 7.258845, 7.102321, 6.715246)), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -8L)), A1R = structure(list(
route = c(1, 1, 2, 2, 2, 3, 3, 3), routeType = c("stremming",
"stremming", "omleiding", "omleiding", "omleiding", "omleiding",
"omleiding", "omleiding"), punt = c(1, 2, 1, 2, 3, 1, 2,
3), puntType = c("start", "eind", "start", "via", "eind",
"start", "via", "eind"), lat = c(52.284267, 52.341886, 52.303024,
52.19279, 52.354846, 52.303024, 52.19279, 52.339145), lon = c(6.754951,
7.251379, 6.713831, 7.104181, 7.258402, 6.713831, 7.104181,
7.285606)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA,
-8L)))
我的问题
示例数据是一个简化的问题。只有两个列表条目,A1L 和 A1R。在我的生产数据中会有更多条目。
结果,我想要的是下面代码的动态版本。在这里,我在各处对图层组 A1L 和 A1R 进行了硬编码。但是虽然这可以作为概念验证,但在生产中是行不通的。
如前所述,我需要几个传单插件的功能,所以我非常依赖 htmlwidgets::onRender()
- 功能来获取我需要的东西。这也是我的致命弱点,因为我是 javascript 中的一个完整的 n00b。
期望输出
我愿意接受所有可以复制下面代码结果的建议,而无需对 filtering/Layergroups..
注意:折线末端的箭头仅在传单显示在浏览器中时显示。他们 not 在 rstudio 查看器中显示(我很沮丧地发现了一个;-))
我的代码
library(tidyverse)
library(readxl)
library(osrm)
library(leaflet)
library(geojsonsf)
# below commented out, xldata is already provided
# # read excel file
# bestand <- "./data/myfile.xlsx"
# bladen <- readxl::excel_sheets(bestand)
# xldata <- lapply(bladen, function(x) {
# readxl::read_excel(path = bestand, sheet = x,
# col_types = c(rep(c("numeric", "text"), 2), rep("numeric", 2)))
# })
# names(xldata) <- bladen
# split individual routes (will become polylines later on)
routes <- lapply(xldata, function(x) split(x, f = x$route))
# create real routes, using osm routing
df <-
dplyr::bind_rows(
lapply(seq.int(routes), function(i) {
dplyr::bind_rows(
lapply(seq.int(lengths(routes)[i]), function(j) {
temp <- osrmRoute(loc = as.data.frame(routes[[i]][[j]][, c("lon", "lat")]),
overview = "full", returnclass = "sf") %>%
mutate(naam = paste0(bladen[i], "_", routes[[i]][[j]][1,2], routes[[i]][[j]][1,1])) %>%
mutate(groep = bladen[i]) %>%
mutate(groepVol = paste0("groups.",bladen[i])) %>%
mutate(type = ifelse(grepl("stremming", naam), "stremming", "omleiding"))
}))
})
)
df
# get boundaries for map
grens <- sf::st_bbox(df) %>% as.vector()
# create named list of geojson routes
plotdata <- lapply(split(df, f = df$naam), sf_geojson)
# PLUGIN SECTION
# from: https://github.com/slutske22/leaflet-arrowheads
arrowHead <- htmlDependency(
"leaflet-arrowheads",
"0.1.2",
src = normalizePath(".\script"),
#src = "./script",
script = "leaflet-arrowheads.js"
)
# from https://github.com/makinacorpus/Leaflet.GeometryUtil
geometryutil <- htmlDependency(
"leaflet.geometryutil",
"0.1.2",
src = normalizePath(".\script"),
#src = "./script",
script = "leaflet.geometryutil.js"
)
registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}
# plot the map and layers
leaflet() %>%
#register plugins
registerPlugin(arrowHead) %>%
registerPlugin(geometryutil) %>%
# add basemap
addProviderTiles(providers$CartoDB.Positron) %>%
# set map boundaries
fitBounds( grens[1], grens[2], grens[3], grens[4]) %>%
onRender("function(el, x, data) {
// funciton to define line color based on
// feature.properties.type
function getColor(d) {
return d == 'stremming' ? 'red' :
d == 'omleiding' ? 'seagreen' :
'black';
}
// funciton to define line dash based on
// feature.properties.type
function getDash(d) {
return d == 'stremming' ? '20' :
d == 'omleiding' ? '' :
'';
}
// function to set style of polylines
function newstyle(feature) {
return {
color: getColor(feature.properties.type),
weight: 10,
opacity: 1,
dashArray: getDash(feature.properties.type),
fillOpacity: 0.7
};
}
///////////////////////////////////////
//would like to make the code below this dynamic
//based on the groep-property in the JSON object
//so A1L and A1R groups (and thereby the filtering)
//are read in directly from the data object df
///////////////////////////////////////
// filtering
function A1L(feature) {if (feature.properties.groep === 'A1L') return true}
function A1R(feature) {if (feature.properties.groep === 'A1R') return true}
// crteation of layergroups
var groups = {
A1L: new L.LayerGroup(),
A1R: new L.LayerGroup()
};
// create layers and add to groups
var A1L = L.geoJSON(data, {
filter: A1L,
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
.addTo(groups.A1L);
var A1R = L.geoJSON(data, {
filter: A1R,
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
.addTo(groups.A1R);
var baseLayers = {
'A1L': A1L,
'A1R': A1R
};
var layerControl = L.control.layers(baseLayers, null, {collapsed: false}).addTo(this);
baseLayers['A1L'].addTo(this);
}", data = sf_geojson(df))
到目前为止我尝试了什么
我找到了可能是解决方案的东西
- 看看这是否确实是要走的路,如果是的话:
- 如何在我的代码中实现这一点。
经过 >1 天的无果而终,我终于找到了 an answer 我可以一起工作。
它现在可以正常工作了,这是我对任何寻找这种可能性的人的回答(我在过去 24 小时内发现了一些 ;-))
# plot the map and layers
leaflet() %>%
#register plugins
registerPlugin(arrowHead) %>%
registerPlugin(geometryutil) %>%
registerPlugin(groupedlayercontrol) %>%
# add basemap
addProviderTiles(providers$CartoDB.Positron) %>%
# set map boundaries
fitBounds( grens[1], grens[2], grens[3], grens[4]) %>%
onRender("function(el, x, data) {
// read data from the named list passd to onRender
// data.name_from_list
var routes = data.routes;
var groups = data.groups;
var types = groups;
// function to define line color based on
// feature.properties.type
function getColor(d) {
return d == 'stremming' ? 'red' :
d == 'omleiding' ? 'seagreen' :
'black';
}
// funciton to define line dash based on
// feature.properties.type
function getDash(d) {
return d == 'stremming' ? '20' :
d == 'omleiding' ? '' :
'';
}
// function to set style of polylines
function newstyle(feature) {
return {
color: getColor(feature.properties.type),
weight: 10,
opacity: 1,
dashArray: getDash(feature.properties.type),
fillOpacity: 0.7
};
}
// layerControl optioesn for groupedOverlays
var options = {
exclusiveGroups: ['Stremming'],
groupCheckboxes: false,
collapsed: false
};
// add empty layercontrol
var layerControl = L.control.groupedLayers(null, null, options).addTo(this);
// iterate over types, filter by that type, and format the layer for that feature type
types.forEach(function(type) {
var layer = L.geoJson(routes, {
filter: function(feature, layer) {
return feature.properties.groep == type;
},
style: newstyle,
arrowheads: {frequency: 'endonly', yawn: 45, size: '30px', fill: true}
})
.on('mouseover', function (e) {e.target.setStyle({weight: 15, opacity: 1 });})
.on('mouseout', function (e) {e.target.setStyle({weight: 10, opacity: 0.75});})
// all done with the layer, add it to the control
layerControl.addOverlay(layer, type, 'Stremming');
});
}", data = list(routes = sf_geojson(df), groups = bladen))