提交 f492e3a3 编写于 作者: M mindspore-ci-bot 提交者: Gitee

!510 UI add comments to step trace, data process and profiling dashboard

Merge pull request !510 from 黄伟锋/myMaster
......@@ -302,9 +302,10 @@ export default {
props: {},
data() {
return {
dir: '',
currentCard: '',
dir: '', // Profiler path
currentCard: '', // Purrent card number
connectQueueChart: {
// Ponnect queue chart object
id: 'connect-queue',
chartDom: null,
data: [],
......@@ -317,6 +318,7 @@ export default {
initOver: false,
},
dataQueueChart: {
// Data queue chart object
id: 'data-queue',
chartDom: null,
data: [],
......@@ -329,6 +331,7 @@ export default {
initOver: false,
},
deviceQueueOpChart: {
// Device queue chart object
id: 'device_queue_op',
chartDom: null,
data: [],
......@@ -339,6 +342,7 @@ export default {
initOver: false,
},
getNextChart: {
// Get next chart object
id: 'get_next',
chartDom: null,
data: [],
......@@ -349,6 +353,7 @@ export default {
initOver: false,
},
processSummary: {
// Process summary object
noData: true,
count: 6,
maxCount: 6,
......@@ -365,17 +370,19 @@ export default {
},
activeName: 'queueInfo',
averageRateChart: {
// Average rate chart object
id: 'average-rate',
chartDom: null,
},
queueDeepChart: {
// Queue deep chart object
id: 'queue-deep',
chartDom: null,
},
current_op: {},
parent_op: {},
pipeData: true,
initOver: false,
initOver: false, // Identify whether the interface returns
allGraphData: {},
graphviz: null,
totalMemory: 16777216 * 2, // Memory size of the graph plug-in
......@@ -427,6 +434,9 @@ export default {
}, 500);
},
methods: {
/**
* Tabs switch
*/
handleClick() {
if (this.activeName === 'pipeLine') {
if (!Object.keys(this.allGraphData).length) {
......@@ -440,6 +450,9 @@ export default {
init() {
this.queryProcessSummary();
},
/**
* Resize callback function
*/
resizeCallback() {
const chartArr = [
'connectQueueChart',
......@@ -457,6 +470,10 @@ export default {
}
});
},
/**
* Query minddata data
* @param {Object} chart Chart object
*/
queryMinddataOp(chart) {
const params = {
profile: this.dir,
......@@ -502,6 +519,10 @@ export default {
},
);
},
/**
* Query queue info
* @param {Object} chart Chart object
*/
queryQueueInfo(chart) {
const params = {
profile: this.dir,
......@@ -523,7 +544,7 @@ export default {
chart.initOver = true;
chart.size = result.size;
this.$nextTick(() => {
this.setOption(chart, result.size);
this.setOption(chart);
});
} else {
if (chart.chartDom) {
......@@ -543,7 +564,11 @@ export default {
},
);
},
setOption(chart, size) {
/**
* Chart set option
* @param {Object} chart Chart object
*/
setOption(chart) {
const myChart = echarts.init(document.getElementById(chart.id));
const option = {
title: {
......@@ -618,6 +643,9 @@ export default {
]);
}
},
/**
* Query process summary info
*/
queryProcessSummary() {
const params = {
profile: this.dir,
......@@ -656,6 +684,10 @@ export default {
},
);
},
/**
* Deal process data
* @param {Object} data Process data
*/
dealProcess(data) {
this.processSummary.device = {
empty: 0,
......@@ -687,6 +719,9 @@ export default {
this.processSummary.noData = false;
}
},
/**
* Query average rate info
*/
queryAverageRate() {
const params = {
params: {
......@@ -820,6 +855,10 @@ export default {
},
);
},
/**
* Query queue info
* @param {Number} id Op id
*/
queryQueue(id) {
const params = {
profile: this.dir,
......
......@@ -16,6 +16,7 @@ limitations under the License.
<template>
<div class="pro-router-wrap">
<div class="pro-router-left">
<!-- Timeline display area -->
<div class="step-trace">
<div class="title-wrap">
<div class="title">{{ $t('profiling.stepTrace') }}</div>
......@@ -25,6 +26,7 @@ limitations under the License.
:class="{disabled:svg.noData && svg.data.length === 0}">{{ $t('profiling.viewDetail') }}
<i class="el-icon-d-arrow-right"></i></button>
</div>
<!-- Timeline description -->
<div class="tip-icon">
<el-tooltip placement="bottom"
effect="light">
......@@ -50,14 +52,15 @@ limitations under the License.
<span>{{totalTime}}{{$t('profiling.millisecond')}}</span>
</div>
<div>{{$t('profiling.totalSteps')}}<span>{{totalSteps}}</span></div>
<div>{{$t('profiling.iterationGapTimeRatio')}}<span>{{iteration_interval_percent}}</span></div>
<div>{{$t('profiling.fpbpTimeRatio')}}<span>{{fp_and_bp_percent}}</span></div>
<div>{{$t('profiling.iterativeTailingTimeRatio')}}<span>{{tail_percent}}</span></div>
<div>{{$t('profiling.iterationGapTimeRatio')}}<span>{{iterationIntervalPercent}}</span></div>
<div>{{$t('profiling.fpbpTimeRatio')}}<span>{{fpBpPercent}}</span></div>
<div>{{$t('profiling.iterativeTailingTimeRatio')}}<span>{{tailPercent}}</span></div>
</div>
<i class="el-icon-info"></i>
</el-tooltip>
</div>
</div>
<!-- Timeline SVG container -->
<div class="trace-container">
<div id="trace"
class="training-trace"
......@@ -101,6 +104,7 @@ limitations under the License.
</div>
</div>
</div>
<!-- Process summary display area -->
<div class="minddata">
<div class="title-wrap">
<div class="title">{{ $t('profiling.mindData') }}</div>
......@@ -248,6 +252,7 @@ limitations under the License.
</div>
</div>
</div>
<!-- Operator information display area -->
<div class="pro-router-right">
<div class="op-time-consume">
<div class="title-wrap">
......@@ -272,6 +277,7 @@ limitations under the License.
<div id="pieChart"
class="pie-chart"
v-if="pieChart.data.length"></div>
<!-- Operator time consumption top5 -->
<div class="time-list"
v-if="pieChart.data.length">
<ul>
......@@ -292,6 +298,7 @@ limitations under the License.
</div>
</div>
</div>
<!-- Time line display area -->
<div class="time-line">
<div class="title-wrap">
<div class="title">{{ $t('profiling.timeLine') }}</div>
......@@ -325,6 +332,7 @@ limitations under the License.
</el-tooltip>
</div>
</div>
<!-- Time line detail -->
<div class="timeline-info"
v-if="!timelineInfo.noData">
<div class="info-line">
......@@ -360,37 +368,39 @@ import CommonProperty from '../../common/common-property';
export default {
data() {
return {
fp_and_bp_percent: '--',
iteration_interval_percent: '--',
totalSteps: '--',
totalTime: '--',
tail_percent: '--',
queueInfoShow: false,
deviceInfoShow: false,
queueInfoEmptyNum: '--',
queueInfoTotalNum: '--',
deviceInfoEmptyNum: '--',
deviceInfoTotalNum: '--',
deviceInfoFullNum: '--',
fpBpPercent: '--', // Ratio of time consumed by forward and backward propagation
iterationIntervalPercent: '--', // Ratio of time consumed by step interval
totalSteps: '--', // Total steps
totalTime: '--', // Total time
tailPercent: '--', // Ratio of time consumed by step tail
queueInfoShow: false, // Whether to show queue information
deviceInfoShow: false, // Whether to show device information
queueInfoEmptyNum: '--', // The number of empty queue information
queueInfoTotalNum: '--', // Total number of queues
deviceInfoEmptyNum: '--', // Number of empty device information
deviceInfoTotalNum: '--', // Total number of devices
deviceInfoFullNum: '--', // Number of full queues
svg: {
data: [],
svgPadding: 20,
totalWidth: 0,
totalTime: 0,
// Step trace svg information
data: [], // Data of svg
svgPadding: 20, // Padding of svg
totalWidth: 0, // Total width of svg
totalTime: 0, // Total time
cellHeight: 40,
cellPadding: 0,
rowPadding: 20,
rowMargin: 10,
totalHeight: 0,
markerPadding: 4,
minRate: 0.1,
minTime: 0,
minWidth: 1,
minRate: 0.1, // Minimum time share threshold of non wrapping display
minTime: 0, // Minimum time for non wrapping display
minWidth: 1, // Minimum width of graphics in SVG
fontSize: 12,
textMargin: 21,
namespaceURI: 'http://www.w3.org/2000/svg',
resizeTimer: null,
textMargin: 21, // The minimum margin of the text from the border
namespaceURI: 'http://www.w3.org/2000/svg', // XML namespace
resizeTimer: null, // Response delay of resize event
colors: {
// Colors of different types of data presentation
iteration_interval: ['#A6DD82', '#edf8e6'],
fp_and_bp: ['#6CBFFF', '#e2f2ff'],
tail: ['#fa8e5b', '#fff4de'],
......@@ -399,54 +409,60 @@ export default {
noData: true,
initOver: false,
},
trainingJobId: this.$route.query.id,
summaryPath: this.$route.query.dir,
relativePath: this.$route.query.path,
currentCard: '',
trainingJobId: this.$route.query.id, // Training job id
summaryPath: this.$route.query.dir, // Summary path data
relativePath: this.$route.query.path, // Relative path of summary log
currentCard: '', // Data of current card
pieChart: {
// Pie graph information of operators
chartDom: null,
data: [],
noData: true,
topN: [],
colorList: ['#6C92FA', '#6CBFFF', '#4EDED2', '#7ADFA0', '#A6DD82'],
initOver: false,
initOver: false, // Is initialization complete
},
timeLine: {
// Time line data
data: null,
waiting: true,
waiting: true, // Is it waiting for interface return
},
timelineInfo: {
// Time line information
totalTime: 0,
streamNum: 0,
opNum: 0,
opTimes: 0,
opNum: 0, // Number of operators
opTimes: 0, // Operator time consuming
noData: true,
initOver: false,
initOver: false, // Is initialization complete
},
processSummary: {
// Data of process summary
noData: true,
count: 6,
maxCount: 6,
device: {
empty: 0,
full: 0,
total: 0,
empty: 0, // Number of empty devices
full: 0, // Number of full devices
total: 0, // Total number of devices
},
get_next: {
empty: 0,
full: 0,
total: 0,
},
initOver: false,
initOver: false, // Is initialization complete
},
};
},
mounted() {
// Collapse the left column to respond to events
setTimeout(() => {
this.$bus.$on('collapse', this.resizeTrace);
}, 500);
},
watch: {
// Monitor current card information
'$parent.curDashboardInfo': {
handler(newValue, oldValue) {
if (newValue.curCardNum === '') {
......@@ -483,6 +499,9 @@ export default {
},
},
methods: {
/**
* Initialization function
*/
init() {
this.queryTimeline();
this.queryTrainingTrace();
......@@ -490,6 +509,9 @@ export default {
this.initPieChart();
window.addEventListener('resize', this.resizeTrace, false);
},
/**
* Get the data of proccess summary
*/
getProccessSummary() {
const params = {
train_id: this.trainingJobId,
......@@ -651,6 +673,9 @@ export default {
this.pieChart.initOver = true;
});
},
/**
* Get the data of training trace
*/
queryTrainingTrace() {
const params = {
dir: this.relativePath,
......@@ -674,19 +699,20 @@ export default {
);
});
// Set the display information in tip
if (res.data.summary) {
this.fp_and_bp_percent = res.data.summary.fp_and_bp_percent;
this.iteration_interval_percent =
this.fpBpPercent = res.data.summary.fp_and_bp_percent;
this.iterationIntervalPercent =
res.data.summary.iteration_interval_percent;
this.totalSteps = res.data.summary.total_steps;
this.totalTime = res.data.summary.total_time;
this.tail_percent = res.data.summary.tail_percent;
this.tailPercent = res.data.summary.tail_percent;
} else {
this.fp_and_bp_percent = '--';
this.iteration_interval_percent = '--';
this.fpBpPercent = '--';
this.iterationIntervalPercent = '--';
this.totalSteps = '--';
this.totalTime = '--';
this.tail_percent = '--';
this.tailPercent = '--';
}
} else {
this.svg.totalHeight = 0;
......@@ -704,7 +730,10 @@ export default {
},
);
},
/**
* Encapsulating the data of training trace
* @param {Object} traceGraph Data of training trace
*/
packageTraceData(traceGraph) {
this.svg.totalTime = 0;
this.svg.minTime = 0;
......@@ -715,6 +744,8 @@ export default {
this.svg.totalTime = traceGraph[0][0].duration;
this.svg.minTime = this.svg.minRate * this.svg.totalTime;
// If there is data less than the minimum time in each row,
// the data in each row is divided into several rows
traceGraph.forEach((row, index) => {
const rowObj = {
rowCount: 0,
......@@ -759,7 +790,9 @@ export default {
});
}
},
/**
* Processing the data of training trace, Control data generation svg
*/
dealTraceData() {
const traceDom = document.querySelector('#trace');
if (traceDom) {
......@@ -783,7 +816,11 @@ export default {
}
}
},
/**
* Generate a container with multiple rows
* @param {Object} item Multi row data
* @return {Object} Generated DOM object
*/
createMultipleRowContainer(item) {
const rectContainer = document.createElementNS(
this.svg.namespaceURI,
......@@ -806,7 +843,12 @@ export default {
rectContainer.appendChild(temp);
return rectContainer;
},
/**
* DOM for generating a single SVG image
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of box
* @return {Object}
*/
createRowContainer(data, startY) {
const g = document.createElementNS(this.svg.namespaceURI, 'g');
......@@ -830,22 +872,28 @@ export default {
});
return g;
},
/**
* Create a box DOM from the data
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of box
* @return {Object}
*/
createRect(data, startY) {
const color =
data.name && this.svg.colors[data.name]
? this.svg.colors[data.name]
: this.svg.colors.stream_parallel;
// Start x position of box
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
// The width of the box
const width = Math.max(
this.svg.minWidth,
(data.duration / this.svg.totalTime) * this.svg.totalWidth,
);
// Contents of the box
let name = '';
switch (data.name) {
case 'iteration_interval':
......@@ -911,7 +959,12 @@ export default {
g.appendChild(title);
return g;
},
/**
* Create a arrow DOM from the data
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of arrow
* @return {Object}
*/
createArrow(data, startY) {
const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth;
const x1 =
......@@ -945,6 +998,7 @@ export default {
const textWidth = text.textContent
? this.getTextWidth(text.textContent)
: 0;
// The position of the text cannot go beyond the border of the SVG
text.setAttribute(
'x',
Math.min(
......@@ -978,6 +1032,11 @@ export default {
g.appendChild(text);
return g;
},
/**
* Gets the width of a string
* @param {String} text
* @return {Number}
*/
getTextWidth(text) {
const body = document.querySelector('body');
const temp = document.createElement('span');
......@@ -988,6 +1047,9 @@ export default {
body.removeChild(temp);
return textWidth;
},
/**
* Remove SVG DOM from page
*/
removeTrace() {
const svgDom = document.querySelector('#trace svg');
if (svgDom) {
......@@ -1001,6 +1063,9 @@ export default {
}
}
},
/**
* Respond to the reset event and update the page display
*/
resizeTrace() {
if (this.svg.resizeTimer) {
clearTimeout(this.svg.resizeTimer);
......@@ -1011,6 +1076,11 @@ export default {
this.svg.resizeTimer = null;
}, 500);
},
/**
* Converts a string to data in uint8array format
* @param {String} str The string to be converted
* @return {Array}
*/
stringToUint8Array(str) {
const arr = [];
for (let i = 0, strLen = str.length; i < strLen; i++) {
......@@ -1018,6 +1088,9 @@ export default {
}
return new Uint8Array(arr);
},
/**
* Query the data of time line
*/
queryTimeline() {
this.timeLine.waiting = true;
const params = {
......@@ -1055,6 +1128,9 @@ export default {
})
.catch(() => {});
},
/**
* Download Perfetto data file
*/
downloadPerfetto() {
const downloadLink = document.createElement('a');
downloadLink.download = this.getDocName();
......@@ -1065,6 +1141,10 @@ export default {
downloadLink.click();
document.body.removeChild(downloadLink);
},
/**
* Set the data of process
* @param {Object} data The data of process
*/
dealProcess(data) {
this.processSummary.device = {
empty: 0,
......@@ -1096,6 +1176,10 @@ export default {
this.processSummary.noData = false;
}
},
/**
* Generate a download file name
* @return {String}
*/
getDocName() {
const dealNumber = (value) => {
const prefix = value < 10 ? '0' : '';
......
......@@ -71,9 +71,10 @@ export default {
'minddata_warning_op',
],
moreParameter: ['minddata_device_queue', 'minddata_get_next_queue'],
CardNumArr: [],
CardNumArr: [], // Card list
collapse: false,
curDashboardInfo: {
// Current Select card info
curCardNum: '',
query: {},
},
......@@ -86,6 +87,9 @@ export default {
});
},
methods: {
/**
* Init function
*/
init() {
if (this.$route.query && this.$route.query.id && this.$route.query.dir) {
this.curDashboardInfo.query.id = this.$route.query.id;
......@@ -99,11 +103,17 @@ export default {
this.$message.error(this.$t('trainingDashboard.invalidId'));
}
},
/**
* When card mumber changed,request data again.
*/
selectValueChange() {
const helperDiv = document.getElementById('helper-tips');
helperDiv.innerHTML = '';
this.getDataOfProfileHelper();
},
/**
* Get card number list
*/
getDeviceList() {
const params = {
profile: this.curDashboardInfo.query.dir,
......@@ -129,7 +139,9 @@ export default {
})
.catch(() => {});
},
/**
* Get profile helper data
*/
getDataOfProfileHelper() {
const params = {
train_id: this.curDashboardInfo.query.id,
......@@ -267,6 +279,9 @@ export default {
})
.catch(() => {});
},
/**
* Router back to profiling-dashboard
*/
backToDdashboard() {
this.$router.push({
path: '/profiling/profiling-dashboard',
......@@ -318,7 +333,7 @@ export default {
.cur-card {
margin-bottom: 32px;
.card-select {
width: calc(100% - 70px);
width: calc(100% - 120px);
}
& > label {
margin-right: 14px;
......
......@@ -140,38 +140,41 @@ import RequestService from '../../services/request-service';
export default {
data() {
return {
dir: this.$route.query.dir,
train_id: this.$route.query.id,
relativePath: this.$route.query.path,
fp_start: '--',
bp_end: '--',
dir: this.$route.query.dir, // Summary path data
train_id: this.$route.query.id, // Training job id
relativePath: this.$route.query.path, // Relative path of summary log
fp_start: '--', // FP start operator
bp_end: '--', // BP termination operator
steps: {
step: null,
trueStep: null,
max: 0,
// Information of training steps
step: null, // Step value of page presentation
trueStep: null, // True step value
max: 0, // Maximum value of step
disabled: true,
label: this.$t('profiling.stepInputTip'),
},
charts: [],
svg: {
data: [],
svgPadding: 20,
totalWidth: 0,
totalTime: 0,
// Step trace svg information
data: [], // Data of svg
svgPadding: 20, // Padding of svg
totalWidth: 0, // Total width of svg
totalTime: 0, // Total time
cellHeight: 40,
cellPadding: 0,
rowPadding: 20,
rowMargin: 10,
totalHeight: 0,
markerPadding: 4,
minRate: 0.1,
minTime: 0,
minWidth: 1,
minRate: 0.1, // Minimum time share threshold of non wrapping display
minTime: 0, // Minimum time for non wrapping display
minWidth: 1, // Minimum width of graphics in SVG
fontSize: 12,
textMargin: 21,
namespaceURI: 'http://www.w3.org/2000/svg',
resizeTimer: null,
textMargin: 21, // The minimum margin of the text from the border
namespaceURI: 'http://www.w3.org/2000/svg', // XML namespace
resizeTimer: null, // Response delay of resize event
colors: {
// Colors of different types of data presentation
iteration_interval: ['#A6DD82', '#edf8e6'],
fp_and_bp: ['#6CBFFF', '#e2f2ff'],
tail: ['#fa8e5b', '#fff4de'],
......@@ -183,6 +186,7 @@ export default {
deviceId: 0,
radio: this.$t('profiling.lterationGap'),
tabsArr: [
// Detailed chart of data in step trace
{
name: this.$t('profiling.lterationGap'),
id: 'iter-gap',
......@@ -220,6 +224,7 @@ export default {
};
},
watch: {
// Monitor current card information
'$parent.curDashboardInfo': {
handler(newValue, oldValue) {
if (newValue.curCardNum || newValue.curCardNum === 0) {
......@@ -254,6 +259,7 @@ export default {
},
computed: {},
mounted() {
// Collapse the left column to respond to events
setTimeout(() => {
this.$bus.$on('collapse', () => {
this.resizeTrace();
......@@ -262,6 +268,9 @@ export default {
}, 500);
},
methods: {
/**
* Initialization function
*/
init() {
window.addEventListener('resize', this.resizeTrace, false);
window.addEventListener('resize', this.resizeEchart, false);
......@@ -283,6 +292,10 @@ export default {
this.getTimeInfo('tailing', 'tail');
this.queryTrainingTrace(0);
},
/**
* Change the current step value
* @param {Number} value The current step value
*/
changeStep(value) {
if (value === 0 || (!this.steps.step && this.steps.step !== 0)) {
this.steps.step = null;
......@@ -301,11 +314,19 @@ export default {
);
}
},
/**
* Reset the current step value
*/
resetStep() {
setTimeout(() => {
this.steps.step = this.steps.trueStep;
}, 200);
},
/**
* Get different types of time information
* @param {String} id Dom id
* @param {String} type Types of time information
*/
getTimeInfo(id, type) {
const params = {
dir: this.relativePath,
......@@ -416,6 +437,11 @@ export default {
},
);
},
/**
* Initialization chart
* @param {Object} option Chart options
* @param {String} id Dom id
*/
initChart(option, id) {
this.$nextTick(() => {
const chart = echarts.init(document.getElementById(id));
......@@ -423,6 +449,9 @@ export default {
this.charts.push(chart);
});
},
/**
* Resize chart
*/
resizeEchart() {
setTimeout(() => {
this.charts.forEach((val) => {
......@@ -430,6 +459,10 @@ export default {
});
}, 300);
},
/**
* Get training trace information
* @param {Number} step Current step value
*/
queryTrainingTrace(step) {
const params = {
dir: this.relativePath,
......@@ -482,6 +515,10 @@ export default {
},
);
},
/**
* Encapsulating the data of training trace
* @param {Object} traceGraph Data of training trace
*/
packageTraceData(traceGraph) {
this.svg.totalTime = 0;
this.svg.minTime = 0;
......@@ -492,6 +529,8 @@ export default {
this.svg.totalTime = traceGraph[0][0].duration;
this.svg.minTime = this.svg.minRate * this.svg.totalTime;
// If there is data less than the minimum time in each row,
// the data in each row is divided into several rows
traceGraph.forEach((row, index) => {
const rowObj = {
rowCount: 0,
......@@ -537,6 +576,9 @@ export default {
}
},
/**
* Processing the data of training trace, Control data generation svg
*/
dealTraceData() {
const traceDom = document.querySelector('#trace');
if (traceDom) {
......@@ -561,6 +603,11 @@ export default {
}
},
/**
* Generate a container with multiple rows
* @param {Object} item Multi row data
* @return {Object} Generated DOM object
*/
createMultipleRowContainer(item) {
const rectContainer = document.createElementNS(
this.svg.namespaceURI,
......@@ -584,6 +631,12 @@ export default {
return rectContainer;
},
/**
* DOM for generating a single SVG image
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of box
* @return {Object}
*/
createRowContainer(data, startY) {
const g = document.createElementNS(this.svg.namespaceURI, 'g');
......@@ -608,21 +661,28 @@ export default {
return g;
},
/**
* Create a box DOM from the data
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of box
* @return {Object}
*/
createRect(data, startY) {
const color =
data.name && this.svg.colors[data.name]
? this.svg.colors[data.name]
: this.svg.colors.stream_parallel;
// Start x position of box
const x1 =
(data.start / this.svg.totalTime) * this.svg.totalWidth +
this.svg.svgPadding;
// The width of the box
const width = Math.max(
this.svg.minWidth,
(data.duration / this.svg.totalTime) * this.svg.totalWidth,
);
// Contents of the box
let name = '';
switch (data.name) {
case 'iteration_interval':
......@@ -689,6 +749,12 @@ export default {
return g;
},
/**
* Create a arrow DOM from the data
* @param {Object} data Data of single SVG image
* @param {Number} startY Start y position of arrow
* @return {Object}
*/
createArrow(data, startY) {
const width = (data.duration / this.svg.totalTime) * this.svg.totalWidth;
const x1 =
......@@ -722,6 +788,8 @@ export default {
const textWidth = text.textContent
? this.getTextWidth(text.textContent)
: 0;
// The position of the text cannot go beyond the border of the SVG
text.setAttribute(
'x',
Math.min(
......@@ -755,6 +823,11 @@ export default {
g.appendChild(text);
return g;
},
/**
* Gets the width of a string
* @param {String} text
* @return {Number}
*/
getTextWidth(text) {
const body = document.querySelector('body');
const temp = document.createElement('span');
......@@ -765,6 +838,9 @@ export default {
body.removeChild(temp);
return textWidth;
},
/**
* Remove SVG DOM from page
*/
removeTrace() {
const svgDom = document.querySelector('#trace svg');
if (svgDom) {
......@@ -778,6 +854,9 @@ export default {
}
}
},
/**
* Respond to the reset event and update the page display
*/
resizeTrace() {
if (this.svg.resizeTimer) {
clearTimeout(this.svg.resizeTimer);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册