// Fichier JSExportGrapheNestedFunc.inc // appelé par UnitGraphes1.pas // contenant les sous-fonctions de la méthode suivante (* Exporter le graphe en Javascript procedure TPathFindingGraphe.ExporterGrapheEnJavascript(const DocTitle: string; const FileNameJS: RawByteString; const QIDStationDepart, QIDStationArrivee: string; const BackgroundColorCarte, CouleurCenterlines: TColor; const CanvasWidthInPixels, CanvasHeightInPixels, WidthMenuLateralInPixels: integer); //*) // 2022-02-15: Ajout du bouton 'Permuter' //****************************************************************************** // primitives de base procedure WriteLine(const S: string); inline; begin WriteLn(fp, S); end; procedure WrtLinFmt(Const Fmt : String; const Args : Array of const); begin WriteLn(fp, Format(Fmt, Args)); end; procedure WriteDebugLine(const S: string); inline; begin WriteLn(fp, Format('console.log(%s);', [S])); end; procedure WrtDebugFmtLin(const fmt: string; const Args : Array of const); inline; begin WriteDebugLine(Format(Fmt, Args)); end; procedure JSSeparateur(const QMotif: Char = '='; const nb: integer = 80); begin WriteLine('//' + StringOfChar(QMotif, nb)); end; // utilisé notamment pour tester les nouvelles fonctions // sans avoir à les sauvegarder ailleurs procedure BeginJSVerbatim(const Desc: string); begin WriteLine(StringOfChar('/', 132)); WriteLine('// VERBATIM: ' + Desc); WriteLine(StringOfChar('/', 132)); end; procedure JSVerbatim(const L: string); begin WriteLine('// **** ' + L); end; procedure EndJSVerbatim(); begin WriteLine(StringOfChar('/', 132)); WriteLine('// END VERBATIM:'); WriteLine(StringOfChar('/', 132)); end; // fonctions utilitaires function QColorToHTMLColor(const Couleur: TColor): string; begin Result := Format('#%.2X%.2X%.2X', [Red(Couleur), Green(Couleur), Blue(Couleur)]); end; function ToJSCoord(const X: double): integer; begin result := trunc(TO_DECIMETERS * X); end; // wrappers des structures de contrôle de flux (IF, WHILE, SWITCH, ...) procedure jsFOR(const QVarCounter, QVarNb: string; const QStart: integer = 0; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%sfor (var %s = %d; %s < %s; %s++) // -- FOR %s', [WU, QVarCounter, QStart, QVarCounter, QVarNb, QVarCounter, QTag]); WrtLinFmt('%s{', [WU]); end; procedure jsNEXT(const QVarCounter: string; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s} // -- NEXT %s ... %s', [WU, QVarCounter, QTag]); end; procedure jsWHILE(const QCondition: string; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%swhile (%s) // -- WHILE %s', [WU, QCondition, QTag]); WrtLinFmt('%s{', [WU]); end; procedure jsWEND(const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s} // -- WEND %s', [WU, QTag]); end; procedure jsIF(const QCondition: string; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%sif (%s) // %s', [WU, QCondition, QTag]); WrtLinFmt('%s{', [WU]); end; procedure jsELSE(const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s} else { // %s', [WU, QTag]); end; procedure jsENDIF(const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s} // %s', [WU, QTag]); end; procedure jsSELECT_CASE(const QSelecteur: string; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%sswitch(%s) { // %s', [WU, QSelecteur, QTag]); end; procedure jsCASE(const QItem: integer; const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s case %d: // %s', [WU, QItem, QTag]); end; procedure jsBREAK(const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s break;', [WU]); end; procedure jsCASE_ELSE(const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s default: // %s', [WU, QTag]); end; procedure jsEND_SELECT(const QTag: string = ''; const QIndent: integer = 4); var WU: String; begin WU := StringOfChar(' ', QIndent); WrtLinFmt('%s} // switch %s', [WU, QTag]); end; // les classes CSS procedure BeginCSSClass(const QCSSClass: string); begin WrtLinFmt(' #%s{', [QCSSClass]); end; procedure EndCSSClass(); begin WriteLine(' }'); end; // les différentes sections du fichier HTML procedure BeginHTML(); begin WriteLine(''); WrtLinFmt('', [DateTimePascalToDateTimeSQL(Now), ApplicationName, GetGHTopoVersion()]); WriteLine(''); end; procedure EndHTML(); begin WriteLine(''); end; procedure BeginCSS_Styles(); begin WriteLine(''); end; procedure BeginHEAD(); begin WriteLine(''); WrtLinFmt(' %s', [DocTitle]); WrtLinFmt(' ', ['utf-8']); end; procedure EndHEAD(); begin WriteLine(''); end; procedure BeginScriptSection(); begin WrtLinFmt(' '); end; procedure BeginBODY(const MyJS_FUNCTION_INITIALISER, MyIDStationDepart, MyIDStationArrivee: string); begin WrtLinFmt('', [MyJS_FUNCTION_INITIALISER, MyIDStationDepart, MyIDStationArrivee]); end; procedure EndBODY(); begin WriteLine(' ' ); WriteLine(''); end; // composants d'un doc html: divs, forms, tableaux procedure BeginDiv(const QID: string; const QIndent: integer = 2); begin WrtLinFmt('%s
', [StringOfChar(' ', QIndent), QID]); end; procedure EndDiv(const QIndent: integer = 2); begin WrtLinFmt('%s
', [StringOfChar(' ', QIndent)]); end; procedure BeginForm(const QName: string; const QIndent: integer = 4); begin WrtLinFmt('%s
', [StringOfChar(' ', QIndent), QName]); end; procedure AddFormLabel(const QID, QCaption: string); begin WrtLinFmt('
' , [QID , QCaption]); end; procedure EndForm(const QIndent: integer = 4); begin WrtLinFmt('%s
', [StringOfChar(' ', QIndent)]); end; procedure BeginTable(const WidthInPercent, HeightInPercent: integer; const QIndent: integer = 4); overload; begin WrtLinFmt(' %s', [StringOfChar(' ', QIndent), WidthInPercent, HeightInPercent]); end; procedure BeginRow(const QIndent: integer = 6); overload; begin WrtLinFmt(' %s', [StringOfChar(' ', QIndent)]); end; procedure EndRow(const QIndent: integer = 6); overload; begin WrtLinFmt(' %s', [StringOfChar(' ', QIndent)]); end; procedure EndTable(const QIndent: integer = 4); begin WrtLinFmt(' %s
', [StringOfChar(' ', QIndent)]); end; // positionnement d'objets HTML (DIV, tableaux) procedure PositionnerPanneau(const QNamePanneau: string; const QLeft, QTop, QWidth, QHeight: integer; const QBorderStyle: string; const QBorderColor, QBackGroundColor: TColor; const QFontName: string = DEFAULT_FONT_NAME; const QFontSize: integer = 15; const QFontAttr: string = 'bold'); begin BeginCSSClass(QNamePanneau); // WrtLinFmt(' #%s{', []); WrtLinFmt(' %s:%s;' , ['position', 'absolute']); WrtLinFmt(FMT_POSITION_DIV_IN_PIXELS, ['left' , QLeft]); WrtLinFmt(FMT_POSITION_DIV_IN_PIXELS, ['top' , QTop]); WrtLinFmt(FMT_POSITION_DIV_IN_PIXELS, ['width' , QWidth]); WrtLinFmt(FMT_POSITION_DIV_IN_PIXELS, ['height', QHeight]); WrtLinFmt(' %s:%s;' , ['border-style', QBorderStyle]); WrtLinFmt(' %s:%s;' , ['color' , QColorToHTMLColor(QBorderColor)]); WrtLinFmt(' %s:%s;' , ['background', QColorToHTMLColor(QBackGroundColor)]); WrtLinFmt(' %s:%dpx %s;' , ['font', QFontSize, QFontName]); WrtLinFmt(' %s:%s;' , ['font-weight', QFontAttr]); EndCSSClass(); end; procedure JSMakeButtonInTable(const btnName, btnCaption, btnOnClick: string); begin WrtLinFmt(' ', [33, 33, btnName, btnCaption, NAMEREF_STYLE_BUTTON_VUE, btnOnClick]); end; procedure JSMakeLabelledEditText(const LbName, LbCaption: string; const EditName, EditText: string); begin WrtLinFmt('
' , [LbName, GetResourceString(LbCaption)]); WrtLinFmt('
', [EditName, 95, EditName, EditText]); end; procedure JSMakeLabelledEditToporobotStation(const LbName, LbCaption: string; const EditName, EditText: string); begin WrtLinFmt('
' , [LbName, GetResourceString(LbCaption)]); WrtLinFmt('
', [EditName, 95, EditName, EditText]); //WrtLinFmt(' required pattern="%s"
', [EditName, 95, EditName, EditText, '[0-9]'); end; // définitions de variables globales procedure QRedigeDeclGlobalVars(); const VAR_FMT_NUM = 'var %s = %d;'; VAR_FMT_UNDEF = 'var %s;'; begin WriteLine(''); WriteLine('// Variables globales'); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FXMini, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FXMaxi, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FYMini, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FYMaxi, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FXCentreMap, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FYCentreMap, 0]); WrtLinFmt(VAR_FMT_NUM, [JS_GLOBAL_VAR_FLastIdxFound, -1]); WrtLinFmt('var %s = new T%s;', [JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPHE_CLASS_VAR_NAME]); WriteLine('// Variables des contrôles'); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MyContainer]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MyCanvas]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MylbMouseCoords]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MylbRoadmapNbPoints]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MylsbRoadMap]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MyeditFindWhat]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MyeditStationDepart]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_MyeditStationArrivee]); WrtLinFmt(VAR_FMT_UNDEF, [JS_GLOBAL_VAR_FGlobalNoeudCourant]); WriteLine('// Variables globales pour mettre en cache l''état de l''événement'); WrtLinFmt('var %s = new Array();', [JS_GLOBAL_VAR_EvtCache]); WrtLinFmt('var %s = %d;', [JS_GLOBAL_VAR_PrevDiff, -1]); JSSeparateur('=', 120); end; // définition de variables JS procedure jsSetLocalVar(const QVarName: string; const QExpr: string; const QComment: string = ''); overload; begin WrtLinFmt(' var %s = %s; // %s', [QVarName, QExpr, QComment]); end; procedure jsSetLocalVar(const QVarName: string; const QValue: integer; const QComment: string = ''); overload; begin WrtLinFmt(' var %s = %d; // %s', [QVarName, QValue, QComment]); end; procedure jsSetLocalVar(const QVarName: string; const QValue: double; const QComment: string = ''); overload; var qat: String; begin qat := Format(' var %s = %.10f; // %s', [QVarName, QValue, QComment]); qat := StringReplace(qat, ',', '.', [rfReplaceAll]); WriteLine(qat); end; // définitions de fonctions JS procedure BeginJSFunction(const QProcName: string; const QParams: string = ''); begin FCurrentProcName := QProcName; WrtLinFmt('function %s(%s)', [FCurrentProcName, QParams]); WriteLine('{'); end; procedure EndJSFunction(); begin WrtLinFmt('} // EndJSFunction %s ', [FCurrentProcName]); JSSeparateur('-', 60); end; procedure BeginJSNestedFunction(const QProcName: string; const QParams: string = ''); begin WrtLinFmt(' function %s(%s) // %s', [QProcName, QParams, 'Nested']); WriteLine(' {'); end; procedure EndJSNestedFunction(); begin WriteLine(' } // EndJSNestedFunction'); end; procedure BeginJSEventListener(const EventName: string; const Desc: string = ''); begin WrtLinFmt(' // Listener: %s - %s', [EventName, Desc]); WrtLinFmt(' %s.addEventListener("%s", function(e) {', ['window', EventName]); end; procedure EndJSEventListener(); begin WriteLine(' });'); JSSeparateur('-', 60); end; //****************************************************************************** procedure QBeginRedigerFonctionsUtilitaires(); begin JSSeparateur(); WrtLinFmt('// Les %s', [JS_SECTION_FUNCTIONS_UTILITAIRES]); end; procedure QEndRedigerFonctionsUtilitaires(); begin JSSeparateur(); WrtLinFmt('// Fin section %s', [JS_SECTION_FUNCTIONS_UTILITAIRES]); WriteLine(''); end; procedure QRedigeFunctionGetAzimut(); const VARNAME_TWO_PI = 'TWO_PI'; VARNAME_a = 'a'; begin BeginJSFunction(JS_UTILITY_FUNC_GetAzimut, 'dx, dy, Unite'); WrtLinFmt(' const %s = 2 * %s.PI;', [VARNAME_TWO_PI, JS_MATH_LIBRARY]); WrtLinFmt(' var %s = %s.atan2(dy, dx + 1e-12);', [VARNAME_a, JS_MATH_LIBRARY]); WrtLinFmt(' if (%s < 0) %s = %s + %s;', [VARNAME_a, VARNAME_a, VARNAME_a, VARNAME_TWO_PI]); WrtLinFmt(' %s = 0.50 * %s.PI - %s;', [VARNAME_a, JS_MATH_LIBRARY, VARNAME_a]); // a := 0.50 * PI - a; WrtLinFmt(' if (%s < 0) %s = %s + %s;', [VARNAME_a, VARNAME_a, VARNAME_a, VARNAME_TWO_PI]); WrtLinFmt(' return %s * 0.50 * Unite / %s.PI;', [VARNAME_a, JS_MATH_LIBRARY]); EndJSFunction(); end; procedure QRedigeFunctionGetBearingInc(); const VARNAME_dx = 'dx'; VARNAME_dy = 'dy'; VARNAME_dz = 'dz'; VARNAME_fUB = 'fUB'; VARNAME_fUC = 'fUC'; VARNAME_qdist = 'qdist'; VARNAME_qdp = 'qdp'; VARNAME_qAz = 'qaz'; VARNAME_qInc = 'qincl'; QFMT_HYPOT = '%s.hypot(%s, %s)'; var WU: String; begin WU := format('%s, %s, %s, %s, %s', [VARNAME_dx , VARNAME_dy, VARNAME_dz, VARNAME_fUB , VARNAME_fUC]); BeginJSFunction(JS_UTILITY_FUNC_GetBearingInc, WU); jsSetLocalVar(VARNAME_qdp , format(QFMT_HYPOT, [JS_MATH_LIBRARY, VARNAME_dx , VARNAME_dy]), 'Dist HZ'); jsSetLocalVar(VARNAME_qdist , format(QFMT_HYPOT, [JS_MATH_LIBRARY, VARNAME_qdp, VARNAME_dz]), 'Distance'); jsSetLocalVar(VARNAME_qInc , format('%s.atan2(%s, %s) * 0.5 * %s / %s.PI', [JS_MATH_LIBRARY, VARNAME_dz, VARNAME_qdp, VARNAME_fUC, JS_MATH_LIBRARY]), ''); jsSetLocalVar(VARNAME_qAz , format('%s(%s, %s, %s)', [JS_UTILITY_FUNC_GetAzimut, VARNAME_dx, VARNAME_dy, VARNAME_fUB]), ''); WriteLine(' return {'); WrtLinFmt(' %s: %s / %s,', [JS_VARNAME_OUT_Dist, VARNAME_qdist, FormatterNombreWithDotDecimal(10.00, 2)]); WrtLinFmt(' %s: %s,', [JS_VARNAME_OUT_Az , VARNAME_qAz]); WrtLinFmt(' %s: %s', [JS_VARNAME_OUT_Inc , VARNAME_qInc]); WriteLine(' }; // return tuple'); EndJSFunction(); end; procedure JSTraceLigne(const SX1, SY1, SX2, SY2: string); begin WrtLinFmt(' %s(%s, %s);', [JS_FUNC_CoordsToPlan, SX1, SY1]); WriteLine(' PS1X = PX;'); WriteLine(' PS1Y = PY;'); WrtLinFmt(' %s(%s, %s);', [JS_FUNC_CoordsToPlan, SX2, SY2]); WriteLine(' PS2X = PX;'); WriteLine(' PS2Y = PY;'); WrtLinFmt(' %s.beginPath();' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.moveTo(PS1X, PS1Y);' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.lineTo(PS2X, PS2Y);' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.stroke();' , [NAMEREF_CANVAS_DC]); end; procedure JSToto(const BeginOrEndPath, JS_FRM_EditStation, JS_Varname_Station, JS_Varname_IdxStation: string); begin WrtLinFmt(' var %s = %s.value;', [JS_Varname_Station, JS_FRM_EditStation]); WrtLinFmt(' var %s = %s.FindIdxNoeudByCle(%s);', [JS_Varname_IdxStation, JS_GRAPHE_CLASS_VAR_NAME, JS_Varname_Station]); jsIF(Format('%s < 0', [JS_Varname_IdxStation]), ''); WrtLinFmt(' window.alert("Station %s ''" + %s + "'' introuvable");', [BeginOrEndPath, JS_Varname_Station]); WriteLine(' return;'); jsENDIF(); end; // définitions de méthodes de classe procedure BeginClassJSFunction(const QClassName, QMethod: string; const QParams: string = ''); begin FCurrentClassName:= QClassName; FCurrentProcName := QMethod; WrtLinFmt('// BeginClassJSFunction: *** ----- %s -- %s', [FCurrentClassName, FCurrentProcName]); WrtLinFmt(' %s.%s = function(%s)', [FCurrentClassName, FCurrentProcName, QParams]); WriteLine(' {'); end; procedure EndClassJSFunction(); begin WrtLinFmt(' } // EndClassJSFunction // %s.%s', [FCurrentClassName, FCurrentProcName]); JSSeparateur('-', 60); end; procedure JSSetMemberAtThis(const Varname: string); begin WrtLinFmt(' %s.%s = Q%s;', [JS_THIS, Varname, Varname]); end; // Classe TJSGraphe procedure QBeginClasseTJSGraphe(); begin WrtLinFmt('// La classe T%s', [JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt('function T%s() {', [JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s.%s = new Array();', [JS_THIS, JS_GRAPH_LISTE_NOEUDS]); WrtLinFmt(' %s.%s = new Array();', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); WrtLinFmt(' %s.FXMini = %d;', [JS_THIS, ToJSCoord(self.FEtendue.X1)]); WrtLinFmt(' %s.FYMini = %d;', [JS_THIS, ToJSCoord(self.FEtendue.Y1)]); WrtLinFmt(' %s.FXMaxi = %d;', [JS_THIS, ToJSCoord(self.FEtendue.X2)]); WrtLinFmt(' %s.FYMaxi = %d;', [JS_THIS, ToJSCoord(self.FEtendue.Y2)]); BeginClassJSFunction(JS_THIS, 'Init'); pass; EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'AddNoeud', JS_ARGS_ADD_NOEUD); WrtLinFmt(' %s.%s.push(new TJSGrapheNode(%s));', [JS_THIS, JS_GRAPH_LISTE_NOEUDS, JS_ARGS_ADD_NOEUD]); WrtLinFmt(' %s.FNbNoeuds = %s.%s.length;', [JS_THIS, JS_THIS, JS_GRAPH_LISTE_NOEUDS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'GetNoeud', 'Index'); WrtLinFmt(' return %s.%s[Index];', [JS_THIS, JS_GRAPH_LISTE_NOEUDS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'GetNbNoeuds'); WrtLinFmt(' return %s.%s.length;', [JS_THIS, JS_GRAPH_LISTE_NOEUDS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'FindIdxNoeudByCle', 'Cle'); jsSetLocalVar('Nb', Format('%s.GetNbNoeuds()', [JS_THIS]), 'Nombre de noeuds (test)'); WriteLine(' if (0 == Nb) return -1;'); jsFOR('i', 'Nb', 0, '', 4); WrtLinFmt(' if (%s.%s[i].IDNoeud === Cle) return i;', [JS_THIS, JS_GRAPH_LISTE_NOEUDS]); jsNEXT('i'); WriteLine(' return -1;'); EndClassJSFunction(); end; procedure QEndClasseTJSGraphe(); begin WriteLine('} // End class' + JS_GRAPHE_CLASS_VAR_NAME); JSSeparateur('+', 132); end; procedure QRedigeClasseTJSGrapheNode(); const CLASSNAME_TJSGrapheNode = 'TJSGrapheNode'; begin BeginJSFunction(CLASSNAME_TJSGrapheNode, JS_ARGS_ADD_NOEUD); JSSetMemberAtThis('IDNoeud'); JSSetMemberAtThis('X'); JSSetMemberAtThis('Y'); JSSetMemberAtThis('Z'); JSSetMemberAtThis('ListeVoisins'); EndJSFunction(); end; procedure QRedigeClassJSGrapheFunctionFindIdxNoeudNearestToXY(); const FMT_QDXY = '(%s - %s.%s[i].%s)'; begin BeginClassJSFunction(JS_THIS, 'FindIdxNoeudNearestToXY', 'QX, QY'); jsSetLocalVar('Result', -1); // WrtLinFmt(' var %s = %d;', ['Result', -1]); jsSetLocalVar('Nb', format('%s.GetNbNoeuds()', [JS_THIS]), 'cuicui'); ; // WrtLinFmt(' var Nb = %s.GetNbNoeuds();', [JS_THIS]); WriteLine(' if (0 == Nb) return -1;'); jsSetLocalVar('QDistance', JS_CONST_INFINITY, 'Infinité');// WrtLinFmt(' var %s = %s;', ['QDistance', JS_CONST_INFINITY]); jsFOR('i', 'Nb', 0, '', 4); jsSetLocalVar('qdx' , Format(FMT_QDXY, ['QX', JS_THIS, JS_GRAPH_LISTE_NOEUDS, 'X']), 'Qdx'); // WrtLinFmt(' var %s = (QX - %s.%s[i].%s);', ['qdx', JS_THIS, JS_GRAPH_LISTE_NOEUDS, 'X']); jsSetLocalVar('qdy' , Format(FMT_QDXY, ['QY', JS_THIS, JS_GRAPH_LISTE_NOEUDS, 'Y']), 'Qdy'); // WrtLinFmt(' var %s = (QY - %s.%s[i].%s);', ['qdy', JS_THIS, JS_GRAPH_LISTE_NOEUDS, 'Y']); jsSetLocalVar('qdist', format('%s * %s + %s * %s', ['qdx', 'qdx', 'qdy', 'qdy']), 'distance en plan'); // WrtLinFmt(' var %s = %s * %s + %s * %s;', ['qdist', 'qdx', 'qdx', 'qdy', 'qdy']); jsIF(format('%s < %s', ['qdist', 'QDistance']), '', 8); WrtLinFmt(' %s = %s;', ['QDistance', 'qdist']); WrtLinFmt(' %s = %s;', ['Result', 'i']); jsENDIF('', 8); jsNEXT('i'); WriteLine(' return Result;'); EndClassJSFunction(); end; procedure QRedigeClassJSGrapheFunctionDijkstra(); const FMT_FIND_IDX_NOEUD = '%s.FindIdxNoeudByCle(%s)'; begin WriteLine(' // Algo de Dijkstra'); BeginClassJSFunction(JS_THIS, 'Dijkstra', 'StationDepart, StationArrivee'); jsSetLocalVar(JS_VAR_IDX_ND_DEPART , Format(FMT_FIND_IDX_NOEUD, [JS_THIS, 'StationDepart']) , 'Recherche départ'); jsSetLocalVar(JS_VAR_IDX_ND_ARRIVEE, Format(FMT_FIND_IDX_NOEUD, [JS_THIS, 'StationArrivee']), 'Recherche arrivée'); WrtLinFmt(' if (%s === -1) return -1;', [JS_VAR_IDX_ND_DEPART]); WrtLinFmt(' if (%s === -1) return -2;', [JS_VAR_IDX_ND_ARRIVEE]); WrtLinFmt(' if (%s === %s) return -3;', [JS_VAR_IDX_ND_DEPART, JS_VAR_IDX_ND_ARRIVEE]); WrtLinFmt(' %s.%s = []; // vider le chemin le plus court', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); WriteLine(' // Variables locales'); jsSetLocalVar(JS_VARNAME_CURRENT_NODE, 'null'); jsSetLocalVar('MyNodeVoisin', 'null'); jsSetLocalVar('QIdxVoisin', 0); jsSetLocalVar('NbVoisins' , 0); jsSetLocalVar('QDistance' , 0.00); jsSetLocalVar(JS_VARNAME_NbNoeuds, format('%s.GetNbNoeuds()', [JS_THIS]), 'miaou'); jsSetLocalVar(JS_LOCAL_ListePreds, 'new Array()', 'Liste des prédécesseurs'); jsFOR('i', JS_VARNAME_NbNoeuds, 0, '', 4); WrtLinFmt(' %s[i] = %d;', [JS_LOCAL_ListePreds, 0]); jsNEXT('i'); jsSetLocalVar(JS_LOCAL_ListeDistances, 'new Array()', 'Liste des distances'); jsFOR('i', JS_VARNAME_NbNoeuds, 0, '', 4); WrtLinFmt(' %s[i] = %s; ', [JS_LOCAL_ListeDistances, JS_CONST_INFINITY]); jsNEXT('i', '', 4); WrtLinFmt(' %s[%s] = 0;', [JS_LOCAL_ListeDistances, JS_VAR_IDX_ND_DEPART]); jsSetLocalVar(JS_LOCAL_ListeNdsVisites, 'new Array()', 'Liste des déjà vus'); jsFOR('i', JS_VARNAME_NbNoeuds, 0, '', 4); WrtLinFmt(' %s[i] = false;', [JS_LOCAL_ListeNdsVisites]); jsNEXT('i'); WriteLine(' // Retourne le nombre de noeuds visités'); BeginJSNestedFunction(JS_FUNCTION_NbNoeudsVisites); WriteLine(' Result = 0;'); jsFOR('i', JS_VARNAME_NbNoeuds, 0, '', 4); WrtLinFmt(' if (%s[i]) Result++;', [JS_LOCAL_ListeNdsVisites]); jsNEXT('i'); WriteLine(' return Result;'); EndJSNestedFunction(); WriteLine(' // Retourne le noeud le plus proche dans les noeuds non visités'); BeginJSNestedFunction(JS_FUNCTION_TrouveMin); jsSetLocalVar('Result', -1); jsSetLocalVar('DistMini', JS_CONST_INFINITY); jsFOR('i', JS_VARNAME_NbNoeuds, 0, '', 6); jsIF(Format('!%s[i]', [JS_LOCAL_ListeNdsVisites]), '', 8); jsIF(Format('%s[i] < DistMini', [JS_LOCAL_ListeDistances]), '', 10); WrtLinFmt(' DistMini = %s[i];', [JS_LOCAL_ListeDistances]); WriteLine(' Result = i;'); jsENDIF('', 10); jsENDIF('', 8); jsNEXT('i', '', 6); WriteLine(' return Result;'); EndJSNestedFunction(); jsWHILE(Format('%s() < %s', [JS_FUNCTION_NbNoeudsVisites, JS_VARNAME_NbNoeuds]), 'Boucle while principale', 4); jsSetLocalVar('N1', format('%s()', [JS_FUNCTION_TrouveMin]), ''); WrtLinFmt(' if (N1 == %s) break;', [JS_VAR_IDX_ND_ARRIVEE]); WrtLinFmt(' %s[N1] = true;', [JS_LOCAL_ListeNdsVisites]); WrtLinFmt(' %s = %s.GetNoeud(N1);', [JS_VARNAME_CURRENT_NODE, JS_THIS]); WrtLinFmt(' NbVoisins = %s.ListeVoisins.length;', [JS_VARNAME_CURRENT_NODE]); jsIF('NbVoisins > 0', '', 8); jsFOR('k', 'NbVoisins', 0, '', 10); WrtLinFmt(' QIdxVoisin = %s.ListeVoisins[k];', [JS_VARNAME_CURRENT_NODE]); WriteLine(' // fonction MajDistances() déroulée '); WrtLinFmt(' var Poids = %s.%s(N1, QIdxVoisin);', [JS_THIS, JS_FUNCTION_DistanceBetweenNodes]); jsIF(Format('%s[QIdxVoisin] > (%s[N1] + Poids)', [JS_LOCAL_ListeDistances, JS_LOCAL_ListeDistances]), '', 12); WrtLinFmt(' %s[QIdxVoisin] = %s[N1] + Poids;', [JS_LOCAL_ListeDistances, JS_LOCAL_ListeDistances]); WrtLinFmt(' %s[QIdxVoisin] = N1;', [JS_LOCAL_ListePreds]); jsENDIF('', 12); jsNEXT('k', '', 10); jsENDIF('', 8); jsWEND('', 4); WriteLine(' // Et maintenant, on remonte'); WrtLinFmt(' %s.%s = [];', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); jsSetLocalVar('N2', JS_VAR_IDX_ND_ARRIVEE, ''); jsWHILE(format('N2 != %s', [JS_VAR_IDX_ND_DEPART]), 'While de remontée', 4); WrtLinFmt(' %s.%s(N2);', [JS_THIS, JS_FUNCTION_AddIdxNoeudAtPathFound]); WrtLinFmt(' N2 = %s[N2];', [JS_LOCAL_ListePreds]); jsWEND('', 4); EndClassJSFunction(); end; procedure QRedigeClassJSGrapheFunctionsPathFound(); begin BeginClassJSFunction(JS_THIS, JS_FUNCTION_AddIdxNoeudAtPathFound, 'IdxNoeud'); WriteLine(' // L''algo Dijkstra construit la liste des parcourus "à l''envers"'); WriteLine(' // aussi, l''ajout se fait en début de tableau"'); WrtLinFmt(' %s.%s.splice(%d, %d, IdxNoeud);', [JS_THIS, JS_GRAPH_SHORTEST_PATH, 0, 0]); WrtLinFmt(' // %s.%s.push(IdxNoeud);', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, JS_FUNCTION_GetIdxNoeudOfPathFound, 'IdxNoeud'); WrtLinFmt(' return %s.%s[IdxNoeud];', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, JS_FUNCTION_GetNbStationsOfPathFound, ''); WrtLinFmt(' return %s.%s.length;', [JS_THIS, JS_GRAPH_SHORTEST_PATH]); EndClassJSFunction(); end; procedure QRedigeClassJSGrapheFunctionsGetBounds(); begin WriteLine(' // GetBounds'); BeginClassJSFunction(JS_THIS, 'GetXMini', ''); WrtLinFmt(' return %s.FXMini;', [JS_THIS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'GetYMini', ''); WrtLinFmt(' return %s.FYMini;', [JS_THIS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'GetXMaxi', ''); WrtLinFmt(' return %s.FXMaxi;', [JS_THIS]); EndClassJSFunction(); BeginClassJSFunction(JS_THIS, 'GetYMaxi', ''); WrtLinFmt(' return %s.FYMaxi;', [JS_THIS]); EndClassJSFunction(); end; procedure QRedigeClassJSGrapheFunctionDistanceBetweenNodes(); const FMT_GET_NOEUD = '%s.GetNoeud(%s)'; begin BeginClassJSFunction(JS_THIS, JS_FUNCTION_DistanceBetweenNodes, Format('%s, %s', [JS_VAR_IDX_ND_DEPART, JS_VAR_IDX_ND_ARRIVEE])); jsSetLocalVar('ST1', format(FMT_GET_NOEUD, [JS_THIS, JS_VAR_IDX_ND_DEPART]), ''); // WrtLinFmt(' var ST1 = %s.GetNoeud(%s);', []); jsSetLocalVar('ST2', format(FMT_GET_NOEUD, [JS_THIS, JS_VAR_IDX_ND_ARRIVEE]), ''); // WrtLinFmt(' var ST2 = %s.GetNoeud(%s);', []); jsSetLocalVar(JS_VARNAME_dx, 'ST2.X - ST1.X', ''); jsSetLocalVar(JS_VARNAME_dy, 'ST2.Y - ST1.Y', ''); jsSetLocalVar('QDist', format('%s.sqrt(%s * %s + %s * %s)', [JS_MATH_LIBRARY, JS_VARNAME_dx, JS_VARNAME_dx, JS_VARNAME_dy, JS_VARNAME_dy]), 'distance'); WriteLine(' if (QDist < 0.01) return(0.01)'); WriteLine(' else return QDist; // sécurisation: aucun poids nul autorisé dans Dijkstra'); EndClassJSFunction(); end; procedure QRedigeFunctionListerRoadMap(); const QVAR_LongParcours = 'LongParcours'; FMT_METHOD_GetNoeud = '%s.GetNoeud(%s.%s(%s))'; begin BeginJSFunction(JS_FUNCTION_ListerRoadMap); jsSetLocalVar('Nb', Format('%s.%s.length', [JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPH_SHORTEST_PATH])); WriteLine(' if (Nb == 0) return;'); jsSetLocalVar(QVAR_LongParcours, 0.00); WrtLinFmt(' %s.options.length = Nb;', [JS_DOCUMENT_FORM_lsbRoadMap]); jsFOR('i', 'Nb', 0, '', 4); jsSetLocalVar(JS_VARNAME_CURRENT_NODE, Format(FMT_METHOD_GetNoeud, [JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound, 'i'])); jsIF('i >= 1', '', 6); jsSetLocalVar(JS_VARNAME_PREVIOUS_NODE, Format(FMT_METHOD_GetNoeud, [JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound, 'i-1'])); jsSetLocalVar(JS_VARNAME_dx, format('%s.X - %s.X', [JS_VARNAME_CURRENT_NODE, JS_VARNAME_PREVIOUS_NODE])); jsSetLocalVar(JS_VARNAME_dy, format('%s.Y - %s.Y', [JS_VARNAME_CURRENT_NODE, JS_VARNAME_PREVIOUS_NODE])); WrtLinFmt(' %s += %s.hypot(dx, dy);', [QVAR_LongParcours, JS_MATH_LIBRARY, JS_VARNAME_dx, JS_VARNAME_dy]); jsENDIF('', 6); WrtLinFmt(' %s.options[i].value = %s.IDNoeud;', [JS_DOCUMENT_FORM_lsbRoadMap, JS_VARNAME_CURRENT_NODE]); WrtLinFmt(' %s.options[i].text = %s.IDNoeud;', [JS_DOCUMENT_FORM_lsbRoadMap, JS_VARNAME_CURRENT_NODE]); jsNEXT('i', '', 4); WrtLinFmt(' %s = %s.ceil(%s / 10);', [QVAR_LongParcours, JS_MATH_LIBRARY, QVAR_LongParcours]); WrtLinFmt(' My%s.innerHTML = Nb.toString() + " stations (" + %s.toFixed(2) +" m)";', [JS_DOCUMENT_FORM_lbRoadmapNbPoints, QVAR_LongParcours]); EndJSFunction(); end; procedure QRedigeFunctionCalcCheminMinimalBetweenTwoNodes(); begin BeginJSFunction(JS_FUNCTION_CalcCheminMinimalBetweenTwoNodes, 'St1, St2'); WrtLinFmt(' %s.Dijkstra(St1, St2); ', [JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s(%s);', [JS_FUNCTION_DRAW_GRAPHE, JS_VAR_FLAG_DO_DRAW_GRAPHE]); WrtLinFmt(' %s();', [JS_FUNCTION_ListerRoadMap]); EndJSFunction(); end; procedure QRedigeCallbackOnResizeCanvas(); const FMT_FLOOR = ' %s = %s.floor(0.50 * (%s + %s));'; begin BeginJSFunction(JS_CALLBACK_CANVAS_OnResizeCanvas); jsSetLocalVar('r', Format('%s.clientHeight / %s.clientWidth', [JS_GLOBAL_VAR_MyContainer, JS_GLOBAL_VAR_MyContainer])); WrtLinFmt(' %s = %s.floor(%s + r * (%s - %s));', [JS_GLOBAL_VAR_FYMaxi, JS_MATH_LIBRARY, JS_GLOBAL_VAR_FYMini, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini]); WrtLinFmt(FMT_FLOOR, [JS_GLOBAL_VAR_FXCentreMap, JS_MATH_LIBRARY, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini]); WrtLinFmt(FMT_FLOOR, [JS_GLOBAL_VAR_FYCentreMap, JS_MATH_LIBRARY, JS_GLOBAL_VAR_FYMaxi, JS_GLOBAL_VAR_FYMini]); WrtLinFmt(' %s(%s);', [JS_FUNCTION_DRAW_GRAPHE, JS_VAR_FLAG_DO_DRAW_GRAPHE]); EndJSFunction(); end; procedure QRedigeCallbackOnClickCanvas(); begin BeginJSFunction(JS_CALLBACK_CANVAS_OnClickCanvas); (* WrtLinFmt(' var %s = %s.GetNoeud(%d);', [JS_VARNAME_CURRENT_NODE , JS_GRAPHE_CLASS_VAR_NAME, 1]); WrtLinFmt(' var Nb = %s.FindIdxNoeudNearestToXY(%s.X, %s.Y);', [JS_GRAPHE_CLASS_VAR_NAME, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); Wrtln( (' if (Nb >= 0)')); Wrtln( (' {')); WrtLinFmt(' var %s = %s.GetNoeud(%s);', ['QSt' , JS_GRAPHE_CLASS_VAR_NAME,'Nb']); WrtLinFmt(' window.alert("Station: " + %s.IDNoeud);', ['QSt']); Wrtln( (' }')); Wrtln( (' else')); Wrtln( (' {')); Wrtln( (' window.alert("Station introuvable");')); Wrtln( (' }')); WrtLinFmt(' var EWE = (Nb >= 0) ? "ID = " + %s.IDNoeud : "%s";', [JS_VARNAME_CURRENT_NODE, '']); //*) EndJSFunction(); end; procedure QRedigeCallbackOnMouseDownCanvas(); const FMT_DELTA = '%s - %s'; begin BeginJSFunction(JS_CALLBACK_CANVAS_OnMouseDownCanvas, 'e'); jsSetLocalVar('QX', 'e.x'); jsSetLocalVar('QY', 'e.y'); jsSetLocalVar('qdx', Format(FMT_DELTA, [JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini])); jsSetLocalVar('qdy', Format(FMT_DELTA, [JS_GLOBAL_VAR_FYMaxi, JS_GLOBAL_VAR_FYMini])); jsSetLocalVar('rx', Format('qdx / %s.width' , [JS_GLOBAL_VAR_MyCanvas])); jsSetLocalVar('ry', Format('qdy / %s.height', [JS_GLOBAL_VAR_MyCanvas])); jsSetLocalVar('XM', Format('rx * QX + %s', [JS_GLOBAL_VAR_FXMini])); jsSetLocalVar('YM', Format('-ry * QY + %s', [JS_GLOBAL_VAR_FYMaxi])); jsSetLocalVar('Nb', Format('%s.FindIdxNoeudNearestToXY(XM, YM)', [JS_GRAPHE_CLASS_VAR_NAME])); jsIF('Nb >= 0', '', 4); WrtLinFmt(' %s = %s.GetNoeud(%s);', [JS_GLOBAL_VAR_FGlobalNoeudCourant , JS_GRAPHE_CLASS_VAR_NAME,'Nb']); WrtLinFmt(' %s.innerHTML = "ID = " + %s.IDNoeud;', [JS_DOCUMENT_FORM_lbCanvasMousePos, JS_GLOBAL_VAR_FGlobalNoeudCourant]); jsELSE('', 4); WrtLinFmt(' %s.innerHTML = "%s";', [JS_DOCUMENT_FORM_lbCanvasMousePos, 'Not found']); jsENDIF('', 4); EndJSFunction(); end; procedure QRedigeFunctionsPanZoomPlan(); type TPanDirection = (tpdLEFT, tpdRIGHT, tpdUP, tpdDOWN); const QFMT_IDND = ' %s.value = %s.IDNoeud;'; FMT_FACTOR_EWE = ' %s %s= Factor * %s;'; FMT_DELTAXY = ' %s += Delta%s;'; FMT_FLOOR_DELTA = '%s.floor(0.05 * (%s - %s))'; procedure QRedigerPickingFunction(const QFuncPickName, QEditBoxName: string); const VAR_ST1 = 'QStDepart'; VAR_ST2 = 'QStArrivee'; begin BeginJSFunction(QFuncPickName); WrtLinFmt(QFMT_IDND, [QEditBoxName, JS_GLOBAL_VAR_FGlobalNoeudCourant]); jsSetLocalVar(VAR_ST1, format('%s.value', [JS_DOCUMENT_FORM_editStationDepart])); jsSetLocalVar(VAR_ST2, format('%s.value', [JS_DOCUMENT_FORM_editStationArrivee])); WrtLinFmt(' // %s', ['et recalculer le trajet thurlutté']); WrtLinFmt(' %s(%s, %s);', [JS_FUNCTION_CalcCheminMinimalBetweenTwoNodes, VAR_ST1, VAR_ST2]); EndJSFunction(); end; procedure QRedigerPanFunction(const QFuncPickName: string; const QDirection: TPanDirection); begin BeginJSFunction(QFuncPickName); case QDirection of tpdLEFT : EWE := ' PanVue( %s, 0);'; // JS_VUE_PanVueL tpdRIGHT: EWE := ' PanVue(-%s, 0);'; // JS_VUE_PanVueR tpdUP : EWE := ' PanVue(0, -%s);'; // JS_VUE_PanVueU tpdDOWN : EWE := ' PanVue(0, %s);'; // JS_VUE_PanVueD end; jsSetLocalVar(JS_VARNAME_LOCAL_EWE, Format(FMT_FLOOR_DELTA, [JS_MATH_LIBRARY, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini])); WrtLinFmt(EWE, [JS_VARNAME_LOCAL_EWE]); EndJSFunction(); end; procedure QRedigerZoomFunction(const QFuncZoomName: string; const QFacteur: integer); const QFMT_FUNC_ZOOM = ' ZoomVue(%d);'; begin BeginJSFunction(QFuncZoomName, ''); WrtLinFmt(QFMT_FUNC_ZOOM, [QFacteur]); EndJSFunction(); end; begin JSSeparateur('*', 100); WriteLine('// Zoom et pan vue'); BeginJSFunction('PanVue', 'DeltaX, DeltaY'); WrtLinFmt(FMT_DELTAXY, [JS_GLOBAL_VAR_FXMini, 'X']); WrtLinFmt(FMT_DELTAXY, [JS_GLOBAL_VAR_FXMaxi, 'X']); WrtLinFmt(FMT_DELTAXY, [JS_GLOBAL_VAR_FYMini, 'Y']); WrtLinFmt(FMT_DELTAXY, [JS_GLOBAL_VAR_FYMaxi, 'Y']); WrtLinFmt(' %s();', [JS_CALLBACK_CANVAS_OnResizeCanvas]); EndJSFunction(); BeginJSFunction('ZoomVue', 'Factor'); WrtLinFmt(' var %s = %s.floor(0.05 * (%s - %s));', [JS_VARNAME_LOCAL_EWE, JS_MATH_LIBRARY, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini]); WrtLinFmt(FMT_FACTOR_EWE, [JS_GLOBAL_VAR_FXMini, '+', JS_VARNAME_LOCAL_EWE]); WrtLinFmt(FMT_FACTOR_EWE, [JS_GLOBAL_VAR_FXMaxi, '-', JS_VARNAME_LOCAL_EWE]); WrtLinFmt(FMT_FACTOR_EWE, [JS_GLOBAL_VAR_FYMini, '+', JS_VARNAME_LOCAL_EWE]); WrtLinFmt(FMT_FACTOR_EWE, [JS_GLOBAL_VAR_FYMaxi, '-', JS_VARNAME_LOCAL_EWE]); WrtLinFmt(' %s();', [JS_CALLBACK_CANVAS_OnResizeCanvas]); EndJSFunction(); BeginJSFunction(JS_VUE_ResetVue, ''); WrtLinFmt(' %s = %s.GetXMini();', [JS_GLOBAL_VAR_FXMini, JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s = %s.GetXMaxi();', [JS_GLOBAL_VAR_FXMaxi, JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s = %s.GetYMini();', [JS_GLOBAL_VAR_FYMini, JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s = %s.GetYMaxi();', [JS_GLOBAL_VAR_FYMaxi, JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s();', [JS_CALLBACK_CANVAS_OnResizeCanvas]); EndJSFunction(); BeginJSFunction(JS_VUE_CentrerSurCourant, ''); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNCTION_CentrerSurXY, JS_GLOBAL_VAR_FGlobalNoeudCourant, JS_GLOBAL_VAR_FGlobalNoeudCourant]); EndJSFunction(); QRedigerPanFunction(JS_VUE_PanVueL , tpdLEFT); QRedigerPanFunction(JS_VUE_PanVueR , tpdRIGHT); QRedigerPanFunction(JS_VUE_PanVueU , tpdUP); QRedigerPanFunction(JS_VUE_PanVueD , tpdDOWN); QRedigerZoomFunction(JS_VUE_ZoomPlus , 1); QRedigerZoomFunction(JS_VUE_ZoomMoins, -1); QRedigerPickingFunction(JS_VUE_PickStationDep, JS_DOCUMENT_FORM_editStationDepart); QRedigerPickingFunction(JS_VUE_PickStationArr, JS_DOCUMENT_FORM_editStationArrivee); end; procedure QRedigeFunctionCentrerSurXY(); const FMT_FLOOR_DELTA = '%s.floor(0.5 * (%s - %s))'; begin BeginJSFunction(JS_FUNCTION_CentrerSurXY, 'QX, QY'); jsSetLocalVar('QL', format(FMT_FLOOR_DELTA, [JS_MATH_LIBRARY, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini])); jsSetLocalVar('QH', format(FMT_FLOOR_DELTA, [JS_MATH_LIBRARY, JS_GLOBAL_VAR_FYMaxi, JS_GLOBAL_VAR_FYMini])); WrtLinFmt(' %s = QX - QL;', [JS_GLOBAL_VAR_FXMini]); WrtLinFmt(' %s = QX + QL;', [JS_GLOBAL_VAR_FXMaxi]); WrtLinFmt(' %s = QY - QH;', [JS_GLOBAL_VAR_FYMini]); WrtLinFmt(' %s = QY + QH;', [JS_GLOBAL_VAR_FYMaxi]); WrtLinFmt(' %s();', [JS_CALLBACK_CANVAS_OnResizeCanvas]); EndJSFunction(); end; procedure QDrawShortestPath(const DoDrawEtiquettes: boolean; const LineWidth: integer; const LC: TColor; const LAlpha: byte); begin WrtLinFmt(' %s.strokeStyle = "rgba(%d, %d, %d, %.0f)";',[NAMEREF_CANVAS_DC, Red(LC), Green(LC), Blue(LC), LAlpha/256.0]); WrtLinFmt(' %s.lineWidth = %d;',[NAMEREF_CANVAS_DC, LineWidth]); WrtLinFmt(' var %s = %s.GetNoeud(%s.%s(0));',[JS_VARNAME_CURRENT_NODE, JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound]); WrtLinFmt(' %s.beginPath();',[NAMEREF_CANVAS_DC]); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNC_CoordsToPlan, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); WriteLine(' PS1X = PX;'); WriteLine(' PS1Y = PY;'); WrtLinFmt(' %s.moveTo(PS1X, PS1Y);', [NAMEREF_CANVAS_DC]); jsFOR('i', 'Nb', 0, '', 4); WrtLinFmt(' var %s = %s.GetNoeud(%s.%s(i));', [JS_VARNAME_CURRENT_NODE, JS_GRAPHE_CLASS_VAR_NAME, JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound]); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNC_CoordsToPlan, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); WriteLine(' PS1X = PX;'); WriteLine(' PS1Y = PY;'); WrtLinFmt(' %s.lineTo(PS1X, PS1Y);', [NAMEREF_CANVAS_DC]); if (DoDrawEtiquettes) then WrtLinFmt(' %s.fillText(%s.IDNoeud, PX + %d, PY + %d);', [NAMEREF_CANVAS_DC, JS_VARNAME_CURRENT_NODE, SIZE_STATION_MARKER + 1, SIZE_STATION_MARKER + 1]); jsNEXT('i'); WrtLinFmt(' %s.stroke();', [NAMEREF_CANVAS_DC]); end; procedure QRedigeFunctionDrawGraphe(); const QFMT_DELTA = '%s - %s'; QVAR_ETENDUE_X = 'QEtendueX'; QVAR_QIdxVoisin = 'QIdxVoisin'; QVAR_NbVoisins = 'NbVoisins'; QVAR_MyNodeVoisin = 'MyNodeVoisin'; procedure QRedigeNestConvFunc(); begin WriteLine(' // Fonction nested de conversion'); BeginJSFunction(JS_FUNC_CoordsToPlan, 'QX, QY'); jsSetLocalVar('qdx', Format(QFMT_DELTA, [JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini])); jsSetLocalVar('qdy', Format(QFMT_DELTA, [JS_GLOBAL_VAR_FYMaxi, JS_GLOBAL_VAR_FYMini])); jsSetLocalVar('XM', format('QX - %s', [JS_GLOBAL_VAR_FXMini])); jsSetLocalVar('YM', format('QY - %s', [JS_GLOBAL_VAR_FYMini])); jsSetLocalVar('r' , format('%s.width / qdx', [JS_GLOBAL_VAR_MyCanvas])); WrtLinFmt(' PX = %s.floor(r * XM);', [JS_MATH_LIBRARY]); WrtLinFmt(' PY = %s.height - %s.floor(r * YM);', [JS_GLOBAL_VAR_MyCanvas, JS_MATH_LIBRARY]); EndJSFunction(); WriteLine(' // Fin fonctions nested') end; begin BeginJSFunction(JS_FUNCTION_DRAW_GRAPHE, 'DoDrawLabelStations'); WrtLinFmt(' var Nb = %s.GetNbNoeuds();', [JS_GRAPHE_CLASS_VAR_NAME]); WriteLine(' if (Nb === 0) return;'); WrtLinFmt(' %s.width = %s.clientWidth;', [JS_GLOBAL_VAR_MyCanvas, JS_GLOBAL_VAR_MyContainer]); WrtLinFmt(' %s.height = %s.clientHeight;', [JS_GLOBAL_VAR_MyCanvas, JS_GLOBAL_VAR_MyContainer]); WrtLinFmt(' var %s = %s.getContext("%s");', [NAMEREF_CANVAS_DC, JS_GLOBAL_VAR_MyCanvas, '2d']); WrtLinFmt(' %s.strokeStyle = "rgba(%d, %d, %d, %.0f)";', [NAMEREF_CANVAS_DC, Red(CouleurCenterlines), Green(CouleurCenterlines), Blue(CouleurCenterlines), 1.0]); WrtLinFmt(' %s.lineWidth = "%dpx";', [NAMEREF_CANVAS_DC, QLineWidth]); WrtLinFmt(' %s.fillStyle = "rgba(200, 0, 0, 1)";', [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.font = "%dpx %s";', [NAMEREF_CANVAS_DC, 12, 'sans-serif']); WriteLine(' // variables semi-globales'); jsSetLocalVar('PX', 0); jsSetLocalVar('PY', 0); jsSetLocalVar('PS1X', 0); jsSetLocalVar('PS1Y', 0); jsSetLocalVar('PS2X', 0); jsSetLocalVar('PS2Y', 0); QRedigeNestConvFunc(); WriteLine(' // Traçage du graphe'); jsSetLocalVar(QVAR_ETENDUE_X, Format(QFMT_DELTA,[JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FXMini]), 'Etendue du réseau en X'); jsFOR('i', 'Nb', 0, '', 4); WrtLinFmt(' %s = %s.GetNoeud(i);', [JS_VARNAME_CURRENT_NODE, JS_GRAPHE_CLASS_VAR_NAME]); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNC_CoordsToPlan, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); WriteLine(' PS1X = PX;'); WriteLine(' PS1Y = PY;'); WrtLinFmt(' %s.fillRect(PX - %d, PY - %d, %d, %d);', [NAMEREF_CANVAS_DC, SIZE_STATION_MARKER, SIZE_STATION_MARKER, 2 * SIZE_STATION_MARKER, 2 * SIZE_STATION_MARKER]); WrtLinFmt(' if (%s < %.0f) %s.fillText(%s.IDNoeud, PX + %d, PY + %d);', [QVAR_ETENDUE_X, 10 * ETENDUE_X_MAX_FOR_DISP_LBL_STATIONS, NAMEREF_CANVAS_DC, JS_VARNAME_CURRENT_NODE, SIZE_STATION_MARKER + 1, SIZE_STATION_MARKER + 1]); jsSetLocalVar(QVAR_NbVoisins, Format('%s.ListeVoisins.length', [JS_VARNAME_CURRENT_NODE])); jsIF(Format('%s > 0', [QVAR_NbVoisins]), '', 4); jsFOR('k', QVAR_NbVoisins, 0, '', 6); //WriteLine(' for (var k = 0; k < NbVoisins; k++)'); jsSetLocalVar(QVAR_QIdxVoisin, Format('%s.ListeVoisins[%s]', [JS_VARNAME_CURRENT_NODE, 'k'])); jsSetLocalVar(QVAR_MyNodeVoisin, Format('%s.GetNoeud(%s)', [JS_GRAPHE_CLASS_VAR_NAME, QVAR_QIdxVoisin])); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNC_CoordsToPlan, QVAR_MyNodeVoisin, QVAR_MyNodeVoisin]); WrtLinFmt(' %s.beginPath();' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.moveTo(PS1X, PS1Y);' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.lineTo(PX , PY);' , [NAMEREF_CANVAS_DC]); WrtLinFmt(' %s.stroke();' , [NAMEREF_CANVAS_DC]); jsNEXT('k', '', 6); jsENDIF('', 4); jsNEXT('i'); WriteLine(' // On trace le réticule'); // WrtLinFmt(' %s.strokeStyle = "rgba(%d, %d, %d, %.0f)";', [NAMEREF_CANVAS_DC, Red(clGray), Green(clGray), Blue(clGray), 192/256.0]); WrtLinFmt(' %s.lineWidth = "%dpx";', [NAMEREF_CANVAS_DC, QLineWidth]); JSTraceLigne(JS_GLOBAL_VAR_FXMini, JS_GLOBAL_VAR_FYCentreMap, JS_GLOBAL_VAR_FXMaxi, JS_GLOBAL_VAR_FYCentreMap); JSTraceLigne(JS_GLOBAL_VAR_FXCentreMap, JS_GLOBAL_VAR_FYMini, JS_GLOBAL_VAR_FXCentreMap, JS_GLOBAL_VAR_FYMaxi); WriteLine(' // Tracé du plus court chemin: '); WrtLinFmt(' Nb = %s.%s();', [JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetNbStationsOfPathFound]); jsIF('Nb > 2', '', 4); QDrawShortestPath(false, 7, clRed , 128); QDrawShortestPath(false, 4, clYellow , 192); QDrawShortestPath(true , 1, clMaroon , 255); jsENDIF('', 4); WriteLine(' // et on met en évidence le dernier point trouvé'); jsIF(Format('%s >= 0', [JS_GLOBAL_VAR_FLastIdxFound]), '', 4); WrtLinFmt(' %s.font = "%dpx %s";', [NAMEREF_CANVAS_DC, 16, 'sans-serif']); WrtLinFmt(' %s = %s.GetNoeud(%s);', [JS_VARNAME_CURRENT_NODE, JS_GRAPHE_CLASS_VAR_NAME, JS_GLOBAL_VAR_FLastIdxFound]); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNC_CoordsToPlan, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); WrtLinFmt(' %s.fillText(%s.IDNoeud, PX + %d, PY + %d);', [NAMEREF_CANVAS_DC, JS_VARNAME_CURRENT_NODE, SIZE_STATION_MARKER + 1, SIZE_STATION_MARKER + 1]); jsENDIF('', 4); EndJSFunction(); end; // interaction avec la page procedure QRedigeFunctionProcOnSubmit(); // OK begin BeginJSFunction(JS_DOCUMENT_FORM_btnSearch_ProcOnSubmit); jsSetLocalVar(JS_VARNAME_LOCAL_EWE, format('%s.value', [JS_DOCUMENT_FORM_editFindWhat])); jsSetLocalVar('QIdx',format('%s.FindIdxNoeudByCle(%s)', [JS_GRAPHE_CLASS_VAR_NAME, JS_VARNAME_LOCAL_EWE])); jsIF('QIdx >= 0', '', 4); WrtLinFmt(' %s = QIdx;', [JS_GLOBAL_VAR_FLastIdxFound]); jsSetLocalVar(JS_VARNAME_CURRENT_NODE, format('%s.GetNoeud(%s)', [JS_GRAPHE_CLASS_VAR_NAME, JS_GLOBAL_VAR_FLastIdxFound])); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNCTION_CentrerSurXY, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); jsELSE('', 4); WrtLinFmt(' window.alert("Station " + %s + " introuvable");', [JS_VARNAME_LOCAL_EWE]); jsENDIF('', 4); EndJSFunction(); end; procedure QRedigeFunctionBtnCalcShortestPathClick(); const VAR_ST1 = 'St1'; VAR_ST2 = 'St2'; begin BeginJSFunction(JS_DOCUMENT_FORM_btnCalcShortestPath_ProcOnSubmit); JSToto('départ' , JS_DOCUMENT_FORM_editStationDepart , VAR_ST1, 'IdxSt1'); JSToto('arrivée' , JS_DOCUMENT_FORM_editStationArrivee, VAR_ST2, 'IdxSt2'); WrtLinFmt(' %s(%s, %s);', [JS_FUNCTION_CalcCheminMinimalBetweenTwoNodes, VAR_ST1, VAR_ST2]); EndJSFunction(); end; procedure QRedigeFunctionBtnSwapDepartArriveeClick(); const FMT_AFFECTER_VAR = ' %s = %s;'; VAR_ST1 = 'St1'; VAR_ST2 = 'St2'; VAR_TMP = 'tmp'; begin BeginJSFunction(JS_DOCUMENT_FORM_btnSwapDepartArrivee_ProcOnSubmit); jsSetLocalVar(VAR_ST1, format('%s.value', [JS_DOCUMENT_FORM_editStationDepart])); jsSetLocalVar(VAR_ST2, format('%s.value', [JS_DOCUMENT_FORM_editStationArrivee])); jsSetLocalVar(VAR_TMP, '""'); WrtLinFmt(FMT_AFFECTER_VAR, [VAR_TMP, VAR_ST1]); WrtLinFmt(FMT_AFFECTER_VAR, [VAR_ST1, VAR_ST2]); WrtLinFmt(FMT_AFFECTER_VAR, [VAR_ST2, VAR_TMP]); WrtLinFmt(' %s.value = %s;', [JS_DOCUMENT_FORM_editStationDepart , VAR_ST1]); WrtLinFmt(' %s.value = %s;', [JS_DOCUMENT_FORM_editStationArrivee, VAR_ST2]); WrtLinFmt(' // %s', ['et recalculer le trajet']); WrtLinFmt(' %s(%s, %s);', [JS_FUNCTION_CalcCheminMinimalBetweenTwoNodes, VAR_ST1, VAR_ST2]); EndJSFunction(); end; procedure QRedigeFunctionLsbRoadmapOnSelect(); const QVAR_QIdxPathPtCurr = 'QIdxPathPtCurr'; QVAR_QIdxPathPtNext = 'QIdxPathPtNext'; QFMT_COORDS_INNER_HTML = ' %s.innerHTML = "%s: " + %s.%s.toFixed(2);'; procedure MiouMiouIF(const QVar: string); begin WriteLine(Format(' if (%s === %d) return;', [QVar, -1])); end; begin WriteLine('// Interaction avec la feuille de route'); BeginJSFunction(JS_DOCUMENT_FORM_lsbRoadmap_ProcOnSelect, ''); jsSetLocalVar('QIdx', Format('%s.selectedIndex', [JS_DOCUMENT_FORM_lsbRoadMap]), 'Index courant'); jsSetLocalVar(QVAR_QIdxPathPtCurr, Format('%s.%s(%s)', [JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound, 'QIdx']), 'Recherche du point courant'); MiouMiouIF(QVAR_QIdxPathPtCurr); jsSetLocalVar(JS_VARNAME_CURRENT_NODE, Format('%s.GetNoeud(%s)', [JS_GRAPHE_CLASS_VAR_NAME, QVAR_QIdxPathPtCurr]), ''); WriteLine(' // et centrage sur le point courant'); WrtLinFmt(' %s(%s.X, %s.Y);', [JS_FUNCTION_CentrerSurXY, JS_VARNAME_CURRENT_NODE, JS_VARNAME_CURRENT_NODE]); jsSetLocalVar(QVAR_QIdxPathPtNext, Format('%s.%s(%s)', [JS_GRAPHE_CLASS_VAR_NAME, JS_FUNCTION_GetIdxNoeudOfPathFound, 'QIdx + 1']), 'Recherche du point suivant'); MiouMiouIF(QVAR_QIdxPathPtNext); jsSetLocalVar(JS_VARNAME_NEXT_NODE, Format('%s.GetNoeud(%s)', [JS_GRAPHE_CLASS_VAR_NAME, QVAR_QIdxPathPtNext]), ''); jsSetLocalVar(JS_VARNAME_CapToNext, Format('%s(%s.X - %s.X, %s.Y - %s.Y, %s.Z - %s.Z, %s, %s)', [JS_UTILITY_FUNC_GetBearingInc, JS_VARNAME_NEXT_NODE, JS_VARNAME_CURRENT_NODE, JS_VARNAME_NEXT_NODE, JS_VARNAME_CURRENT_NODE, JS_VARNAME_NEXT_NODE, JS_VARNAME_CURRENT_NODE, FormatterNombreWithDotDecimal(360.00, 2), FormatterNombreWithDotDecimal(360.00, 2)]), 'Cap et distance'); WrtLinFmt(' %s.innerHTML = "Next: " + %s.IDNoeud;' , [JS_DOCUMENT_FORM_lbCanvasMousePos, JS_VARNAME_NEXT_NODE]); WrtLinFmt(QFMT_COORDS_INNER_HTML, [JS_DOCUMENT_FORM_lbDistNextPoint , 'Dist', JS_VARNAME_CapToNext, JS_VARNAME_OUT_Dist]); WrtLinFmt(QFMT_COORDS_INNER_HTML, [JS_DOCUMENT_FORM_lbAzimutNextPoint, 'Cap' , JS_VARNAME_CapToNext, JS_VARNAME_OUT_Az]); WrtLinFmt(QFMT_COORDS_INNER_HTML, [JS_DOCUMENT_FORM_lbPenteNextPoint , 'Incl', JS_VARNAME_CapToNext, JS_VARNAME_OUT_Inc]); EndJSFunction(); end; // listeners et autres procedure QInitialiserEventsOfTactilePointer(); begin WriteLine(' // Gestion des mouvements de doigts sur la tablette (gestures)'); WriteLine(' // A implanter dans Initialiser() après assignation des contrôles via GetElementByID()'); WriteLine(' // https://developer.mozilla.org/fr/docs/Web/API/Pointer_events/gestes_pincer_zoom'); WrtLinFmt(' %s.onpointerdown = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointerdown_handler]); WrtLinFmt(' %s.onpointerup = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointerup_handler]); WrtLinFmt(' %s.onpointercancel = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointerup_handler]); WrtLinFmt(' %s.onpointermove = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointermove_handler]); WrtLinFmt(' %s.onpointerout = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointerup_handler]); WrtLinFmt(' %s.onpointerleave = %s;', [JS_GLOBAL_VAR_MyCanvas, JS_TACTILE_EVENT_pointerup_handler]); WriteLine(' // Fin Gestures'); end; procedure QRedigerTactileHandlers(); const ARG_EVENT = 'event'; COUNTER_VAR = 'i'; VAR_CURRDIFF = 'currDiff'; var WU: String; begin WriteLine('// Callbacks des handlers de tactile'); BeginJSFunction(JS_TACTILE_PROC_remove_event, ARG_EVENT); // Supprime l'événement du cache WU := Format('%s.length', [ARG_EVENT]); jsFOR(COUNTER_VAR, WU, 0, '', 4); jsIF(Format('%s[%s].pointerId === %s.pointerId', [JS_GLOBAL_VAR_EvtCache, COUNTER_VAR, ARG_EVENT]), '', 6); WrtLinFmt(' %s.splice(%s, %d);', [JS_GLOBAL_VAR_EvtCache, COUNTER_VAR, 1]); jsBREAK(8); jsENDIF('', 6); jsNEXT(COUNTER_VAR, '', 4); EndJSFunction(); // L'événement pointerdown signale le début d'une interraction de toucher. // OnMouseDown BeginJSFunction(JS_TACTILE_EVENT_pointerdown_handler, ARG_EVENT); // L'événement est mis en cache pour prendre en charge les gestes à 2 doigts WrtLinFmt(' %s.push(%s);', [JS_GLOBAL_VAR_EvtCache, ARG_EVENT]); //WrtLinFmt(' console.log("%s", %s);', [JS_TACTILE_EVENT_pointerdown_handler, ARG_EVENT]); EndJSFunction(); // OnMouseMove BeginJSFunction(JS_TACTILE_EVENT_pointermove_handler, ARG_EVENT); //WrtLinFmt(' console.log("%s", %s);', [JS_TACTILE_EVENT_pointermove_handler, ARG_EVENT]); // Trouve le pointeur en cours dans le cache et le met à jour avec cet événement WU := Format('%s.length', [ARG_EVENT]); jsFOR(COUNTER_VAR, WU, 0, '', 4); jsIF(Format('%s.pointerId === %s[%s].pointerId', [ARG_EVENT, JS_GLOBAL_VAR_EvtCache, COUNTER_VAR]), '', 6); // if (ev.pointerId == evCache[i].pointerId) { WrtLinFmt(' %s[%s] = %s;', [JS_GLOBAL_VAR_EvtCache, COUNTER_VAR, ARG_EVENT]); // evCache[i] = ev; jsBREAK(8); jsENDIF('', 4); jsNEXT(COUNTER_VAR, '', 4); // Si deux pointeurs sont utilisés, vérifie le geste de pincement jsIF(Format('%s.length === %d', [ARG_EVENT, 2]), '', 4); // if (evCache.length == 2) { WrtLinFmt(' var %s = %s.abs(%s[%d].clientX - %s[%d].clientX);', [VAR_CURRDIFF, JS_MATH_LIBRARY, JS_GLOBAL_VAR_EvtCache, 0, JS_GLOBAL_VAR_EvtCache, 1]); jsIF(Format('%s > %d', [JS_GLOBAL_VAR_PrevDiff, 0]), '', 6); jsIF(Format('%s > %s', [VAR_CURRDIFF, JS_GLOBAL_VAR_PrevDiff, 0]), 'La distance entre les deux pointeurs a augmenté', 8); //WrtLinFmt(' console.log("%s");', ['Zoom Plus']); jsENDIF('', 8); jsIF(Format('%s < %s', [VAR_CURRDIFF, JS_GLOBAL_VAR_PrevDiff, 0]), 'La distance entre les deux pointeurs a diminué', 8); //WrtLinFmt(' console.log("%s");', ['Zoom Moins']); jsENDIF('', 8); jsENDIF('', 6); jsENDIF('', 4); WrtLinFmt('%s = %s; // %s', [JS_GLOBAL_VAR_PrevDiff, VAR_CURRDIFF, 'Met en cache la distance pour les événements suivants']); EndJSFunction(); // OnMouseUp BeginJSFunction(JS_TACTILE_EVENT_pointerup_handler, ARG_EVENT); WrtLinFmt(' console.log("%s", %s);', [JS_TACTILE_EVENT_pointerup_handler, ARG_EVENT]); // Retire ce pointeur du cache et rétablit l'arrière-plan et WrtLinFmt(' %s(%s);', [JS_TACTILE_PROC_remove_event, ARG_EVENT]); // traitements //ev.target.style.border = "1px solid black"; // Si le nombre de pointeurs restant est inférieur à deux, remet à zéro la différence WrtLinFmt(' if (%s.length < %d) %s = -1;', [JS_GLOBAL_VAR_EvtCache, 2, JS_GLOBAL_VAR_PrevDiff]); EndJSFunction(); end;