我有一个包含散点图的自定义控件。按下按钮时,它会打开一个显示图表的模态/对话框控件(参见下图)。唯一的问题是图表显示两次!打开开发工具后,似乎所有生命周期都会呈现两次。我不知道为什么会发生这种情况,但我需要只渲染一次。
这是我的主控制器:
main.controller.js
jQuery.sap.registerModulePath("vizConcept.ScatterPlot", "controls/ScatterPlot");
jQuery.sap.require("vizConcept.ScatterPlot");
jQuery.sap.registerModulePath("vizConcept.ScatterPlotItem", "controls/ScatterPlot");
jQuery.sap.require("vizConcept.ScatterPlotItem");
sap.ui.define([
'jquery.sap.global',
'vizConcept/controller/BaseController',
'sap/ui/model/json/JSONModel',
'vizConcept/model/viewControls',
'sap/m/Button',
'sap/m/Dialog',
],
function (jQuery, BaseController, JSONModel, viewControls, Button, Dialog) {
"use strict";
var controls;
var mainController = BaseController.extend("vizConcept.controller.Main", {
onInit: function(oEvent) {
// Access/expose the defined model(s) configured in the Component.js or Manifest.json within the controller.
this.getView().setModel(this.getOwnerComponent().getModel("products"), "products");
var oModel = this.getView().getModel("products");
this.getView().setModel(oModel);
//
console.log('onInit');
var sUrl = "#" + this.getOwnerComponent().getRouter().getURL("page2");
//IIFE renders our chart, will need to move this in a modular way
},
onAfterRendering: function () {
this._rebindAll();
},
_rebindAll : function() {
var oModel = new sap.ui.model.json.JSONModel({
"buckets": [
{
"quarter": "Q2 2013",
"values": [
{ "name": "Segment A",
"value": "3228",
"value2": "12"
},
{
"name": "Segment B",
"value": "11752",
"value2": "37"
},
{
"name": "Segment C",
"value": "492",
"value2": "3"
},
{
"name": "Segment D",
"value": "654",
"value2": "6"
},
{
"name": "Segment E",
"value": "39165",
"value2": "167"
},
{
"name": "Segment F",
"value": "4745",
"value2": "9"
}
]
},
{
"quarter": "Q3 2013",
"values": [
{ "name": "Segment A",
"value": "6806",
"value2": "24"
},
{
"name": "Segment B",
"value": "11372",
"value2": "51"
},
{
"name": "Segment C",
"value": "2306",
"value2": "10"
},
{
"name": "Segment D",
"value": "1492",
"value2": "7"
},
{
"name": "Segment E",
"value": "33944",
"value2": "170"
},
{
"name": "Segment F",
"value": "6498",
"value2": "16"
}
]
},
{
"quarter": "Q4 2013",
"values": [
{ "name": "Segment A",
"value": "11228",
"value2": "23"
},
{
"name": "Segment B",
"value": "31324",
"value2": "83"
},
{
"name": "Segment C",
"value": "1291",
"value2": "17"
},
{
"name": "Segment D",
"value": "4350",
"value2": "17"
},
{
"name": "Segment E",
"value": "52265",
"value2": "155"
},
{
"name": "Segment F",
"value": "23785",
"value2": "66"
}
]
},
{
"quarter": "Q1 2014",
"values": [
{ "name": "Segment A",
"value": "3708",
"value2": "18"
},
{
"name": "Segment B",
"value": "20176",
"value2": "74"
},
{
"name": "Segment C",
"value": "5169",
"value2": "61"
},
{
"name": "Segment D",
"value": "31322",
"value2": "76"
},
{
"name": "Segment E",
"value": "49069",
"value2": "191"
},
{
"name": "Segment F",
"value": "8928",
"value2": "19"
}
]
},
{
"quarter": "Q2 2014",
"values": [
{ "name": "Segment A",
"value": "2950",
"value2": "26"
},
{
"name": "Segment B",
"value": "6807",
"value2": "54"
},
{
"name": "Segment C",
"value": "3789",
"value2": "110"
},
{
"name": "Segment D",
"value": "12867",
"value2": "91"
},
{
"name": "Segment E",
"value": "21411",
"value2": "128"
},
{
"name": "Segment F",
"value": "18478",
"value2": "21"
}
]
}
]
});
var oScatterPlotHolder = this.byId("RegionScatterPlotHolder");
var oScatterPlotItem = new vizConcept.ScatterPlotItem({quarter:"{quarter}", values:"{values}"});
/* new chart */
var oScatterPlot = new vizConcept.ScatterPlot({
items: {path : "/buckets", template : oScatterPlotItem}
});
//var oModel = sap.ui.getCore().getModel("growth-regions-scatter");
oScatterPlot.setModel(oModel);
oScatterPlotHolder.addItem(oScatterPlot);
$(function() {
var dlg = new sap.m.Dialog({
id: 'vizModal',
title: 'Scatter Plot Example Viz',
width : "1800px",
height : "600px",
content : [oScatterPlotHolder],
beginButton: new Button({
text: 'Close',
press: function () {
dlg.close();
}
})
});
(new sap.m.Button({
text: 'open',
type: 'Accept',
press: function() {
dlg.open();
oScatterPlotHolder.invalidate();
}
})).placeAt('content');
});
},
onToPage2 : function () {
this.getOwnerComponent().getRouter().navTo("page2");
},
});
return mainController;
});
ScatterPlot.js(自定义控件)
jQuery.sap.require("sap/ui/thirdparty/d3");
jQuery.sap.declare("vizConcept.ScatterPlot");
sap.ui.core.Element.extend("vizConcept.ScatterPlotItem", { metadata : {
properties : {
"quarter" : {type : "string", group : "Misc", defaultValue : null},
"values" : {type : "object", group : "Misc", defaultValue : null}
}
}});
sap.ui.core.Control.extend("vizConcept.ScatterPlot", {
metadata : {
properties: {
"title": {type : "string", group : "Misc", defaultValue : "ScatterPlot Title"}
},
aggregations : {
"items" : { type: "vizConcept.ScatterPlotItem", multiple : true, singularName : "item"}
},
defaultAggregation : "items",
events: {
"onPress" : {},
"onChange":{}
}
},
init : function() {
console.log("vizConcept.ScatterPlot.init()");
this.sParentId = "";
},
createScatterPlot : function() {
/*
* Called from renderer
*/
console.log("vizConcept.ScatterPlot.createScatterPlot()");
var oScatterPlotLayout = new sap.m.VBox({alignItems:sap.m.FlexAlignItems.Center,justifyContent:sap.m.FlexJustifyContent.Center});
var oScatterPlotFlexBox = new sap.m.FlexBox({height:"auto",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=oScatterPlotFlexBox.getIdForLabel();
oScatterPlotLayout.addItem(oScatterPlotFlexBox);
return oScatterPlotLayout;
},
/**
* 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.createScatterPlot();
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("vizConcept.ScatterPlot.onAfterRendering()");
//console.log(this.sParentId);
var cItems = this.getItems();
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 .createScatterPlot()
* Here we're picking up a handle to the "parent" FlexBox with the ID we got in .createScatterPlot()
* Now simply .append SVG elements as desired
* EVERYTHING BELOW THIS IS PURE D3.js
*/
var margin = {
top: 15,
right: 15,
bottom: 30,
left: 40
},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Our X scale
var x = d3.scale.linear()
.range([0, width-80]);
// Our Y scale
var y = d3.scale.linear()
.range([height, 0]);
// Our color bands
var color = d3.scale.ordinal()
.range(["#004460", "#0070A0", "#008BC6", "#009DE0", "#45B5E5", "8CCDE9", "#DAEBF2"]); //"#00A6ED",
// Use our X scale to set a bottom axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
// Smae for our left axis
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var tip = d3.select("body").append("div")
.attr("class", "sctooltip")
.style("position", "absolute")
.style("text-align", "center")
.style("width", "80px")
.style("height", "42px")
.style("padding", "2px")
.style("font", "11px sans-serif")
.style("background", "#F0F0FF")
.style("border", "0px")
.style("border-radius", "8px")
.style("pointer-events", "none")
.style("opacity", 0);
var vis = d3.select("#" + this.sParentId);
var svg = vis.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("background-color","white")
.style("font", "12px sans-serif")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain([0, d3.max(data, function (d) {
var max = d3.max(d.values, function (dd){
return(+dd.value);
})
return max;
})]);
// Our Y domain is from zero to our highest total
y.domain([0, d3.max(data, function (d) {
var max = d3.max(d.values, function (dd){
return(+dd.value2);
})
return max;
})]);
var totalval = 0;
var totalval2 = 0;
data.forEach(function (d) {
var quarter = d.quarter;
d.values.forEach(function (dd){
dd.quarter = quarter;
totalval += +dd.value;
totalval2 += +dd.value2;
});
});
var average = totalval/totalval2;
var line_data = [{"x": 0, "y": 0},{"x": (y.domain()[1]*average), "y": y.domain()[1]}];
var avgline = d3.svg.line()
.x(function(d){ return x(d.x); })
.y(function(d){ return y(d.y); })
.interpolate("linear");
svg.append("g")
.attr("class", "x axis")
.style("fill", "none")
.style("stroke", "grey")
.style("shape-rendering", "crispEdges")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis")
.style("fill", "none")
.style("stroke", "grey")
.style("shape-rendering", "crispEdges")
.call(yAxis);
//average line
svg.append("path")
.attr("class", "avgline")
.style("stroke", "#000")
.style("stroke-width", "1px")
.style("stroke-dasharray", ("4, 4"))
.attr("d", avgline(line_data));
/*
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("XXXXX");
*/
var plot = svg.selectAll(".quarter")
.data(data)
.enter().append("g");
plot.selectAll("dot")
.data(function (d) {
return d.values;
})
.enter().append("circle")
.attr("class", "dot")
.attr("r", 5)
.attr("cx", function (d){
return x(d.value);
})
.attr("cy", function (d) {
return y(d.value2);
})
.style("stroke", "#004460")
.style("fill", function (d) {
return color(d.name);
})
.style("opacity", .9)
.style("visibility", function(d){
if(+d.value != 0){
return "visible";
}else{
return "hidden";
}
})
.style("pointer-events", "visible")
.on("mouseover", function(d){
tip.transition()
.duration(200)
.style("opacity", .8);
tip.html(d.name + "<br/>" + d.quarter + "<br />" + "Avg. " +(+d.value/+d.value2).toFixed(2))
.style("left", (d3.event.pageX-40) + "px")
.style("top", (d3.event.pageY-50) + "px");
})
.on("mouseout", function(d){
tip.transition()
.duration(500)
.style("opacity", 0);
});;
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) {
return "translate(0," + i * 16 + ")";
});
legend.append("rect")
.attr("x", width - 12)
.attr("width", 12)
.attr("height", 12)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 6)
.attr("dy", ".35em")
.style("text-anchor", "end")
.style("font", "11px sans-serif")
.text(function (d) {
return d;
});
var avglabel = svg.append("g")
.attr("transform", "translate(" + (width-40) + ",140)");
avglabel.append("text")
.style("text-anchor", "middle")
.text("Average: " + average.toFixed(2));
}
});
答案 0 :(得分:0)
我注意到,根据渲染周期中的生命周期事件可能会很棘手,我认为可以通过UI5来确定何时运行。如果您只想运行一次,那么您可以使用python -m pip install package
python3 -m pip install package
或onRoutePatternMatched()
,这些对我来说更加一致。
如果您不想这样做,可以使用全局布尔值并将其设置为onBeforeShow()
,这样下次运行时就不会通过测试。像这样:
onAfterRendering()