Przeglądaj źródła

重构js公共工具,修改试评详情弹出框实现代码

luoshi 6 lat temu
rodzic
commit
9f29be1333

+ 1 - 2
stmms-web/src/main/webapp/WEB-INF/views/include/head.jsp

@@ -33,7 +33,6 @@
 <link href="${ctxStatic}/jquery-jbox/2.3/Skins/Bootstrap/jbox.css" rel="stylesheet" />
 <script src="${ctxStatic}/jquery-jbox/2.3/jquery.jBox-2.3.min.js" type="text/javascript"></script>
 <script src="${ctxStatic}/jquery-jbox/2.3/i18n/jquery.jBox-zh-CN.min.js" type="text/javascript"></script>
-<script src="${ctxStatic}/utils/easy-canvas.js" type="text/javascript"></script>
-<script src="${ctxStatic}/utils/image-loader.js" type="text/javascript"></script>
+<script src="${ctxStatic}/utils/image-utils.js" type="text/javascript"></script>
 
 <link rel="shortcut icon" href="${ctxStatic}/favicon.ico">

+ 14 - 20
stmms-web/src/main/webapp/WEB-INF/views/include/trialDetail.jsp

@@ -5,7 +5,6 @@
 <div id="trial-detail-content" class="container-fluid" style="display:none">
 <div class="row-fluid">
     <div id="trial-left-div" class="span7" style="overflow-y:scroll">
-        <canvas id="trial-canvas"></canvas>
     </div>
     <div id="trial-right-div" class="span5">
         <table id="contentTable" class="table table-striped table-bordered table-condensed">
@@ -25,8 +24,7 @@
 </div>
 
 <script type="text/javascript">
