图例中使用的 Amcharts 填充适配器在切换时被覆盖
Amcharts fill adapter used in legend gets overridden on toggling
我正在做一个考虑到设计的项目,它具有自定义图例外观。使用 React 和 TypeScript,我需要创建一个类似于此的图表:
Required design
TLDR:尝试在 this codepen 上切换图例。下面列出了问题。
我试过的:
chart.legend = new Legend();
chart.legend.position = "top";
chart.legend.contentAlign = "left";
chart.legend.margin(0, 0, 30, 0);
// Disabled default markers that resemble color.
chart.legend.useDefaultMarker = true;
chart.legend.labels.template.marginLeft = 26;
chart.legend.labels.template.paddingTop = 3;
然后我开始自己修改图例
// Create checkbox outline
const marker = chart.legend.markers.template;
const markerColumn = marker.children.getIndex(0) as Sprite;
markerColumn.defaultState.properties.fillOpacity = 0;
markerColumn.defaultState.properties.strokeWidth = 1;
markerColumn.defaultState.properties.stroke = color("#3896CB");
markerColumn.defaultState.properties.strokeOpacity = 1;
然后我添加了复选框和圆形精灵,following this tutorial:
const checkbox = marker.createChild(Image);
checkbox.width = 20;
checkbox.height = 20;
checkbox.verticalCenter = "top";
checkbox.horizontalCenter = "left";
checkbox.href = "https://cdn.onlinewebfonts.com/svg/img_207414.png";
const checkboxActiveState = checkbox.states.create("active");
checkboxActiveState.properties.opacity = 0;
const circle = marker.createChild(Circle);
circle.strokeWidth = 0;
circle.width = 8;
circle.height = 8;
circle.dx = 36;
circle.dy = 12;
然后我偶然发现了一个问题:我没有找到 select 精确容器的 children 的方法,这样我就可以用我想要的任何颜色填充它们。大多数示例使用模板,每个模板都会更改 child。
我发现适配器可能对我有帮助。并写下这段代码:
const colorValues: string[] = ["#8BC4D7", "#009299", "#1ABDB5", "#3896CB"];
function createSeries(chart: XYChart, data: ChartData[], field: string, name: string, setColor: string) {
// ... Creating line series
series.dummyData = {
fill: setColor,
};
return series;
}
function colorAdapter(fill, target) {
if (!target.dataItem) {
return fill;
}
const settings = target.dataItem.dataContext.dummyData;
return settings.fill;
}
// Finally, adding color via dummyData:
// Correctly sets colors on first render, BUT on legend toggle forgets them
circle?.adapter.add("fill", (fill, target) => {
if (!target.dataItem) {
return fill;
}
const settings = target.dataItem.dataContext.dummyData;
return settings.fill;
});
问题:
尝试切换图例!再次打开后,带有虚拟数据的那些仍然是灰色的。
This 当我尝试打开和关闭图例时会发生什么(查看前两个图例项):
您可以在 this codepen 上玩类似的案例。
更新:这是我的 codepen 我的情况。
问题:
- (主要问题)如何使用适配器解决这个问题?预期结果:打开后,他们应该恢复填充颜色。
- (只是为了增长知识)如果可以的话,如何在不使用适配器的情况下解决这个问题?如何使用我想要的 hard-code、select 任何容器的 child?
- (替代解决方案?) 如果我希望这些圆圈在切换后仍保持颜色怎么办?我该怎么做?
- (可选,这可能在文档中的某处) 我不太明白如何在没有外部互联网的情况下用图像替换 sprite link。 .href 可以通过相对路径处理 svgs 吗?
要获得所需的颜色,您可以将适配器添加到状态更改中。应用于您的 codePen 它看起来像这样:
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [ {
"year": "2003",
"europe": 2.5,
"namerica": 2.5,
"asia": 2.1,
"lamerica": 1.2,
"meast": 0.2,
"africa": 0.1
}, {
"year": "2004",
"europe": 2.6,
"namerica": 2.7,
"asia": 2.2,
"lamerica": 1.3,
"meast": 0.3,
"africa": 0.1
}, {
"year": "2005",
"europe": 2.8,
"namerica": 2.9,
"asia": 2.4,
"lamerica": 1.4,
"meast": 0.3,
"africa": 0.1
} ];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "year";
categoryAxis.title.text = "Local country offices";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 20;
categoryAxis.renderer.cellStartLocation = 0.1;
categoryAxis.renderer.cellEndLocation = 0.9;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.title.text = "Expenditure (M)";
// Create series
function createSeries(field, name, stacked) {
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = field;
series.dataFields.categoryX = "year";
series.name = name;
series.columns.template.tooltipText = "{name}: [bold]{valueY}[/]";
series.stacked = stacked;
series.columns.template.width = am4core.percent(95);
// Let's try red, for example
series.dummyData = {
fill: "red",
};
}
createSeries("europe", "Europe", false);
createSeries("namerica", "North America", true);
createSeries("asia", "Asia", false);
createSeries("lamerica", "Latin America", true);
createSeries("meast", "Middle East", true);
createSeries("africa", "Africa", true);
// Add legend
chart.legend = new am4charts.Legend();
chart.legend.labels.template.marginLeft = 26;
chart.legend.useDefaultMarker = true;
const marker = chart.legend.markers.template;
const markerColumn = marker.children.getIndex(0);
const markerColumnActiveState = markerColumn.states.getKey("active");
markerColumn.defaultState.properties.fillOpacity = 0;
markerColumn.defaultState.properties.strokeWidth = 1;
markerColumn.defaultState.properties.stroke = am4core.color("#000");
markerColumn.defaultState.properties.strokeOpacity = 1;
// Add custom image instead
const checkbox = marker.createChild(am4core.Image);
checkbox.width = 20;
checkbox.height = 20;
checkbox.verticalCenter = "top";
checkbox.horizontalCenter = "left";
checkbox.href = "https://cdn.onlinewebfonts.com/svg/img_207414.png";
checkbox.dx = 1;
checkbox.dy = 1;
const checkboxActiveState = checkbox.states.create("active");
checkboxActiveState.properties.opacity = 0;
const circle = marker.createChild(am4core.Circle);
circle.width = 8;
circle.height = 8;
circle.verticalCenter = "top";
circle.horizontalCenter = "left";
circle.dx = 36;
circle.dy = 8;
//REM: https://www.amcharts.com/docs/v4/concepts/states/
const circleActiveState = circle.states.create("active");
circleActiveState.adapter.add("fill", (fill, target) => {
return "#000000"
});
const circleDefaultState = circle.states.create("default");
circleDefaultState.adapter.add("fill", (fill, target) => {
const settings = target?.sprite?.dataItem?.dataContext?.dummyData;
return settings?.fill || fill;
});
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div id = 'chartdiv'></div>
我正在做一个考虑到设计的项目,它具有自定义图例外观。使用 React 和 TypeScript,我需要创建一个类似于此的图表: Required design
TLDR:尝试在 this codepen 上切换图例。下面列出了问题。
我试过的:
chart.legend = new Legend();
chart.legend.position = "top";
chart.legend.contentAlign = "left";
chart.legend.margin(0, 0, 30, 0);
// Disabled default markers that resemble color.
chart.legend.useDefaultMarker = true;
chart.legend.labels.template.marginLeft = 26;
chart.legend.labels.template.paddingTop = 3;
然后我开始自己修改图例
// Create checkbox outline
const marker = chart.legend.markers.template;
const markerColumn = marker.children.getIndex(0) as Sprite;
markerColumn.defaultState.properties.fillOpacity = 0;
markerColumn.defaultState.properties.strokeWidth = 1;
markerColumn.defaultState.properties.stroke = color("#3896CB");
markerColumn.defaultState.properties.strokeOpacity = 1;
然后我添加了复选框和圆形精灵,following this tutorial:
const checkbox = marker.createChild(Image);
checkbox.width = 20;
checkbox.height = 20;
checkbox.verticalCenter = "top";
checkbox.horizontalCenter = "left";
checkbox.href = "https://cdn.onlinewebfonts.com/svg/img_207414.png";
const checkboxActiveState = checkbox.states.create("active");
checkboxActiveState.properties.opacity = 0;
const circle = marker.createChild(Circle);
circle.strokeWidth = 0;
circle.width = 8;
circle.height = 8;
circle.dx = 36;
circle.dy = 12;
然后我偶然发现了一个问题:我没有找到 select 精确容器的 children 的方法,这样我就可以用我想要的任何颜色填充它们。大多数示例使用模板,每个模板都会更改 child。 我发现适配器可能对我有帮助。并写下这段代码:
const colorValues: string[] = ["#8BC4D7", "#009299", "#1ABDB5", "#3896CB"];
function createSeries(chart: XYChart, data: ChartData[], field: string, name: string, setColor: string) {
// ... Creating line series
series.dummyData = {
fill: setColor,
};
return series;
}
function colorAdapter(fill, target) {
if (!target.dataItem) {
return fill;
}
const settings = target.dataItem.dataContext.dummyData;
return settings.fill;
}
// Finally, adding color via dummyData:
// Correctly sets colors on first render, BUT on legend toggle forgets them
circle?.adapter.add("fill", (fill, target) => {
if (!target.dataItem) {
return fill;
}
const settings = target.dataItem.dataContext.dummyData;
return settings.fill;
});
问题: 尝试切换图例!再次打开后,带有虚拟数据的那些仍然是灰色的。
This 当我尝试打开和关闭图例时会发生什么(查看前两个图例项):
您可以在 this codepen 上玩类似的案例。
更新:这是我的 codepen 我的情况。
问题:
- (主要问题)如何使用适配器解决这个问题?预期结果:打开后,他们应该恢复填充颜色。
- (只是为了增长知识)如果可以的话,如何在不使用适配器的情况下解决这个问题?如何使用我想要的 hard-code、select 任何容器的 child?
- (替代解决方案?) 如果我希望这些圆圈在切换后仍保持颜色怎么办?我该怎么做?
- (可选,这可能在文档中的某处) 我不太明白如何在没有外部互联网的情况下用图像替换 sprite link。 .href 可以通过相对路径处理 svgs 吗?
要获得所需的颜色,您可以将适配器添加到状态更改中。应用于您的 codePen 它看起来像这样:
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [ {
"year": "2003",
"europe": 2.5,
"namerica": 2.5,
"asia": 2.1,
"lamerica": 1.2,
"meast": 0.2,
"africa": 0.1
}, {
"year": "2004",
"europe": 2.6,
"namerica": 2.7,
"asia": 2.2,
"lamerica": 1.3,
"meast": 0.3,
"africa": 0.1
}, {
"year": "2005",
"europe": 2.8,
"namerica": 2.9,
"asia": 2.4,
"lamerica": 1.4,
"meast": 0.3,
"africa": 0.1
} ];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "year";
categoryAxis.title.text = "Local country offices";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 20;
categoryAxis.renderer.cellStartLocation = 0.1;
categoryAxis.renderer.cellEndLocation = 0.9;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.title.text = "Expenditure (M)";
// Create series
function createSeries(field, name, stacked) {
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = field;
series.dataFields.categoryX = "year";
series.name = name;
series.columns.template.tooltipText = "{name}: [bold]{valueY}[/]";
series.stacked = stacked;
series.columns.template.width = am4core.percent(95);
// Let's try red, for example
series.dummyData = {
fill: "red",
};
}
createSeries("europe", "Europe", false);
createSeries("namerica", "North America", true);
createSeries("asia", "Asia", false);
createSeries("lamerica", "Latin America", true);
createSeries("meast", "Middle East", true);
createSeries("africa", "Africa", true);
// Add legend
chart.legend = new am4charts.Legend();
chart.legend.labels.template.marginLeft = 26;
chart.legend.useDefaultMarker = true;
const marker = chart.legend.markers.template;
const markerColumn = marker.children.getIndex(0);
const markerColumnActiveState = markerColumn.states.getKey("active");
markerColumn.defaultState.properties.fillOpacity = 0;
markerColumn.defaultState.properties.strokeWidth = 1;
markerColumn.defaultState.properties.stroke = am4core.color("#000");
markerColumn.defaultState.properties.strokeOpacity = 1;
// Add custom image instead
const checkbox = marker.createChild(am4core.Image);
checkbox.width = 20;
checkbox.height = 20;
checkbox.verticalCenter = "top";
checkbox.horizontalCenter = "left";
checkbox.href = "https://cdn.onlinewebfonts.com/svg/img_207414.png";
checkbox.dx = 1;
checkbox.dy = 1;
const checkboxActiveState = checkbox.states.create("active");
checkboxActiveState.properties.opacity = 0;
const circle = marker.createChild(am4core.Circle);
circle.width = 8;
circle.height = 8;
circle.verticalCenter = "top";
circle.horizontalCenter = "left";
circle.dx = 36;
circle.dy = 8;
//REM: https://www.amcharts.com/docs/v4/concepts/states/
const circleActiveState = circle.states.create("active");
circleActiveState.adapter.add("fill", (fill, target) => {
return "#000000"
});
const circleDefaultState = circle.states.create("default");
circleDefaultState.adapter.add("fill", (fill, target) => {
const settings = target?.sprite?.dataItem?.dataContext?.dummyData;
return settings?.fill || fill;
});
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div id = 'chartdiv'></div>