/** * שכבת הערות אישית — המשתמש מסמן/מצייר/כותב על המפה, והשכבה ניתנת * לייצוא כקובץ DXF תקני בקואורדינטות רשת ישראל (נפתח ב-AutoCAD, * ב-govmap, וגם חזרה באפליקציה הזו). * * ההערות נשמרות כרשומת קובץ רגילה ב-IndexedDB (coordSys='itm'), * כך שכל שרשרת הרינדור/govmap/כיבוי-הדלקה עובדת עליהן כמו על כל שכבה. */ (function (global) { "use strict"; var NOTES_ID = "notes_default"; var PALETTE = [ { hex: "#e53935", aci: 1, name: "אדום" }, { hex: "#1e88e5", aci: 5, name: "כחול" }, { hex: "#43a047", aci: 3, name: "ירוק" }, { hex: "#fb8c00", aci: 30, name: "כתום" }, { hex: "#111111", aci: 7, name: "שחור" }, ]; function newRecord() { return { id: NOTES_ID, isNotes: true, name: "ההערות שלי", addedAt: new Date().toISOString(), entities: [], bbox: null, coordSys: "itm", calibration: null, opacity: 1, weight: 3, visible: true, hiddenLayers: [], }; } function colorPair(hex) { // גם על רקע כהה ההערות נשארות בצבע שנבחר (מלבד שחור → לבן) return { color: hex, colorDark: hex === "#111111" ? "#ffffff" : hex }; } function makePoint(itm, hex) { var c = colorPair(hex); return { type: "point", layer: "NOTES", pt: itm, color: c.color, colorDark: c.colorDark }; } function makePoly(itmPts, closed, hex) { var c = colorPair(hex); return { type: "poly", layer: "NOTES", pts: itmPts, closed: !!closed, color: c.color, colorDark: c.colorDark }; } function makeText(itm, text, hex) { var c = colorPair(hex); return { type: "text", layer: "NOTES", pt: itm, text: text, height: 2.5, rotation: 0, color: c.color, colorDark: c.colorDark }; } function recalcBbox(rec) { rec.bbox = global.DXF.bbox(rec.entities); } // ---------- כתיבת DXF ---------- function aciFor(hex) { for (var i = 0; i < PALETTE.length; i++) { if (PALETTE[i].hex === hex) return PALETTE[i].aci; } return 1; } function tag(code, value) { return code + "\n" + value + "\n"; } function fmt(v) { return (Math.round(v * 1000) / 1000).toString(); } /** * טקסט DXF בטוח: כל תו שאינו ASCII (עברית וכו') מקודד בסימון * ‎\U+XXXX הרשמי של AutoCAD — הקובץ כולו נשאר ASCII נקי, בלי * תלות בקידוד/codepage. */ function escapeDxfText(s) { return (s || "").replace(/\n/g, " ").replace(/[^\x20-\x7e]/g, function (ch) { var hex = ch.charCodeAt(0).toString(16).toUpperCase(); return "\\U+" + ("0000" + hex).slice(-4); }); } /** * בונה קובץ DXF מישויות ההערות, בפורמט R12 ‏(AC1009). * * דווקא הפורמט הישן בכוונה: AutoCAD מקבל R12 גם במבנה מינימלי, * בעוד שקבצים המוצהרים כגרסאות חדשות (AC1015+) חייבים סט טבלאות * מלא — APPID, VPORT, BLOCK_RECORD, handles — אחרת: * ‏"Error in APPID Table … drawing discarded". * לכן ב-R12: קווים כ-POLYLINE/VERTEX (אין LWPOLYLINE ב-R12) * וטקסט ב-ASCII עם ‎\U+XXXX לעברית. * קואורדינטות ברשת ישראל — נפתח ב-AutoCAD במיקום הנכון. */ function buildDxf(entities) { var s = ""; // HEADER s += tag(0, "SECTION") + tag(2, "HEADER"); s += tag(9, "$ACADVER") + tag(1, "AC1009"); s += tag(0, "ENDSEC"); // TABLES — סוג קו, סגנון טקסט ושכבת NOTES (המינימום שמכבד R12) s += tag(0, "SECTION") + tag(2, "TABLES"); s += tag(0, "TABLE") + tag(2, "LTYPE") + tag(70, 1); s += tag(0, "LTYPE") + tag(2, "CONTINUOUS") + tag(70, 0) + tag(3, "Solid line") + tag(72, 65) + tag(73, 0) + tag(40, "0.0"); s += tag(0, "ENDTAB"); s += tag(0, "TABLE") + tag(2, "LAYER") + tag(70, 1); s += tag(0, "LAYER") + tag(2, "NOTES") + tag(70, 0) + tag(62, 1) + tag(6, "CONTINUOUS"); s += tag(0, "ENDTAB"); s += tag(0, "TABLE") + tag(2, "STYLE") + tag(70, 2); // LEGEND — הסגנון שסביבת אופטק ממפה לפונט עברי ["STANDARD", "LEGEND"].forEach(function (styleName) { s += tag(0, "STYLE") + tag(2, styleName) + tag(70, 0) + tag(40, "0.0") + tag(41, "1.0") + tag(50, "0.0") + tag(71, 0) + tag(42, "2.5") + tag(3, "txt") + tag(4, ""); }); s += tag(0, "ENDTAB"); s += tag(0, "ENDSEC"); // ENTITIES s += tag(0, "SECTION") + tag(2, "ENTITIES"); entities.forEach(function (e) { var aci = aciFor(e.color); if (e.type === "poly") { s += tag(0, "POLYLINE") + tag(8, "NOTES") + tag(62, aci) + tag(66, 1) + tag(70, e.closed ? 1 : 0); e.pts.forEach(function (p) { s += tag(0, "VERTEX") + tag(8, "NOTES") + tag(10, fmt(p[0])) + tag(20, fmt(p[1])) + tag(30, 0); }); s += tag(0, "SEQEND") + tag(8, "NOTES"); } else if (e.type === "point") { s += tag(0, "POINT") + tag(8, "NOTES") + tag(62, aci); s += tag(10, fmt(e.pt[0])) + tag(20, fmt(e.pt[1])) + tag(30, 0); // עיגול קטן סביב הנקודה כדי שתהיה בולטת גם בשרטוט s += tag(0, "CIRCLE") + tag(8, "NOTES") + tag(62, aci); s += tag(10, fmt(e.pt[0])) + tag(20, fmt(e.pt[1])) + tag(30, 0) + tag(40, 1); } else if (e.type === "text") { s += tag(0, "TEXT") + tag(8, "NOTES") + tag(7, "LEGEND") + tag(62, aci); s += tag(10, fmt(e.pt[0])) + tag(20, fmt(e.pt[1])) + tag(30, 0); s += tag(40, e.height || 2.5) + tag(1, escapeDxfText(e.text)); } }); s += tag(0, "ENDSEC") + tag(0, "EOF"); return s; } /** ייצוא ושיתוף: Web Share אם זמין (וואטסאפ/מייל בטלפון), אחרת הורדה */ function exportAndShare(rec) { if (!rec || !rec.entities.length) return Promise.reject(new Error("EMPTY_NOTES")); var text = buildDxf(rec.entities); var stamp = new Date().toISOString().slice(0, 10); var fileName = "optech-notes-" + stamp + ".dxf"; var blob = new Blob([text], { type: "application/dxf" }); var file; try { file = new File([blob], fileName, { type: "application/dxf" }); } catch (e) { file = null; } if (file && navigator.canShare && navigator.canShare({ files: [file] })) { return navigator.share({ files: [file], title: "שכבת הערות — Optech GIS" }) .catch(function (err) { if (err && err.name === "AbortError") return; // המשתמש ביטל download(blob, fileName); }); } download(blob, fileName); return Promise.resolve(); } function download(blob, fileName) { var a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = fileName; document.body.appendChild(a); a.click(); setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 2000); } global.Notes = { NOTES_ID: NOTES_ID, PALETTE: PALETTE, newRecord: newRecord, makePoint: makePoint, makePoly: makePoly, makeText: makeText, recalcBbox: recalcBbox, buildDxf: buildDxf, exportAndShare: exportAndShare, }; })(window);