Giter Club home page Giter Club logo

tileview's Introduction

Release Badge

This project isn't maintained anymore. It is now recommended to use https://github.com/peterLaurence/MapView.

MapView is maintained by Peter, one of our main contributors. MapView is an highly optimized Kotlin version (which can be used from Java projects) that's very cool and fast. It's 100% production ready and open source. Peter uses this widget in his app at https://github.com/peterLaurence/TrekMe/.

TileView: Version 4

The TileView widget is a subclass of ViewGroup renders and positions bitmap tiles to compose a larger, original image, often one too large to display normally.

tileview

Vesion 4 is effectively the promotion of version 3 from beta to production-ready, fixing the issues brought up by you, the users. While normally this'd probably be done using a series of minor version bumps, and this might be 3.4.11, there was a change to the base package name, and this requires a major change according to semver, since it's a breaking change for past versions.

Also of note, the universal (2-D) ScrollView class, and related classes like ScalingScrollView (which is a subclass of the 2D universal ScrollView, but also manages scaling and scale gestures) is now it's own repository: https://github.com/moagrius/ScrollView, and available with implementation 'com.moagrius:scrollview:1.0.3'. It is now included in the TileView project using normal gradle dependency operations, specifically using api rather than implementation but otherwise similar to other dependencies and is being pulled down from jcenter and reconciled normally.

Demos for ScrollView are in the ScrollView repo. Demos for TileView are in this repository.

Feel free to use ScrollView as a standalone widget if you don't need image tiling.

Change Log

4.0.7 (most recent)

  • Fixed bug with MarkerPlugin where markers clipped when scaled beyond 100%.

4.0.5 (most recent)

  • Save and restore instance state properly implemented.
  • Removed a bug that produced an increasing number of delayed callbacks from a Handler. This is a serious memory leak and all users on versions 4.0.3 and 4.0.4 should immediately upgrade to 4.0.5.

4.0.4

  • Update ScalingScrollView to version 1.0.10, which provides additional methods and method exposure (many private access methods became protected)

4.0.3

  • You can scale greater than 1f now without flicker, and without clipping.
  • Remote images should decode now with a much higher rate of success, nearing 100%.
  • Marker plugin API has been updated and show now work propertly (see TileViewDemoAdvanced Activity).
  • LowFidelityBackgroundPlugin now scaled and positions appropriately with the TileView host.
  • The COVER and CONTAIN MinimumScaleModes should work properly now.
  • Upgraded from com.moagrius:scrollview:1.0.4 to 1.0.9

TileView

Very large images in Android will often result in an OutOfMemoryError. Memory is finite, and bitmaps take a great deal of it. TileView solves this by stitching together small pieces of the image (tiles) and displaying them reconstructed in the area of the screen visible to your user.

Out of the box, the TileView will manage the tiled image, including subsampling when needed, flinging, dragging, scaling, and multiple levels of detail.

Additional plugins are provided to allow adding overlaying Views (markers), info windows, hot spots, path drawing, and coordinate translation.

Version 4 is fairly young. If you're need a stable version, the last release of version 2 is 2.7.7, and is available as a branch, here: https://github.com/moagrius/TileView/tree/version-2.7.7, or from the releases page. You can also get it from gradle using the old namespace: implementation 'com.qozix:tileview:2.7.7'

No further work will be done on version 2.

This is truly open source. I'm very happy to accept improvements or bug fixes - no caveats; create an issue, branch, and create a PR. While I'm not super interested in finding bugs and don't want the issues page to become a wasteland (I already know what most of them are, and will start to document them as this make its way into the wild), I am very interested in fixing those bugs - if you have the time to locate and correct a bug, please open a PR.

Installation

Add this to your app module's build.gradle.

implementation 'com.moagrius:tileview:4.0.7'
Quick Setup
  1. Tile an image into image slices of a set size, e.g., 256x256 instructions // TODO
  2. Name the tiles by the column and row number, e.g., 'tile-1-2.png' for the image tile that would be at the 2nd column from left and 3rd row from top.
  3. Create a new application with a single activity ('Main').
  4. Save the image tiles to your assets directory.
  5. Add the latest version to your gradle dependencies.
  6. In the Main Activity, use this for onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  TileView tileView = new TileView.Builder(this)
  	.setSize(3000, 3000)
  	.defineZoomLevel("tile-%d-%d.png")
  	.build();
  setContentView(tileView);
}

That's it. You should have a tiled image that only renders the pieces of the image that are within the current viewport, and pans and zooms with gestures.

Note that String replacements for rows and columns is not required - you can supply literally any Object instance to a DetailLevel, and a BitmapProvider implementation can use that Object to generate a Bitmap instance however you want.

What Changed

