Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 23
Expand All @@ -24,7 +25,7 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.github.Lukle:ClickableAreasImages:v0.1'
implementation project(':clickableareasimage')
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
// compile project(':clickableareasimage')
Expand Down
59 changes: 42 additions & 17 deletions app/src/main/java/at/lukle/clickableareas/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
Expand All @@ -11,11 +12,17 @@
import java.util.ArrayList;
import java.util.List;

import at.lukle.clickableareasimage.AbstractArea;
import at.lukle.clickableareasimage.ClickableArea;
import at.lukle.clickableareasimage.ClickableAreasImage;
import at.lukle.clickableareasimage.ClickableCircleArea;
import at.lukle.clickableareasimage.ClickablePolyArea;
import at.lukle.clickableareasimage.ClickableRectangleArea;
import at.lukle.clickableareasimage.OnClickableAreaClickedListener;
import at.lukle.clickableareasimage.PixelPosition;
import uk.co.senab.photoview.PhotoViewAttacher;

@SuppressWarnings("rawtypes")
public class MainActivity extends AppCompatActivity implements OnClickableAreaClickedListener {

private final String TAG = getClass().getSimpleName();
Expand All @@ -33,8 +40,7 @@ protected void onCreate(Bundle savedInstanceState) {
ClickableAreasImage clickableAreasImage = new ClickableAreasImage(new PhotoViewAttacher(image), this);

// Define your clickable area (pixel values: x coordinate, y coordinate, width, height) and assign an object to it
List<ClickableArea> clickableAreas = getClickableAreas();
clickableAreasImage.setClickableAreas(clickableAreas);
clickableAreasImage.setClickableAreas(getClickableAreas());
}

// Listen for touches on your images:
Expand All @@ -47,21 +53,40 @@ public void onClickableAreaTouched(Object item) {
}

@NonNull
private List<ClickableArea> getClickableAreas() {

List<ClickableArea> clickableAreas = new ArrayList<>();

clickableAreas.add(new ClickableArea(600, 100, 50, 50, new State("Lower Austria")));
clickableAreas.add(new ClickableArea(440, 125, 50, 50, new State("Upper Austria")));
clickableAreas.add(new ClickableArea(700, 126, 50, 50, new State("Vienna")));

clickableAreas.add(new ClickableArea(685, 270, 50, 50, new State("Burgenland")));
clickableAreas.add(new ClickableArea(420, 350, 50, 50, new State("Carinthia")));
clickableAreas.add(new ClickableArea(370, 245, 50, 50, new State("Salzburg")));

clickableAreas.add(new ClickableArea(170, 280, 50, 50, new State("Tyrol")));
clickableAreas.add(new ClickableArea(30, 280, 50, 50, new State("Vorarlberg")));
clickableAreas.add(new ClickableArea(570, 250, 50, 50, new State("Styria")));
private List<AbstractArea> getClickableAreas() {

List<AbstractArea> clickableAreas = new ArrayList<>();

clickableAreas.add(new ClickableRectangleArea<>(600, 100, 50, 50, new State("Lower Austria")));
clickableAreas.add(new ClickableRectangleArea<>(440, 125, 50, 50, new State("Upper Austria")));
clickableAreas.add(new ClickableRectangleArea<>(700, 126, 50, 50, new State("Vienna")));

clickableAreas.add(new ClickableCircleArea<>(715, 300, 27, new State("Burgenland")));
clickableAreas.add(new ClickableCircleArea<>(450, 380, 27, new State("Carinthia")));
clickableAreas.add(new ClickableCircleArea<>(400, 275, 27, new State("Salzburg")));


clickableAreas.add(new ClickablePolyArea<>(new State("Tyrol"),
new PixelPosition(170,280),
new PixelPosition(160,330),
new PixelPosition(190, 340),
new PixelPosition(220,330),
new PixelPosition(220, 280),
new PixelPosition(195, 270)));
clickableAreas.add(new ClickablePolyArea<>(new State("Vorarlberg"),
new PixelPosition(30, 280),
new PixelPosition(20, 330),
new PixelPosition(50, 340),
new PixelPosition(80, 330),
new PixelPosition(80, 280),
new PixelPosition(55, 270)));
clickableAreas.add(new ClickablePolyArea<>(new State("Styria"),
new PixelPosition(570, 250),
new PixelPosition(560, 300),
new PixelPosition(590, 310),
new PixelPosition(620, 300),
new PixelPosition(620, 250),
new PixelPosition(595, 240)));

return clickableAreas;
}
Expand Down
13 changes: 12 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.5.30'
ext.kotlin_version = "1.4.32"
repositories {
jcenter()
google()
maven {
url "https://maven.google.com"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.android.tools.build:gradle:4.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand All @@ -15,6 +22,10 @@ buildscript {
allprojects {
repositories {
jcenter()
google()
maven {
url "https://maven.google.com"
}
}
}

Expand Down
27 changes: 23 additions & 4 deletions clickableareasimage/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 23
Expand All @@ -16,11 +17,29 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

testOptions {
unitTests.returnDefaultValues = true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}

dependencies {
compile 'com.android.support:appcompat-v7:23.+'
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.commit451:PhotoView:1.2.4'
testCompile 'junit:junit:4.12'
api 'com.android.support:appcompat-v7:23.+'
api fileTree(dir: 'libs', include: ['*.jar'])
api 'com.commit451:PhotoView:1.2.4'
testImplementation 'junit:junit:4.13.2'
testImplementation "io.mockk:mockk:1.12.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
mavenCentral()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package at.lukle.clickableareasimage

abstract class AbstractArea<T>(var item : T) {

abstract fun isInside(positionX: Int, positionY: Int): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,20 @@
/**
* Created by Lukas on 10/22/2015.
*/
public class ClickableArea<T> {
@Deprecated //use ClickableRectangleArea
public class ClickableArea<T> extends AbstractArea<T> {

private int x;
private int y;
private int w;
private int h;

private T item;

public ClickableArea(int x, int y, int w, int h, T item){
super(item);
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.item = item;
}

public int getX() {
Expand Down Expand Up @@ -52,11 +51,16 @@ public void setH(int h) {
this.h = h;
}

public T getItem() {
return item;
public void setLabel(T item) {
super.setItem(item);
}

public void setLabel(T item) {
this.item = item;
@Override
public boolean isInside(int positionX, int positionY) {
return isBetween(this.x, this.x + this.w, positionX) && isBetween(this.y, this.y + this.h, positionY);
}

private boolean isBetween(int start, int end, int actual){
return (start <= actual && actual <= end);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.VisibleForTesting;
import android.view.View;
import android.widget.ImageView;

Expand All @@ -13,12 +14,13 @@
/**
* Created by Lukas on 10/22/2015.
*/
@SuppressWarnings("rawtypes")
public class ClickableAreasImage implements PhotoViewAttacher.OnPhotoTapListener{

private PhotoViewAttacher attacher;
private OnClickableAreaClickedListener listener;

private List<ClickableArea> clickableAreas;
private List<? extends AbstractArea> clickableAreas;

private int imageWidthInPx;
private int imageHeightInPx;
Expand All @@ -35,51 +37,39 @@ private void init(OnClickableAreaClickedListener listener) {
}


@VisibleForTesting
private void getImageDimensions(ImageView imageView){

BitmapDrawable drawable2 = (BitmapDrawable) imageView.getDrawable();
//After SDK 28 (Android Pie), getBitmap() returns the actual size of the image on the screen
if (Build.VERSION.SDK_INT > 27) {
imageWidthInPx = (int) (drawable2.getBitmap().getWidth());
imageHeightInPx = (int) (drawable2.getBitmap().getHeight());
} else {
imageWidthInPx = (int) (drawable2.getBitmap().getWidth() / Resources.getSystem().getDisplayMetrics().density);
imageHeightInPx = (int) (drawable2.getBitmap().getHeight() / Resources.getSystem().getDisplayMetrics().density);
}

imageWidthInPx = (int) (drawable2.getBitmap().getWidth() / Resources.getSystem().getDisplayMetrics().density);
imageHeightInPx = (int) (drawable2.getBitmap().getHeight() / Resources.getSystem().getDisplayMetrics().density);
}


@Override
public void onPhotoTap(View view, float x, float y) {
PixelPosition pixel = ImageUtils.getPixelPosition(x, y, imageWidthInPx, imageHeightInPx);
List<ClickableArea> clickableAreas = getClickAbleAreas(pixel.getX(), pixel.getY());
for(ClickableArea ca : clickableAreas){
List<AbstractArea> clickableAreas = getClickAbleAreas(pixel.getX(), pixel.getY());
for(AbstractArea ca : clickableAreas){
listener.onClickableAreaTouched(ca.getItem());
}
}

private List<ClickableArea> getClickAbleAreas(int x, int y){
List<ClickableArea> clickableAreas= new ArrayList<>();
for(ClickableArea ca : getClickableAreas()){
if(isBetween(ca.getX(),(ca.getX()+ca.getW()),x)){
if(isBetween(ca.getY(),(ca.getY()+ca.getH()),y)){
clickableAreas.add(ca);
}
private List<AbstractArea> getClickAbleAreas(int x, int y){
List<AbstractArea> clickableAreas= new ArrayList<>();
for(AbstractArea ca : getClickableAreas()){
if (ca.isInside(x, y)) {
clickableAreas.add(ca);
}
}
return clickableAreas;
}

private boolean isBetween(int start, int end, int actual){
return (start <= actual && actual <= end);
}

public void setClickableAreas(List<ClickableArea> clickableAreas) {
public void setClickableAreas(List<? extends AbstractArea> clickableAreas) {
this.clickableAreas = clickableAreas;
}

public List<ClickableArea> getClickableAreas() {
public List<? extends AbstractArea> getClickableAreas() {
return clickableAreas;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package at.lukle.clickableareasimage

import android.util.Log
import kotlin.math.sqrt

public class ClickableCircleArea<T>(
private val x: Int,
private val y: Int,
private val radius : Int,
item: T
) : AbstractArea<T>(item) {

override fun isInside(positionX: Int, positionY: Int): Boolean {
var ret = false
val dx = x - positionX
val dy = y - positionY

// if tap is less than radius distance from the center
val d = sqrt((dx * dx + dy * dy).toDouble()).toFloat()
if (d <= radius) {
ret = true
}
return ret
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package at.lukle.clickableareasimage

public class ClickablePolyArea<T>(item: T,
private vararg val points: PixelPosition)
: AbstractArea<T>(item) {

override fun isInside(positionX: Int, positionY: Int): Boolean {
var c = false
var j = points.size - 1
for(i in points.indices) {
val pointI = points[i]
val pointJ = points[j]

//case of point on the line
if ((positionX - pointI.x).toFloat() / (pointJ.x - pointI.x) == (positionY - pointI.y).toFloat() / (pointJ.y - pointI.y)) {
return true
}

if (pointI.y > positionY != pointJ.y > positionY
&& positionX < (pointJ.x - pointI.x) * (positionY - pointI.y)/ (pointJ.y - pointI.y) + pointI.x) {
c = !c
}
j = i
}
return c
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package at.lukle.clickableareasimage

public class ClickableRectangleArea<T>(
private val x: Int,
private val y: Int,
private val w: Int,
private val h: Int,
item: T) : AbstractArea<T>(item) {

override fun isInside(positionX: Int, positionY: Int): Boolean {
return isBetween(this.x, this.x + this.w, positionX) && isBetween(this.y, this.y + this.h, positionY)
}

private fun isBetween(start: Int, end: Int, actual: Int): Boolean {
return actual in start..end
}
}
Loading