认为能够为热图设置一系列颜色而不是仅仅是两个(min and max)是很好的。就像我们为梯度列表所做的事情一样。
类似...
function am4themes_myHeatmap(target) {
if (target instanceof am4core.ColorSet) {
target.list = [
am4core.color("#F7E3D4"),
am4core.color("#FFC480"),
am4core.color("#DC60BF"),
am4core.color("#A43B7D"),
am4core.color("#5B0A25")
];
}
}
请参见Mockup中的示例
如果已经存在类似的东西,我很乐意看到它。
不存在类似的东西。
不幸的是,只有使用heatRules
和HeatLegend
并让它们使用其他颜色的简单方法。但是,模仿heatRules
并不过于复杂,如果您仅在HeatLegend
中使用1个marker
(即一个长条,而不是多个条),则使用自定义的梯度覆盖其梯度。
我从您提供的图像中获取了2种颜色,并将其扔进了一个阵列中:
var heatColors = [
am4core.color("rgb(248, 227, 211)"),
am4core.color("rgb(237, 137, 166)"),
am4core.color("rgb(0,0,0)")
];
这不是必需的,但是很有用。这些是3色梯度的颜色。我选择使用3种颜色,以便我们可以在梯度的左/右半之间均匀分配计算,它应该简化下面的演示。您共享的图片可能需要在左半部分中添加额外的颜色,您必须相应地调整计算,但这也是可行的。
要模拟heatRules
,我们将为mapPolygons
'fill
提供一个适配器。在那里,我们将将mapPolygon
的value
与值的最小值进行比较,可以通过系列的dataItem.values["value"].low
和.high
找到后者。这将使我们在小数中获得一个百分比,以从多种颜色中获取颜色。从范围选择颜色的实用程序功能是am4core.colors.interpolate
,其前两个参数是iRGB
S(具有r
,g
,b
和a
属性/值的普通对象,第三个是小数中的百分比。如果百分比在上半年之内,我们将让适配器返回上面heatColors
中的前两种颜色,如果是下半年,我们将从后两个中返回颜色。
这是该代码的样子:
polygonSeries.mapPolygons.template.adapter.add("fill", function(
fill,
mapPolygon
) {
var workingValue = mapPolygon.dataItem.values["value"].workingValue;
var minValue = polygonSeries.dataItem.values["value"].low;
var maxValue = polygonSeries.dataItem.values["value"].high;
var percent = (workingValue - minValue) / (maxValue - minValue);
if (am4core.type.isNumber(percent)) {
if (percent > 0.5) {
return new am4core.Color(
am4core.colors.interpolate(
heatColors[1].rgb,
heatColors[2].rgb,
(percent - 0.5) * 2
)
);
} else {
return new am4core.Color(
am4core.colors.interpolate(
heatColors[0].rgb,
heatColors[1].rgb,
percent * 2
)
);
}
}
return fill;
});
如果您有1个标记的heatLegend
,即只有一个带有梯度的栏,则可以制作自己的梯度并将其分配给适配器:
var gradient = new am4core.LinearGradient();
heatColors.forEach(function(color) {
gradient.addColor(color);
});
heatLegend.markers.template.adapter.add("fill", function() {
return gradient;
});
如果您在heatLegend
中有多个标记(根据图片中的顶级传说),则自定义着色更像我们为heatRules
所做的,而不是适配器,因为我们需要知道它们的位置和位置和没有dataItem
或index
可用,一旦准备就绪,我们将通过markers
迭代,然后在那里覆盖其颜色:
var heatLegendTop = chart.createChild(am4maps.HeatLegend);
heatLegendTop.series = polygonSeries;
heatLegendTop.minColor = heatColors[0];
heatLegendTop.maxColor = heatColors[2];
heatLegendTop.marginBottom = 10;
heatLegendTop.markerCount = 10;
heatLegendTop.events.on("inited", function() {
heatLegendTop.markers.each(function(marker, markerIndex) {
// Gradient colors!
if (markerIndex < heatLegendTop.markerCount / 2) {
marker.fill = new am4core.Color(
am4core.colors.interpolate(
heatColors[0].rgb,
heatColors[1].rgb,
(markerIndex / heatLegendTop.markerCount) * 2
)
);
} else {
marker.fill = new am4core.Color(
am4core.colors.interpolate(
heatColors[1].rgb,
heatColors[2].rgb,
((markerIndex - heatLegendTop.markerCount / 2) /
heatLegendTop.markerCount) *
2
)
);
}
});
});
i用上述代码分配了我们的美国热量(Choropleth)映射演示,然后有些贴近您共享的图像的外观/感觉:
https://codepen.io/team/amcharts/pen/7fd84c880922a6fc50f80330d778654a
我简化了演示,并使其响应:https://codepen.io/team/amcharts/pen/eyjzvev
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create map instance
var chart = am4core.create("chartdiv", am4maps.MapChart);
// Set map definition
chart.geodata = am4geodata_usaAlbersLow;
// Set projection
chart.projection = new am4maps.projections.Miller();
// Create map polygon series
var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
// Make map load polygon data (state shapes and names) from GeoJSON
polygonSeries.useGeodata = true;
// //Set min/max fill color for each area
// polygonSeries.heatRules.push({
// property: "fill",
// target: polygonSeries.mapPolygons.template,
// min: chart.colors.getIndex(1).brighten(1),
// max: chart.colors.getIndex(1).brighten(-0.3)
// });
// make room for heatLegends
chart.chartContainer.paddingBottom = 50;
// Base colors for custom "heatRules" gradient
var heatColors = [
am4core.color("rgb(248, 227, 211)"),
am4core.color("rgb(237, 137, 166)"),
am4core.color("rgb(0,0,0)")
];
// Let hover state colors be relative to the "heatRule" color
var hoverState = polygonSeries.mapPolygons.template.states.create("hover");
hoverState.adapter.add("fill", function(fill) {
return fill.lighten(-0.1);
});
// Emulate heatRule but with 2 color ranges instead of 1
polygonSeries.mapPolygons.template.adapter.add("fill", function(
fill,
mapPolygon
) {
var workingValue = mapPolygon.dataItem.values["value"].workingValue;
var minValue = polygonSeries.dataItem.values["value"].low;
var maxValue = polygonSeries.dataItem.values["value"].high;
var percent = (workingValue - minValue) / (maxValue - minValue);
// This may run before workingValue is even a thing. Let's only do our thing
// if workingValue and ergo percent are a thing.
if (am4core.type.isNumber(percent)) {
if (percent > 0.5) {
return new am4core.Color(
am4core.colors.interpolate(
heatColors[1].rgb,
heatColors[2].rgb,
(percent - 0.5) * 2
)
);
} else {
return new am4core.Color(
am4core.colors.interpolate(
heatColors[0].rgb,
heatColors[1].rgb,
percent * 2
)
);
}
}
return fill;
});
// Set up heat legends
var heatLegendTop = chart.createChild(am4maps.HeatLegend);
heatLegendTop.series = polygonSeries;
heatLegendTop.align = "center";
heatLegendTop.width = am4core.percent(38);
heatLegendTop.minValue = 0;
heatLegendTop.maxValue = 40000000;
heatLegendTop.minColor = heatColors[0];
heatLegendTop.maxColor = heatColors[2];
heatLegendTop.marginBottom = 10;
heatLegendTop.markerCount = 10;
heatLegendTop.markerContainer.minHeight = 10;
heatLegendTop.markers.template.minHeight = 10;
var markerWidth = 20;
heatLegendTop.events.on("inited", function() {
heatLegendTop.markers.each(function(marker, markerIndex) {
// Override default heatLegend functionality
marker.width = markerWidth;
// Distribute the space, this needs to be repeated e.g. on window resize,
// orientation change, etc.
if (markerIndex < heatLegendTop.markers.length - 1) {
marker.marginRight =
(heatLegendTop.markerContainer.pixelWidth -
heatLegendTop.markerCount * markerWidth) /
(heatLegendTop.markerCount - 1);
}
// Gradient colors!
if (markerIndex < heatLegendTop.markerCount / 2) {
marker.fill = new am4core.Color(
am4core.colors.interpolate(
heatColors[0].rgb,
heatColors[1].rgb,
(markerIndex / heatLegendTop.markerCount) * 2
)
);
} else {
marker.fill = new am4core.Color(
am4core.colors.interpolate(
heatColors[1].rgb,
heatColors[2].rgb,
((markerIndex - heatLegendTop.markerCount / 2) /
heatLegendTop.markerCount) *
2
)
);
}
});
});
// Blank out internal heat legend value axis labels
heatLegendTop.valueAxis.renderer.labels.template.disabled = true;
var heatLegend = chart.createChild(am4maps.HeatLegend);
heatLegend.series = polygonSeries;
heatLegend.align = "center";
heatLegend.width = am4core.percent(38);
heatLegend.minValue = 0;
heatLegend.maxValue = 40000000;
heatLegend.markerContainer.minHeight = 10;
heatLegend.markers.template.minHeight = 10;
// Set up custom heat map legend labels using axis ranges
var minRange = heatLegend.valueAxis.axisRanges.create();
minRange.value = heatLegend.minValue;
minRange.label.inside = true;
minRange.label.horizontalCenter = "right";
minRange.label.dy = 5;
minRange.label.dx = -3;
minRange.label.text = "Less";
var maxRange = heatLegend.valueAxis.axisRanges.create();
maxRange.value = heatLegend.maxValue;
maxRange.label.inside = true;
maxRange.label.horizontalCenter = "left";
maxRange.label.dy = 5;
maxRange.label.dx = 3;
maxRange.label.text = "More";
// Blank out internal heat legend value axis labels
heatLegend.valueAxis.renderer.labels.template.adapter.add("text", function(
labelText
) {
return "";
});
// Allow the heatLegend to function in general
heatLegend.minColor = heatColors[0];
heatLegend.maxColor = heatColors[2];
// Override heatLegend gradient
var gradient = new am4core.LinearGradient();
heatColors.forEach(function(color) {
gradient.addColor(color);
});
heatLegend.markers.template.adapter.add("fill", function() {
return gradient;
});
// Configure series tooltip
var polygonTemplate = polygonSeries.mapPolygons.template;
polygonTemplate.tooltipText = "{name}: {value}";
// // Create hover state and set alternative fill color
// var hs = polygonTemplate.states.create("hover");
// hs.properties.fill = am4core.color("#3c5bdc");
// Set heatmap values for each state
polygonSeries.data = [
{
id: "US-AL",
value: 4447100
},
{
id: "US-AK",
value: 626932
},
{
id: "US-AZ",
value: 5130632
},
{
id: "US-AR",
value: 2673400
},
{
id: "US-CA",
value: 33871648
},
{
id: "US-CO",
value: 4301261
},
{
id: "US-CT",
value: 3405565
},
{
id: "US-DE",
value: 783600
},
{
id: "US-FL",
value: 15982378
},
{
id: "US-GA",
value: 8186453
},
{
id: "US-HI",
value: 1211537
},
{
id: "US-ID",
value: 1293953
},
{
id: "US-IL",
value: 12419293
},
{
id: "US-IN",
value: 6080485
},
{
id: "US-IA",
value: 2926324
},
{
id: "US-KS",
value: 2688418
},
{
id: "US-KY",
value: 4041769
},
{
id: "US-LA",
value: 4468976
},
{
id: "US-ME",
value: 1274923
},
{
id: "US-MD",
value: 5296486
},
{
id: "US-MA",
value: 6349097
},
{
id: "US-MI",
value: 9938444
},
{
id: "US-MN",
value: 4919479
},
{
id: "US-MS",
value: 2844658
},
{
id: "US-MO",
value: 5595211
},
{
id: "US-MT",
value: 902195
},
{
id: "US-NE",
value: 1711263
},
{
id: "US-NV",
value: 1998257
},
{
id: "US-NH",
value: 1235786
},
{
id: "US-NJ",
value: 8414350
},
{
id: "US-NM",
value: 1819046
},
{
id: "US-NY",
value: 18976457
},
{
id: "US-NC",
value: 8049313
},
{
id: "US-ND",
value: 642200
},
{
id: "US-OH",
value: 11353140
},
{
id: "US-OK",
value: 3450654
},
{
id: "US-OR",
value: 3421399
},
{
id: "US-PA",
value: 12281054
},
{
id: "US-RI",
value: 1048319
},
{
id: "US-SC",
value: 4012012
},
{
id: "US-SD",
value: 754844
},
{
id: "US-TN",
value: 5689283
},
{
id: "US-TX",
value: 20851820
},
{
id: "US-UT",
value: 2233169
},
{
id: "US-VT",
value: 608827
},
{
id: "US-VA",
value: 7078515
},
{
id: "US-WA",
value: 5894121
},
{
id: "US-WV",
value: 1808344
},
{
id: "US-WI",
value: 5363675
},
{
id: "US-WY",
value: 493782
}
];