As a user, the biggest things you'll notice are:

  1. You no longer need redandant tile sets or detail levels. If your image doesn't change the details (e.g., show different images or labels at different zoom levels), you don't need to create tiles sets besides the original, full size one. The program will now use subsampling to do this work for you without any setup on your part: one call to defineDetail(anyObject) is sufficient.
  2. No more BitmapProvider. We're just doing way too much management of Bitmaps, including re-use and caching, to allow any stray Bitmap to wander in. This may change in the future, but the replacement for now is StreamProvider - basically the same thing but you just return an InputStream _instead of a Bitmap, and we take care of the rest.
  3. Greatly improved bitmap management. For details, see How It Works
  4. Touch events are now managed appropriately, rather than blindly consumed. We now use the same logic as the framework's ScrollView, so you can assign normal OnClickListeners or similiar gesture management devices on things like markers and callouts, without interrupting drag or fling operations.
  5. Plugin architecture. Only sign up for things you need - if you don't need markers, don't install the plugin, and keep things snappy and simple. Check TileViewDemoSimple for a very bare implementation, and TileViewDemoAdvanced for a more dressed up version.
  6. Much smaller codebase. Almost all the magic now happens in either Tile or TileView - if you understand those 2 classes, you understand the majority of the project.
  7. Decomposition. This takes a little explanation. There are now 3 major, public widgets: ScrollView, ScalingScrollView, and TileView. Each inherits from the last. You'll notice the demo module has Activities for each of these classes.
ScrollView

com.moagrius.widgets.ScrollView is a clone of AOSP's ScrollView and HorizontalScrollView, with some inspiration taken from RecyclerView and GestureDetector. That means the APIs will be very familiar to anyone who's used the framework-provided ScrollView. The big difference here is that com.moagrius.widgets.ScrollView functions along both axes, without configuation. For example, if you have a layout that matches parent width and expands vertically, ScrollView will scroll it vertically - the converse holds. If you have a layout that larger in both directions than the parent, ScrollView will scroll in any direction.

Again, no configration is required - there is no orientation attribute - it does it's best to figure out what makes sense.

ScalingScrollView

ScalingScrollView extends ScrollView and adds scaling APIs, as well as built-in scaling gesture managent (pinch and double tap to zoom). By default, it will visually scale its content, but that can be disabled with a single setter setShouldVisuallyScaleContents(false), and you can manage your content with a porportional scaled value. Similarly, it will lay itself out to the current scale value, unless that too is disabled setWillHandleContentSize(true)

At some point, ScalingScrollView will be it's own repository, and will be a dependency of TileView.

TileView inherits from ScalingScrollView, and adds tiling functionality.

From here down may be a bit dry but might be interesting to people interested in contributing to the process.

How It Works

Problem

You have an image too large to display with an OutOfMemoryError.

Solution

Chop the image into tiles and reconstruct them to fill the viewport, and only the viewport. As the user scrolls (or scales), aggressively recycle any bitmap data that is not visible to the user at any given time, and render any new "tiles" that are not within the viewable area.

Basic operation

Use the width and height of the view that contains this image, plus it's scroll position, to determine space we call the viewport.

Divide the corners of the viewport (left, top, right, bottom) by the size of the cell, which provide the start and end row and column. Round down the left and top and round up the right and bottom to make sure there are not empty patches - as long as any pixel of a tile is visible in the viewport, it must be rendered (one reason - among many - to carefully consider tile size, and not default to as large as possible).

From start column to end column and start row to end row are the tiles (imagine a 2D array) that should be rendered at that moment.

For example, let's consider...

  • image is 10,000 square
  • viewport is 1080 by 1920
  • viewport is at scroll position (1000, 500)
  • so our computed viewport is (1000, 500 - 2080, 2420)
  • out tiles are 256 square

so grid is

  1. start column 1000 / 256 = 3
  2. end column is 2080 / 256 = 9
  3. start row is 500 / 256 = 2
  4. end row is 2420 / 256 = 10

Iterate between those points...

