동적 셰이프

다음 샘플에서는 SpreadJS 스프레드시트를 사용하여 JavaScript 응용 프로그램의 데이터를 기반으로 셰이프를 동적으로 생성하는 방법을 보여 줍니다. 데이터와 수식을 사용하여 사용자 정의 셰이프를 작성해 동적 셰이프와 셰이프 값을 만들 수 있습니다. 예를 들어 각 기계의 상태를 보여 주는 동적 제조 생산/공장 라인을 만들고, 사용 가능한 공간을 보여 주는 사무실 평면도를 작성하며, 서버실에 있는 각 서버의 상태를 보여 줄 수 있습니다.

이 샘플은 "Sheets2" 시트의 좌석 값(B열)을 기준으로 수식을 사용하여 "좌석" 셰이프의 색 속성이 할당된 비행기 좌석 배치도를 보여 줍니다.

이러한 기본 제공 셰이프와 함께 사용자 정의 셰이프도 만들 수 있습니다. 필요에 맞는 이 사용자 정의 셰이프를 만들 수 있습니다. 셀에 있는 데이터에 따라 동적으로 셰이프를 생성할 수 있습니다. 이제 동적으로 생성된 셰이프를 이용하여 대화형 좌석 예약 앱을 만들어보겠습니다.
var cmdMap = { moveTo: 'M', lineTo: 'L', bezierCurveTo: 'B', quadraticCurveTo: 'Q', arc: 'A', arcTo: 'AT', closePath: 'Z' }; var spread; var sheet; var sheetData; var selectedSeatsArray = []; // convert svg points to shape path function pointsToPath(points) { var ps = points.split(' '); var mx = 10000; // shift the shape to (0, 0) var my = 10000; ps = ps.map(function (p) { var t = p.split(','); if (parseFloat(t[0]) < mx) { mx = parseFloat(t[0]); } if (parseFloat(t[1]) < my) { my = parseFloat(t[1]); } return { x: parseFloat(t[0]), y: parseFloat(t[1]) }; }); var cmds = []; cmds.push(['M', ps[0].x - mx, ps[0].y - my]); for (var i = 1; i < ps.length; i++) { cmds.push(['L', ps[i].x - mx, ps[i].y - my]); } cmds.push(['Z']); return [cmds]; } // convert svg path to shape path function convertPath(d) { var cmds = parser.parse(d); var mx = 10000; // shift the shape to (0, 0) var my = 10000; var pathCommands = cmds.map(function (cmd) { for (var i = 0; i < cmd.args.length; i = i + 2) { if (cmd.args[i] < mx) { mx = cmd.args[i]; } if (cmd.args[i + 1] < my) { my = cmd.args[i + 1]; } } return [cmdMap[cmd.type]].concat(cmd.args); }); var ret = []; var t = []; for (var i = 0; i < pathCommands.length; i++) { var cmd = pathCommands[i]; for (var j = 1; j < cmd.length; j = j + 2) { cmd[j] = cmd[j] - mx; cmd[j + 1] = cmd[j + 1] - my; } t.push(cmd); if (cmd[0] == 'Z') { ret.push(t); t = []; } } return ret; } function convertStatus(seatStatus) { var ret = -1 //O: Open: green //1: Reserved: red //2: Upgrade: orange switch (seatStatus) { case 0: ret = "green"; break; case 1: ret = "red"; break; case 2: ret = "orange"; break; } return ret } function convertNumbertoLetter(ssCol) { var ret = "" switch (ssCol) { case 0: ret = "A"; break; case 1: ret = "B"; break; case 2: ret = "C"; break; case 3: ret = "D"; break; case 4: ret = "E"; break; case 5: ret = "F"; break; } return ret } var shapeFormula = "=CHOOSE(VLOOKUP(name,Sheet2!A1:B186,2,False)+1, \"green\", \"red\", \"orange\")"; function createShape(serverpathCommands, sleft, stop, swidth, sheight, shapename) { var servermodel = { name: shapename, left: sleft, top: stop, width: swidth, height: sheight, angle: 0, options: { fill: { type: GC.Spread.Sheets.Shapes.ShapeFillType.solid, color: shapeFormula }, stroke: { type: GC.Spread.Sheets.Shapes.ShapeFillType.solid, color: shapeFormula }, textFormatOptions: { allowTextToOverflowShape: false, wrapTextInShape: false, font: '="11px Arial"', fill: { type: GC.Spread.Sheets.Shapes.ShapeFillType.solid, color: 'black' } } }, path: serverpathCommands }; return servermodel; } function addData(sheet) { //O: Open: green //1: Reserved: red //2: Upgrade: orange sheet.setValue(2, 5, "Available Seats:") sheet.getCell(2, 7).backColor("green"); sheet.setValue(4, 5, "Reserved Seats:") sheet.getCell(4, 7).backColor("red"); sheet.setValue(6, 5, "Premium Seats") sheet.getCell(6, 7).backColor("orange"); sheet.setValue(11, 5, "You have Selected:"); sheet.addSpan(11, 5, 1, 3); sheet.options.protectionOptions.allowEditObjects = false; sheet.setColumnWidth(7, 20); sheet.options.colHeaderVisible = false; sheet.options.rowHeaderVisible = false; sheet.options.selectionBorderColor = "Transparent"; } window.onload = initFunction; function initFunction() { var constleft = 137.5; var consttop = 230; var aislespacer = 25; var rowspacer = 32.8; var shapewidth = 25; var shapeheight = 25; var shapeleft = constleft; var shapetop = consttop; var i; var j; var sheetDataRow = 0; //counter for Seats on Data sheet var sheetDataSeatRow = 2; //seat number counter for display - 2A, 2B, 3A, etc var seatNum = "" //seat number as shown on ticket- 2A, 2B, 3A, etc var selectedSeat = ""; spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 }); spread.setSheetCount(2); spread.suspendPaint(); spread.suspendCalcService(); sheet = spread.getSheet(0); sheet.setRowCount(100); sheetData = spread.getSheet(1); sheetData.setRowCount(200); sheet.setColumnWidth(0, 200); sheet.addSpan(0, 0, 80, 5); sheet.getCell(0, 0).backgroundImage("$DEMOROOT$/spread/source/images/airplane.png"); sheet.options.isProtected = true; sheet.options.gridline = { showVerticalGridline: false, showHorizontalGridline: false }; sheet.setColumnResizable(-1, true, GC.Spread.Sheets.SheetArea.colHeader); sheet.setRowResizable(-1, true, GC.Spread.Sheets.SheetArea.rowHeader); addData(sheet); var airseat1 = "M 151.917 691.735 h -14.676 c -0.039 0 -3.689 -0.066 -3.689 -4.245 l 0.004 -17.254 c 0.096 -0.683 0.735 -1.976 2.47 -1.976 c 1.552 0 2.339 0.682 2.339 2.029 v 14.269 c 0.153 0.357 1.246 2.427 5.952 2.427 c 5.117 0 6.417 -2.265 6.522 -2.473 V 670.29 c 0.031 -0.713 0.52 -2.029 2.149 -2.029 c 1.149 0 1.909 0.606 2.257 1.802 c 0.009 0.029 0.015 0.051 0.021 0.067 l -0.015 0.005 c 0.103 0.431 0.113 2.671 0.052 17.723 c 0.005 0.042 0.126 1.774 -0.934 2.918 C 153.781 691.412 152.956 691.735 151.917 691.735 Z M 134.324 670.321 v 17.169 c 0 3.4 2.802 3.473 2.921 3.474 h 14.672 c 0.814 0 1.45 -0.24 1.888 -0.713 c 0.832 -0.9 0.73 -2.352 0.729 -2.366 c 0.026 -6.665 0.05 -16.629 0.007 -17.496 c -0.012 -0.034 -0.022 -0.071 -0.034 -0.112 c -0.17 -0.581 -0.496 -1.247 -1.518 -1.247 c -1.308 0 -1.377 1.224 -1.379 1.275 l 0 14.253 c 0 0.65 -1.903 3.197 -7.293 3.197 c -5.646 0 -6.663 -2.882 -6.704 -3.005 l -0.02 -0.058 V 670.29 c 0 -0.44 0 -1.258 -1.568 -1.258 C 134.629 669.031 134.363 670.107 134.324 670.321 Z M 135.261 669.105 c -0.002 -0.047 -0.046 -1.17 0.788 -2.047 c 0.627 -0.657 1.56 -0.99 2.773 -0.99 l 12.006 0.005 c 0.969 0.16 2.8 0.996 2.8 3.014 h -0.771 c 0 -1.779 -1.86 -2.197 -2.126 -2.248 h -11.91 c -0.995 0 -1.74 0.252 -2.215 0.751 c -0.6 0.629 -0.577 1.469 -0.577 1.477 L 135.261 669.105 Z"; //Get the seat shape var s1commands = convertPath(airseat1); //Rows loop //USE 30 for (var r = 0; r <= 185; r++) { sheetData.setValue(r, 1, Math.floor(Math.random() * Math.floor(3))); } for (i = 0; i < 31; i++) { for (j = 0; j < 6; j++) { seatNum = sheetDataSeatRow + "" + convertNumbertoLetter(j) //airline Seat var s1shape = createShape(s1commands, shapeleft, shapetop, shapewidth, shapeheight, seatNum); //Add Name var ret2 = sheet.shapes.add(seatNum, s1shape); ret2.allowMove(false); ret2.allowResize(false); ret2.dynamicMove(false); ret2.dynamicSize(false); ret2.isLocked(true); //Add the SeatNumber to first column sheetData.setValue(sheetDataRow, 0, seatNum); sheetDataRow = sheetDataRow + 1; if (j == 5) { sheetDataSeatRow = sheetDataSeatRow + 1; } //increment shapeleft = shapeleft + shapewidth; if (j == 2) { // D,E,F seats. Add aisle spacer shapeleft = shapeleft + aislespacer; } } //reset left and top to start new rows shapeleft = constleft; shapetop = shapetop + rowspacer; if (i == 12) { shapetop = shapetop + 10; } if (i == 13) { shapetop = shapetop + 10; } if (i == 22) { shapetop = shapetop - 3; } } spread.resumeCalcService(); spread.resumePaint(); //handle spread div click event for shapes document.getElementById("ss").addEventListener("click", function (e) { var sp = document.getElementById("ss"); var x = e.pageX - sp.offsetLeft; var y = e.pageY - sp.offsetTop; var target = spread.getActiveSheet().hitTest(x, y); if (target.shapeHitInfo == null && x > 700) { y = y - 300; target = spread.getActiveSheet().hitTest(x, y); } var preselectionseatval = ""; if (target.shapeHitInfo) { var shape = target.shapeHitInfo.shape; // var preselectionseatval = if (shape) { spread.suspendPaint(); if (selectedSeat == "") { var searchCondition = new GC.Spread.Sheets.Search.SearchCondition(); searchCondition.searchString = shape.name(); searchCondition.startSheetIndex = 1; searchCondition.endSheetIndex = 1; searchCondition.searchOrder = GC.Spread.Sheets.Search.SearchOrder.nOrder; searchCondition.searchTarget = GC.Spread.Sheets.Search.SearchFoundFlags.cellText; searchCondition.searchFlags = GC.Spread.Sheets.Search.SearchFlags.ignoreCase | GC.Spread.Sheets.Search.SearchFlags.useWildCards; var searchresult = spread.search(searchCondition); var val = sheetData.getValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1); if (val == 0) { sheetData.setValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1, 1, GC.Spread.Sheets.SheetArea.viewport, false); selectedSeat = shape.name(); sheet.setValue(11, 8, selectedSeat); preselectionseatval = val; } else if (val == 2) { if (confirm("This is a Premium seat. Are you sure you want to upgrade?")) { sheetData.setValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1, 1, GC.Spread.Sheets.SheetArea.viewport, false); selectedSeat = shape.name(); sheet.setValue(11, 8, selectedSeat); preselectionseatval = val; } } else { alert("This seat is already reserved"); } } else { sheetData.suspendPaint(); var searchCondition = new GC.Spread.Sheets.Search.SearchCondition(); searchCondition.searchString = selectedSeat; searchCondition.startSheetIndex = 1; searchCondition.endSheetIndex = 1; searchCondition.searchOrder = GC.Spread.Sheets.Search.SearchOrder.nOrder; searchCondition.searchTarget = GC.Spread.Sheets.Search.SearchFoundFlags.cellText; searchCondition.searchFlags = GC.Spread.Sheets.Search.SearchFlags.ignoreCase | GC.Spread.Sheets.Search.SearchFlags.useWildCards; var searchresult = spread.search(searchCondition); var selectedseatval = sheetData.getValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1); var searchCondition1 = new GC.Spread.Sheets.Search.SearchCondition(); searchCondition1.searchString = shape.name(); searchCondition1.startSheetIndex = 1; searchCondition1.endSheetIndex = 1; searchCondition1.searchOrder = GC.Spread.Sheets.Search.SearchOrder.nOrder; searchCondition1.searchTarget = GC.Spread.Sheets.Search.SearchFoundFlags.cellText; searchCondition1.searchFlags = GC.Spread.Sheets.Search.SearchFlags.ignoreCase | GC.Spread.Sheets.Search.SearchFlags.useWildCards; var searchresult1 = spread.search(searchCondition1); var val = sheetData.getValue(searchresult1.foundRowIndex, searchresult1.foundColumnIndex + 1); if (val == 1) { alert("This seat is already reserved"); } else if (val == 0) { sheetData.setValue(searchresult1.foundRowIndex, searchresult1.foundColumnIndex + 1, 1, GC.Spread.Sheets.SheetArea.viewport, false); sheetData.setValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1, 0, GC.Spread.Sheets.SheetArea.viewport, false); selectedSeat = shape.name(); sheet.setValue(11, 8, selectedSeat); } else if (val == 2) { if (confirm("This is a Premium seat. Are you sure you want to upgrade?")) { sheetData.setValue(searchresult1.foundRowIndex, searchresult1.foundColumnIndex + 1, 1, GC.Spread.Sheets.SheetArea.viewport, false); sheetData.setValue(searchresult.foundRowIndex, searchresult.foundColumnIndex + 1, 0, GC.Spread.Sheets.SheetArea.viewport, false); selectedSeat = shape.name(); sheet.setValue(11, 8, selectedSeat); } } sheetData.resumePaint(); } spread.resumePaint(); } } }, false); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture" content="ko-kr"/> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-resources-ko/dist/gc.spread.sheets.resources.ko.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/data/svgpath.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" style="width:100%;height:100%"></div> </div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }