곰믹스 채점 기준 수정버전
This commit is contained in:
Binary file not shown.
@@ -181,8 +181,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"videoStartTime": 170,
|
|
||||||
"openingStartTime": 0,
|
|
||||||
"1": {
|
"1": {
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[not(@Length<='5' and @ClipLength='-1')]/@ClipIndex",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[not(@Length<='5' and @ClipLength='-1')]/@ClipIndex",
|
||||||
"type": "mediaOrder",
|
"type": "mediaOrder",
|
||||||
@@ -378,63 +376,60 @@
|
|||||||
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
},
|
},
|
||||||
"22": {
|
"22": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr/@Name",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@Name",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']/@Name",
|
|
||||||
"type": "opening",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
|
"type": "video.Text",
|
||||||
"value": "전통 공원 (Traditional Park)",
|
"value": "전통 공원 (Traditional Park)",
|
||||||
"point": 3
|
"point": 3
|
||||||
},
|
},
|
||||||
"23": {
|
"23": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "opening",
|
"type": "video.Text",
|
||||||
"value": "궁서체",
|
"value": "궁서체",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"24": {
|
"24": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "opening",
|
"type": "video.Text",
|
||||||
"value": "140",
|
"value": "140",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"25": {
|
"25": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "opening",
|
"type": "video.Text.Color",
|
||||||
"value": "-14592003",
|
"value": "fd5721",
|
||||||
"point": 2
|
"point": 2,
|
||||||
|
"desc": "컬러값은 RGB로 입력한다, [대소문자, #]허용 (#FFFFFF, ffffff 두 값 모두 허용)"
|
||||||
},
|
},
|
||||||
"26": {
|
"26": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='2']/@*[name()='VID100' or name()='VID101']",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='2']",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']//GCUnitPool/GCUnit[@Type='2']/@*[name()='VID100' or name()='VID101']",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "opening",
|
"type": "video.Text.Outline",
|
||||||
"value": [
|
"value": {
|
||||||
"0.30000001",
|
"width": "30",
|
||||||
"-3868161"
|
"color": "fff9c4"
|
||||||
],
|
},
|
||||||
"point": 2
|
"point": 2,
|
||||||
|
"desc": "두께는 XML에서는 소수점으로 표기되지만, 프로그램 내부적으로 변환하여 사용하므로 현재 파일에서는 정수로 작성"
|
||||||
},
|
},
|
||||||
"27": {
|
"27": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr/@*[name()='VID505' or name()='VID507']",
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr",
|
||||||
"ele2": "//CRCUnitArr[@Name='{search}']/@*[name()='VID505' or name()='VID507']",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "opening",
|
"type": "opening.Text.FadeInEffect",
|
||||||
"value": [
|
"value": {
|
||||||
"4",
|
"ID": "4",
|
||||||
"2"
|
"PlayTime": "2"
|
||||||
],
|
},
|
||||||
"point": 3
|
"point": 3,
|
||||||
|
"desc": "오프닝자막의 나타나기 효과를 확인하는 문항. id속성은 VID505, playtime속성은 VID507으로 XML 내부에 표기되어 있다."
|
||||||
},
|
},
|
||||||
"28": {
|
"28": {
|
||||||
"ele": "{search}",
|
"ele": "{search}",
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "openingStartTime",
|
"type": "opening.StartTime",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"point": 2,
|
"point": 2,
|
||||||
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
||||||
@@ -442,21 +437,34 @@
|
|||||||
"29": {
|
"29": {
|
||||||
"ele": "{search}",
|
"ele": "{search}",
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "openingLength",
|
"type": "opening.Length",
|
||||||
"value": 120,
|
"value": 120,
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"30": {
|
"30": {
|
||||||
"ele": "//CRTrackList[@Name='오디오1'][@Count>='1']/CRTrackClip[1][not(@ClipIndex='-1')]",
|
"ele": "",
|
||||||
|
"type": "audio.StartTime",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": 0,
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"31": {
|
"31": {
|
||||||
"ele": "//CRTrackArr/CRAudioTrackArr/CRTrackList[@Name='오디오1']/CRTrackClip[@Length='810']",
|
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
||||||
|
"type": "audio.EndTime",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": 810,
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"32": {
|
"32": {
|
||||||
"ele": "//CRTrackArr/CRAudioTrackArr/CRTrackList[@Name='오디오1']//CRFilter[@Type='2'][@ID='1'][@VID8='90']",
|
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
"point": 2
|
"type": "audio.Effect",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": {
|
||||||
|
"ID": "1",
|
||||||
|
"PlayTime": "90"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "ID속성-페이드인[0]/페이드아웃[1]"
|
||||||
},
|
},
|
||||||
"33": {
|
"33": {
|
||||||
"ele": "none",
|
"ele": "none",
|
||||||
|
|||||||
362
psdExport_2.js
362
psdExport_2.js
@@ -182,7 +182,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
tolerance = 0, // 숫자 비교 시 허용 오차
|
tolerance = 0, // 숫자 비교 시 허용 오차
|
||||||
type = 'auto', // 'auto' | 'number[]' | 'string[]' | 'object' | 'primitive'
|
type = 'auto', // 'auto' | 'number[]' | 'string[]' | 'object' | 'primitive'
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
if (type === 'force-correct') {
|
if (type === 'force-correct') {
|
||||||
isEqual = true;
|
isEqual = true;
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
} else if (type === 'object' || (type === 'auto' && typeof right === 'object' && typeof user === 'object')) {
|
} else if (type === 'object' || (type === 'auto' && typeof right === 'object' && typeof user === 'object')) {
|
||||||
isEqual = JSON.stringify(user) === JSON.stringify(right);
|
isEqual = JSON.stringify(user) === JSON.stringify(right);
|
||||||
} else {
|
} else {
|
||||||
isEqual = user == right; // primitive 비교
|
isEqual = user == right; // primitive 비교
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,12 +238,15 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
const scoringData = scoringJson[index];
|
const scoringData = scoringJson[index];
|
||||||
// console.log(scoringData);
|
// console.log(scoringData);
|
||||||
|
|
||||||
|
// 동영상 시작시간, 오프닝 시작시간 상수값 저장
|
||||||
|
const videoStartTime = scoringData['10'].value;
|
||||||
|
const openingStartTime = scoringData['28'].value;
|
||||||
|
|
||||||
let totalScore = 0;
|
let totalScore = 0;
|
||||||
|
|
||||||
// 채점기준표 문항별 분류
|
// 채점기준표 문항별 분류
|
||||||
for (const key in scoringData) {
|
for (const key in scoringData) {
|
||||||
function getClipIndexByMediaPath(mediaName) {
|
function getCRClipIndex(mediaName) {
|
||||||
// CRClipArr/CRClip 요소의 Path속성 리스트를 구함
|
// CRClipArr/CRClip 요소의 Path속성 리스트를 구함
|
||||||
// 모션 클립 이미지도 고려해 처리
|
// 모션 클립 이미지도 고려해 처리
|
||||||
const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc);
|
const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc);
|
||||||
@@ -297,7 +300,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
// 자막의 인덱스를 구함
|
// 자막의 인덱스를 구함
|
||||||
function getCilpIndexByStartTime(startTime) {
|
function getCilpIndexByStartTime(startTime) {
|
||||||
const crTrackClips = xpath.select("//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip", gmepXmlDoc);
|
const crTrackClips = xpath.select("//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip", gmepXmlDoc);
|
||||||
const subtitleStartTimeList = getSubtitleStartTime();
|
const subtitleStartTimeList = getStartTimeList('텍스트');
|
||||||
const startTimeIndex = subtitleStartTimeList.findIndex(value => value === startTime);
|
const startTimeIndex = subtitleStartTimeList.findIndex(value => value === startTime);
|
||||||
|
|
||||||
let subtitleClipIndex = null;
|
let subtitleClipIndex = null;
|
||||||
@@ -316,8 +319,15 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 영상내 존재하는 자막과 자막사이 공백의 시작시간 리스트를 구함
|
// 영상내 존재하는 자막과 자막사이 공백의 시작시간 리스트를 구함
|
||||||
function getSubtitleStartTime() {
|
function getStartTimeList(type) {
|
||||||
const trackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc);
|
let trackClips = null;
|
||||||
|
|
||||||
|
if (type === '텍스트') {
|
||||||
|
trackClips = xpath.select(`//CRTrackList[@Name='${type}' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc);
|
||||||
|
}
|
||||||
|
else if (type === '비디오1' || type === '오디오1') {
|
||||||
|
trackClips = xpath.select(`//CRTrackList[@Name='${type}']/CRTrackClip`, gmepXmlDoc);
|
||||||
|
}
|
||||||
|
|
||||||
let cumulativeLengths = [];
|
let cumulativeLengths = [];
|
||||||
let total = 0;
|
let total = 0;
|
||||||
@@ -333,29 +343,30 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
return cumulativeLengths;
|
return cumulativeLengths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextTrackClipIndex(clipIndex) {
|
function getCRTrackClipIndex(crclipIndex, type) {
|
||||||
const crTrackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc);
|
let xpathQuery;
|
||||||
|
if (type === '텍스트') {
|
||||||
|
xpathQuery = `//CRTrackList[@Name='${type}' or @Name='비디오2']/CRTrackClip`;
|
||||||
|
}
|
||||||
|
else if (type === '비디오1' || type === '오디오1') {
|
||||||
|
xpathQuery = `//CRTrackList[@Name='${type}']/CRTrackClip`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(`Unknown type: ${type}`);
|
||||||
|
}
|
||||||
|
|
||||||
let index = null;
|
const crTrackClips = xpath.select(xpathQuery, gmepXmlDoc);
|
||||||
for (let i = 0; crTrackClips.length; i++) {
|
|
||||||
if (clipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) {
|
let index = -1;
|
||||||
|
// crTrackClips에서 ClipIndex가 crclipIndex와 일치하는 요소의 인덱스를 찾음
|
||||||
|
// 처음 발견하는 요소의 인덱스를 반환
|
||||||
|
for (let i = 0; i < crTrackClips.length; i++) {
|
||||||
|
if (crclipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getVideoTrackClipIndex(clipIndex) {
|
|
||||||
const crTrackClips = xpath.select(`//CRTrackList[@Name='비디오1']/CRTrackClip`, gmepXmlDoc);
|
|
||||||
|
|
||||||
let index = null;
|
|
||||||
for (let i = 0; crTrackClips.length; i++) {
|
|
||||||
if (clipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,8 +380,9 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
let search = scoringData[key].search;
|
let search = scoringData[key].search;
|
||||||
const media = scoringData[key].media;
|
const media = scoringData[key].media;
|
||||||
|
|
||||||
const videoStartTime = scoringData.videoStartTime;
|
// const videoStartTime = scoringData.videoStartTime;
|
||||||
const openingStartTime = scoringData.openingStartTime;
|
// const openingStartTime = scoringData.openingStartTime;
|
||||||
|
|
||||||
const image = scoringData[key].image;
|
const image = scoringData[key].image;
|
||||||
|
|
||||||
let userAnswer = null;
|
let userAnswer = null;
|
||||||
@@ -474,7 +486,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (type == "startEnd") {
|
else if (type == "startEnd") {
|
||||||
const crclipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getCRClipIndex(media);
|
||||||
// 해당 미디어가 없을경우 clipIndex값 -1
|
// 해당 미디어가 없을경우 clipIndex값 -1
|
||||||
if (crclipIndex == -1) {
|
if (crclipIndex == -1) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
@@ -499,7 +511,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
// 동영상 클립 이펙트 [2-4]
|
// 동영상 클립 이펙트 [2-4]
|
||||||
// 이미지 클립 오버레이 [2-14, 17, 20]
|
// 이미지 클립 오버레이 [2-14, 17, 20]
|
||||||
else if (type == "effect" || type === "imageOverlay") {
|
else if (type == "effect" || type === "imageOverlay") {
|
||||||
const crclipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getCRClipIndex(media);
|
||||||
// 해당 미디어가 없을경우 clipIndex값 -1
|
// 해당 미디어가 없을경우 clipIndex값 -1
|
||||||
if (crclipIndex == -1) {
|
if (crclipIndex == -1) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
@@ -510,6 +522,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
const crFilter = xpath.select1(xpathExpr, gmepXmlDoc);
|
const crFilter = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
if (!crFilter) {
|
if (!crFilter) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
userAnswer = {}
|
userAnswer = {}
|
||||||
@@ -529,8 +542,8 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
|
|
||||||
// 동영상 클립 트랜지션 [2-15, 18, 21]
|
// 동영상 클립 트랜지션 [2-15, 18, 21]
|
||||||
else if (type === 'clipTransition') {
|
else if (type === 'clipTransition') {
|
||||||
const crclipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getCRClipIndex(media);
|
||||||
let crtrackClipIndex = getVideoTrackClipIndex(crclipIndex);
|
let crtrackClipIndex = getCRTrackClipIndex(crclipIndex, "비디오1");
|
||||||
|
|
||||||
if (crtrackClipIndex == -1) {
|
if (crtrackClipIndex == -1) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
@@ -603,11 +616,10 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('🟥🟧🟨🟩🟦🟪⬛')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == "Mute") {
|
else if (type == "Mute") {
|
||||||
const crclipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getCRClipIndex(media);
|
||||||
if (crclipIndex == -1) {
|
if (crclipIndex == -1) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
@@ -620,7 +632,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
// 이미지 클립 길이 [2-13, 16, 19]
|
// 이미지 클립 길이 [2-13, 16, 19]
|
||||||
else if (type === 'imageLength') {
|
else if (type === 'imageLength') {
|
||||||
const crclipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getCRClipIndex(media);
|
||||||
if (crclipIndex == -1) {
|
if (crclipIndex == -1) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
@@ -632,6 +644,45 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (type.includes('audio')) {
|
||||||
|
const crclipIndex = getCRClipIndex(media);
|
||||||
|
const crtrackClipIndex = getCRTrackClipIndex(crclipIndex, "오디오1")
|
||||||
|
const startTimeList = getStartTimeList('오디오1');
|
||||||
|
|
||||||
|
if (type.includes('StartTime')) {
|
||||||
|
const startTime = startTimeList[crtrackClipIndex];
|
||||||
|
userAnswer = startTime;
|
||||||
|
}
|
||||||
|
else if (type.includes('EndTime')) {
|
||||||
|
const xpathQuery = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
|
const crTrackClip = xpath.select1(xpathQuery, gmepXmlDoc);
|
||||||
|
if (!crTrackClip) {
|
||||||
|
userAnswer = null;
|
||||||
|
} else {
|
||||||
|
const length = parseInt(crTrackClip.getAttribute('Length'), 10);
|
||||||
|
userAnswer = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type.includes('Effect')) {
|
||||||
|
const xpathQuery = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
|
const fadeoutEffect = xpath.select1(xpathQuery, gmepXmlDoc);
|
||||||
|
if (!fadeoutEffect) {
|
||||||
|
userAnswer = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const attributes = fadeoutEffect.attributes;
|
||||||
|
const id = attributes.getNamedItem('ID').value;
|
||||||
|
const playtime = attributes.getNamedItem('VID8').value;
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
"ID": id,
|
||||||
|
"PlayTime": playtime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
}
|
||||||
|
|
||||||
else if (type.includes('opening') || type.includes('video')) {
|
else if (type.includes('opening') || type.includes('video')) {
|
||||||
// 자막의 정보를 이용해 CROwneUnit의 인덱스를 구함
|
// 자막의 정보를 이용해 CROwneUnit의 인덱스를 구함
|
||||||
// 1. 텍스트
|
// 1. 텍스트
|
||||||
@@ -652,8 +703,8 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
// <CRTrackClip> 요소들의 시작시간을 갖고 있는 startTimeList를 구하고
|
// <CRTrackClip> 요소들의 시작시간을 갖고 있는 startTimeList를 구하고
|
||||||
// 해당 인덱스의 자막 시작시간을 구함
|
// 해당 인덱스의 자막 시작시간을 구함
|
||||||
if (type.includes('StartTime')) {
|
if (type.includes('StartTime')) {
|
||||||
const crtrackClipIndex = getTextTrackClipIndex(index)
|
const crtrackClipIndex = getCRTrackClipIndex(index, "텍스트")
|
||||||
const startTimeList = getSubtitleStartTime();
|
const startTimeList = getStartTimeList('텍스트');
|
||||||
const startTime = startTimeList[crtrackClipIndex];
|
const startTime = startTimeList[crtrackClipIndex];
|
||||||
|
|
||||||
userAnswer = startTime;
|
userAnswer = startTime;
|
||||||
@@ -662,14 +713,14 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
// 자막 길이 [2-11] [2-29]
|
// 자막 길이 [2-11] [2-29]
|
||||||
// <CRTrackClip> 요소의 Length 속성을 구함
|
// <CRTrackClip> 요소의 Length 속성을 구함
|
||||||
else if (type.includes('Length')) {
|
else if (type.includes('Length')) {
|
||||||
const crtrackClipIndex = getTextTrackClipIndex(index) + 1 // XML 1-based index
|
const crtrackClipIndex = getCRTrackClipIndex(index, "텍스트") + 1 // XML 1-based index
|
||||||
const clipLength = xpath.select1(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[${crtrackClipIndex}]/@Length`, gmepXmlDoc);
|
const clipLength = xpath.select1(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[${crtrackClipIndex}]/@Length`, gmepXmlDoc);
|
||||||
|
|
||||||
userAnswer = parseInt(clipLength.value, 10);
|
userAnswer = parseInt(clipLength.value, 10);
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
// 자막 텍스트(글자, 폰트, 크기, 색상) [2-5, 6, 7, 8] [2-22, 23, 24, 25]
|
// 자막 텍스트(글자, 폰트, 크기, 색상) [2-5, 6, 7, 8] [2-22, 23, 24, 25]
|
||||||
else if (type.includes('Text') || type.includes('Color')) {
|
else if (type.includes('Text')) {
|
||||||
const xmlIndex = index + 1 // XML 1-based index
|
const xmlIndex = index + 1 // XML 1-based index
|
||||||
const subtitleXpath = ele?.replace(/{index}/g, xmlIndex);
|
const subtitleXpath = ele?.replace(/{index}/g, xmlIndex);
|
||||||
const subtitleResult = xpath.select1(subtitleXpath, gmepXmlDoc);
|
const subtitleResult = xpath.select1(subtitleXpath, gmepXmlDoc);
|
||||||
@@ -679,10 +730,31 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
const hex = convertColorToHex(subtitleResult.value);
|
const hex = convertColorToHex(subtitleResult.value);
|
||||||
userAnswer = hex;
|
userAnswer = hex;
|
||||||
}
|
}
|
||||||
|
else if (type.includes('Outline')) {
|
||||||
|
const attributes = subtitleResult.attributes;
|
||||||
|
const width = Math.round(parseFloat(attributes.getNamedItem('VID100').value * 100)).toString();
|
||||||
|
const color = convertColorToHex(attributes.getNamedItem('VID101').value);
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
"width": width,
|
||||||
|
"color": color,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (type.includes('FadeInEffect')) {
|
||||||
|
const attributes = subtitleResult.attributes;
|
||||||
|
const id = attributes.getNamedItem('VID505').value;
|
||||||
|
const playtime = attributes.getNamedItem('VID507').value;
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
"ID": id,
|
||||||
|
"PlayTime": playtime,
|
||||||
|
};
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
userAnswer = subtitleResult.value;
|
userAnswer = subtitleResult.value;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,6 +771,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
userAnswer = subtitleResult.map(r => r.value);
|
userAnswer = subtitleResult.map(r => r.value);
|
||||||
const errorRange = 0.1;
|
const errorRange = 0.1;
|
||||||
|
|
||||||
|
// userAnswer가 정수형 배열인 경우 type을 'number[]'로 설정
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
tolerance: errorRange,
|
tolerance: errorRange,
|
||||||
type: 'number[]',
|
type: 'number[]',
|
||||||
@@ -710,222 +783,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == "color") {
|
|
||||||
const result = xpath.select(ele, gmepXmlDoc);
|
|
||||||
|
|
||||||
if (result.length == 0) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`value: ${rightAnswer} result: ${result[0].value}`);
|
|
||||||
// value와 result[0].value를 비교하여 같으면 점수 point 부여
|
|
||||||
totalScore += result.length > 0 && rightAnswer === result[0].value ? point : 0;
|
|
||||||
scoringResult[key] = result.length > 0 && rightAnswer === result[0].value ? point : 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (type == "multi") {
|
|
||||||
try {
|
|
||||||
const result = xpath.select(ele, gmepXmlDoc);
|
|
||||||
let isSame = true;
|
|
||||||
// console.log(`ele: ${ele}, value: ${value} result: ${result}`);
|
|
||||||
|
|
||||||
if (result.length == 0) {
|
|
||||||
console.log('result length 0');
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.forEach((v, i) => {
|
|
||||||
// value[i] 값이 정수형인 경우에는 float로 변환하여 비교
|
|
||||||
// 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림
|
|
||||||
let temp = v.value;
|
|
||||||
let answer = rightAnswer[i];
|
|
||||||
|
|
||||||
if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) {
|
|
||||||
temp = parseFloat(v.value);
|
|
||||||
answer = parseFloat(rightAnswer[i]);
|
|
||||||
// 소수점 3자리까지 버림
|
|
||||||
temp = Math.floor(temp * 1000) / 1000;
|
|
||||||
}
|
|
||||||
// answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함
|
|
||||||
if (typeof answer == "string" && answer.indexOf(':') > -1) {
|
|
||||||
const [answerStart, answerEnd] = answer.split(':').map(Number);
|
|
||||||
const [tempStart, tempEnd] = temp.split(':').map(Number);
|
|
||||||
answer = answerEnd - answerStart;
|
|
||||||
temp = tempEnd - tempStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`temp: ${temp} answer: ${answer}`);
|
|
||||||
if (answer !== temp) {
|
|
||||||
console.log(`answer !== temp`);
|
|
||||||
isSame = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
totalScore += isSame ? point : 0;
|
|
||||||
scoringResult[key] = isSame ? point : 0;
|
|
||||||
} catch (e) {
|
|
||||||
console.log('err :', e);
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "searchIndex") {
|
|
||||||
// let existEle = scoringData[key].existEle;
|
|
||||||
// XPath를 사용하여 ELE 요소가 존재하는지 확인
|
|
||||||
const crcUnitArrNode = xpath.select1(existEle, gmepXmlDoc);
|
|
||||||
|
|
||||||
if (crcUnitArrNode) {
|
|
||||||
// ELE 요소가 몇번째 요소인지 찾고 필요한 요소 확인
|
|
||||||
const unitOrderNode = xpath.select1(ele, gmepXmlDoc);
|
|
||||||
console.log(`unitOrderNode: ${unitOrderNode}`);
|
|
||||||
if (unitOrderNode === undefined) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (unitOrderNode.value === rightAnswer) {
|
|
||||||
console.log(`unit: ${unitOrderNode.value} === ${rightAnswer}`);
|
|
||||||
scoringResult[key] = point;
|
|
||||||
totalScore += point;
|
|
||||||
}
|
|
||||||
else if (unitOrderNode === rightAnswer) {
|
|
||||||
console.log(`unitValue: ${unitOrderNode} === ${rightAnswer}`);
|
|
||||||
scoringResult[key] = point;
|
|
||||||
totalScore += point;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(`not found. ${existEle} `);
|
|
||||||
let result;
|
|
||||||
|
|
||||||
if (ele2 !== undefined) {
|
|
||||||
result = xpath.select1(ele2, gmepXmlDoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == rightAnswer) {
|
|
||||||
totalScore += point;
|
|
||||||
scoringResult[key] = point;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 문제의 타입이 video(동영상자막) 또는 opening(오프닝자막)일 경우
|
|
||||||
else if (type == "video" || type == "opening") {
|
|
||||||
|
|
||||||
// 찾으려는 자막이 존재하지 않는 경우
|
|
||||||
// (2-28) 문항의 경우 오프닝 자막이 없어도 xpath구문의 sum함수 결과값이 0이 반환되는것을 방지
|
|
||||||
if (trackClipNode === undefined && textClipIndex === null) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const result = ele ? xpath.select(ele, gmepXmlDoc) : [];
|
|
||||||
const result2 = ele2 ? xpath.select(ele2, gmepXmlDoc) : [];
|
|
||||||
const result3 = ele3 ? xpath.select(ele3, gmepXmlDoc) : [];
|
|
||||||
|
|
||||||
// 결과값이 배열이 아닌 경우 배열로 변환
|
|
||||||
// 예시) (2-9)는 xpath를 통해 클립(자막) 시작시간(number숫자자료형)을 반환받으므로 배열로 변환하여 비교
|
|
||||||
const resultValues = Array.isArray(result) ?
|
|
||||||
result.map(r => (typeof r === 'object' ? r.value : r)) : [result];
|
|
||||||
const resultValues2 = Array.isArray(result2) ?
|
|
||||||
result2.map(r => (typeof r === 'object' ? r.value : r)) : [result2];
|
|
||||||
const resultValues3 = Array.isArray(result3) ?
|
|
||||||
result3.map(r => (typeof r === 'object' ? r.value : r)) : [result3];
|
|
||||||
|
|
||||||
// 결과값들을 하나의 배열로 합침
|
|
||||||
const allResults = [...[resultValues], ...[resultValues2], ...[resultValues3]];
|
|
||||||
// console.log("🚀 ~ allResults:", allResults)
|
|
||||||
|
|
||||||
// 정답(rightAnswer)의 값이 단일값이 아닐 경우 값 비교를 위해 배열로 변환
|
|
||||||
// 예시) (2-11) 자막의 위치 좌표값 비교를 위해 [x, y] 값을 가져오므로 배열로 변환하여 비교
|
|
||||||
const rightAnswerArray = Array.isArray(rightAnswer) ? rightAnswer : [rightAnswer];
|
|
||||||
|
|
||||||
// 결과값이 범위값인 경우 소수점 3자리까지 비교
|
|
||||||
const formattedResults = allResults.map(result => {
|
|
||||||
// result의 길이가 1이상인 조건은 result값이 [x, y](좌표값, 두개 이상의 값)인 경우를 말한다
|
|
||||||
if (Array.isArray(result) && result.length > 1) {
|
|
||||||
return result.map(r => {
|
|
||||||
// xml파일에 저장된 곰믹스 좌표값이 소수점 3자리 아래 버리는 형식이므로
|
|
||||||
// 동일하게 결과값 소수점 3자리 아래 버린 후 반환
|
|
||||||
const parsedValue = parseFloat(r);
|
|
||||||
if (parsedValue >= 0 && parsedValue < 1) {
|
|
||||||
// 소수점 3자리 아래 버림
|
|
||||||
return (Math.floor(parsedValue * 1000) / 1000).toFixed(3);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
console.log("🚀 ~ formattedResults:", formattedResults)
|
|
||||||
|
|
||||||
// 배열 비교 함수
|
|
||||||
function arraysEqual(arr1, arr2) {
|
|
||||||
if (arr1.length !== arr2.length) return false;
|
|
||||||
if (arr2.length === 1) {
|
|
||||||
for (let i = 0; i < arr1.length; i++) {
|
|
||||||
if (arr1[i] !== arr2[i]) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (arr2.length > 1) {
|
|
||||||
for (let i = 0; i < arr1.length; i++) {
|
|
||||||
// 좌표값 범위 비교
|
|
||||||
const errorRange = 0.1;
|
|
||||||
if (Math.abs(arr1[i] - arr2[i]) > errorRange) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// allResults에 rightAnswerArray와 일치하는 배열이 있는지 확인
|
|
||||||
const isIncluded = formattedResults.some(arr => arraysEqual(arr, rightAnswerArray));
|
|
||||||
|
|
||||||
if (isIncluded) {
|
|
||||||
console.log("🚀 ~ getGmepScore ~ 정답:", rightAnswerArray);
|
|
||||||
totalScore += point;
|
|
||||||
scoringResult[key] = point;
|
|
||||||
} else {
|
|
||||||
console.log("🚀 ~ getGmepScore ~ 오답:", rightAnswerArray);
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
console.log('Unknown type:', ele);
|
|
||||||
let result = ele ? xpath.select(ele, gmepXmlDoc) : null;
|
|
||||||
let result2 = null;
|
|
||||||
let isCheck = false;
|
|
||||||
|
|
||||||
if (!result || result.length === 0) {
|
|
||||||
isCheck = true;
|
|
||||||
}
|
|
||||||
if (isCheck && ele2) {
|
|
||||||
result2 = ele2 ? xpath.select(ele2, gmepXmlDoc) : null;
|
|
||||||
|
|
||||||
if (!result2 || result2.length == 0) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result = result2;
|
|
||||||
// console.log(`1st isChecked: ${isCheck}, result: ${result}`)
|
|
||||||
}
|
|
||||||
// value와 result[0].value를 비교하여 같으면 점수 point 부여
|
|
||||||
// console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `)
|
|
||||||
// console.log(`2nd isChecked: ${isCheck}, result: ${result}`)
|
|
||||||
totalScore += result?.length > 0 ? point : 0;
|
|
||||||
scoringResult[key] = result?.length > 0 ? point : 0;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error processing XPath query for ele: ${ele}`, error);
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scoringResult['총점'] = totalScore;
|
scoringResult['총점'] = totalScore;
|
||||||
return scoringResult;
|
return scoringResult;
|
||||||
|
|||||||
Reference in New Issue
Block a user