for (int i = grid.columns.start; i < grid.columns.end; i++) {
  for (int j = grid.rows.start; j < grid.rows.end; j++) {

And your grid looks like this:

(03, 02), (04, 02), (05, 02), (06, 02), (07, 02), (08, 02), (09, 02)
(03, 03), (04, 03), (05, 03), (06, 03), (07, 03), (08, 03), (09, 03)
(03, 04), (04, 04), (05, 04), (06, 04), (07, 04), (08, 04), (09, 04)
(03, 05), (04, 05), (05, 05), (06, 05), (07, 05), (08, 05), (09, 05)
(03, 06), (04, 06), (05, 06), (06, 06), (07, 06), (08, 06), (09, 06)
(03, 07), (04, 07), (05, 07), (06, 07), (07, 07), (08, 07), (09, 07)
(03, 08), (04, 08), (05, 08), (06, 08), (07, 08), (08, 08), (09, 08)
(03, 09), (04, 09), (05, 09), (06, 09), (07, 09), (08, 09), (09, 09)
(03, 10), (04, 10), (05, 10), (06, 10), (07, 10), (08, 10), (09, 10)

As long as there's only the one size, scale is uniformly applied - just multiple tile size in the previous math by the current scale, and your grid remains intact.

Scaling

At every half way point, the image is at 50% or smaller, so subsample it to save memory: https://developer.android.com/topic/performance/graphics/load-bitmap#load-bitmap

Remember that each subsample (representing half the size) will actually quarter the amount of memory required for the bitmap. Do this at every half: 50%, 25, 12.5, 6.25, 3.625, etc.

When you add another detail level, things get a little more complicated, but not terribly...

Detail/Zoom Levels
  • Subsampling starts over at the last provided detail level, so it's no longer directly taken from the scale
  • Your grid now has to be "unscaled" - now it's tile size * scale (as it was before), but now must be unscaled by an amount equal to the emulation of the detail level.
  • This unscaled value is effectively the inverse of the scale, so 50% scale would be times 2, 25% would be times 4, 12.5% would be times 8
  • However, this is a constant value, so anything from 50% to 26% would be times 2, so a better descript might be "zoom left shift one" or (zoom << 1)
  • This works fairly well as is at this point, but on large screens with high density, you end up with lots of very small tiles, unless you provide a ton of detail levels.
  • If you have a single detail level and let the program subsample for you, the total memory footprint stays (about) the same, but the number of times the disk or caches are hit is very high, and this can appear very slow
  • To remedy this, we use "patching". With patching, things get a lot more complicated.
Patching
  • "Patching" is basically grabbing as many subsampled tiles as needed to create a full sized tiles, stitching them together into a single bitmap, and stuffing that in the cache
  • A very important number here is the "image subsample". this is distinct from the "zoom sample" described above
  • The image subsample is derived from the distance you are from the last provided detail level. so if you have only 1 detail level (0) and you're at 20%, you're at image subsample 4 (50% would be 2, 25% would be 4, 12.5% would be 8, etc)
  • To do that, your grid math has to change a little. you now have to round down to the nearest image subsample on the west and north, and round up to the nearest image subsample on the south and east, and skip a number of columns and rows equal to the image subsample
  • So now your viewport computation becomes very different:
for (int i = grid.columns.start; i < grid.columns.end; i += imageSample) {
  for (int j = grid.rows.start; j < grid.rows.end; j += imageSample) {

And for each of those tiles, we grab the last good detail level and fill in the blanks, so tile (0,4) would draw it's neighbors:

(0,0), (0,1), (0,2), (0,3)
(1,0), (1,1), (1,2), (1,3)
(2,0), (2,1), (2,2), (2,3)
(3,0), (3,1), (3,2), (3,3)

This allows us to then save the "patched" bitmap tile to both a memory and a disk cache, so we're not decoding very large files and discarding excess data after the first time.

The next thing that comes up is when changing between zoom levels. If we just swap out levels, the screen will be blank for a second, regardless of whether that's a defined, supplied detail level, or just subsampling the tiles. Since View.onDraw uses a Canvas, we need to redraw the entire thing each time invalidation occurs. That means if you switch between zoom level, the canvas will clear the old tiles before drawing the new tiles. This behavior is generally good (and what ensures that we're generally only going to drawing as much bitmap data as we need to fill the screen, even if we do a bad job of cleaning up), but in this case the visual effect is jarring.

To remedy this, we:

  • Populate a Region instance with the virtual viewport (scaled)
  • For each fully decoded tile in the current (the detail level we just entered), punch a hole in that Region. What's left are pixels that will remain unfilled after we draw current tiles.
  • For each fully decoded and drawn tiles from the previous detail level - the detail level we're exiting - we use Region.quickReject to determine if that previous tile intersects any part of the virtual viewport that will not be filled with current tile pixel data.
    • If a previous tile does intersect this unfilled region, we need to draw it.
    • If a previous tile does not intersect this unfilled region, that means we have completely covered that area with pixel data from the new level, and can both destroy the previous tile (and it's bitmap), as well as remove it from the list of previous tiles we're testing.
      • Since we remove every previous tile that's covered by current tiles, this set will become empty once the current viewport is filled with current pixel data.

So all the preceding "works" pretty well, but decoding the same data over and over is a lot of work that we can probably skip if we're smart about it.

Bitmap Caching and Re-use

Emphasis on and reuse - the reuse bit is as important as (maybe even more than) the traditional caching piece.

The default providers assume we're reading tiles from disk already, so the only thing that goes into disk-cache are the patched tiles, mentioned above (this behavior can be modified, if for example you're reading tiles from a server). Everything, however, is subject to a memory cache. The default is one-quarter of available RAM, but the more you can spare for this, the better your performance will be. This serves as both a straight bitmap cache, and a pool of re-usable objects: When we first go to decode a tile, we check if that exact bitmap is in the memory cache - if it is, great, use it - if it's not, grab the oldest bitmap in the cache and re-use the underlying bitmap (BitmapFactory.Options.inBitmap)

Reusing bimaps prevents frequent, large memory allocation and de-allocation, and can greatly improve the perceived performance of your app. I'll let Colt explain: https://www.youtube.com/watch?v=_ioFW3cyRV0

Threading

Threading is accomplished using a dedicated ThreadPoolExecutor. It's basically a fixed size pool with a pool size equal to the number of cores on the device (so 2 or 4 commonly, on newer phones as much as 8). There's a 0 keep-alive and tasks are queued with a LinkedBlockingQueue. A custom factory provides Thread instances that use Thread.MIN_PRIORITY to we don't consume resource the main thread needs to perform nice scrolls and flings. Going further on this, each Tile (which is a Runnable submitted to the ThreadPoolExecutor also calls Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); which gives a larger range than Thread.setPriority, and this is actually very noticeable. On a real Nexus 6, the jank without call to setThreadPriority isnt' terrible but is obvious, and immediately remedied with the call just mentioned.

This general approach is very similar to what you'd get with Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()).

tileview's People

Contributors

marcomirisola avatar moagrius avatar p-lr avatar yashx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tileview's Issues

Tiles are not showing

Im using tileview for showing image and i have diffrent zoom level images in assests.
Im calling ddDetailLevel with zom level and apth of corresponding and im adding tileview to layout but im not able to see tiles.

Please suggest this.

Package name for DiskLruCache

I'm pretty sure i'm just bad, but i don't understand one thing... When i work with the sources, in tileview.tiles.TileCache.java DiskLruCache is imported by import com.jakewharton.DiskLruCache; but the package name of this is : com.jakewharton.disklrucache.DiskLruCache; so, I get an error until I don't change this one.

Can you explain to my slow brain ...

How to get the Position

Is there a way to get the position of a Tileview so i can set another Tileview to the same position with moveTo() ?

Horizontal and Vertical Paths not drawn

If I attempt to draw Horizontal or Vertical paths then this line

if ( !canvas.quickReject( drawingPath, Canvas.EdgeType.BW ) ) {

causes them to not be to drawn.

Changing from Canvas.EdgeType.BW to Canvas.EdgeType.AA has no effect, the only resolution I can come up with is to remove the check and that seems extreme/risky.

Marker Positioning Logic

Hello moagrius,

First of all great work on building something like this from scratch. I've been working on something similar in iOS that renders markers to a static map that has geolocation and user tracking abilities.

I have, however, encountered what appears to be some error in logic in regards to the placement of markers. At first I thought that it must have been my own custom implementation, but upon starting a fresh project from the demo, it appears that the markers do not correlate to their real world positions.

tile-view-bug

As you can see from the attached image, I have just rendered one marker on the Boston map, but when I input the same coordinates into Google Maps, the marker renders in a different position to that in Google Maps.

Am I missing something here, or is this a known issue?

Also, I found the comments in the documentation regarding the parameters in the defineRelativeBounds() method in tileView to be confusing, as the supplied arguments do not match what is defined in the comments.

Shouldn't it be NW (latitude, longitude), SE (latitude, longitude)?

The documentation reads (SE longitude, NW latitude), (NW longitude, SE latitude)

NW = north west
SE = south east

I look forward to your feedback :)

Callout sometimes doesn't show

Ok now i seriously have a problem.

I click on hotspot but at first callout appears and a while later it doesn't...
Do you know the cause? Thank you..

EDIT: callout only doesn't show on below 100% zoom
EDIT 2: if i pinch it a little, about near 100% zoom.. callout shows but in wrong coordinate..

Animation for smoothScaleTo while zoom out

When I use the function smoothScaleTo, the amimation is fine when I zoom in, but not good while zoom out (example zoom from 4 to 1).

In class ZoomPanLayout, it might be interesting to update the function smoothScaleTo that will check if the current scale (scale class variable ?) is less or greater than the destination parameter.
If it's greater, use as usual:

        tween.setDuration( duration );
        tween.start();

Else use another tween:

    private Tween tweenIn = new Tween();
    {
        tween.setAnimationEase( Strong.EaseIn );
        tween.addTweenListener( tweenListener );
    }

exemple:

    public void smoothScaleTo( double destination, int duration ) {
        if ( isTweening ) {
            return;
        }
        doubleTapDestinationScale = destination;

        if(scale > destination){
            tween.setDuration( duration );
            tween.start();
        }else{
            tweenIn.setDuration( duration );
            tweenIn.start();
        }
    }

I have tried, but I might have missed something as it doesn't work as expected :-/

Crash when setCacheEnabled(..) is set to true

When I load app with setCacheEnabled(..) to true, its crashing at below method

  private void addBitmapToMemoryCache( String key, Bitmap bitmap ) {        
    if ( getBitmapFromMemoryCache( key ) == null ) {
    // crashing here
        memoryCache.put( key, bitmap );
    }
}

Here, both key and bitmap are null. May be some null check should work.

Add layer support for TileView

Is it possible to add the layer support in the TileView? For example, one can add the satellite layer and the place name layer at the same time.

TileView not refreshing when configuration changes are manually handled

If the TileView is in an activity defined as:

<activity
            android:name="com.example.MainActivity"
            android:screenOrientation="fullSensor"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustResize"
            android:label="@string/app_name" >

and the scale level is 0 (or min) then the TileView doesn't refresh properly on device orientation change. I've tried adding following code, but it does not help:

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // refresh map
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            tileView.refresh();
        }
    }

More to say, panning the view after orientation change doesnt invalidate the tiles, only zooming in invalidates them actually.

hi , center alignment with min scale less than one

hi Moagrius , i m using the large Image tileview ,it show the pivot for scaling on the top left corner when the scale limit had go less than 1 during zoom out.is that anyway to set it to the center?Thank you :)

