wp7 webbrowser control opening a centered image - windows-phone-7

I have been looking for a simple way to allow a similar functionality to the built-in Image Viewer (Zooming in and out of an image with 2 fingers, pinch zoom / zoom out, and the floating effect, if someone gently pushes an image in one of the directions).
Initially I was trying to achieve it with the Image control, but It turned out to be extremely difficult.
I decided to go with the Webbrowser control, as it seemed to offer just what I need and it had a benefit of clipping it's content to the parent container ( an Image control wouldn't do that by default ).
I placed the Webbrowser control in the second Row of a 2-row parent Grid container (Its basically the default Page generated by Visual Studio)
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<toolkit:PerformanceProgressBar x:Name="ProgressBar" IsIndeterminate="True" />
<phone:WebBrowser Visibility="Collapsed" x:Name="BrowserWindow" IsScriptEnabled="True" />
</Grid>
The C# code backing the View is this:
public partial class ItemDetailView : PhoneApplicationPage
{
public static string HtmlTemplate =
#"<!doctype html>
<html>
<head>
<meta name='viewport' content='initial-scale=0.1,minimum-scale=0.1,user-scalable=yes,width=480' />
<title></title>
<script type='text/javascript'>
function imageLoadFailed() {{
window.external.notify('ImageLoadFailed');
}}
</script>
</head>
<body style='margin:0; padding:0; width:100%; background-color: {0};'>
<div style='margin:0 auto;'><img onerror='imageLoadFailed()' src='{1}' alt='' /></div>
</body>
</html>";
public ItemDetailView() {
InitializeComponent();
this.BrowserWindow.LoadCompleted += (s, e) => {
this.ProgressBar.IsIndeterminate = false;
this.BrowserWindow.Visibility = Visibility.Visible;
};
this.BrowserWindow.ScriptNotify += (s, e) => {
if (e.Value == "ImageLoadFailed") {
MessageBox.Show("Image failed to load");
}
};
}
public ItemDetailViewModel VM {
get {
return this.DataContext as ItemDetailViewModel
}
}
public bool IsBackgroundBlack() {
return Visibility.Visible == (Visibility)Resources["PhoneDarkThemeVisibility"];
}
protected override void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
App app = App.Current as App;
this.VM.Item = app.CurrentItem;
string css = "";
if (this.IsBackgroundBlack()) {
css = "black";
}
else {
css = "white";
}
this.BrowserWindow.NavigateToString(string.Format(ItemDetailView.HtmlTemplate, css, app.CurrentItem.Url));
}
}
As you may see, I set the width to 480 in the Viewport meta tag. This is the only value that is close enough to center the image so it appears naturally as if placed in an Image control (it fits within the width of the phones screen and is scaled appropriately)
I tried to set the viewport meta tag width property to 'device-width', but with this setting, the image reaches beyond the phones screen width upon initial load.
I also have noticed that with width set to 480, if a user taps on the Web browser for the first time, the browser centers the image a little bit, so 480 is not a perfect value. I am also concerned that this may not be the greatest solution given multiple screen sizes of other devices.
I am curious, if there is a cross-device way to center the image in the web browser control.
Reference Image:
Left Image - What I want, and what it more or less looks like with Viewport meta tag's width=480 (Entire image is seen)
Right Image - What it looks like with Viewport meta tag's width=device-width;
(A single tap is needed to zoom out and position it in the center like the left image)

It appears that there is no need for setting the meta tag at all (it just caused trouble in my case)
the html template:
<!doctype html>
<html>
<head>
<title></title>
<script type='text/javascript'>
function imageLoadFailed() {
window.external.notify('ImageLoadFailed');
}
</script>
</head>
<body style='background-color: {0};'>
<img width='100%' onerror='imageLoadFailed()' src='{1}' alt='' /></div>
</body>
</html>
does the trick

Related

How to communicate 'externally' between Adobe Animate CC animations?

