mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 14:46:10 +03:00
1540 Add feature to crop tiledImage with multiple polygons
This commit is contained in:
parent
d97fe5b1eb
commit
2d971af445
@ -166,6 +166,38 @@ $.Drawer.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* This function gets the top left point from the viewport using the pixel point
|
||||
* @param {OpenSeadragon.Point} point - the pixel points to convert
|
||||
*/
|
||||
viewportCoordToDrawerCoord: function(point) {
|
||||
var topLeft = this.viewport.pixelFromPointNoRotate(point, true);
|
||||
return new $.Point(
|
||||
topLeft.x * $.pixelDensityRatio,
|
||||
topLeft.y * $.pixelDensityRatio
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will create multiple polygon paths on the drawing context by provided polygons,
|
||||
* then clip the context to the paths.
|
||||
* @param {(OpenSeadragon.Point[])[]} polygons - an array of polygons. A polygon is an array of OpenSeadragon.Point
|
||||
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
|
||||
*/
|
||||
clipWithPolygons: function (polygons, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
var context = this._getContext(useSketch);
|
||||
context.beginPath();
|
||||
polygons.forEach(function (polygon) {
|
||||
polygon.forEach(function (coord, i) {
|
||||
context[i == 0 ? 'moveTo' : 'lineTo'](coord.x, coord.y);
|
||||
});
|
||||
});
|
||||
context.clip();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the opacity of the drawer.
|
||||
* @param {Number} opacity
|
||||
|
@ -674,6 +674,27 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
this._setScale(height / this.normHeight, immediately);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an array of polygons to crop the TiledImage during draw tiles.
|
||||
* The render function will use the default non-zero winding rule.
|
||||
* @param Polygons represented in an array of pair array in pixels.
|
||||
* Example format: [
|
||||
* [[197,172],[226,172],[226,198],[197,198]], // First polygon
|
||||
* [[328,200],[330,199],[332,201],[329,202]] // Second polygon
|
||||
* ]
|
||||
*/
|
||||
setCroppingPolygons: function( polygons ) {
|
||||
this._croppingPolygons = polygons;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the cropping polygons, thus next render will remove all cropping
|
||||
* polygon effects.
|
||||
*/
|
||||
resetCroppingPolygons: function() {
|
||||
this._croppingPolygons = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Positions and scales the TiledImage to fit in the specified bounds.
|
||||
* Note: this method fires OpenSeadragon.TiledImage.event:bounds-change
|
||||
@ -1932,6 +1953,28 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
usedClip = true;
|
||||
}
|
||||
|
||||
if (tiledImage._croppingPolygons) {
|
||||
tiledImage._drawer.saveContext(useSketch);
|
||||
try {
|
||||
var polygons = tiledImage._croppingPolygons.map(function (polygon) {
|
||||
return polygon.map(function (pointPair) {
|
||||
var point = tiledImage
|
||||
.imageToViewportCoordinates(pointPair[0], pointPair[1], true)
|
||||
.rotate(-tiledImage.getRotation(true), tiledImage._getRotationPoint(true));
|
||||
var clipPoint = tiledImage._drawer.viewportCoordToDrawerCoord(point);
|
||||
if (sketchScale) {
|
||||
clipPoint = clipPoint.times(sketchScale);
|
||||
}
|
||||
return clipPoint;
|
||||
});
|
||||
});
|
||||
tiledImage._drawer.clipWithPolygons(polygons, useSketch);
|
||||
} catch (e) {
|
||||
$.console.error(e);
|
||||
}
|
||||
usedClip = true;
|
||||
}
|
||||
|
||||
if ( tiledImage.placeholderFillStyle && tiledImage._hasOpaqueTile === false ) {
|
||||
var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true));
|
||||
if (sketchScale) {
|
||||
|
128
test/demo/cropping-polygons.html
Normal file
128
test/demo/cropping-polygons.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Cropping PolygonList Demo</title>
|
||||
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
|
||||
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
|
||||
<style type="text/css">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
background: lightgreen;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.box-with-title {
|
||||
padding-top: 1em;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.box-with-title button{
|
||||
display: block;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>
|
||||
Simple demo page to show cropping with polygonList in a OpenSeadragon viewer.
|
||||
</h3>
|
||||
<div id="contentDiv" class="openseadragon1"></div>
|
||||
<span>Click on Viewer to save polygon points</span>
|
||||
<div>
|
||||
<button id='resetBtn'>Reset</button>
|
||||
<button id='exampleBtn'>Load Example</button>
|
||||
</div>
|
||||
<div class='box-with-title'>
|
||||
<button id="addBtn">Add As Polygon</button>
|
||||
<textarea id="polygonEl"></textarea>
|
||||
</div>
|
||||
<div class='box-with-title'>
|
||||
<button id="cropBtn">Crop With Polygon</button>
|
||||
<textarea id='previewEl'></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Setup Viewer -->
|
||||
<script type="text/javascript">
|
||||
var viewer = OpenSeadragon({
|
||||
// debugMode: true,
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
tileSources: "../data/testpattern.dzi",
|
||||
showNavigator: false,
|
||||
gestureSettingsMouse: {
|
||||
clickToZoom: false
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Global Variables
|
||||
var previewEl = document.getElementById('previewEl');
|
||||
var polygonEl = document.getElementById('polygonEl');
|
||||
var examples = [
|
||||
[[480,300],[300,420],[600,420]], // Triangle
|
||||
[[300,550],[300,750],[600,750],[600,550]] // Rectangle
|
||||
];
|
||||
var polygon = [];
|
||||
var polygonList = [];
|
||||
|
||||
// Load default examples
|
||||
function loadExample(){
|
||||
polygonList = JSON.parse(JSON.stringify(examples));
|
||||
previewEl.innerHTML = JSON.stringify(polygonList);
|
||||
}
|
||||
loadExample();
|
||||
|
||||
// Add click handler to clicked point tracker
|
||||
viewer.addHandler('canvas-click', function(event) {
|
||||
var webPoint = event.position;
|
||||
var viewportPoint = viewer.viewport.pointFromPixel(webPoint);
|
||||
var p = viewer.viewport.viewportToImageCoordinates(viewportPoint);
|
||||
p.x = Math.round((p.x + Number.EPSILON) * 100) / 100
|
||||
p.y = Math.round((p.y + Number.EPSILON) * 100) / 100
|
||||
polygon.push([p.x, p.y]);
|
||||
polygonEl.innerHTML += '['+p.x+','+ p.y+']';
|
||||
});
|
||||
|
||||
// Add clicked points to polygon tracker variable
|
||||
document.getElementById('addBtn').onclick = function(){
|
||||
if (polygon.length == 0) { return; }
|
||||
polygonList.push(polygon);
|
||||
polygon = [];
|
||||
polygonEl.innerHTML = '';
|
||||
previewEl.innerHTML = JSON.stringify(polygonList);
|
||||
};
|
||||
|
||||
document.getElementById('cropBtn').onclick = function(){
|
||||
polygonList = JSON.parse(previewEl.innerHTML);
|
||||
polygonEl.innerHTML = '';
|
||||
var tiledImage = viewer.world.getItemAt(0);
|
||||
tiledImage.setCroppingPolygons(polygonList);
|
||||
viewer.forceRedraw();
|
||||
};
|
||||
|
||||
document.getElementById('resetBtn').onclick = function(){
|
||||
polygonList = []
|
||||
polygon = []
|
||||
polygonEl.innerHTML = '';
|
||||
previewEl.innerHTML = '';
|
||||
var tiledImage = viewer.world.getItemAt(0);
|
||||
tiledImage.resetCroppingPolygons();
|
||||
viewer.forceRedraw();
|
||||
};
|
||||
|
||||
document.getElementById('exampleBtn').onclick = loadExample;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user