Marker Tap event not triggered after dynamic add

I add dynamically a marker, it works fine, but the event onTap is not triggered.
But if I zoom a bit (out or in) the the event is trigged on the markers :-/

What is done during the zoom that help the Marker to be triggered after.

Note: I launch a redraw() after adding the marker (so the clip is recalculated).

Test Hooks

I feel like this is a dumb question but I am afraid I'm in need of assistance.

I was trying to write some tests on a Custom View Component that I wrote the extends from TileView and I have been unable figure out how to get the current TileView settings,

For example I was trying to get the center of view port in world co-ordinates.

Thanks.

GreatMaps in android

there is program GreatMaps (greatmaps.codeplex.com) it's open source and want to build something like that but in android.
it is same as your library. it downloads tiles,saves them in SDcard , and then put them next to each other and display it. i want to use google satellite tiles to cover it.
i used View class to handle it. but i have problem to handle all of this tiles, in just onDraw method.
when i saw your library it seemed vary sophisticated.
i want to know how you put tiles together, i know you find it's location by it's col and row but i wanna know what's your algorithm,and what kind of method do you use for this . and what's your algorithm to load tiles when you drag the map, for example my algorithm was if i drag it 256 pixel to right remove my last tile column and add one column before the first column of map but it didn't work because of some reason.
please help me.
thanks in advance

