Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Mappe - programmering 2
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Sverre Grønhaug Halvorsen
Mappe - programmering 2
Merge requests
!32
Resolve "Enable zoom on Transformation"
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Resolve "Enable zoom on Transformation"
23-enable-zoom-on-transformation
into
dev
Overview
0
Commits
4
Pipelines
2
Changes
2
Merged
Sverre Grønhaug Halvorsen
requested to merge
23-enable-zoom-on-transformation
into
dev
1 year ago
Overview
0
Commits
4
Pipelines
2
Changes
2
Expand
Closes
#23 (closed)
0
0
Merge request reports
Compare
dev
version 1
5c03c2c7
1 year ago
dev (base)
and
latest version
latest version
da4496f4
4 commits,
1 year ago
version 1
5c03c2c7
3 commits,
1 year ago
2 files
+
170
−
28
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
2
Search (e.g. *.vue) (Ctrl+P)
src/main/java/edu/ntnu/idatt2003/view/ChaosImage.java
+
165
−
23
Options
package
edu.ntnu.idatt2003.view
;
import
edu.ntnu.idatt2003.model.ChaosCanvas
;
import
javafx.beans.property.ObjectProperty
;
import
javafx.beans.property.SimpleObjectProperty
;
import
javafx.geometry.Point2D
;
import
javafx.scene.image.ImageView
;
import
javafx.scene.image.WritableImage
;
import
javafx.scene.input.ScrollEvent
;
import
javafx.scene.layout.Pane
;
import
javafx.scene.layout.StackPane
;
import
javafx.scene.paint.Color
;
import
javafx.scene.shape.Rectangle
;
import
javafx.scene.transform.Scale
;
/**
* The ChaosImage class provides methods for creating and manipulating images based on a
@@ -10,18 +19,23 @@ import javafx.scene.paint.Color;
* an image by a specified factor.
*/
public
class
ChaosImage
{
class
ChaosImage
{
private
static
final
int
MAX_SCALE
=
5
;
private
static
final
int
MIN_SCALE
=
1
;
private
static
final
double
ZOOM_FACTOR
=
1.05
;
private
ChaosImage
()
{
}
/**
* Creates a WritableImage from a given ChaosCanvas object.
* Each element in the canvas array is mapped to a pixel in the image,
* where a value of 1 is black and 0 is white.
*
* @param chaosCanvas The ChaosCanvas object containing the data for the image.
* @return A
WritableImage
representing the canvas data.
* @return A
Pane containing the image generated
representing the canvas data.
*/
public
static
WritableImag
e
createImageFromCanvas
(
ChaosCanvas
chaosCanvas
)
{
public
static
Pan
e
createImageFromCanvas
(
ChaosCanvas
chaosCanvas
)
{
int
width
=
chaosCanvas
.
getWidth
();
int
height
=
chaosCanvas
.
getHeight
();
WritableImage
image
=
new
WritableImage
(
width
,
height
);
@@ -36,34 +50,162 @@ public class ChaosImage {
}
}
}
ImageView
imageView
=
new
ImageView
(
image
);
imageView
.
setFitWidth
(
600
);
imageView
.
setFitHeight
(
600
);
Pane
pane
=
new
Pane
(
imageView
);
pane
.
setMaxHeight
(
height
);
pane
.
setMaxWidth
(
width
);
StackPane
.
setAlignment
(
imageView
,
javafx
.
geometry
.
Pos
.
CENTER
);
pane
.
setClip
(
new
Rectangle
(
600
,
600
));
enableZoom
(
imageView
);
enablePan
(
imageView
);
return
pane
;
}
return
image
;
/**
* Enables zooming on an ImageView object, using a Scale transform.
*
* @param imageView The ImageView object to enable zooming on.
*/
private
static
void
enableZoom
(
ImageView
imageView
)
{
Scale
scaleTransform
=
new
Scale
();
imageView
.
getTransforms
().
add
(
scaleTransform
);
imageView
.
setOnScroll
(
e
->
zoom
(
imageView
,
e
));
}
/**
* Enables panning on an ImageView object, by translating the image based on mouse drag events
* and the last mouse coordinates. The panning is limited to the edges of the image.
*
* @param imageView The ImageView object to enable panning on.
*/
private
static
void
enablePan
(
ImageView
imageView
)
{
final
ObjectProperty
<
Point2D
>
lastMouseCoordinates
=
new
SimpleObjectProperty
<>();
imageView
.
setOnMousePressed
(
e
->
lastMouseCoordinates
.
set
(
new
Point2D
(
e
.
getX
(),
e
.
getY
())));
imageView
.
setOnMouseDragged
(
e
->
{
double
deltaX
=
e
.
getX
()
-
lastMouseCoordinates
.
get
().
getX
();
double
deltaY
=
e
.
getY
()
-
lastMouseCoordinates
.
get
().
getY
();
int
newX
=
(
int
)
(
imageView
.
getTranslateX
()
+
deltaX
);
int
newY
=
(
int
)
(
imageView
.
getTranslateY
()
+
deltaY
);
checkEdgesPan
(
imageView
,
newX
,
newY
);
});
}
/**
* Scales a given WritableImage by a specified factor.
* The method creates a new image with dimensions scaled by the scaleFactor and copies the color
* data from the original image.
* Zooms in or out on an ImageView object based on the scroll event, by scaling the image.
* The zooming is centered around the mouse position.
*
* @param image The original WritableImage to be scaled.
* @param scaleFactor The factor by which to scale the image. A scaleFactor > 1 enlarges the
* image,while a scaleFactor < 1 reduces its size.
* @return A new WritableImage that is scaled by the specified factor.
* @param imageView The ImageView object to enable panning on.
*/
private
static
void
zoom
(
ImageView
imageView
,
ScrollEvent
e
)
{
double
zoomFactor
=
calculateZoomFactor
(
e
.
getDeltaY
());
public
static
WritableImage
scaleImage
(
WritableImage
image
,
double
scaleFactor
)
{
int
newWidth
=
(
int
)
(
image
.
getWidth
()
*
scaleFactor
);
int
newHeight
=
(
int
)
(
image
.
getHeight
()
*
scaleFactor
);
WritableImage
scaledImage
=
new
WritableImage
(
newWidth
,
newHeight
);
for
(
int
y
=
0
;
y
<
newHeight
;
y
++)
{
for
(
int
x
=
0
;
x
<
newWidth
;
x
++)
{
Color
originalColor
=
image
.
getPixelReader
()
.
getColor
((
int
)
(
x
/
scaleFactor
),
(
int
)
(
y
/
scaleFactor
));
scaledImage
.
getPixelWriter
().
setColor
(
x
,
y
,
originalColor
);
}
final
double
scaleBefore
=
imageView
.
getScaleX
();
double
scale
=
imageView
.
getScaleX
()
*
zoomFactor
;
scale
=
clamp
(
scale
,
MIN_SCALE
,
MAX_SCALE
);
imageView
.
setScaleX
(
scale
);
imageView
.
setScaleY
(
scale
);
double
mouseX
=
e
.
getX
()
-
imageView
.
getFitWidth
()
/
2
;
double
mouseY
=
e
.
getY
()
-
imageView
.
getFitHeight
()
/
2
;
double
newTranslateX
=
calculateNewTranslate
(
mouseX
,
scale
,
scaleBefore
,
imageView
.
getTranslateX
());
double
newTranslateY
=
calculateNewTranslate
(
mouseY
,
scale
,
scaleBefore
,
imageView
.
getTranslateY
());
checkEdgesZoom
(
imageView
,
newTranslateX
,
newTranslateY
);
}
/**
* Checks if the image is within the bounds of the ImageView after zooming.
* If the image is outside the bounds, the image is translated back into the bounds.
*
* @param imageView The ImageView object to check the edges of.
* @param newX The new x-coordinate of the image.
* @param newY The new y-coordinate of the image.
*/
private
static
void
checkEdgesZoom
(
ImageView
imageView
,
double
newX
,
double
newY
)
{
double
imageWidthHalf
=
imageView
.
getFitWidth
()
/
2
;
double
imageHeightHalf
=
imageView
.
getFitHeight
()
/
2
;
if
((
newX
+
imageWidthHalf
)
/
imageView
.
getScaleX
()
<=
imageWidthHalf
&&
(
newX
-
imageWidthHalf
)
/
imageView
.
getScaleX
()
>=
-
imageWidthHalf
)
{
imageView
.
setTranslateX
(
newX
);
}
else
if
(
imageView
.
getScaleX
()
<=
1
)
{
imageView
.
setTranslateX
(
0
);
}
if
((
newY
+
imageHeightHalf
)
/
imageView
.
getScaleY
()
<=
imageHeightHalf
&&
(
newY
-
imageHeightHalf
)
/
imageView
.
getScaleY
()
>=
-
imageHeightHalf
)
{
imageView
.
setTranslateY
(
newY
);
}
else
if
(
imageView
.
getScaleY
()
<=
1
)
{
imageView
.
setTranslateY
(
0
);
}
return
scaledImage
;
}
}
/**
* Checks if the image is within the bounds of the ImageView after panning.
* If the image is outside the bounds, the image is not moved.
*
* @param imageView The ImageView object to check the edges of.
* @param newX The new x-coordinate of the image.
* @param newY The new y-coordinate of the image.
*/
private
static
void
checkEdgesPan
(
ImageView
imageView
,
double
newX
,
double
newY
)
{
double
imageWidthHalf
=
imageView
.
getFitWidth
()
/
2
;
double
imageHeightHalf
=
imageView
.
getFitHeight
()
/
2
;
if
((
newX
+
imageWidthHalf
)
/
imageView
.
getScaleX
()
<=
imageWidthHalf
&&
(
newX
-
imageWidthHalf
)
/
imageView
.
getScaleX
()
>=
-
imageWidthHalf
)
{
imageView
.
setTranslateX
(
newX
);
}
if
((
newY
+
imageHeightHalf
)
/
imageView
.
getScaleY
()
<=
imageHeightHalf
&&
(
newY
-
imageHeightHalf
)
/
imageView
.
getScaleY
()
>=
-
imageHeightHalf
)
{
imageView
.
setTranslateY
(
newY
);
}
}
/**
* Calculates the zoom factor based on the way the mouse wheel is scrolled.
* if deltaY is negative, the image is zoomed out, otherwise it is zoomed in.
* The zoom factor is calculated as 1.05, for zooming in, and 1/1.05 for zooming out.
*
* @param deltaY The amount the mouse wheel is scrolled.
* @return The calculated zoom factor.
*/
private
static
double
calculateZoomFactor
(
double
deltaY
)
{
return
deltaY
<
0
?
1
/
ZOOM_FACTOR
:
ZOOM_FACTOR
;
}
/**
* Calculates the new translation of the image after zooming, based on the mouse position,
* the scale factor after zooming, the scale factor before zooming, and the translation before
* zooming.
*
* @param mousePosition The position of the mouse.
* @param scale The scale factor after zooming.
* @param scaleBefore The scale factor before zooming.
* @param translateBefore The translation before zooming.
* @return The new translation of the image.
*/
private
static
double
calculateNewTranslate
(
double
mousePosition
,
double
scale
,
double
scaleBefore
,
double
translateBefore
)
{
return
-
mousePosition
*
scale
+
mousePosition
*
scaleBefore
+
translateBefore
;
}
/**
* Clamp a value between a minimum and maximum value. Makes sure the value is within the bounds.
*
* @param value The value to clamp.
* @param min The minimum value.
* @param max The maximum value.
* @return The clamped value.
*/
private
static
double
clamp
(
double
value
,
double
min
,
double
max
)
{
return
Math
.
max
(
min
,
Math
.
min
(
max
,
value
));
}
}
\ No newline at end of file
Loading