本文提供一套完整的 JavaScript 解決方案,實現網頁中圖片元素的動態生成、滑鼠拖曳移動、縮放調整大小,並支援表單提交時將圖片位置與尺寸資料回傳伺服器。適用於甘特圖、排程器等視覺化編輯場景。
<script type="text/javascript">
var topPos, leftPos;
var srcElem, dragFlag, dir, operation, referX, halfWidth;
var UNIT = 30;
var aryItems, itemCount = 10, index, isInit, elemId, MAX_ITEM = 23;
function PageLoad() {
document.form1.onsubmit = OnSubmit;
aryItems = new Array(itemCount);
var tableRect = document.getElementById("TABLE").getClientRects()[0];
topPos = tableRect.top;
leftPos = tableRect.left;
// 從隱藏欄位恢復甘特圖資料
var ganttVal = document.getElementById("__Gantt").value;
if (ganttVal && ganttVal !== "") {
var records = ganttVal.split(";");
var len = records.length - 1;
for (index = 0; index < len; index++) {
var item = records[index].split(",");
var start = parseInt(item[0]), width = parseInt(item[1]);
elemId = "Item" + index;
aryItems[index] = elemId;
createTrack(elemId, topPos + UNIT * index, leftPos + UNIT * start, UNIT * width);
}
} else {
// 預設生成
for (index = 0; index < itemCount; index++) {
elemId = "Item" + index;
aryItems[index] = elemId;
createTrack(elemId, topPos + UNIT * index, leftPos + UNIT * index, UNIT);
}
}
dragFlag = false;
leftPos = document.getElementById(aryItems[0]).getClientRects()[0].left;
}
function createTrack(id, top, left, width) {
var img = document.createElement("IMG");
img.id = id;
img.src = "blue.gif";
document.body.appendChild(img);
var style = img.style;
style.position = "absolute";
style.top = top + "px";
style.left = left + "px";
img.width = width;
style.zIndex = 9;
}
</script>
function OnDrag() {
var elem = event.srcElement;
if (elem.tagName !== "IMG" && !dragFlag) {
if (elem.id === "BTnTrim") { /* OnTrim(); */ }
return;
}
if (!dragFlag) {
srcElem = elem;
halfWidth = srcElem.width / 2;
dragFlag = true;
// 判斷縮放方向:點擊左半部為向後縮放,右半部為向前縮放
if (event.clientX < srcElem.getClientRects()[0].left + halfWidth) {
dir = "Backward";
referX = srcElem.getClientRects()[0].left + srcElem.width;
} else {
dir = "Forward";
referX = srcElem.getClientRects()[0].left;
}
// 判斷操作模式:Shift 鍵按下為移動,否則為縮放
if (event.shiftKey) {
operation = "Move";
referX = event.clientX - srcElem.getClientRects()[0].left;
} else {
operation = "Scale";
}
} else {
// 拖曳結束:套用最終位置/寬度並校正重疊
if (operation === "Scale") {
applyScale();
}
if (operation === "Move") {
applyMove();
}
dragFlag = false;
OnTrim();
}
}
function OnScale() {
if (!srcElem || !dragFlag) return;
if (operation === "Scale") {
if (dir === "Forward") {
var newW = event.clientX - referX;
if (newW >= UNIT) srcElem.width = newW;
} else {
var newL = event.clientX;
var newW = referX - srcElem.getClientRects()[0].left;
if (newW > UNIT) {
srcElem.style.left = newL + "px";
srcElem.width = newW;
}
}
} else if (operation === "Move") {
srcElem.style.left = Math.ceil((srcElem.getClientRects()[0].left - leftPos) / UNIT - 1) * UNIT + leftPos + "px";
}
// 滑鼠游標樣式切換
var target = event.srcElement;
if (target && target.tagName === "IMG") {
var rect = target.getClientRects()[0];
target.style.cursor = (event.clientX < rect.left + UNIT / 2) ? "w-resize" : "e-resize";
}
}
function OnTrim() {
// 修正相鄰項目間隙
for (var i = 0; i < itemCount - 1; i++) {
var pre = document.getElementById(aryItems[i]);
var nxt = document.getElementById(aryItems[i + 1]);
if (pre.getClientRects()[0].left + pre.width !== nxt.getClientRects()[0].left) {
nxt.style.left = (pre.getClientRects()[0].left + pre.width - 2) + "px";
}
}
// 限制最大範圍
var maxLeft = leftPos + UNIT * MAX_ITEM;
for (var i = 0; i < itemCount; i++) {
var elem = document.getElementById(aryItems[i]);
var rect = elem.getClientRects()[0];
if (rect.left >= maxLeft) {
elem.style.left = (maxLeft - 2) + "px";
elem.width = UNIT;
} else if (rect.left < maxLeft && rect.left + elem.width > maxLeft) {
elem.width = maxLeft - rect.left;
}
}
}
function OnSubmit() {
var dataStr = "";
for (var i = 0; i < itemCount; i++) {
var elem = document.getElementById(aryItems[i]);
var rect = elem.getClientRects()[0];
var start = (rect.left - leftPos) / UNIT;
var width = elem.width / UNIT;
dataStr += start + "," + width + ";";
}
document.getElementById("__Gantt").value = dataStr;
}
document.onmousedown = OnDrag;
document.onmousemove = OnScale;
</script>
<%-- ASP.NET (VB) 範例 --%>
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Response.Write(Request.Params("__Gantt") & "<br>")
Dim strGantt As String = Request.Params("__Gantt")
ClientScript.RegisterHiddenField("__Gantt", strGantt)
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
ClientScript.RegisterHiddenField("__Gantt", String.Empty)
End If
End Sub
伺服器端可直接讀取 __Gantt 隱藏欄位,解析後存入資料庫或進一步處理。