SmoothScale to a position?

I'm trying to achieve smooth scale to a given position in Tileview. I've used scrolling and sliding methods in TileView and ZoomPanLayout in combination with smoothScaleTo. Translation methods do their job, but smoothScaleTo always scales to provided destination scale but having the upper left corner of (0,0) in Tileview.
Tried the frameViewport method, with similar results. Is there any preferred way of achieving this that I'm not aware of?

Jar package

  • Package the project into an easy-to-import jar.
  • Create 'release' on Github.
  • Add link to readme.

Tile Size

Hi,

I'm looking at improving the performance of my implementation of TileView and was wondering about the impact of the tile size on memory usage. Do you have any suggestions on how to select an optimum tile size for a given image's dimensions?

Thanks in advance for your help.

Phil

Zoom issues on large tile map

Hey,

I have a tile map that consist of 30000 x 30000 tiles each of them with a size of 256*256 pixels.
I use the method TileViewActivity.frameTo(x, y) to move to the center of my map. It works and I can see my tiles, but I noticed a weired behavior that I can't explain. If I zoom out, the whole map appears to be empty (no tiles visible). If I continue to zoom out, the map appears again (tiles visible again). I can reproduce this issue if I zoom in again. There is a range of scale where no tiles are rendered.
For me it seems that the higher the row and colum values are, the bigger is the range of scale where no tiles are visible.

  1. Is this a known issue?
  2. Are there any limitations specified how big a map can be? For example a maximum number of rows/columns? Or the highest possible position in pixels?
    I tried to use a bigger map with 100000 x 100000 tiles but after moving to the center nothing was rendered anymore :)

Could you have the callout only close on tap?

Hi,

I would like to pan/scroll the map without having the callouts closed. Have issues when not the whole callout is visible.

Intuitively it feels like the behaviour you would like to have. Tryied to implement it but looks like when you return true in onTouchEvent in CalloutManager you are not able to interact with the map.

Should I use a marker if I want the "callout" to stay put when taping? Or is it possible to implement?

Thanks

Tobias

Markers and map out of sync with the zooming

Hi!

I have a problem when I am changing the LayoutParams for a view in a Callout that is visible. After I have updated the LayoutParams the map and the markers get out of sync with the zooming.

