Skip to content
Draft
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
5 changes: 5 additions & 0 deletions androidsvg/src/main/java/com/caverock/androidsvg/SVG.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Set;

/**
Expand Down Expand Up @@ -739,4 +740,8 @@ SVGBase.Svg getRootElement()
{
return base.getRootElement();
}

Collection<SVGBase.SvgObject> getElementsAt(float x, float y) {
return base.getElementsAt(x, y, true);
}
}
112 changes: 112 additions & 0 deletions androidsvg/src/main/java/com/caverock/androidsvg/SVGImageView.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Collection;

import android.annotation.SuppressLint;
import android.content.Context;
Expand All @@ -31,9 +32,12 @@
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

import com.caverock.androidsvg.utils.SVGBase;

/**
* SVGImageView is a View widget that allows users to include SVG images in their layouts.
*
Expand All @@ -54,6 +58,7 @@ public class SVGImageView extends ImageView

private static Method setLayerTypeMethod = null;

private SVGElementClickListener svgElementClickListener;

static {
try
Expand Down Expand Up @@ -328,6 +333,102 @@ protected void onPostExecute(SVG svg)

//===============================================================================================

@Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = super.onTouchEvent(event);

if(svgElementClickListener != null && !handled && event.getAction() == MotionEvent.ACTION_DOWN) {
ScaleType scaleType = getScaleType();
float relativePointerX = event.getX();
float relativePointerY = event.getY();

float svgWidth = this.svg.getDocumentWidth();
float svgHeight = this.svg.getDocumentHeight();

float viewWidth = this.getWidth();
float viewHeight = this.getHeight();

switch (scaleType) {
//TODO add support for CENTER_INSIDE, FIT_XY, MATRIX
case CENTER:
float spacingWidth = viewWidth - svgWidth;
float spacingHeight = viewHeight - svgHeight;

relativePointerX = (event.getX() - spacingWidth/2) / (viewWidth - spacingWidth);
relativePointerY = (event.getY() - spacingHeight/2) / (viewHeight - spacingHeight);
break;

case CENTER_CROP:
relativePointerX = event.getX() / viewWidth;
relativePointerY = event.getY() / viewHeight;

if (svgWidth / svgHeight < 1) {
float factor = svgWidth / viewWidth;
float spacing = ((factor * viewHeight) - svgHeight) / factor;

relativePointerY = (event.getY() - spacing / 2) / (viewHeight - spacing);
} else {
float factor = svgHeight / viewHeight;
float spacing = ((factor * viewWidth) - svgWidth) / factor;

relativePointerX = (event.getX() - spacing / 2) / (viewWidth - spacing);
}
break;

case FIT_START:
case FIT_END:
case FIT_CENTER:
relativePointerX = event.getX() / viewWidth;
relativePointerY = event.getY() / viewHeight;

float spacing;
if (svgWidth / svgHeight < 1) {
float factor = svgHeight / viewHeight;
spacing = ((factor * viewWidth) - svgWidth) / factor;
} else {
float factor = svgWidth / viewWidth;
spacing = ((factor * viewHeight) - svgHeight) / factor;
}

switch (scaleType) {
case FIT_START:
if (svgWidth / svgHeight < 1) {
relativePointerX = event.getX() / (viewWidth - spacing);
} else {
relativePointerY = event.getY() / (viewHeight - spacing);
}
break;
case FIT_END:
if (svgWidth / svgHeight < 1) {
relativePointerX = (event.getX() - spacing) / (viewWidth - spacing);
} else {
relativePointerY = (event.getY() - spacing) / (viewHeight - spacing);
}
break;
case FIT_CENTER:
if (svgWidth / svgHeight < 1) {
relativePointerX = (event.getX() - spacing / 2) / (viewWidth - spacing);
} else {
relativePointerY = (event.getY() - spacing / 2) / (viewHeight - spacing);
}
break;
}

}

if (relativePointerX >= 0 && relativePointerX <= 1 &&
relativePointerY >= 0 && relativePointerY <= 1) {
Collection<SVGBase.SvgObject> elements = this.svg.getElementsAt(relativePointerX * svgWidth, relativePointerY * svgHeight);

for (SVGBase.SvgObject element : elements) {
svgElementClickListener.onClick(element);
handled = true;
}
}
}

return handled;
}

/*
* Use reflection to call an API 11 method from this library (which is configured with a minSdkVersion of 8)
Expand Down Expand Up @@ -358,4 +459,15 @@ private void doRender()
setImageDrawable(new PictureDrawable(picture));
}

public SVGElementClickListener getSVGElementClickListener(){
return this.svgElementClickListener;
}

public void setSVGElementClickListener(SVGElementClickListener listener){
this.svgElementClickListener = listener;
}

public interface SVGElementClickListener {
void onClick(SVGBase.SvgObject elementClicked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,10 @@ private void render(SvgObject obj)
render((Text) obj);
}

if(obj instanceof SvgElementBase && ((SvgElementBase) obj).id != null){
document.putElementById(((SvgElementBase) obj).id, (SvgElementBase) obj);
}

// Restore state
statePop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -2127,6 +2128,11 @@ void enumeratePath(PathInterface handler)
}


SvgElementBase putElementById(String id, SvgElementBase obj) {
return idToElementMap.put(id, obj);
}


SvgElementBase getElementById(String id)
{
if (id == null || id.length() == 0)
Expand Down Expand Up @@ -2190,5 +2196,40 @@ private void getElementsByTagName(List<SvgObject> result, SvgObject obj, String
}
}

public Collection<SvgObject> getElementsAt(float x, float y, boolean withIdsOnly)
{
List<SvgObject> result = new ArrayList<>();

// Search the object tree for nodes at the given coordinates
if(!withIdsOnly){
getElementsAt(result, rootElement, x, y);
} else {
for (SvgElementBase obj: idToElementMap.values()){
if(obj instanceof SvgElement && containsCoords((SvgElement) obj, x, y)){
result.add((SvgElement) obj);
}
}
}
return result;
}


private void getElementsAt(List<SvgObject> result, SvgObject obj, float x, float y)
{
if (obj instanceof SvgContainer)
{
for (SvgObject child: ((SvgContainer) obj).getChildren())
getElementsAt(result, child, x, y);

} else if (obj instanceof SvgElement && containsCoords((SvgElement) obj, x, y)) {
result.add((SvgElement) obj);
}
}

private boolean containsCoords(SvgElement elm, float x, float y){
Box box = elm.boundingBox;
if (box != null)
return (x >= box.minX && x <= box.maxX() && y >= box.minY && y <= box.maxY());
else return false;
}
}