0

我使用单个 kendoChart 来显示多达 10 行数据。

每条线代表可能具有广泛不同的上下文和最小/最大范围的过程数据,但所有线都在时间上相关,即 categoryAxis。显示时,每个 valueAxis 正确显示相应行的比例。

但是,对于 10 行,10 个 valueAxes 占用了太多屏幕,无法满足我的要求。

我尝试隐藏除一个之外的所有轴,并期望图表会扩展以填充隐藏轴占用的空间,但这并没有发生。我得到一个被空白包围的孤轴,并且图表的绘图区域保持相同的大小。

我尝试将所有系列设置为使用相同的 valueAxis,然后通过单击图例项来改变每个活动通道的 valueAxis 最小值/最大值。这会根据需要扩展绘图区域,但由于比例特定于一条线,因此无法查看所有线。

kendoChart 是否可以独立于单个 valueAxis 显示多个图(例如,值在 0.5 和 0.7 之间的线会显示为整个图表区域,值在 25 和 100 之间的线也会显示,但 valueAxis 可能会显示任何规模。)

4

1 回答 1

0

我用于这个问题的解决方案比我预期的需要更多的代码。也许 Telerik 的其他产品为此提供了 API。

本质上,我在 kendoChart 之外维护了一个结构,用于存储每个系列的真实数据,并将这些真实数据映射到当前可见 valueAxis 的预期比例。映射函数是从一种尺度到另一种尺度的标准变换。

valueAxis 根据单击的图例项“交换”,并且该事件触发图表上的重绘,其中所有系列数据都映射到“活动”轴。

一些代码片段。一个系列也被描述为一个频道。

// The data structure.
this._channelDescriptors.push({
    fullName: ch.fullName || "",
    axisTitle: (ch.fullName + axisEUString) || "",
    axisFont: ch.axisFont || "",
    axisColor: ch.color || "#000000",
    realData: [],
    minData: Number.MAX_VALUE,
    maxData: Number.MIN_VALUE
});

// This event causes the switching of valueAxis for all members of the series.
$("#" + chartID).kendoChart({
    // Other kendoChart configurations
    //
    legendItemClick: function (e) {
        var idx = e.seriesIndex;
        sncTrender.updateAxis(idx);
        e.preventDefault();
    },
    tooltip: {
        visible: true,
        template: "#=series.name# : #=kendo.format('{0:N4}', dataItem.realValue)#<br />#=kendo.format('{0:MM-dd HH:mm:ss.fff}', dataItem.Time)#",
    },
    //
    // Other kendoChart configurations
});

// All code snippets are members of a wrapper object.
updateAxis: function (ch) {
    if (this.series[ch].visible) {
        this.setAxis(ch);
    }
},

// Every series is set to the same valueAxis via the selected series' valueAxis.name property.
setAxis: function (ch) {
    var i,
        channel = this._channelDescriptors[ch];
    this._currentChannel = ch;
    for (i = 0; i < this.series.length; i++) {
        this.series[i].axis = this._channelDescriptors[ch].fullName;
    }
    // Set the active valueAxis properties. This is the only axis visible maintained for the chart.
    this.valueAxis.name = channel.fullName;
    this.valueAxis.title.text = channel.axisTitle;
    this.valueAxis.title.font = channel.axisFont;
    this.valueAxis.line.color = channel.axisColor;
},

// The mapping occurs here, and the transform calculation is this line
//    Y: (yRange * (chDesc.realData[k].realValue - newMin) / newRange) + this.valueAxis.min,
//
updateChart: function (allTrends) {
    // ...
    timeStamps = trendDataResponse.curve.Timestamp;
    t1 = trendArgs.t1;
    t2 = trendArgs.t2;
    xValues = trendDataResponse.curve.X;
    yValues = trendDataResponse.curve.Y;
    pointCount = xValues.length;
    min = Number.MAX_VALUE;
    max = Number.MIN_VALUE;
    categoryTimes = [pointCount];
    newData = [];
    for (l = 0; l < pointCount; l++) {
        min = Math.min(min, yValues[l]);
        max = Math.max(max, yValues[l]);
        ts = new Date(timeStamps[l]);
        categoryTimes[l] = ts;
        // The Y data will be plotted on the chart, but the cursor tooltip will
        // use the realValue data. In this way, the series can be visible regardless of
        // the valueAxis scaling, but the actual data is also available. Refer to the
        // tooltip template.
        newData.push({ X: xValues[l], Y: yValues[l], realValue: yValues[l], Time: ts });
    }

    // Real data for each channel is stored in channelDescriptors.
    chDesc = this._channelDescriptors[channelID];
    chDesc.realData = newData;
    chDesc.minData = min;
    chDesc.maxData = max;

    // The valueAxis min/max is set only for the 'active' series.
    if (this._currentChannel === channelID) {
        this.categoryAxis.categories = categoryTimes;
        yRange = max - min;
        scaleAdjustment = yRange * SNC.CONST_yAxisScaleAdjustmentFactor;
        this.valueAxis.min = min - scaleAdjustment;
        this.valueAxis.max = max + scaleAdjustment;
    }
    }
    // Scale curves to current axis.
    // Use real data for the current series.
    for (j = 0; j < this.series.length; ++j) {
    chDesc = this._channelDescriptors[j];
    if (j === this._currentChannel) {
        this.series[j].data = chDesc.realData;
        continue;
    }

    // Use mapped data for all other series.
    recalcData = [];
    newMin = chDesc.minData;
    newMax = chDesc.maxData;
    newRange = newMax - newMin;
    rangeAdjustment = newRange * SNC.CONST_yAxisScaleAdjustmentFactor;
    newMin = newMin - rangeAdjustment;
    newMax = newMax + rangeAdjustment;
    for (k = 0; k < chDesc.realData.length; ++k) {
        recalcData.push({
            X: chDesc.realData[k].X,
            Y: (yRange * (chDesc.realData[k].realValue - newMin) / newRange) + this.valueAxis.min,
            realValue: chDesc.realData[k].realValue,
            Time: chDesc.realData[k].Time,
        });
    }
    this.series[j].data = recalcData;
    }
    chart.redraw();
}
于 2016-06-03T13:36:46.760 回答