Sometimes markers and map are connected but goes against the topleft corner instead of zooming, other times maps and markers are not in sync and goes in different directions.

Do you have a clue of what this could be?

Best regards

Tobias

Downsample lost

I was scrolling and then moving to home, so the app was paused. Then i opened it again, my tiles loaded with black background... anybody having similar issue?

EDIT: nevermind, i was calling requestRender() not resume().

Tiles don't always load successfully

I've adapted the BitmapDecoderAssets to enable it to access files which are stored in an APKExtension package (obb file) the maps we're using are 10000 by 6667 pixels in size and we have 6 of them totalling 300Mb of data. Loading tiles is slow, but with the downsample underneath is passable. However, not all tiles will successfully load the tiles which fail to load are usually towards the bottom and right but are essentially random.

Can you recommend anything which would improve this situation, e.g. adding a timed retry to load tiles?

Rotation of the TileView

I attempted to add rotation support to the TileView by using View.rotate() using the something like this:

                    this.mDegree = (float) Math.toDegrees(Math.atan2((event.getY(0) - event.getY(1)),
                                    (event.getX(0) - event.getX(1)))) + rotation_angle;
                    this.mDeltaDegree = this.mDegree - this.mStartDegree;
                    this.mTileView.setRotation(this.mDeltaDegree);
                    this.mTileView.updateViewport();
                    this.mTileView.requestRender();

Unfortunately when i zoom in and the rotate 90 degrees i get the "letterbox" effect.

I have tried forcing the DetailLevel.getIntersections() to return more tiles and I have tried to fool various components into drawing more or expanding the viewport with no success.

Do you have any suggestions as to what I could try next?

Thanks

Path

Hi

i have problem draw path. Can someone pls write sample code?

thanks

Calling addMarker causes a crash

08-07 15:59:00.230: E/AndroidRuntime(20562): FATAL EXCEPTION: main
08-07 15:59:00.230: E/AndroidRuntime(20562): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
08-07 15:59:00.230: E/AndroidRuntime(20562): at android.view.ViewGroup.addViewInner(ViewGroup.java:3435)
08-07 15:59:00.230: E/AndroidRuntime(20562): at android.view.ViewGroup.addView(ViewGroup.java:3306)
08-07 15:59:00.230: E/AndroidRuntime(20562): at android.view.ViewGroup.addView(ViewGroup.java:3282)
08-07 15:59:00.230: E/AndroidRuntime(20562): at com.qozix.tileview.markers.MarkerManager.addMarker(MarkerManager.java:46)
08-07 15:59:00.230: E/AndroidRuntime(20562): at com.qozix.tileview.markers.MarkerManager.addMarker(MarkerManager.java:42)
08-07 15:59:00.230: E/AndroidRuntime(20562): at com.qozix.tileview.TileView.addMarker(TileView.java:449)

Removing my calls to addMarker prevents the crash, am I missing something?

Issue while adding marker in onTap(..) and marker position wrt zoom level

I am trying to add markers when I tap on TileView as below.

    @Override
    public void onTap(int x, int y) {
    Log.i(TAG, "onTap : "+x+" - "+y);               
    View marker = new ImageView( this);
    ((ImageView) marker).setImageResource( R.drawable.maps_marker_blue );

     mTileView.addMarker( marker, x,  y );          
   }

When I tap, Its adding marker in some other place and when and as I zoom, markers getting relocated.
I don't know whether its right way to add marker in onTap or not.
Please suggest.

Double tapping zoom animation flicker sometimes.

Hi
I think you may already know this problem.
When I double tap, view scales to that position smoothly but sometimes it flickers.

I can't see what is going on since it is so fast but seems like scroll and scale is not applied at some moment.

It doesn't happen all the time, but when I try double tap 3~5 times I can see it.

Is there any timing issue on double tap scaling or drawing cache rebuild or something like that?

I tested on my personal project and sample app. Both happens.
Tested on Galaxy Note 2. Android 4.1.2

How to Polygon

Does polygon only consist of four points?
What is Region class that's used in the constructor?

Many thanks for this release..

Redrawing tiles on touch events

I noticed that the tiles are not redrawn when dragging or zooming the TileView. Redraw happens only after some time when the touch events stop. Is it possible to enable this, so when I'm dragging the view around or zooming the tiles get updated automatically?

Mini map feature

In 1 of the IOS apps, named plangrid, there is a feature called mini map, which shows the summary of whole map in a small portion (probably in any of the corners). Using this mini map, user can navigate to any part of the map in all zoom levels. So, can we do same with the TileView for Android?

Below is a sample image showing mini map feature.

sample_mini_map

TranslationLayout NullPointerException

Hi,

I get an error that make my app crash. It says that it is a problem in the TranslationLayout. Right before the stacktrace that i add below I get this warning:

