Skip to content
Snippets Groups Projects
Commit b097d260 authored by srosse's avatar srosse
Browse files

no-jira: hotspot without applet

parent f4c771dc
No related branches found
No related tags found
No related merge requests found
...@@ -24,6 +24,7 @@ import java.net.URI; ...@@ -24,6 +24,7 @@ import java.net.URI;
import org.olat.core.gui.UserRequest; import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.AbstractComponent; import org.olat.core.gui.components.AbstractComponent;
import org.olat.core.gui.components.ComponentRenderer; import org.olat.core.gui.components.ComponentRenderer;
import org.olat.core.gui.control.JSAndCSSAdder;
import org.olat.core.gui.render.ValidationResult; import org.olat.core.gui.render.ValidationResult;
import org.olat.ims.qti21.ui.CandidateSessionContext; import org.olat.ims.qti21.ui.CandidateSessionContext;
...@@ -96,7 +97,10 @@ public class AssessmentTestComponent extends AbstractComponent { ...@@ -96,7 +97,10 @@ public class AssessmentTestComponent extends AbstractComponent {
@Override @Override
public void validate(UserRequest ureq, ValidationResult vr) { public void validate(UserRequest ureq, ValidationResult vr) {
super.validate(ureq, vr); super.validate(ureq, vr);
vr.getJsAndCSSAdder().addRequiredStaticJsFile("assessment/rendering/javascript/QtiWorksRendering.js");
JSAndCSSAdder jsa = vr.getJsAndCSSAdder();
jsa.addRequiredStaticJsFile("assessment/rendering/javascript/QtiWorksRendering.js");
jsa.addRequiredStaticJsFile("js/jquery/maphilight/jquery.maphilight.js");
} }
@Override @Override
......
...@@ -54,6 +54,8 @@ import javax.xml.transform.stream.StreamResult; ...@@ -54,6 +54,8 @@ import javax.xml.transform.stream.StreamResult;
import org.olat.core.dispatcher.impl.StaticMediaDispatcher; import org.olat.core.dispatcher.impl.StaticMediaDispatcher;
import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.StringOutput;
import org.olat.core.helpers.Settings; import org.olat.core.helpers.Settings;
import org.olat.core.util.StringHelper;
import org.olat.core.util.WebappHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BeanPropertyBindingResult;
...@@ -73,6 +75,7 @@ import uk.ac.ed.ph.jqtiplus.state.TestSessionState; ...@@ -73,6 +75,7 @@ import uk.ac.ed.ph.jqtiplus.state.TestSessionState;
import uk.ac.ed.ph.jqtiplus.state.marshalling.ItemSessionStateXmlMarshaller; import uk.ac.ed.ph.jqtiplus.state.marshalling.ItemSessionStateXmlMarshaller;
import uk.ac.ed.ph.jqtiplus.state.marshalling.TestSessionStateXmlMarshaller; import uk.ac.ed.ph.jqtiplus.state.marshalling.TestSessionStateXmlMarshaller;
import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator;
import uk.ac.ed.ph.jqtiplus.xmlutils.locators.FileResourceLocator;
import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator;
import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.SimpleXsltStylesheetCache; import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.SimpleXsltStylesheetCache;
import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetManager; import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltStylesheetManager;
...@@ -98,30 +101,47 @@ public class AssessmentRenderer { ...@@ -98,30 +101,47 @@ public class AssessmentRenderer {
private static final Logger logger = LoggerFactory.getLogger(AssessmentRenderer.class); private static final Logger logger = LoggerFactory.getLogger(AssessmentRenderer.class);
private static final URI serializeXsltUri = URI.create("classpath:/rendering-xslt/serialize.xsl"); private static final URI serializeXsltUri;
private static final URI ctopXsltUri = URI.create("classpath:/rendering-xslt/ctop.xsl"); private static final URI ctopXsltUri;
private static final URI itemStandaloneXsltUri = URI.create("classpath:/rendering-xslt/item-standalone.xsl"); private static final URI itemStandaloneXsltUri;
private static final URI testItemXsltUri = URI.create("classpath:/rendering-xslt/test-item.xsl"); private static final URI testItemXsltUri;
private static final URI testEntryXsltUri = URI.create("classpath:/rendering-xslt/test-entry.xsl"); private static final URI testEntryXsltUri;
private static final URI testPartNavigationXsltUri = URI.create("classpath:/rendering-xslt/test-testpart-navigation.xsl"); private static final URI testPartNavigationXsltUri;
private static final URI testPartFeedbackXsltUri = URI.create("classpath:/rendering-xslt/test-testpart-feedback.xsl"); private static final URI testPartFeedbackXsltUri;
private static final URI testFeedbackXsltUri = URI.create("classpath:/rendering-xslt/test-feedback.xsl"); private static final URI testFeedbackXsltUri;
private static final URI terminatedXsltUri = URI.create("classpath:/rendering-xslt/terminated.xsl"); private static final URI terminatedXsltUri;
private static final URI explodedXsltUri = URI.create("classpath:/rendering-xslt/exploded.xsl"); private static final URI explodedXsltUri;
static {
String path;
if(Settings.isDebuging() && StringHelper.containsNonWhitespace(WebappHelper.getSourcePath())) {
path = "file://" + WebappHelper.getSourcePath().replace("/src/main/java", "/src/main/resources");
} else {
path = "classpath:";
}
serializeXsltUri = URI.create(path + "/rendering-xslt/serialize.xsl");
ctopXsltUri = URI.create(path + "/rendering-xslt/ctop.xsl");
itemStandaloneXsltUri = URI.create(path + "/rendering-xslt/item-standalone.xsl");
testItemXsltUri = URI.create(path + "/rendering-xslt/test-item.xsl");
testEntryXsltUri = URI.create(path + "/rendering-xslt/test-entry.xsl");
testPartNavigationXsltUri = URI.create(path + "/rendering-xslt/test-testpart-navigation.xsl");
testPartFeedbackXsltUri = URI.create(path + "/rendering-xslt/test-testpart-feedback.xsl");
testFeedbackXsltUri = URI.create(path + "/rendering-xslt/test-feedback.xsl");
terminatedXsltUri = URI.create(path + "/rendering-xslt/terminated.xsl");
explodedXsltUri = URI.create(path + "/rendering-xslt/exploded.xsl");
}
/** Manager for the XSLT stylesheets, created during init. */ /** Manager for the XSLT stylesheets, created during init. */
private XsltStylesheetManager stylesheetManager; private XsltStylesheetManager stylesheetManager;
//----------------------------------------------------
//---------------------------------------------------- //----------------------------------------------------
public AssessmentRenderer() { public AssessmentRenderer() {
this.stylesheetManager = new XsltStylesheetManager(new ClassPathResourceLocator(), new SimpleXsltStylesheetCache()); if(Settings.isDebuging() && StringHelper.containsNonWhitespace(WebappHelper.getSourcePath())) {
stylesheetManager = new XsltStylesheetManager(new FileResourceLocator(), null);
} else {
stylesheetManager = new XsltStylesheetManager(new ClassPathResourceLocator(), new SimpleXsltStylesheetCache());
}
} }
//---------------------------------------------------- //----------------------------------------------------
......
...@@ -22,37 +22,82 @@ ...@@ -22,37 +22,82 @@
<xsl:variable name="object" select="qti:object" as="element(qti:object)"/> <xsl:variable name="object" select="qti:object" as="element(qti:object)"/>
<xsl:variable name="appletContainerId" select="concat('qtiworks_id_appletContainer_', @responseIdentifier)" as="xs:string"/> <xsl:variable name="appletContainerId" select="concat('qtiworks_id_appletContainer_', @responseIdentifier)" as="xs:string"/>
<xsl:variable name="responseValue" select="qw:get-response-value(/, @responseIdentifier)" as="element(qw:responseVariable)?"/>
<div id="{$appletContainerId}" class="appletContainer v2"> <div id="{$appletContainerId}" class="appletContainer v2">
<object type="application/x-java-applet" height="{$object/@height + 40}" width="{$object/@width}"> <img id="{$appletContainerId}_img" width="206" height="280" src="{qw:convert-link-full($object/@data)}" usemap="#{$appletContainerId}_map"></img>
<param name="code" value="BoundedGraphicalApplet"/> <map name="{$appletContainerId}_map">
<param name="codebase" value="{$appletCodebase}"/> <xsl:for-each select="qti:hotspotChoice">
<param name="identifier" value="{@responseIdentifier}"/> <!-- Match group, label -->
<param name="operation_mode" value="hotspot_interaction"/> <area id="{@identifier}" shape="{@shape}" coords="{@coords}" href="javascript:clickArea('{@identifier}')" data-maphilight=''></area>
<!-- (BoundedGraphicalApplet uses -1 to represent 'unlimited') --> </xsl:for-each>
<param name="number_of_responses" value="{if (@maxChoices &gt; 0) then @maxChoices else -1}"/> </map>
<param name="background_image" value="{qw:convert-link-full($object/@data)}"/>
<xsl:variable name="hotspotChoices" select="qw:filter-visible(qti:hotspotChoice)" as="element(qti:hotspotChoice)*"/>
<param name="hotspot_count" value="{count($hotspotChoices)}"/>
<xsl:for-each select="qti:hotspotChoice">
<param name="hotspot{position()-1}"
value="{@identifier}::::{@shape}::{@coords}{if (@label) then concat('::hotSpotLabel',@label) else ''}{if (@matchGroup) then concat('::', translate(normalize-space(@matchGroup), ' ', '::')) else ''}"/>
</xsl:for-each>
<xsl:variable name="responseValue" select="qw:get-response-value(/, @responseIdentifier)" as="element(qw:responseVariable)?"/> <script type="text/javascript">
<xsl:if test="qw:is-not-null-value($responseValue)"> jQuery(function() {
<param name="feedback"> jQuery('#<xsl:value-of select="$appletContainerId"/>_img').maphilight({
<xsl:attribute name="value"> fillColor: '888888',
<xsl:value-of select="$responseValue/qw:value" separator=","/> strokeColor: '0000ff',
</xsl:attribute> strokeWidth: 3
</param> });
</xsl:if> });
</object>
<script type="text/javascript"> <xsl:choose>
jQuery(document).ready(function() { <xsl:when test="qw:is-not-null-value($responseValue)">
QtiWorksRendering.registerAppletBasedInteractionContainer('<xsl:value-of
select="$appletContainerId"/>', ['<xsl:value-of select="@responseIdentifier"/>']); jQuery(function() {
}); var areaIds = '<xsl:value-of select="$responseValue/qw:value" separator=","/>'.split(',');
</script> for(i=areaIds.length; i-->0; ) {
var areaEl = jQuery('#' + areaIds[i])
var data = areaEl.data('maphilight') || {};
data.alwaysOn = true;
areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
}
});
function clickArea(spot) { };
</xsl:when><xsl:otherwise>
function clickArea(spot) {
var areaEl = jQuery('#' + spot)
var data = areaEl.data('maphilight') || {};
if(!data.alwaysOn) {
var numOfChoices = 1;
if(numOfChoices > 0) {
var countChoices = 0;
jQuery("area", "map[name='<xsl:value-of select="$appletContainerId"/>_map']").each(function(index, el) {
var cData = jQuery(el).data('maphilight') || {};
if(cData.alwaysOn) {
countChoices++;
}
});
if(countChoices >= numOfChoices) {
return false;
}
}
}
data.alwaysOn = !data.alwaysOn;
areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
var divContainer = jQuery('#<xsl:value-of select="$appletContainerId"/>');
divContainer.find("input[type='hidden']").remove();
jQuery("area", "map[name='<xsl:value-of select="$appletContainerId"/>_map']").each(function(index, el) {
var cAreaEl = jQuery(el);
var cData = cAreaEl.data('maphilight') || {};
if(cData.alwaysOn) {
var inputElement = jQuery('<input type="hidden"/>')
.attr('name', 'qtiworks_response_<xsl:value-of select="@responseIdentifier"/>')
.attr('value', areaEl.attr('id'));
divContainer.append(inputElement);
}
});
};
</xsl:otherwise>
</xsl:choose>
</script>
</div> </div>
</div> </div>
</xsl:template> </xsl:template>
......
(function($) {
var has_VML, has_canvas, create_canvas_for, add_shape_to, clear_canvas, shape_from_area,
canvas_style, hex_to_decimal, css3color, is_image_loaded, options_from_area;
has_canvas = !!document.createElement('canvas').getContext;
// VML: more complex
has_VML = (function() {
var a = document.createElement('div');
a.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
var b = a.firstChild;
b.style.behavior = "url(#default#VML)";
return b ? typeof b.adj == "object": true;
})();
if(!(has_canvas || has_VML)) {
$.fn.maphilight = function() { return this; };
return;
}
if(has_canvas) {
hex_to_decimal = function(hex) {
return Math.max(0, Math.min(parseInt(hex, 16), 255));
};
css3color = function(color, opacity) {
return 'rgba('+hex_to_decimal(color.substr(0,2))+','+hex_to_decimal(color.substr(2,2))+','+hex_to_decimal(color.substr(4,2))+','+opacity+')';
};
create_canvas_for = function(img) {
var c = $('<canvas style="width:'+$(img).width()+'px;height:'+$(img).height()+'px;"></canvas>').get(0);
c.getContext("2d").clearRect(0, 0, $(img).width(), $(img).height());
return c;
};
var draw_shape = function(context, shape, coords, x_shift, y_shift) {
x_shift = x_shift || 0;
y_shift = y_shift || 0;
context.beginPath();
if(shape == 'rect') {
// x, y, width, height
context.rect(coords[0] + x_shift, coords[1] + y_shift, coords[2] - coords[0], coords[3] - coords[1]);
} else if(shape == 'poly') {
context.moveTo(coords[0] + x_shift, coords[1] + y_shift);
for(i=2; i < coords.length; i+=2) {
context.lineTo(coords[i] + x_shift, coords[i+1] + y_shift);
}
} else if(shape == 'circ') {
// x, y, radius, startAngle, endAngle, anticlockwise
context.arc(coords[0] + x_shift, coords[1] + y_shift, coords[2], 0, Math.PI * 2, false);
}
context.closePath();
}
add_shape_to = function(canvas, shape, coords, options, name) {
var i, context = canvas.getContext('2d');
// Because I don't want to worry about setting things back to a base state
// Shadow has to happen first, since it's on the bottom, and it does some clip /
// fill operations which would interfere with what comes next.
if(options.shadow) {
context.save();
if(options.shadowPosition == "inside") {
// Cause the following stroke to only apply to the inside of the path
draw_shape(context, shape, coords);
context.clip();
}
// Redraw the shape shifted off the canvas massively so we can cast a shadow
// onto the canvas without having to worry about the stroke or fill (which
// cannot have 0 opacity or width, since they're what cast the shadow).
var x_shift = canvas.width * 100;
var y_shift = canvas.height * 100;
draw_shape(context, shape, coords, x_shift, y_shift);
context.shadowOffsetX = options.shadowX - x_shift;
context.shadowOffsetY = options.shadowY - y_shift;
context.shadowBlur = options.shadowRadius;
context.shadowColor = css3color(options.shadowColor, options.shadowOpacity);
// Now, work out where to cast the shadow from! It looks better if it's cast
// from a fill when it's an outside shadow or a stroke when it's an interior
// shadow. Allow the user to override this if they need to.
var shadowFrom = options.shadowFrom;
if (!shadowFrom) {
if (options.shadowPosition == 'outside') {
shadowFrom = 'fill';
} else {
shadowFrom = 'stroke';
}
}
if (shadowFrom == 'stroke') {
context.strokeStyle = "rgba(0,0,0,1)";
context.stroke();
} else if (shadowFrom == 'fill') {
context.fillStyle = "rgba(0,0,0,1)";
context.fill();
}
context.restore();
// and now we clean up
if(options.shadowPosition == "outside") {
context.save();
// Clear out the center
draw_shape(context, shape, coords);
context.globalCompositeOperation = "destination-out";
context.fillStyle = "rgba(0,0,0,1);";
context.fill();
context.restore();
}
}
context.save();
draw_shape(context, shape, coords);
// fill has to come after shadow, otherwise the shadow will be drawn over the fill,
// which mostly looks weird when the shadow has a high opacity
if(options.fill) {
context.fillStyle = css3color(options.fillColor, options.fillOpacity);
context.fill();
}
// Likewise, stroke has to come at the very end, or it'll wind up under bits of the
// shadow or the shadow-background if it's present.
if(options.stroke) {
context.strokeStyle = css3color(options.strokeColor, options.strokeOpacity);
context.lineWidth = options.strokeWidth;
context.stroke();
}
context.restore();
if(options.fade) {
$(canvas).css('opacity', 0).animate({opacity: 1}, 100);
}
};
clear_canvas = function(canvas) {
canvas.getContext('2d').clearRect(0, 0, canvas.width,canvas.height);
};
} else { // ie executes this code
create_canvas_for = function(img) {
return $('<var style="zoom:1;overflow:hidden;display:block;width:'+img.width+'px;height:'+img.height+'px;"></var>').get(0);
};
add_shape_to = function(canvas, shape, coords, options, name) {
var fill, stroke, opacity, e;
for (var i in coords) { coords[i] = parseInt(coords[i], 10); }
fill = '<v:fill color="#'+options.fillColor+'" opacity="'+(options.fill ? options.fillOpacity : 0)+'" />';
stroke = (options.stroke ? 'strokeweight="'+options.strokeWidth+'" stroked="t" strokecolor="#'+options.strokeColor+'"' : 'stroked="f"');
opacity = '<v:stroke opacity="'+options.strokeOpacity+'"/>';
if(shape == 'rect') {
e = $('<v:rect name="'+name+'" filled="t" '+stroke+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+coords[0]+'px;top:'+coords[1]+'px;width:'+(coords[2] - coords[0])+'px;height:'+(coords[3] - coords[1])+'px;"></v:rect>');
} else if(shape == 'poly') {
e = $('<v:shape name="'+name+'" filled="t" '+stroke+' coordorigin="0,0" coordsize="'+canvas.width+','+canvas.height+'" path="m '+coords[0]+','+coords[1]+' l '+coords.join(',')+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+canvas.width+'px;height:'+canvas.height+'px;"></v:shape>');
} else if(shape == 'circ') {
e = $('<v:oval name="'+name+'" filled="t" '+stroke+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(coords[0] - coords[2])+'px;top:'+(coords[1] - coords[2])+'px;width:'+(coords[2]*2)+'px;height:'+(coords[2]*2)+'px;"></v:oval>');
}
e.get(0).innerHTML = fill+opacity;
$(canvas).append(e);
};
clear_canvas = function(canvas) {
// jquery1.8 + ie7
var $html = $("<div>" + canvas.innerHTML + "</div>");
$html.children('[name=highlighted]').remove();
canvas.innerHTML = $html.html();
};
}
shape_from_area = function(area) {
var i, coords = area.getAttribute('coords').split(',');
for (i=0; i < coords.length; i++) { coords[i] = parseFloat(coords[i]); }
return [area.getAttribute('shape').toLowerCase().substr(0,4), coords];
};
options_from_area = function(area, options) {
var $area = $(area);
return $.extend({}, options, $.metadata ? $area.metadata() : false, $area.data('maphilight'));
};
is_image_loaded = function(img) {
if(!img.complete) { return false; } // IE
if(typeof img.naturalWidth != "undefined" && img.naturalWidth === 0) { return false; } // Others
return true;
};
canvas_style = {
position: 'absolute',
left: 0,
top: 0,
padding: 0,
border: 0
};
var ie_hax_done = false;
$.fn.maphilight = function(opts) {
opts = $.extend({}, $.fn.maphilight.defaults, opts);
if(!has_canvas && !ie_hax_done) {
$(window).ready(function() {
document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
var style = document.createStyleSheet();
var shapes = ['shape','rect', 'oval', 'circ', 'fill', 'stroke', 'imagedata', 'group','textbox'];
$.each(shapes,
function() {
style.addRule('v\\:' + this, "behavior: url(#default#VML); antialias:true");
}
);
});
ie_hax_done = true;
}
return this.each(function() {
var img, wrap, options, map, canvas, canvas_always, mouseover, highlighted_shape, usemap;
img = $(this);
if(!is_image_loaded(this)) {
// If the image isn't fully loaded, this won't work right. Try again later.
return window.setTimeout(function() {
img.maphilight(opts);
}, 200);
}
options = $.extend({}, opts, $.metadata ? img.metadata() : false, img.data('maphilight'));
// jQuery bug with Opera, results in full-url#usemap being returned from jQuery's attr.
// So use raw getAttribute instead.
usemap = img.get(0).getAttribute('usemap');
if (!usemap) {
return
}
map = $('map[name="'+usemap.substr(1)+'"]');
if(!(img.is('img,input[type="image"]') && usemap && map.size() > 0)) {
return;
}
if(img.hasClass('maphilighted')) {
// We're redrawing an old map, probably to pick up changes to the options.
// Just clear out all the old stuff.
var wrapper = img.parent();
img.insertBefore(wrapper);
wrapper.remove();
$(map).unbind('.maphilight').find('area[coords]').unbind('.maphilight');
}
wrap = $('<div></div>').css({
display:'block',
background:'url("'+this.src+'")',
position:'relative',
padding:0,
width:this.width,
height:this.height
});
if(options.wrapClass) {
if(options.wrapClass === true) {
wrap.addClass($(this).attr('class'));
} else {
wrap.addClass(options.wrapClass);
}
}
img.before(wrap).css('opacity', 0).css(canvas_style).remove();
if(has_VML) { img.css('filter', 'Alpha(opacity=0)'); }
wrap.append(img);
canvas = create_canvas_for(this);
$(canvas).css(canvas_style);
canvas.height = this.height;
canvas.width = this.width;
mouseover = function(e) {
var shape, area_options;
area_options = options_from_area(this, options);
if(
!area_options.neverOn
&&
!area_options.alwaysOn
) {
shape = shape_from_area(this);
add_shape_to(canvas, shape[0], shape[1], area_options, "highlighted");
if(area_options.groupBy) {
var areas;
// two ways groupBy might work; attribute and selector
if(/^[a-zA-Z][\-a-zA-Z]+$/.test(area_options.groupBy)) {
areas = map.find('area['+area_options.groupBy+'="'+$(this).attr(area_options.groupBy)+'"]');
} else {
areas = map.find(area_options.groupBy);
}
var first = this;
areas.each(function() {
if(this != first) {
var subarea_options = options_from_area(this, options);
if(!subarea_options.neverOn && !subarea_options.alwaysOn) {
var shape = shape_from_area(this);
add_shape_to(canvas, shape[0], shape[1], subarea_options, "highlighted");
}
}
});
}
// workaround for IE7, IE8 not rendering the final rectangle in a group
if(!has_canvas) {
$(canvas).append('<v:rect></v:rect>');
}
}
}
$(map).bind('alwaysOn.maphilight', function() {
// Check for areas with alwaysOn set. These are added to a *second* canvas,
// which will get around flickering during fading.
if(canvas_always) {
clear_canvas(canvas_always);
}
if(!has_canvas) {
$(canvas).empty();
}
$(map).find('area[coords]').each(function() {
var shape, area_options;
area_options = options_from_area(this, options);
if(area_options.alwaysOn) {
if(!canvas_always && has_canvas) {
canvas_always = create_canvas_for(img[0]);
$(canvas_always).css(canvas_style);
canvas_always.width = img[0].width;
canvas_always.height = img[0].height;
img.before(canvas_always);
}
area_options.fade = area_options.alwaysOnFade; // alwaysOn shouldn't fade in initially
shape = shape_from_area(this);
if (has_canvas) {
add_shape_to(canvas_always, shape[0], shape[1], area_options, "");
} else {
add_shape_to(canvas, shape[0], shape[1], area_options, "");
}
}
});
});
$(map).trigger('alwaysOn.maphilight').find('area[coords]')
.bind('mouseover.maphilight', mouseover)
.bind('mouseout.maphilight', function(e) { clear_canvas(canvas); });
img.before(canvas); // if we put this after, the mouseover events wouldn't fire.
img.addClass('maphilighted');
});
};
$.fn.maphilight.defaults = {
fill: true,
fillColor: '000000',
fillOpacity: 0.2,
stroke: true,
strokeColor: 'ff0000',
strokeOpacity: 1,
strokeWidth: 1,
fade: true,
alwaysOn: false,
neverOn: false,
groupBy: false,
wrapClass: true,
// plenty of shadow:
shadow: false,
shadowX: 0,
shadowY: 0,
shadowRadius: 6,
shadowColor: '000000',
shadowOpacity: 0.8,
shadowPosition: 'outside',
shadowFrom: false
};
})(jQuery);
(function(G){var B,J,C,K,N,M,I,E,H,A,L;J=!!document.createElement("canvas").getContext;B=(function(){var P=document.createElement("div");P.innerHTML='<v:shape id="vml_flag1" adj="1" />';var O=P.firstChild;O.style.behavior="url(#default#VML)";return O?typeof O.adj=="object":true})();if(!(J||B)){G.fn.maphilight=function(){return this};return }if(J){E=function(O){return Math.max(0,Math.min(parseInt(O,16),255))};H=function(O,P){return"rgba("+E(O.substr(0,2))+","+E(O.substr(2,2))+","+E(O.substr(4,2))+","+P+")"};C=function(O){var P=G('<canvas style="width:'+O.width+"px;height:"+O.height+'px;"></canvas>').get(0);P.getContext("2d").clearRect(0,0,P.width,P.height);return P};var F=function(Q,O,R,P,S){P=P||0;S=S||0;Q.beginPath();if(O=="rect"){Q.rect(R[0]+P,R[1]+S,R[2]-R[0],R[3]-R[1])}else{if(O=="poly"){Q.moveTo(R[0]+P,R[1]+S);for(i=2;i<R.length;i+=2){Q.lineTo(R[i]+P,R[i+1]+S)}}else{if(O=="circ"){Q.arc(R[0]+P,R[1]+S,R[2],0,Math.PI*2,false)}}}Q.closePath()};K=function(Q,T,U,X,O){var S,P=Q.getContext("2d");if(X.shadow){P.save();if(X.shadowPosition=="inside"){F(P,T,U);P.clip()}var R=Q.width*100;var W=Q.height*100;F(P,T,U,R,W);P.shadowOffsetX=X.shadowX-R;P.shadowOffsetY=X.shadowY-W;P.shadowBlur=X.shadowRadius;P.shadowColor=H(X.shadowColor,X.shadowOpacity);var V=X.shadowFrom;if(!V){if(X.shadowPosition=="outside"){V="fill"}else{V="stroke"}}if(V=="stroke"){P.strokeStyle="rgba(0,0,0,1)";P.stroke()}else{if(V=="fill"){P.fillStyle="rgba(0,0,0,1)";P.fill()}}P.restore();if(X.shadowPosition=="outside"){P.save();F(P,T,U);P.globalCompositeOperation="destination-out";P.fillStyle="rgba(0,0,0,1);";P.fill();P.restore()}}P.save();F(P,T,U);if(X.fill){P.fillStyle=H(X.fillColor,X.fillOpacity);P.fill()}if(X.stroke){P.strokeStyle=H(X.strokeColor,X.strokeOpacity);P.lineWidth=X.strokeWidth;P.stroke()}P.restore();if(X.fade){G(Q).css("opacity",0).animate({opacity:1},100)}};N=function(O){O.getContext("2d").clearRect(0,0,O.width,O.height)}}else{C=function(O){return G('<var style="zoom:1;overflow:hidden;display:block;width:'+O.width+"px;height:"+O.height+'px;"></var>').get(0)};K=function(P,T,U,X,O){var V,W,R,S;for(var Q in U){U[Q]=parseInt(U[Q],10)}V='<v:fill color="#'+X.fillColor+'" opacity="'+(X.fill?X.fillOpacity:0)+'" />';W=(X.stroke?'strokeweight="'+X.strokeWidth+'" stroked="t" strokecolor="#'+X.strokeColor+'"':'stroked="f"');R='<v:stroke opacity="'+X.strokeOpacity+'"/>';if(T=="rect"){S=G('<v:rect name="'+O+'" filled="t" '+W+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+U[0]+"px;top:"+U[1]+"px;width:"+(U[2]-U[0])+"px;height:"+(U[3]-U[1])+'px;"></v:rect>')}else{if(T=="poly"){S=G('<v:shape name="'+O+'" filled="t" '+W+' coordorigin="0,0" coordsize="'+P.width+","+P.height+'" path="m '+U[0]+","+U[1]+" l "+U.join(",")+' x e" style="zoom:1;margin:0;padding:0;display:block;position:absolute;top:0px;left:0px;width:'+P.width+"px;height:"+P.height+'px;"></v:shape>')}else{if(T=="circ"){S=G('<v:oval name="'+O+'" filled="t" '+W+' style="zoom:1;margin:0;padding:0;display:block;position:absolute;left:'+(U[0]-U[2])+"px;top:"+(U[1]-U[2])+"px;width:"+(U[2]*2)+"px;height:"+(U[2]*2)+'px;"></v:oval>')}}}S.get(0).innerHTML=V+R;G(P).append(S)};N=function(P){var O=G("<div>"+P.innerHTML+"</div>");O.children("[name=highlighted]").remove();P.innerHTML=O.html()}}M=function(P){var O,Q=P.getAttribute("coords").split(",");for(O=0;O<Q.length;O++){Q[O]=parseFloat(Q[O])}return[P.getAttribute("shape").toLowerCase().substr(0,4),Q]};L=function(Q,P){var O=G(Q);return G.extend({},P,G.metadata?O.metadata():false,O.data("maphilight"))};A=function(O){if(!O.complete){return false}if(typeof O.naturalWidth!="undefined"&&O.naturalWidth===0){return false}return true};I={position:"absolute",left:0,top:0,padding:0,border:0};var D=false;G.fn.maphilight=function(O){O=G.extend({},G.fn.maphilight.defaults,O);if(!J&&!D){G(window).ready(function(){document.namespaces.add("v","urn:schemas-microsoft-com:vml");var Q=document.createStyleSheet();var P=["shape","rect","oval","circ","fill","stroke","imagedata","group","textbox"];G.each(P,function(){Q.addRule("v\\:"+this,"behavior: url(#default#VML); antialias:true")})});D=true}return this.each(function(){var U,R,Y,Q,T,V,X,S,W;U=G(this);if(!A(this)){return window.setTimeout(function(){U.maphilight(O)},200)}Y=G.extend({},O,G.metadata?U.metadata():false,U.data("maphilight"));W=U.get(0).getAttribute("usemap");if(!W){return }Q=G('map[name="'+W.substr(1)+'"]');if(!(U.is('img,input[type="image"]')&&W&&Q.size()>0)){return }if(U.hasClass("maphilighted")){var P=U.parent();U.insertBefore(P);P.remove();G(Q).unbind(".maphilight").find("area[coords]").unbind(".maphilight")}R=G("<div></div>").css({display:"block",background:'url("'+this.src+'")',position:"relative",padding:0,width:this.width,height:this.height});if(Y.wrapClass){if(Y.wrapClass===true){R.addClass(G(this).attr("class"))}else{R.addClass(Y.wrapClass)}}U.before(R).css("opacity",0).css(I).remove();if(B){U.css("filter","Alpha(opacity=0)")}R.append(U);T=C(this);G(T).css(I);T.height=this.height;T.width=this.width;X=function(c){var a,b;b=L(this,Y);if(!b.neverOn&&!b.alwaysOn){a=M(this);K(T,a[0],a[1],b,"highlighted");if(b.groupBy){var Z;if(/^[a-zA-Z][\-a-zA-Z]+$/.test(b.groupBy)){Z=Q.find("area["+b.groupBy+'="'+G(this).attr(b.groupBy)+'"]')}else{Z=Q.find(b.groupBy)}var d=this;Z.each(function(){if(this!=d){var f=L(this,Y);if(!f.neverOn&&!f.alwaysOn){var e=M(this);K(T,e[0],e[1],f,"highlighted")}}})}if(!J){G(T).append("<v:rect></v:rect>")}}};G(Q).bind("alwaysOn.maphilight",function(){if(V){N(V)}if(!J){G(T).empty()}G(Q).find("area[coords]").each(function(){var Z,a;a=L(this,Y);if(a.alwaysOn){if(!V&&J){V=C(U[0]);G(V).css(I);V.width=U[0].width;V.height=U[0].height;U.before(V)}a.fade=a.alwaysOnFade;Z=M(this);if(J){K(V,Z[0],Z[1],a,"")}else{K(T,Z[0],Z[1],a,"")}}})});G(Q).trigger("alwaysOn.maphilight").find("area[coords]").bind("mouseover.maphilight",X).bind("mouseout.maphilight",function(Z){N(T)});U.before(T);U.addClass("maphilighted")})};G.fn.maphilight.defaults={fill:true,fillColor:"000000",fillOpacity:0.2,stroke:true,strokeColor:"ff0000",strokeOpacity:1,strokeWidth:1,fade:true,alwaysOn:false,neverOn:false,groupBy:false,wrapClass:true,shadow:false,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:0.8,shadowPosition:"outside",shadowFrom:false}})(jQuery);
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment