@@ -135,7 +135,40 @@ ExitStatus App::Application::run() {
135135 const ImVec2 canvas_p0 = ImGui::GetCursorScreenPos ();
136136 const ImVec2 canvas_sz = ImGui::GetContentRegionAvail ();
137137 const auto canvas_p1 = ImVec2 (canvas_p0.x + canvas_sz.x , canvas_p0.y + canvas_sz.y );
138- const ImVec2 origin (canvas_p0.x + canvas_sz.x * 0 .5f , canvas_p0.y + canvas_sz.y * 0 .5f );
138+ // --- PANNING IMPLEMENTATION BEGIN ---
139+ static bool isPanning = false ;
140+ static ImVec2 lastMousePos = {0 .0f , 0 .0f };
141+ static ImVec2 originOffset = {0 .0f , 0 .0f };
142+
143+ // Get mouse position
144+ ImVec2 mousePos = ImGui::GetMousePos ();
145+
146+ // Detect click start only when cursor is inside the graphing area
147+ if (ImGui::IsWindowHovered () && ImGui::IsMouseClicked (ImGuiMouseButton_Left)) {
148+ isPanning = true ;
149+ lastMousePos = mousePos;
150+ }
151+
152+ // Stop panning when mouse released
153+ if (ImGui::IsMouseReleased (ImGuiMouseButton_Left)) {
154+ isPanning = false ;
155+ }
156+
157+ // While dragging, update origin offset
158+ if (isPanning && ImGui::IsMouseDragging (ImGuiMouseButton_Left)) {
159+ ImVec2 delta = ImVec2 (mousePos.x - lastMousePos.x , mousePos.y - lastMousePos.y );
160+ originOffset.x += delta.x ;
161+ originOffset.y += delta.y ;
162+ lastMousePos = mousePos;
163+ }
164+
165+ // Apply offset to origin
166+ const ImVec2 origin (
167+ canvas_p0.x + canvas_sz.x * 0 .5f + originOffset.x ,
168+ canvas_p0.y + canvas_sz.y * 0 .5f + originOffset.y
169+ );
170+ // --- PANNING IMPLEMENTATION END ---
171+
139172 float lineThickness = 6 .0f ;
140173 draw_list->AddLine (ImVec2 (canvas_p0.x , origin.y ), ImVec2 (canvas_p1.x , origin.y ), IM_COL32 (0 , 0 , 0 , 255 ), lineThickness);
141174 draw_list->AddLine (ImVec2 (origin.x , canvas_p0.y ), ImVec2 (origin.x , canvas_p1.y ), IM_COL32 (0 , 0 , 0 , 255 ), lineThickness);
@@ -191,12 +224,13 @@ ExitStatus App::Application::run() {
191224 const double t_step = 0.02 ;
192225
193226 for (t = t_min; t <= t_max; t += t_step) {
194- const double vx = expr_fx.value ();
195- const double vy = expr_gx.value ();
196-
197-
198- ImVec2 screen_pos (origin.x + static_cast <float >(vx * zoom),
199- origin.y - static_cast <float >(vy * zoom));
227+ const double vx = expr_fx.value ();
228+ const double vy = expr_gx.value ();
229+ // The 'origin' variable already includes the pan offset.
230+ ImVec2 screen_pos (
231+ origin.x + static_cast <float >(vx * zoom),
232+ origin.y - static_cast <float >(vy * zoom)
233+ );
200234 points.push_back (screen_pos);
201235 }
202236
@@ -226,11 +260,18 @@ ExitStatus App::Application::run() {
226260 exprtk::parser<double > parser;
227261 parser.compile (function, expression);
228262
229- for (x = -canvas_sz.x / (2 * zoom); x < canvas_sz.x / (2 * zoom); x += 0.05 ) {
230- const double y = expression.value ();
263+ // Calculate the visible x-range in world-space, accounting for the pan
264+ const float world_x_min = (-canvas_sz.x * 0 .5f - originOffset.x ) / zoom;
265+ const float world_x_max = ( canvas_sz.x * 0 .5f - originOffset.x ) / zoom;
231266
232-
233- ImVec2 screen_pos (origin.x + x * zoom, origin.y - y * zoom);
267+ // Evaluate the function across the correct visible world-range
268+ for (x = world_x_min; x <= world_x_max; x += 0.05 ) {
269+ const double y = expression.value ();
270+ // The 'origin' variable already includes the pan offset.
271+ ImVec2 screen_pos (
272+ origin.x + static_cast <float >(x * zoom),
273+ origin.y - static_cast <float >(y * zoom)
274+ );
234275 points.push_back (screen_pos);
235276 }
236277
0 commit comments