threadid=1: thread exiting with uncaught exception (group=0x40bed1f8)

Stacktrace:
dalvik.system.NativeStart ? in main at line -2
com.android.internal.os.ZygoteInit ? in main at line 745
com.android.internal.os.ZygoteInit$MethodAndArgsCaller ? in run at line 978
java.lang.reflect.Method ? in invoke at line 511
java.lang.reflect.Method ? in invokeNative at line -2
android.app.ActivityThread ? in main at line 4507
android.os.Looper ? in loop at line 137
android.os.Handler ? in dispatchMessage at line 99
android.view.ViewRootImpl ? in handleMessage at line 2649
android.view.ViewRootImpl ? in performTraversals at line 1255
android.view.View ? in measure at line 12922
com.android.internal.policy.impl.PhoneWindow$DecorView ? in onMeasure at line 2261
android.widget.FrameLayout ? in onMeasure at line 293
android.view.ViewGroup ? in measureChildWithMargins at line 4706
android.view.View ? in measure at line 12922
android.widget.LinearLayout ? in onMeasure at line 563
android.widget.LinearLayout ? in measureVertical at line 670
android.widget.LinearLayout ? in measureChildBeforeLayout at line 1385
android.view.ViewGroup ? in measureChildWithMargins at line 4706
android.view.View ? in measure at line 12922
android.widget.FrameLayout ? in onMeasure at line 293
android.view.ViewGroup ? in measureChildWithMargins at line 4706
android.view.View ? in measure at line 12922
android.widget.RelativeLayout ? in onMeasure at line 376
android.widget.RelativeLayout ? in measureChildHorizontal at line 594
android.view.View ? in measure at line 12922
android.widget.RelativeLayout ? in onMeasure at line 392
android.widget.RelativeLayout ? in measureChild at line 579
android.view.View ? in measure at line 12922
android.widget.RelativeLayout ? in onMeasure at line 376
android.widget.RelativeLayout ? in measureChildHorizontal at line 594
android.view.View ? in measure at line 12922
android.widget.RelativeLayout ? in onMeasure at line 376
android.widget.RelativeLayout ? in measureChildHorizontal at line 594
android.view.View ? in measure at line 12922
com.qozix.layouts.ZoomPanLayout ? in onMeasure at line 438
android.view.ViewGroup ? in measureChildren at line 4654
android.view.ViewGroup ? in measureChild at line 4677
android.view.View ? in measure at line 12922
com.qozix.layouts.StaticLayout ? in onMeasure at line 16
android.view.ViewGroup ? in measureChildren at line 4654
android.view.ViewGroup ? in measureChild at line 4677
android.view.View ? in measure at line 12922
com.qozix.layouts.TranslationLayout ? in onMeasure at line 46
android.view.ViewGroup ? in measureChildren at line 4653
Caused by: java.lang.NullPointerException ? at line -1

Do you have any ideas?

Resetting and adding DetailLevels does not work

I want to reuse the TileView instance for different maps. When changing the map, I reset the DetailLevels with resetDetailLevels(); after that I set the new DetailLevels with new tile URLs. Then I invoke requestRender(); which re-renders the map with the old tiles. Debugging that, I can see, that the tile URLs are still the old ones.

Animate marker

I am trying to do something like this:

double[] newCords = newCords(); // not pixels - cords Geolocator-wise
double[] newPixels = mapView.latLngToPixels(newCords[0], newCords[1]);

ObjectAnimator animX = ObjectAnimator.ofFloat(myMarker, "x", newPixels[0]);
ObjectAnimator animY = ObjectAnimator.ofFloat(myMarker, "y", newPixels[1]);
animX.start();
animY.start();

But the MapView/TileView won't have any of it. The location of the marker will be very distorted and it will not follow zooming or moving as it should as soon as I touch it's x/y position.

Is this a bug or is there a better way to animate markers on the map/tile?

Load tiles during pinch / drag

Please forgive me but I can find anything in the code.

Is it possible to trigger an update of the tile rendering during a pinch/drag/etc?

setScaleToFit doesn't work as expected

If I call setScaleToFit I'd expect the view to scale to fit the minimum scale required, however in the method calculateMinimumScaleToFit, we see that it uses the maximum between minimumScaleX and minimumScaleY.

I've changed this to use the minimum however the scale is still never set.

If I add to setScaleToFit() a call to setScale(minScale) at the end the view shows up entirely black.

I've also noticed that when you are scaled to the minScale you can still scale the view smaller than the min scale with a pinch gesture.

Highlight an area that maintains its size while zooming

This may be a dumb question, but I haven't been able to achieve this yet. I'd like to highlight an area on the map, and have that area scale differently than the markers. For example, in the TileViewDemo application - say I want to draw a rectangle around the dining room table in the Building Plans layout. I can add a marker to draw the area, but when I zoom in, the area will shrink and no longer surround the entire table.

