我有很多使用过的svg标记(字形)(这要感谢名称为rioV8的SO用户在此方面的帮助-不仅是此-...),并且理想情况下,我希望这些字形能够从要素属性结构中获取形状。
//create feature properties
var p = {
"id": i,
"popup": "Dot_" + i,
"year": parseInt(data[i].year),
"glyphName": "square",
"size": 500 // Fixed size circle radius=~13
};
这些用户定义的字形扩展了L.circleMarker
,为简单起见,我们说它们的形状可以是正方形或菱形。当前,我正在扩展L.Class
并在构造函数中传递glyphName:(随时可以批评一下,如果它对您来说看起来不太好)
var glyph = L.Class.extend({
initialize: function(glyphName) {
glyphName === "square"? this.type = MarkerSquare:
glyphName === "diamond"? this.type = MarkerDiamond:
this.type = L.circleMarker;
},
});
当我需要绘制字形时,我有类似的内容:
L.geoJson(myDots[i], {
pointToLayer: function(feature, latlng) {
var p = latlng;
var myGlyph = new glyph('diamond')
return new myGlyph.type(p, style(feature));
},
onEachFeature: onEachDot
}).addTo(map);
请问我可以具有由要素属性确定的形状吗?最终,我想要实现的是合并这两行
var myGlyph = new glyph('diamond')
return new myGlyph.type(p, style(feature));
类似于
return new myGlyph.type(p, style(feature));
这将使我能够绘制不同的形状,并且这些形状将由用于填充要素属性的输入数据确定。这些属性用于颜色或尺寸的方式类似,现在可以用来设置形状。
谢谢! (下面的完整代码)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Chart</title>
<style>
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 600px;
}
</style>
<script src='https://d3js.org/d3.v4.min.js' type='text/javascript'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js"></script>
</head>
<body>
<div id="map"></div>
<script>
L.Canvas.include({
_updateMarkerDiamond: function(layer) {
if (!this._drawing || layer._empty()) {
return;
}
var p = layer._point,
ctx = this._ctx,
r = Math.max(Math.round(layer._radius), 6);
this._drawnLayers[layer._leaflet_id] = layer;
ctx.beginPath();
ctx.moveTo(p.x - r, p.y);
ctx.lineTo(p.x, p.y - r);
ctx.lineTo(p.x + r, p.y);
ctx.lineTo(p.x, p.y + r);
ctx.lineTo(p.x - r, p.y);
ctx.closePath();
this._fillStroke(ctx, layer);
}
});
var MarkerDiamond = L.CircleMarker.extend({
_updatePath: function() {
this._renderer._updateMarkerDiamond(this);
}
});
L.Canvas.include({
_updateMarkerSquare: function(layer) {
if (!this._drawing || layer._empty()) {
return;
}
var p = layer._point,
ctx = this._ctx,
r = Math.max(Math.round(layer._radius), 5);
this._drawnLayers[layer._leaflet_id] = layer;
ctx.beginPath();
ctx.moveTo(p.x - r, p.y - r);
ctx.lineTo(p.x + r, p.y - r);
ctx.lineTo(p.x + r, p.y + r);
ctx.lineTo(p.x - r, p.y + r);
ctx.lineTo(p.x - r, p.y - r);
ctx.closePath();
this._fillStroke(ctx, layer);
}
});
var MarkerSquare = L.CircleMarker.extend({
_updatePath: function() {
this._renderer._updateMarkerSquare(this);
}
});
var glyph = L.Class.extend({
initialize: function(glyphName) {
glyphName === "square"? this.type = MarkerSquare:
glyphName === "diamond"? this.type = MarkerDiamond:
this.type = L.circleMarker;
},
});
var data = [];
var NumOfPoints = 100;
for (let i = 0; i < NumOfPoints; i++) {
data.push({
num: i,
x: Math.random() * 60,
y: Math.random() * 60,
year: Math.floor(100 * Math.random())
})
}
renderChart(data);
function make_dots(data) {
var arr = [];
var nest = d3.nest()
.key(function(d) {
return Math.floor(d.year / 10);
})
.entries(data);
for (var k = 0; k < nest.length; ++k) {
arr[k] = helper(nest[k].values);
}
return arr;
}
function helper(data) {
dots = {
type: "FeatureCollection",
features: []
};
for (var i = 0; i < data.length; ++i) {
x = data[i].x;
y = data[i].y;
var g = {
"type": "Point",
"coordinates": [x, y]
};
//create feature properties
var p = {
"id": i,
"popup": "Dot_" + i,
"year": parseInt(data[i].year),
//"glyphName": "square",
"size": 500 // Fixed size circle radius=~13
};
//create features with proper geojson structure
dots.features.push({
"geometry": g,
"type": "Feature",
"properties": p
});
}
return dots;
}
//create color ramp
function getColor(y) {
return y > 90 ? '#6068F0' :
y > 80 ? '#6B64DC' :
y > 70 ? '#7660C9' :
y > 60 ? '#815CB6' :
y > 50 ? '#8C58A3' :
y > 40 ? '#985490' :
y > 30 ? '#A3507C' :
y > 20 ? '#AE4C69' :
y > 10 ? '#B94856' :
y > 0 ? '#C44443' :
'#D04030';
}
//calculate radius so that resulting circles will be proportional by area
function getRadius(y) {
r = Math.sqrt(y / Math.PI)
return r;
}
var myRenderer;
//create style, with fillColor picked from color ramp
function style(feature) {
return {
radius: getRadius(feature.properties.size),
fillColor: getColor(feature.properties.year),
color: "#000",
weight: 0,
opacity: 1,
fillOpacity: 0.9,
renderer: myRenderer
};
}
//create highlight style, with darker color and larger radius
function highlightStyle(feature) {
return {
radius: getRadius(feature.properties.size) + 1.5,
fillColor: "#FFCE00",
color: "#FFCE00",
weight: 1,
opacity: 1,
fillOpacity: 0.9,
};
}
//attach styles and popups to the marker layer
function highlightDot(e) {
var layer = e.target;
dotStyleHighlight = highlightStyle(layer.feature);
layer.setStyle(dotStyleHighlight);
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
function resetDotHighlight(e) {
var layer = e.target;
dotStyleDefault = style(layer.feature);
layer.setStyle(dotStyleDefault);
}
function onEachDot(feature, layer) {
layer.on({
mouseover: highlightDot,
mouseout: resetDotHighlight
});
var popup = '<table style="width:110px"><tbody><tr><td><div><b>Marker:</b></div></td><td><div>' + feature.properties.popup +
'</div></td></tr><tr class><td><div><b>Group:</b></div></td><td><div>' + feature.properties.glyphName +
'</div></td></tr><tr><td><div><b>X:</b></div></td><td><div>' + feature.geometry.coordinates[0] +
'</div></td></tr><tr><td><div><b>Y:</b></div></td><td><div>' + feature.geometry.coordinates[1] +
'</div></td></tr></tbody></table>'
layer.bindPopup(popup);
}
function renderChart(data) {
var myDots = make_dots(data);
var minZoom = 0,
maxZoom = 15;
var map = L.map('map', {
minZoom: minZoom,
maxZoom: maxZoom
}).setView([30, 30], 3);
L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
continuousWorld: false,
minZoom: 0,
noWrap: true
}).addTo(map);
myRenderer = L.canvas({
padding: 0.5
});
// Define an array to keep layerGroups
var dotlayer = [];
//create marker layer and display it on the map
for (var i = 0; i < myDots.length; i += 1) {
dotlayer[i] = L.geoJson(myDots[i], {
pointToLayer: function(feature, latlng) {
var p = latlng;
var myGlyph = new glyph('diamond')
return new myGlyph.type(p, style(feature));
},
onEachFeature: onEachDot
}).addTo(map);
}
var cl = L.control.layers(null, {}).addTo(map);
for (j = 0; j < dotlayer.length; j += 1) {
var name = "Group " + j + "0-" + j + "9";
cl.addOverlay(dotlayer[j], name);
}
}
</script>
</body>
</html>
答案 0 :(得分:2)
您需要将标记的shape
设为标记的属性,并将MarkerDiamond
和MarkerSquare
的渲染部分合并到另一个标记中,并确定要绘制的渲染部分基于属性if
的{{1}} 内部 _updateMarkerXX
方法。
shape
包含渲染例程中的形状。
或者在layer.options.shape
例程中完成
Marker
修改
定时使用幻数(Enums)而不是字符串可能会很有用,因为数字的比较比字符串比较便宜。而且Aenaon大约有30万个标记,但它可以忽略不计。