From the script in the html page, I'm trying to control what happens in the Adobe Animate CC animations I've created. For example, here you'll see a script that doesn't work that's trying to tell the ship animation to gotoAndPlay(5). Anyhow, the ship animation is not responding to that. I'm guessing it's because I'm not addressing/naming it correctly. Help me talk to my animations. See the code below.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lets talk to each other</title>
<script src="http://code.createjs.com/easeljs-0.8.1.min.js"></script>
<script src="http://code.createjs.com/tweenjs-0.6.1.min.js"></script>
<script src="http://code.createjs.com/movieclip-0.8.1.min.js"></script>
<script src="ship.js"></script>
<script src="car.js"></script>
<script>
function init () {
var canvas, stage, exportRoot;
canvas = document.getElementById("canvas_ship");
exportRoot = new libs_ship.ship();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
createjs.Ticker.setFPS(libs_ship.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
canvas = document.getElementById("canvas_car");
exportRoot = new libs_car.car();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
createjs.Ticker.setFPS(libs_car.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
}
function Tell_Canvas_Ship_to_gotoAndPlay5(){
canvas_ship.gotoAndPlay(5);
}
</script>
</head>
<body onload="init();" style="background-color:#D4D4D4">
<canvas id="canvas_ship" width="300" height="250" style="background-color:#FFFFFF"></canvas>
<canvas id="canvas_car" width="300" height="250" style="background-color:#FFFFFF"></canvas>
</body>
</html>
It looks like "canvas_ship" is the ID of your actual canvas element. I think what you are trying to do is control the content you are adding to it.
If so, you can call gotoAndPlay on the exportRoot, which is a MovieClip instance with that API.
exportRoot.gotoAndPlay(5);
The issue you will have though, is that once you create your canvas_ship stage and content, you are overwriting the variables. I recommend changing the name of the second canvas, exportRoot, and stage.
You could also add both elements to one canvas. Is there any reason you are using two canvases, other than that you used the exported content from 2 FLAs?
var stage = new createjs.Stage("canvas_ship");
var ship = new libs_ship.ship();
var car = new libs_car.car();
stage.addChild(ship, car);
createjs.Ticker.addEventListener("tick", stage);
Where is your Tell_Canvas_Ship_to_gotoAndPlay5 method getting called from? Is it a frame script in Animate/Flash?
I've received help and will now share the answer. You are welcome. Just invite me over for breakfast sometime.
In Adobe Animate, you'll need to change the library namespace (in the Publish settings in the Advanced tab I think) to lib_jerry or whatever custom name you come up with... so long as it's different than the other animation. Then just follow the setup in this code. You can call the functions from within the Animate animations.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Container</title>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script src="tommy.js"></script>
<script src="jerry.js"></script>
<script>
var canvas, stage, tomtom, jerjer;
function init() {
var exportRoot;
//Tommy
canvas = document.getElementById("canvas_tommy");
tomtom = new lib_tommy.tommy();
stage = new createjs.Stage(canvas);
stage.addChild(tomtom);
stage.update();
createjs.Ticker.setFPS(lib_tommy.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
//Jerry
canvas = document.getElementById("canvas_jerry");
jerjer = new lib_jerry.jerry();
stage = new createjs.Stage(canvas);
stage.addChild(jerjer);
stage.update();
createjs.Ticker.setFPS(lib_jerry.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
}
function button_from_tommy_was_clicked(){
tomtom.gotoAndPlay(5);
}
function button_from_jerry_was_clicked(){
jerjer.gotoAndPlay(5);
}
</script>
</head>
<body onload="init();" style="background-color:#D4D4D4;margin:0px;">
<canvas id="canvas_tommy" width="970" height="90" style="background-color:#727272"></canvas>
<canvas id="canvas_jerry" width="970" height="90" style="background-color:#727272"></canvas>
</body>
</html>

What is best practice for handling resize events in a polymer element?

I'm trying to create a "Viewport" type element extended from a Canvas element. I intended for it to fill the parent container, but that seems not very trivial.
The canvas element does not work with style="width:100%; height:100%" (it will revert to a default value of 300x150 pixels if the special Canvas width and the height attributes are not set, or it will go to 100x100 pixels if I try to set those attributes to "100%". This leaves me with the task of manually setting the width of the canvas element according to the size of the parent element. However I am at a loss when trying to figure out a way to access a resize event I could add a handler to from the perspective of the custom element. I don't seem to get access to window.on.resize from anywhere within the custom element. Do I have to do this from the outside?
Here is an example polymer element definition:
<polymer-element name="canvas-viewport">
<template>
<style>
#host{
:scope {
margin:0px;
padding:0px;
display:block;
position:relative;
width:100%;
height:100%;
background:limegreen;
overflow:visible;
border:0;
}
}
div {
border:0;
margin:0px;
padding:0px;
width:100%;
height:100%;
}
</style>
<div id="container">
<canvas width="{{wpWidth}}" height="{{wpHeight}}" id="theCanvas"></canvas>
</div>
</template>
<script type="application/dart" src="canvas_viewport.dart"></script>
</polymer-element>
Here is some dart code in the accompanying polymer class definition for trying to handle the resize that I made based on a suggested solution to this question.
#override
void attached() {
super.attached();
viewPortContainer = shadowRoot.querySelector("#container");
window.onResize.listen(resizecontainer);
}
void resizecontainer(Event e){
wpWidth = viewPortContainer.clientWidth;
wpHeight = viewPortContainer.clientHeight;
print("resizing Width:$wpWidth , Height:$wpHeight ");
}
However this results in a bug where the height grows by three pixels on each resize event, even though margins and paddings are set to zero.
OnResize works for me inside a custom element.
#override
void attached() {
super.attached();
window.onResize.listen((e) {
print(e.currentTarget.innerWidth);
});
}
This is how I will achieve this in Polymer.
connectedCallback() {
super.connectedCallback();
this._onResize = this.onResize.bind(this);
window.addEventListener("resize", this._onResize);
}
onResize(e) {
console.log('width', e.currentTarget.innerWidth);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener("resize", this._onResize);
}

Viewport meta tag remove bug

My web page has no «meta» viewport tag absolutely.
I have created my own «meta» viewport tag dynamically:
var viewportMeta = document.createElement('meta');
viewportMeta.setAttribute('id', 'myMeta');
viewportMeta.setAttribute('name', 'viewport');
viewportMeta.setAttribute('content', 'width=device-width, initial-scale=1.0, user-scalable=no');
and appended it to the «head» (after some user actions):
document.head.appendChild(viewportMeta);
Then (after user clicks on some button) I need to remove "myMeta" «meta» tag from «head»:
var myMeta = document.getElementById('myMeta');
document.head.removeChild(myMeta);
And it removes, 100%! Checked with desktop browser and with Adobe Edge Inspect Weinre on iPad.
But the whole page does not go to it's previous state! Whole page stays the same, like it has «meta» viewport tag with all defined properties in "viewportMeta" object.
So, is there a way to remove «meta» viewport tag completely? Any ideas?
(This issue is on iPad's Safari and Chrome browsers. Tried not to remove «meta» tag but just changed it's «content» property — no success. Did not checked on Android devices and browsers.)
You should restore the original value of viewport meta tag
<html>
<head>
<title>test dynamic view port</title>
</head>
<body>
<button id="turnOn">on</button>
<button id="turnOff">off</button>
<script type="text/javascript">
function turnOnDeviceViewport() {
removeMetaIfExist();
var viewportMeta = document.createElement('meta');
viewportMeta.setAttribute('id', 'myMeta');
viewportMeta.setAttribute('name', 'viewport');
viewportMeta.setAttribute('content', 'width=device-width, initial-scale=1.0, user-scalable=no');
document.head.appendChild(viewportMeta);
alert("click");
}
function turnOffDeviceViewport() {
removeMetaIfExist();
var viewportMeta = document.createElement('meta');
viewportMeta.setAttribute('id', 'myMeta');
viewportMeta.setAttribute('name', 'viewport');
viewportMeta.setAttribute('content', 'width=980, user-scalable=yes');
document.head.appendChild(viewportMeta);
alert("click");
}
function removeMetaIfExist() {
var metaElement = document.getElementById("myMeta");
if (metaElement) document.head.removeChild(metaElement);
alert("removed");
}
document.getElementById("turnOn").addEventListener("click", turnOnDeviceViewport, false);
document.getElementById("turnOff").addEventListener("click", turnOffDeviceViewport, false);
</script>
</body>
You can find details about viewport meta default values on Apple's developer website:
Safari HTML Reference: Supported Meta Tags
EDIT: the default viewport value "width=980, user-scalable=yes" might not be the same for all devices and browsers so for a complete solution you will need to identify the browser you are running on and set the default value accordingly

Virtual area around vml element

this is my first post, so my deepest excuses if something went wrong :)
I have a little html-control to write and biggest problem is ie6-8 support. There are no alternatives to skip ie6-8 support at all :( So after searching a while, I did found Raphael and it allows me to create custom shapes defined in SVG file. I need to attach 'mouseover' event and select element on hover. Event working great but I did find BIG problems in VML hover behavior.
Code was simplified to RAW html with VML shape.
<html xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<style>v\: * { behavior:url(#default#VML); antialias: false; }</style>
</head>
<body>
<div id="message">hovered: nope</div>
<v:oval id="oval" style="width:100px; height:75px" fillcolor="#bbb"></v:oval>
<script>
var messageElm = document.getElementById('message');
var ovalElm = document.getElementById('oval');
ovalElm.attachEvent('onmouseover', function () { messageElm.innerText = 'hovered: yep'; });
ovalElm.attachEvent('onmouseout', function () { messageElm.innerText = 'hovered: nope'; });
</script>
</body>
</html>
If you try to move mouse over oval element you can noticed that rendered shape is not same as hover shape. I mean, hover triggers 2-3px from rendered shape (not from each side).
So question is: how to disable that virtual area (if it is possible at all)?
i had the same issue and i tried usemap;
first i create a map on a transparent png8 which covered the vml
this.dom.insertAdjacentHTML("AfterBegin",'<map name="'+_id+'"></map><img id="'+_id+'" src="'+transparent.png+
'" style="position:absolute;width:'+dom.clientWidth+';height:'+dom.clientHeight+'" />');
var map = this.dom.getElementsByTagName('map')[0];
this.dom.appendChild(map);
this.map = map;
then get the shape attach to an area; map it;
i made poly demo only;
function _getMap(shape){
this._map = this._map || {};
if(this._map[shape.id]){
}else if(shape.nodeName == 'shape'){
var arrDots = shape.childNodes[0].v.match(/(\d+),(\d+)/g)
this._map[shape.id] = _polyMap(arrDots);
}
return this.map[shape.id]
}
function _polyMap(arrDots){
var map = this.map;
var area = document.createElement('area');
area.setAttribute('shape',"poly");
area.setAttribute('coords',arrDots.join(','));
area.setAttribute('href','##');
area.setAttribute('alt','##');
map.appendChild(area);
}
then you can bind event on it;
function _onIE(shape, evtname, fn){
this._getMap(shape).attachEvent('on'+evtname, fn);
}

How to draw only the visible pixels which are >0% alpha with a custom color in canvas?

I would like to make a good performance hit test for png images and other shapes. I don't really care what shapes they are because with this technique there is no performance issues at checking (not setup).
I intent to collect all the images on the screen in a secondary canvas just for hit test. For each image drawn I will create a new color which is attached to that particular image. Then I draw all of them in the canvas, each image will have a different fill color.
When I click on a pixel (x, y) it will get the color (r, g, b). Every color is mapped to a image, so I get the image clicked with no error (I don't waste with finding what was hit with that click).
I know it will be limited to 256*256*256=16 777 216 items because those are all the colors but I don't think it will be a problem for now...
So what I really need is to know how to put those fill colors on the secondary canvas which is based only on the visible pixels for each image.
UPDATE
As you can see to the right it's the hit test map. So if I click on the black shade (c) I instantly know I've clicked on the blue box without any other calculation.
One improvement it would be to cache the alpha data. Also reuse the same alpha data for each image instance (we must take care about scaling and rotation...).
thanks
Here’s how you would color-mask the non-transparent pixels of a canvas image.
Be sure you replace "PutYourImageHere.png" with your own image url.
<!doctype html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid blue;}
</style>
<script>
$(function(){
var img=new Image();
img.onload=function(){
var red=255;
var blue=0;
var green=0;
var canvasCopy=document.getElementById("canvasCopy");
var ctxCopy=canvasCopy.getContext("2d");
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
ctx.drawImage(this,0,0);
var imgData=ctx.getImageData(0,0,c.width,c.height);
for (var i=0;i<imgData.data.length;i+=4)
{
if(imgData.data[i+3]>0){
imgData.data[i]=red;
imgData.data[i+1]=green;
imgData.data[i+2]=blue;
imgData.data[i+3]=255;
}
}
ctxCopy.putImageData(imgData,0,0);
}
img.src = "PutYourImageHere.png";
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<canvas id="canvasCopy" width="300" height="300"></canvas>
</body>
</html>

Resources