D3.js SAP UI5中自定义d3控件的数据绑定错误

D3.js SAP UI5中自定义d3控件的数据绑定错误,d3.js,sapui5,D3.js,Sapui5,我正在使用SAP UI5中的自定义d3控件。我在这里找到了一个关于如何做到这一点的模板: 所以现在我只是想让这一切顺利。我的主要问题是我的控件不使用模型中的数据。以下是错误: 错误:属性x=“NaN”的值无效 错误:属性height=“-12”的负值无效 错误:属性x=“NaN”的值无效 我认为这是异步请求的问题,所以我添加了:gModel.loadData(“json/performance comparison.json”,null,false)但这仍然不起作用 谢谢你的建议 代码如下:

我正在使用SAP UI5中的自定义d3控件。我在这里找到了一个关于如何做到这一点的模板:

所以现在我只是想让这一切顺利。我的主要问题是我的控件不使用模型中的数据。以下是错误:

  • 错误:属性x=“NaN”的值无效
  • 错误:属性height=“-12”的负值无效
  • 错误:属性x=“NaN”的值无效
我认为这是异步请求的问题,所以我添加了:
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");


    }


});
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>
<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>

我不建议你就因为这个而打同步电话

<>使用数据绑定时要考虑的事项:

  • 您需要一个模型(json、xml、odata等等)
  • 您的模型必须用于控件或使用getCore().setModel()
  • 必须为控件定义路径
但是,请记住:

例如,如果您在定义数据绑定时使用格式化程序函数,那么应该事先加载模型,以避免出现像“NaN”这样的错误。如果创建了绑定路径+模型但未加载,则即使没有数据,也会调用格式化程序函数。换句话说,函数的形式参数将是未定义的

在某个特定时刻,您的模型可能会被创建,但这并不一定意味着将数据加载到您的客户机上——这就是为什么数据绑定的一个好技术就是在加载模型时定义绑定路径。如果您查看任何模型类,您将发现一些方法,这些方法允许您在加载数据或请求失败时定义回调(例如,请参阅方法attachRequestCompleted或attachRequestFailed)


使用这种技术,您可以保持异步调用,并在数据准备就绪时定义数据绑定。

我发誓我曾尝试创建一个类似于您显示的代码的项目。然而,您并没有包括很多必要的东西来帮助您喜欢json文件。此外,我建议您清理您的代码,这是非常混乱。。请直截了当。我决定创建一个尽可能简单的示例,它可能会帮助您清理工作代码。我没有使用数据绑定本身,但我相信它会有所帮助。请看:我建议您创建一个非常小的控件。谢谢您的回答。很抱歉,没有发布数据文件。但我还是不明白问题出在哪里。我已经创建了一个模型,并在控制器的init函数中使用了getCore().setModel(){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”);}
之后,在视图中,我创建了带有数据绑定的自定义控件,如代码中所示。
{
    "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"
        }
    ]
}