我正在使用SAP UI5中的自定义d3控件。我在这里找到了一个关于如何做到这一点的模板:http://scn.sap.com/community/developer-center/front-end/blog/2014/07/17/custom-sapui5-visualization-controls-with-d3js
所以现在我只想努力做到这一点。我的主要问题是我的控件不会消耗模型中的数据。这是错误:
我认为这是异步请求的问题,所以我添加了这个:gModel.loadData("json/performance-comparison.json", null, false);
但这仍然没有用。
感谢任何想法。
以下是代码:
HorizontalBarChart.js
jQuery.sap.require("sap/ui/thirdparty/d3");
jQuery.sap.declare("control.HorizontalBarChart");
sap.ui.core.Element.extend("control.HorizontalBarChartItem", { metadata : {
properties : {
"region" : {type : "string", group : "Misc", defaultValue : null},
"budget" : {type : "string", group : "Misc", defaultValue : null},
"bw" : {type : "string", group : "Misc", defaultValue : null},
"forecast" : {type : "string", group : "Misc", defaultValue : null}
}
}});
sap.ui.core.Control.extend("control.HorizontalBarChart", {
metadata : {
properties: {
"title": {type : "string", group : "Misc", defaultValue : "PerformanceToTargetComparison Chart Title"}
},
aggregations : {
"items" : { type: "control.HorizontalBarChartItem", multiple : false, singularName : "item"}
}
,
defaultAggregation : "items",
events: {
"onPress" : {},
"onChange":{}
}
},
init : function() {
console.log("sap.jaysdk.PerformanceToTargetComparison.init()");
this.sParentId = "";
},
createComparison : function() {
/*
* Called from renderer
*/
//console.log("Creating Chart");
/*
var chartLayout = new sap.ui.commons.Panel();
this.sParentId = chartLayout.getIdForLabel();
console.log(this.sParentId);
return chartLayout;
*/
var oChartLayout = new sap.m.VBox({alignItems:sap.m.FlexAlignItems.Center,justifyContent:sap.m.FlexJustifyContent.Center});
var oChartFlexBox = new sap.m.FlexBox({height:"180px",alignItems:sap.m.FlexAlignItems.Center});
/* ATTENTION: Important
* This is where the magic happens: we need a handle for our SVG to attach to. We can get this using .getIdForLabel()
* Check this in the 'Elements' section of the Chrome Devtools:
* By creating the layout and the Flexbox, we create elements specific for this control, and SAPUI5 takes care of
* ID naming. With this ID, we can append an SVG tag inside the FlexBox
*/
this.sParentId=oChartFlexBox.getIdForLabel();
oChartLayout.addItem(oChartFlexBox);
return oChartLayout;
},
/**
* The renderer render calls all the functions which are necessary to create the control,
* then it call the renderer of the vertical layout
* @param oRm {RenderManager}
* @param oControl {Control}
*/
renderer : function(oRm, oControl) {
var layout = oControl.createComparison();
//layout.addStyleClass('pointer');
// instead of "this" in the renderer function
oRm.write("<div");
oRm.writeControlData(layout); // writes the Control ID and enables event handling - important!
oRm.writeClasses(); // there is no class to write, but this enables
// support for ColorBoxContainer.addStyleClass(...)
oRm.write(">");
oRm.renderControl(layout);
oRm.addClass('verticalAlignment');
oRm.write("</div>");
},
onAfterRendering: function(){
console.log("sap.jaysdk.PerformanceToTargetComparison.onAfterRendering()");
var cItems = this.getItems();
//console.log(cItems);
var data = [];
for (var i=0;i<cItems.length;i++){
var oEntry = {};
for (var j in cItems[i].mProperties) {
oEntry[j]=cItems[i].mProperties[j];
}
data.push(oEntry);
}
//console.log("Data:");
//console.log(data);
/*
* ATTENTION: See .createComparison()
* Here we're picking up a handle to the "parent" FlexBox with the ID we got in .createComparison()
* Now simply .append SVG elements as desired
* EVERYTHING BELOW THIS IS PURE D3.js
*/
var vis = d3.select("#" + this.sParentId);
var colors = {"pos_bw": "green",
"pos_forecast": "darkgreen",
"neg_bw": "darkorange",
"neg_forecast": "red"};
var numElements = data.length;
for (var i=0; i<data.length;i++){
data[i].bw = data[i].bw/data[i].budget;
data[i].forecast = data[i].forecast/data[i].budget;
data[i].budget = 1;
}
console.log("data: ");
console.log(data);
var maxval = d3.max(data, function(d){
return Math.max(d.budget, d.bw, d.forecast);});
if(maxval<1.6){
maxval=1.6;
}
var minval = d3.min(data, function(d){
return Math.min(d.budget, d.bw, d.forecast);});
var width = 600;
var offset = 75;
var svg = vis.append("svg").style("background-color","white").attr("width", width).attr("height", numElements*30);
var xScale = d3.scale.linear().domain([minval, maxval]).range([0, width-(offset+5)]);
//console.log(minval + " - 0 - " + maxval)
//console.log(xScale(minval) + " - " + xScale(1) + " - " + xScale(maxval));
var chart;
// 200% line
if(maxval>2){
chart= svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.append("rect")
.attr("x", xScale(2))
.attr("Y", 0)
.attr("width", 1)
.attr("height", (numElements-1)*25 + 13)
.style("fill", "darkgrey");
chart.append("text").text("200%")
.attr("text-anchor", "middle")
.attr("x", xScale(2))
.attr("y", numElements*25+4)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "darkgrey");
}
// 300% line
if(maxval>3.1){
chart= svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.append("rect")
.attr("x", xScale(3))
.attr("Y", 0)
.attr("width", 1)
.attr("height", (numElements-1)*25 + 13)
.style("fill", "darkgrey");
chart.append("text").text("300%")
.attr("text-anchor", "middle")
.attr("x", xScale(3))
.attr("y", numElements*25+4)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "darkgrey");
}
// 150% line
if(maxval>1.5 && maxval<3.1){
chart= svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.append("rect")
.attr("x", xScale(1.5))
.attr("Y", 0)
.attr("width", 1)
.attr("height", (numElements-1)*25 + 13)
.style("fill", "darkgrey");
chart.append("text").text("150%")
.attr("text-anchor", "middle")
.attr("x", xScale(1.5))
.attr("y", numElements*25+4)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "darkgrey");
}
// 50% line
if(minval<0.5){
chart= svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.append("rect")
.attr("x", xScale(0.5))
.attr("Y", 0)
.attr("width", 1)
.attr("height", (numElements-1)*25 + 13)
.style("fill", "darkgrey");
chart.append("text").text("50%")
.attr("text-anchor", "middle")
.attr("x", xScale(0.5))
.attr("y", numElements*25+4)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "darkgrey");
}
// Booked/Won Percentage
chart = svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.selectAll(".pttc_bw")
.data(data)
.enter()
.append("rect")
.attr("class", "pttc_bw")
.attr("x", function(d) {
if(d.bw<1){
return xScale(d.bw);
}else{
return xScale(1);
}
})
.attr("y", function(d, i){ return 25*i+2;})
.attr("height", 4)
.attr("width", function(d){
if(d.bw<1){
return xScale(1) - xScale(d.bw);
}else{
return xScale(d.bw)-xScale(1);
}
})
.style("fill", function(d){ if(d.bw<1){ return colors.neg_bw;} else {return colors.pos_bw;}});
// Forecast Percentage
chart = svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.selectAll(".pttc_forecast")
.data(data)
.enter().append("rect")
.attr("class", "pttc_forecast")
.attr("x", function(d) {
if(d.forecast<1){
return xScale(d.forecast);
}else{
return xScale(1);
}
})
.attr("y", function(d, i){ return 25*i+7;})
.attr("height", 4)
.attr("width", function(d){
if(d.forecast<1){
return xScale(1) - xScale(d.forecast);
}else{
return xScale(d.forecast) - xScale(1);
}
})
.style("fill", function(d){ if(d.forecast<1){ return colors.neg_forecast;} else {return colors.pos_forecast;}});
// Labels
chart = svg.selectAll(".labels")
chart.data(data)
.enter().append("text")
.attr("class", "labels")
.attr("text-anchor", "end")
.attr("x", offset-6)
.attr("y", function(d, i){ return 25*i + 22})
.text(function(d){ return d.region;})
.attr("font-family", "sans-serif")
.attr("font-size", "16px")
.attr("font-weight", "bold")
.attr("fill", "darkgrey");
// 100% line
chart = svg.append("g").attr("transform", "translate(" + offset + ",10)");
chart.append("rect")
.attr("x", xScale(1))
.attr("Y", 0)
.attr("width", 1)
.attr("height", (numElements-1)*25 + 13)
.style("fill", "grey");
chart.append("text").text("100%")
.attr("text-anchor", "middle")
.attr("x", xScale(1))
.attr("y", numElements*25+4)
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "grey");
}
});
firstXmlView.controller.js
jQuery.sap.registerModulePath("control.HorizontalBarChart", "control/HorizontalBarChart");
jQuery.sap.require("control.HorizontalBarChart");
jQuery.sap.registerModulePath("control.HorizontalBarChartItem", "control/HorizontalBarChart");
jQuery.sap.require("control.HorizontalBarChartItem");
sap.ui.controller("ui.firstXmlView", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* @memberOf ui.firstXmlView
*/
onInit: function() {
var gModel = new sap.ui.model.json.JSONModel("json/performance-comparison.json");
gModel.loadData("json/performance-comparison.json", null, false);
sap.ui.getCore().setModel(gModel, "performance");
var oChartHolder = this.byId("ChartHolder");
var oChartItem = new control.HorizontalBarChartItem({region:"{region}", budget:"{budget}", bw:"{bw_ytd}", forecast:"{forecast}"});
var oChart = new control.HorizontalBarChart({
items: {path : "/regions", template : oChartItem}
});
var oModel = sap.ui.getCore().getModel("performance");
oChart.setModel(oModel);
oChartHolder.addItem(oChart);
},
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* @memberOf ui.firstXmlView
*/
// onBeforeRendering: function() {
// },
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* @memberOf ui.firstXmlView
*/
// onAfterRendering: function() {
//
// },
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* @memberOf ui.firstXmlView
*/
// onExit: function() {
//
// }
});
的index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<!-- SAP UI5 Bootstrap -->
<script src="/sap/ui5/1/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.ui.commons, sap.ui.table, sap.ui.core, sap.m" >
</script>
<!-- SAP UI5 Bootstrap -->
<!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->
<!-- D3 Charts Load -->
<script src="js/d3.min.js"></script>
<script src="js/d3.Stacked.Chart.js"></script>
<script src="js/d3.Pie.Chart.js"></script>
<script src="js/Data.js"></script>
<!-- D3 Charts Load -->
<!-- Loading Custom Control -->
<script>
sap.ui.localResources('control');
jQuery.sap.require("control.HorizontalBarChart");
jQuery.sap.require("control.pieChart");
jQuery.sap.require("control.AutoCompleteValueHolder");
jQuery.sap.require("control.root");
jQuery.sap.require("control.stackedChart");
jQuery.sap.require("control.stackChartItem");
</script>
<!-- Loading Custom Control -->
<!-- Header -->
<script type="text/javascript">
/*
var oAppHeader = new sap.ui.commons.ApplicationHeader("appHeader");
// oAppHeader.setLogoSrc("http://global.sap.com/global/images/SAPLogo.gif");
// oAppHeader.setLogoText("SAP - Link Prediction PoC");
oAppHeader.setDisplayWelcome(true);
oAppHeader.setUserName("");
oAppHeader.setDisplayLogoff(true);
oAppHeader.placeAt("header");
*/
</script>
<!-- Header -->
<!-- Stacked Chart -->
<script type="text/javascript">
/*
var oPanelWheel = new sap.ui.commons.Panel();
oPanelWheel.setTitle(new sap.ui.commons.Title({text: "Stacked Chart"}));
oPanelWheel.setWidth("1000px");
oPanelWheel.setCollapsed(false);
var stackedChart = new sap.ui.core.HTML({
content: "<div id='content' align='center'></div>",
preferDOM: false,
afterRendering: function(Event){
stackBuilding();
}
});
//oPanelWheel.placeAt("content");
stackedChart.placeAt("content");
*/
</script>
<!-- Stacked Chart -->
<script>
sap.ui.localResources("ui");
var view = sap.ui.view({ //id:"idui1",
viewName:"ui.firstXmlView", type:sap.ui.core.mvc.ViewType.XML});
view.placeAt("content");
//var view = new sap.m.Shell({
//app : new sap.ui.core.ComponentContainer({
// name : "sap.jaysdk"
//})
//})
</script>
</head>
<body class="sapUiBody" role="application">
<div id="header"></div>
<div id="drawChart"></div>
<div id="mainPage"></div>
<div id="content"></div>
<div id="test"></div>
<div id="footer"></div>
</body>
firstXMLView.view.xml
<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
controllerName="ui.firstXmlView" xmlns:html="http://www.w3.org/1999/xhtml">
<Page title="working on d3">
<content>
<Panel>
<headerToolbar>
<Toolbar>
<Label text="YTD Booked/Won and Forecast to Budget (Percentage)" />
</Toolbar>
</headerToolbar>
<FlexBox id="ChartHolder" alignItems="Start" justifyContent="Center">
</FlexBox>
</Panel>
</content>
</Page>
性能comparison.json
{
"regions": [
{
"region": "France",
"budget": "10123",
"bw_ytd": "12798",
"forecast": "14885"
},
{
"region": "Germany",
"budget": "11903",
"bw_ytd": "5000",
"forecast": "6500"
},
{
"region": "Japan",
"budget": "7000",
"bw_ytd": "8900",
"forecast": "10500"
},
{
"region": "Mexico",
"budget": "5000",
"bw_ytd": "9000",
"forecast": "10000"
},
{
"region": "UK",
"budget": "12500",
"bw_ytd": "14000",
"forecast": "19634"
},
{
"region": "US",
"budget": "40000",
"bw_ytd": "65000",
"forecast": "82000"
}
]
}
答案 0 :(得分:0)
我不建议您仅仅因此而进行同步通话。
使用数据绑定时需要考虑的事项:
但是,请记住:
例如,如果在定义数据绑定时使用格式化程序函数,则应事先加载模型以避免出现错误(“NaN”)。如果您创建了绑定路径+模型但未加载,即使没有数据,也会调用格式化程序函数。换句话说,函数的形式参数将是未定义的。
在特定时刻,您的模型可能已创建,但不一定意味着您的客户端上已加载数据 - 这就是为什么良好的数据绑定技术是在加载模型时定义绑定路径。如果您查看任何模型类,您将找到使您能够在加载数据或请求失败时定义回调的方法(请参阅attachRequestCompleted或attachRequestFailed方法)。
使用这种技术,您可以保留异步调用并在数据就绪时定义数据绑定。