If I'm not making sense, you can replace the onCreate code in BuildingPlansTileViewActivity with the following code:

    super.onCreate( savedInstanceState );

    // multiple references
    TileView tileView = getTileView();

    // size of original image at 100% scale
    tileView.setSize( 2736, 2880 );

    // detail levels
    tileView.addDetailLevel( 1.000f, "tiles/plans/1000/%col%_%row%.jpg", "samples/plans.JPG");
    tileView.addDetailLevel( 0.500f, "tiles/plans/500/%col%_%row%.jpg", "samples/plans.JPG");
    tileView.addDetailLevel( 0.250f, "tiles/plans/250/%col%_%row%.jpg", "samples/plans.JPG");
    tileView.addDetailLevel( 0.125f, "tiles/plans/125/%col%_%row%.jpg", "samples/plans.JPG");

    ImageView areaPin = new ImageView(this);
    int RED_FADE = Color.argb(100, 209, 50, 57);
    areaPin.setBackgroundColor(RED_FADE);
    areaPin.setMinimumWidth(40);
    areaPin.setMinimumHeight(100);
    tileView.addMarker(areaPin, 1200, 1225, -0.5f, -0.5f);

    // scale it down to manageable size
    tileView.setScale( 0 );

    // center the frame
    frameTo( 0.5, 0.5 );

This will surround the chairs in the living room with an area, but then when I zoom it shrinks (as a marker should). I want that area to keep its borders around both chairs as I zoom in. I'd like to be able to preserve the current marker functionality, but also be able to draw a highlighted area like this. Can this be done? I thought maybe some use of HotSpots could work, but those have no support for drawing.

Thoughts? Thanks in advance.

ZoomPanLayout.smoothScaleTo() is not animating

The ZoomPanLayout.smoothScaleTo() wasn't animating, only moving.
These changes should address that.

Change details:
-Changed System.currentTimeMillis() to SystemClock.elapsedRealtime() for
better animation reliability around clock changes. (This is not necessary and you can ignore if you prefer the previous way)
-Added call to ZoomPanLayout.saveHistoricalScale() in TweenListener this should fix a bug that was preventing scale based animations

Because I based the changes on my earlier PR, I cant seem to be able to PR this to you yet. Please refer to this:
https://github.com/Sage42/TileView/commit/b7715440e228a6b4a634586a89fde36d164ef51e

Add a ColorFIlter to the ImageView

Hi,

for some application, I need to adjust the tile brightness. So I added a ColorFIlter to the imageview when it is created.

However the result is that ๐Ÿ‘

  • TileView loads the tiles and darken them (as expected)
  • and right after that (maybe 1 second maximum) the original tiles (ie the one not darken) take the place of the filtered

Where should I add my ColorFilter in the code ?

Thanks !

Tapping markers doesn't always send event to listener

If I zoom my map and tap on the markers which are on screen after the zoom has finished I'm able to tap the markers and get an expected response. However if I scroll without zooming, the markers which were not on screen after the zoom do not respond to events. These markers are on screen so therefore should be tappable.

However I am using the onScrollChanged event to change which markers are added/removed to/from the map (we compute which markers overlap and group those together into one marker so the user is always able to tap the markers).

DownSample Bitmap Http Decoder Exception ?

Why i cannot put a Bitmap Http Decoder (BitmapDecoderHttp) on the DownSample Decoder ? via this.setDownsampleDecoder(new BitmapDecoderHttp());

I get the following exception : android.os.NetworkOnMainThreadExceptioncause it's not rendering inside a AsynTask as the Tile Rendering.

 android.os.NetworkOnMainThreadException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
        at android.app.ActivityThread.access$600(ActivityThread.java:141)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5103)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:525)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1133)
        at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
        at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
        at java.net.InetAddress.getAllByName(InetAddress.java:214)
        at libcore.net.http.HttpConnection.<init>(HttpConnection.java:70)
        at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)
        at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)
        at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)
        at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
        at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)
        at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
        at com.qozix.tileview.graphics.BitmapDecoderHttp.decode(BitmapDecoderHttp.java:29)
        at com.qozix.tileview.samples.SampleManager.update(SampleManager.java:51)
        at com.qozix.tileview.samples.SampleManager.onDetailLevelChanged(SampleManager.java:61)

Regards,

How can I expand the TileView when it touches the bounds

Hi moagrius,

Great lib, it helps me a lot.

I have a problem, when I scroll the tileView to it's bounds say left, How can I expend the tileView so it can continuously scroll left. The TileView will look like never has bound limits.

Sample App

I'm in the process of creating an app with several implementations of TileView, but it's taking more time than I have at the moment. If anyone wants to take this over, post back. Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.