-var trailDetailModal = new jBox('Modal', {isolateScroll: false});
-var trialCanvas = new EasyCanvas({canvas: document.getElementById('trial-canvas')});
+var trialDetailModal = new jBox('Modal', {isolateScroll: false});
 
 $(document).ready(function() {
     $('#trial-left-div').height($(window).height()*0.83);
@@ -34,15 +32,15 @@ $(document).ready(function() {
 
 function initTrialDetailPopover(title, libraryId) {
 	initTrialDetailContent(libraryId); 
-	trailDetailModal.setWidth($(window).width()*0.9);
-	trailDetailModal.setHeight($(window).height()*0.85);
-	trailDetailModal.setTitle(title);
-	trailDetailModal.open();
+	trialDetailModal.setWidth($(window).width()*0.9);
+	trialDetailModal.setHeight($(window).height()*0.85);
+	trialDetailModal.setTitle(title);
+	trialDetailModal.open();
 }
 
 function initTrialDetailContent(libraryId){
 	$('#trial-history').empty();
-	trialCanvas.clear();
+	$('#trial-left-div').empty();
 	$.ajax({
         type:"GET",
         url:'${ctx}/admin/exam/trial/detail?libraryId='+libraryId,  
@@ -54,20 +52,16 @@ function initTrialDetailContent(libraryId){
 	                $('#trial-history').append('<tr><td>'+history.loginName+'</td><td>'+history.name+'</td><td>'+history.score+'</td><td>'+history.time+'</td></tr>');
 	            }
 	            new ImageLoader( {
-	                server: data.imageServer,
-	                urls: data.urls,
-	                config: data.pictureConfig,
-	                onError: function(error){
-	                    trailDetailModal.setTitle('加载失败');
-	                },
-	                onSuccess: function(images){
-	                    trailDetailModal.setContent($('#trial-detail-content'));
-	                    trialCanvas.changeBoxSize($('#trial-left-div').width()*0.95);
-	                    trialCanvas.drawImages(images, data.pictureConfig);
-	                }
+	                server: data.imageServer
+	            }).merge(data.urls, data.pictureConfig, function(image){
+                    trialDetailModal.setContent($('#trial-detail-content'));
+                    $(image).width($('#trial-left-div').width()*0.95);
+                    $(image).appendTo('#trial-left-div');
+                }, function(error){
+	                trialDetailModal.setTitle('加载失败');
 	            });
 	        }else {
-	            trailDetailModal.setTitle('加载失败')
+	            trialDetailModal.setTitle('加载失败')
 	        }
         }
     });

+ 0 - 150
stmms-web/src/main/webapp/static/utils/easy-canvas.js

@@ -1,150 +0,0 @@
-/**
- * 针对画布的辅助工具类
- * 1. 灵活调整大小与视网膜屏幕下的高清显示
- * 2. 按照云阅卷的图片拼接规则绘制图片内容
- * 
- * @param {} option 
- */
-function EasyCanvas(option) {
-    this.canvas = option.canvas
-    this.context = this.canvas.getContext("2d")
-    this.ratio = this.getPixelRatio()
-
-    this.originSize = {
-        width: 0,
-        height: 0
-    }
-    this.styleSize = {
-        width: 0,
-        height: 0
-    }
-    this.boxSize = {}
-    this.fontConfig = {
-        name: option.fontName || 'Arial',
-        size: option.fontSize || 60,
-        color: option.fontColor || 'red'
-    }
-
-    if (option.boxWidth != undefined && boxWidth.boxWidth > 0) {
-        this.boxSize.width = option.boxWidth
-    } else if (option.boxHeight != undefined && option.boxHeight > 0) {
-        this.boxSize.height = option.boxHeight
-    }
-
-    this.onClick = option.onClick || (function() {})
-
-    let self = this
-    this.canvas.onclick = function(event) {
-        if (self.originSize.width > 0 && self.originSize.height > 0) {
-            self.onClick({
-                left: (event.offsetX - this.offsetLeft),
-                top: (event.offsetY - this.offsetTop)
-            })
-        }
-    }
-}
-
-EasyCanvas.prototype.changeBoxSize = function(width, height) {
-    if (width != undefined) {
-        this.boxSize.width = width
-        this.boxSize.height = undefined
-    } else if (height != undefined) {
-        this.boxSize.height = height
-        this.boxSize.width = undefined
-    }
-}
-
-EasyCanvas.prototype.getPixelRatio = function() {
-    let backingStore = this.context.backingStorePixelRatio ||
-        this.context.webkitBackingStorePixelRatio ||
-        this.context.mozBackingStorePixelRatio ||
-        this.context.msBackingStorePixelRatio ||
-        this.context.oBackingStorePixelRatio ||
-        this.context.backingStorePixelRatio || 1;
-    return (window.devicePixelRatio || 1) / backingStore;
-}
-
-EasyCanvas.prototype.clear = function() {
-    this.context.clearRect(0, 0, this.canvas.width, this.canvas.heigth)
-}
-
-EasyCanvas.prototype.reset = function(width, height) {
-    this.originSize.width = Math.max((width || 0), 0)
-    this.originSize.height = Math.max((height || 0), 0)
-    this.styleSize.width = this.originSize.width
-    this.styleSize.height = this.originSize.height
-
-    if (this.styleSize.width > 0 && this.styleSize.height > 0) {
-        if (this.boxSize.width != undefined) {
-            this.styleSize.width = Math.min(this.originSize.width, this.boxSize.width)
-            this.styleSize.height = this.styleSize.width * this.originSize.height / this.originSize.width
-        } else if (this.boxSize.height != undefined) {
-            this.styleSize.height = Math.min(this.originSize.height, this.boxSize.height)
-            this.styleSize.width = this.styleSize.height * this.originSize.width / this.originSize.height
-        }
-    }
-
-    this.canvas.width = this.styleSize.width * this.ratio
-    this.canvas.height = this.styleSize.height * this.ratio
-    this.canvas.style.width = this.styleSize.width + 'px'
-    this.canvas.style.height = this.styleSize.height + 'px'
-
-    this.clear()
-}
-
-EasyCanvas.prototype.drawImage = function(image) {
-    this.drawImages([image], undefined, 1.0)
-}
-
-EasyCanvas.prototype.drawImages = function(images, config, scale) {
-    scale = scale || 1.0
-    if (config == undefined || config.length == 0) {
-        //不指定拼接配置时,默认按顺序显示所有图片
-        config = []
-        for (let i = 0; i < images.length; i++) {
-            config.push({
-                i: i + 1,
-                x: 0,
-                y: 0,
-                w: 0,
-                h: 0
-            })
-        }
-    }
-    let maxWidth = 0;
-    let totalHeight = 0;
-    for (let i = 0; i < config.length; i++) {
-        //计算最大宽度与合计高度
-        if (config[i].w <= 0) {
-            config[i].w = images[config[i].i - 1].width;
-        }
-        if (config[i].h <= 0) {
-            config[i].h = images[config[i].i - 1].height;
-        }
-        maxWidth = Math.max(maxWidth, config[i].w * scale);
-        totalHeight += config[i].h * scale;
-    }
-    if (maxWidth > 0 && totalHeight > 0) {
-        //设置画布大小
-        this.reset(maxWidth, totalHeight)
-        //绘画到画布
-        scale = scale * this.styleSize.width / this.originSize.width
-        let height = 0;
-        for (let i = 0; i < config.length; i++) {
-            this.context.drawImage(images[config[i].i - 1], config[i].x, config[i].y, config[i].w, config[i].h, 0, height, config[i].w * scale * this.ratio, config[i].h * scale * this.ratio);
-            height += (config[i].h * scale * this.ratio);
-        }
-    } else {
-        this.reset()
-    }
-}
-
-EasyCanvas.prototype.drawText = function(text, left, top) {
-    this.context.font = this.fontConfig.size * this.ratio + 'px ' + this.fontConfig.name
-    this.context.fillStyle = this.fontConfig.color
-    this.context.fillText(text, left * this.ratio, top * this.ratio)
-}
-
-EasyCanvas.prototype.getImageData = function(format) {
-    return this.canvas.toDataUrl(format ? format : 'image/jpeg')
-}

+ 0 - 66
stmms-web/src/main/webapp/static/utils/image-loader.js

@@ -1,66 +0,0 @@
-/**
- * 针对云阅卷场景多图片并行加载的工具
- * 1. 支持指定服务器地址
- * 2. 支持按云阅卷图片拼接规则筛选实际需要加载的图片
- * 3. 支持指定是否强制刷新图片
- * 
- * @param {*} option 
- */
-function ImageLoader(option) {
-    this.server = option.server || ''
-    this.urls = option.urls || []
-    this.config = option.config || []
-    this.flush = option.flush === true
-    this.onSuccess = option.onSuccess || (function() {})
-    this.onError = option.onError || (function() {})
-    this.start()
-}
-
-ImageLoader.prototype.start = function() {
-    this.images = []
-    this.needCount = 0
-    this.successCount = 0
-    for (let i = 0; i < this.urls.length; i++) {
-        let image = new Image()
-        this.images.push(image)
-        if (this.needLoad(i + 1)) {
-            this.needCount++
-
-            image.parent = this
-            image.crossOrigin = ''
-            image.src = this.server + this.urls[i] + (this.flush ? ('?' + new Date().getTime()) : '')
-            image.onload = function() {
-                this.parent.successCount++
-                if (this.parent.successCount == this.parent.needCount) {
-                    this.parent.onFinish()
-                }
-            }
-            image.onerror = function() {
-                this.parent.onFinish(this.url + ' load error')
-            }
-        }
-    }
-}
-
-ImageLoader.prototype.onFinish = function(error) {
-    if (error) {
-        this.onError(error)
-    } else {
-        this.onSuccess(this.images)
-    }
-}
-
-ImageLoader.prototype.needLoad = function(number) {
-    if (this.config != undefined && this.config.length > 0) {
-        let find = false
-        for (let i = 0; i < this.config.length; i++) {
-            if (this.config[i].i == number) {
-                find = true
-                break
-            }
-        }
-        return find
-    } else {
-        return true
-    }
-}

+ 324 - 0
stmms-web/src/main/webapp/static/utils/image-utils.js

@@ -0,0 +1,324 @@
+/**
+ * 兼容高分辨率屏幕高像素比的情况
+ * 
+ * @param {*} context 
+ */
+function getPixelRatio(context) {
+    let backingStore = context.backingStorePixelRatio ||
+        context.webkitBackingStorePixelRatio ||
+        context.mozBackingStorePixelRatio ||
+        context.msBackingStorePixelRatio ||
+        context.oBackingStorePixelRatio ||
+        context.backingStorePixelRatio || 1
+    return (window.devicePixelRatio || 1) / backingStore
+}
+
+/**
+ * 使用指定画布,按照云阅卷拼接规则,将已加载好的图片拼接成新的图片对象
+ * 
+ * @param {canvas} canvas 
+ * @param {array} images 
+ * @param {array} config 
+ * @param {function} onSuccess 
+ * @param {function} onError 
+ */
+function mergeImages(canvas, images, config, onSuccess, onError) {
+    if (config == undefined || config.length == 0) {
+        //不指定拼接配置时,默认按顺序显示所有图片
+        config = []
+        for (let i = 0; i < images.length; i++) {
+            config.push({
+                i: i + 1,
+                x: 0,
+                y: 0,
+                w: 0,
+                h: 0
+            })
+        }
+    }
+    let maxWidth = 0
+    let totalHeight = 0
+    for (let i = 0; i < config.length; i++) {
+        //计算最大宽度与合计高度
+        if (config[i].w <= 0) {
+            config[i].w = images[config[i].i - 1].width
+        }
+        if (config[i].h <= 0) {
+            config[i].h = images[config[i].i - 1].height
+        }
+        maxWidth = Math.max(maxWidth, config[i].w)
+        totalHeight += config[i].h
+    }
+    let context = canvas.getContext("2d")
+    //获取设备像素比
+    //暂时只用原始尺寸,避免转换图片过大导致性能问题
+    //let ratio = getPixelRatio(context)
+    let ratio = 1
+    //设置画布大小
+    canvas.width = maxWidth * ratio
+    canvas.height = totalHeight * ratio
+    context.clearRect(0, 0, canvas.width, canvas.height)
+    context.fillStyle = "white";
+    context.fillRect(0, 0, canvas.width, canvas.height);
+    //绘画到画布
+    //高度位置与图片配置对应关系
+    let array = []
+    let top = 0
+    let height = 0
+    for (let i = 0; i < config.length; i++) {
+        context.drawImage(images[config[i].i - 1], config[i].x, config[i].y, config[i].w, config[i].h, 0, height, config[i].w * ratio, config[i].h * ratio)
+        height += config[i].h * ratio
+        top += config[i].h
+        array.push({
+            offsetY: top,
+            config: config[i]
+        })
+    }
+    let image = new Image()
+    if (onSuccess) {
+        image.onload = function() {
+            onSuccess(image)
+        }
+    }
+    if (onError) {
+        image.onerror = function() {
+            onError('image merge error')
+        }
+    }
+    image.config = array
+    // image.origin = {
+    //     width: maxWidth,
+    //     height: totalHeight
+    // }
+    image.src = canvas.toDataURL()
+    return image
+}
+
+/**
+ * 针对云阅卷场景多图片处理工具
+ * 1. 支持指定服务器地址与是否强制刷新
+ * 2. 支持按云阅卷规则筛选实际需要加载的图片
+ * 3. 支持动态使用画布,按云阅卷规则垂直拼接出新的图片
+ * 
+ * @param {*} option 
+ */
+function ImageLoader(option) {
+    option = option || {}
+    this.server = option.server || ''
+    this.flush = option.flush === true
+}
+
+ImageLoader.prototype.load = function(urls, config, onSuccess, onError) {
+    let promises = []
+    let images = []
+    for (let i = 0; i < urls.length; i++) {
+        let url = this.server + urls[i] + (this.flush ? ('?' + new Date().getTime()) : '')
+        let image = new Image()
+        images.push(image)
+        promises.push(new Promise((resolve, reject) => {
+            if (this.contain(i + 1, config)) {
+                image.onload = function() {
+                    resolve()
+                }
+                image.onerror = function() {
+                    reject(url + ' load error')
+                }
+                image.crossOrigin = ''
+                image.src = url
+            } else {
+                resolve()
+            }
+        }))
+    }
+
+    Promise.all(promises).then(() => {
+        onSuccess ? onSuccess(images) : (function() {})
+    }).catch(error => {
+        onError ? onError(error) : (function() {})
+    })
+}
+
+/**
+ * 判断指定序号的图片是否在拼接规则中存在,默认返回true
+ * 
+ * @param {number} number 
+ * @param {array} config 
+ */
+ImageLoader.prototype.contain = function(number, config) {
+    if (config != undefined && config.length > 0) {
+        let find = false
+        for (let i = 0; i < config.length; i++) {
+            if (config[i].i == number) {
+                find = true
+                break
+            }
+        }
+        return find
+    } else {
+        return true
+    }
+}
+
+ImageLoader.prototype.merge = function(urls, config, onSuccess, onError) {
+    if (this.canvas == undefined) {
+        this.canvas = document.createElement('canvas')
+    }
+    this.canvas.style = 'display:none'
+
+    let canvas = this.canvas
+    this.load(urls, config, function(images) {
+        mergeImages(canvas, images, config, onSuccess, onError)
+    }, onError)
+}
+
+/**
+ * 针对画布的辅助工具类
+ * 1. 灵活调整大小与视网膜屏幕下的高清显示
+ * 2. 按照云阅卷的图片拼接规则绘制图片内容
+ * 
+ * @param {} option 
+ */
+function EasyCanvas(option) {
+    this.canvas = option.canvas
+    this.context = this.canvas.getContext("2d")
+    this.ratio = getPixelRatio()
+
+    this.originSize = {
+        width: 0,
+        height: 0
+    }
+    this.styleSize = {
+        width: 0,
+        height: 0
+    }
+    this.boxSize = {}
+    this.changeBoxSize(option.boxWidth, this.boxHeight)
+
+    this.fontConfig = {
+        name: option.fontName || 'Arial',
+        size: option.fontSize || 60,
+        color: option.fontColor || 'red'
+    }
+    this.lineConfig = {
+        width: option.lineWidth || 3,
+        color: option.lineColor || 'red'
+    }
+
+    this.onClick = option.onClick || (function() {})
+
+    let self = this
+    this.canvas.onclick = function(event) {
+        if (self.originSize.width > 0 && self.originSize.height > 0) {
+            self.onClick({
+                left: event.offsetX,
+                top: event.offsetY
+            })
+        }
+    }
+}
+
+EasyCanvas.prototype.changeBoxSize = function(width, height) {
+    if (width != undefined) {
+        this.boxSize.width = width
+        this.boxSize.height = undefined
+    } else if (height != undefined) {
+        this.boxSize.height = height
+        this.boxSize.width = undefined
+    }
+}
+
+EasyCanvas.prototype.clear = function() {
+    this.context.clearRect(0, 0, this.canvas.width, this.canvas.heigth)
+}
+
+EasyCanvas.prototype.reset = function(width, height) {
+    this.originSize.width = Math.max((width || 0), 0)
+    this.originSize.height = Math.max((height || 0), 0)
+    this.styleSize.width = this.originSize.width
+    this.styleSize.height = this.originSize.height
+
+    if (this.styleSize.width > 0 && this.styleSize.height > 0) {
+        if (this.boxSize.width != undefined) {
+            this.styleSize.width = Math.min(this.originSize.width, this.boxSize.width)
+            this.styleSize.height = this.styleSize.width * this.originSize.height / this.originSize.width
+        } else if (this.boxSize.height != undefined) {
+            this.styleSize.height = Math.min(this.originSize.height, this.boxSize.height)
+            this.styleSize.width = this.styleSize.height * this.originSize.width / this.originSize.height
+        }
+    }
+
+    this.canvas.width = this.styleSize.width * this.ratio
+    this.canvas.height = this.styleSize.height * this.ratio
+    this.canvas.style.width = this.styleSize.width + 'px'
+    this.canvas.style.height = this.styleSize.height + 'px'
+
+    this.clear()
+}
+
+EasyCanvas.prototype.drawImage = function(image, scale) {
+    this.drawImages([image], undefined, scale)
+}
+
+EasyCanvas.prototype.drawImages = function(images, config, scale) {
+    scale = scale || 1.0
+    if (config == undefined || config.length == 0) {
+        //不指定拼接配置时,默认按顺序显示所有图片
+        config = []
+        for (let i = 0; i < images.length; i++) {
+            config.push({
+                i: i + 1,
+                x: 0,
+                y: 0,
+                w: 0,
+                h: 0
+            })
+        }
+    }
+    let maxWidth = 0;
+    let totalHeight = 0;
+    for (let i = 0; i < config.length; i++) {
+        //计算最大宽度与合计高度
+        if (config[i].w <= 0) {
+            config[i].w = images[config[i].i - 1].width;
+        }
+        if (config[i].h <= 0) {
+            config[i].h = images[config[i].i - 1].height;
+        }
+        maxWidth = Math.max(maxWidth, config[i].w * scale);
+        totalHeight += config[i].h * scale;
+    }
+    if (maxWidth > 0 && totalHeight > 0) {
+        //设置画布大小
+        this.reset(maxWidth, totalHeight)
+        //绘画到画布
+        scale = scale * this.styleSize.width / this.originSize.width
+        let height = 0;
+        for (let i = 0; i < config.length; i++) {
+            this.context.drawImage(images[config[i].i - 1], config[i].x, config[i].y, config[i].w, config[i].h, 0, height, config[i].w * scale * this.ratio, config[i].h * scale * this.ratio);
+            height += (config[i].h * scale * this.ratio);
+        }
+    } else {
+        this.reset()
+    }
+}
+
+EasyCanvas.prototype.drawText = function(text, left, top) {
+    this.context.font = this.fontConfig.size * this.ratio + 'px ' + this.fontConfig.name
+    this.context.fillStyle = this.fontConfig.color
+    this.context.fillText(text, left * this.ratio, top * this.ratio)
+}
+
+EasyCanvas.prototype.drawShape = function(trace) {
+    if (trace && trace.length > 0) {
+        this.context.lineWidth = this.lineConfig.width
+        this.context.strokeStyle = this.lineConfig.color
+
+        this.context.beginPath()
+        this.context.moveTo(trace[0].x, trace[0].y)
+        for (let i = 1; i < trace.length; i++) {
+            this.context.lineTo(trace[i].x, trace[i].y)
+            this.context.stroke()
+        }
+        this.context.closePath()
+    }
+}