Reloading labels when scrolling esri map - events

What I'm trying to do is reload my labels when the user moves or scrolls the map to a different position. Currently when the user zooms in past a certain level the labels load and every thing works correct. When the user starts to move the map to a different state the labels disappear and you have to zoom out and zoom back in to regenerate the labels.
I've changed onZoomEnd to update / update-end / load / onLoad
Here is the code:
function initUI(graphics) {
dojo.connect(globals.map, 'onZoomEnd', function () {
console.log("Initial zoom level is :" + globals.map.getZoom());
var font = new esri.symbol.Font(14, esri.symbol.Font.STYLE_NORMAL, esri.symbol.Font.VARIANT_NORMAL, esri.symbol.Font.WEIGHT_BOLDER, "Arial");
var gl = globals.featureLayers[1].graphics;
globals.map.graphics.clear();
if (globals.map.getZoom() >= 9) {
console.log(codeID);
for (var i = 0; i < gl.length ; i++) {
var g = globals.featureLayers[1].graphics[i];
if (codeID == 1 || codeID == 32 || codeID == 28 || codeID == 33 || codeID == 10) {
var strLabel = g.attributes.NAME + ":" + $.formatNumber(findFips(g), { format: '#,###', locale: "us" });//creates string label formatted
var textSymbol = new esri.symbol.TextSymbol(strLabel, font);//create symbol with attribute name
textSymbol.setColor(new dojo.Color([0, 0, 0]));//set the color
var pt = g.geometry.getExtent().getCenter(); //get center of county
var labelPointGraphic = new esri.Graphic(pt, textSymbol); //create label graphic
//add label to the intended graphic
globals.map.graphics.add(labelPointGraphic);
}
else {
var strLabelPct = g.attributes.NAME + " : " + $.formatNumber(findFips(g), {format: '#,###.0', locale: "us"}) + "%";
var textSymbol = new esri.symbol.TextSymbol(strLabelPct);//create symbol with attribute name
textSymbol.setColor(new dojo.Color([0, 0, 0]));//set the color
var pt = g.geometry.getExtent().getCenter(); //get center of county
var labelPointGraphic = new esri.Graphic(pt, textSymbol); //create label graphic
//add label to the intended graphic
globals.map.graphics.add(labelPointGraphic);
}
}//end for
}//end if
});//end on zoom end

If possible, the new 3.7 Esri ArcGIS JavaScript API has a new LabelLayer that may help deal with your issue. It doesn't have as many features but is a great start for a beta feature.
Label Layer
Here is a block of code that I've used (written in 3.7). It uses the new AMD style require and "dojo/on" to attach the updated event triggers to the map.
map.on('zoom-end', function() {
handleMapPanZoom(); // Turns some complex layers on and off.
maxOffset = calcOffset(map); // Updates the max offset at each zoom level.
for (var i = 0; i < lyrs.length; i++) {
lyrs[i].setMaxAllowableOffset(maxOffset);
}
});
map.on('extent-change', function() {
handleMapPanZoom();
});

Related

ckeditor balloonpanel not staying attached to an element when scrolling

UPDATE balloon panels are staying attached in below code. We still have an issue where when we close a balloon panel, and then scroll afterward, the balloon panel that was just closed reappears. Here’s the updated code.
HERE WAS THE ORIGINAL QUESTION I am trying to get the ckeditor balloonpanel to stay attached to the element it was initially attached to; currently, when I scroll in the editor, the balloonpanels do not stay in place. The problem is that the balloonpanels shift when the user scrolls in the editor -- they do not remain attached to their initial element they were attached to when I scroll in the editor. Here is the code for the ckeditor plugin. It creates a balloonpanel in a for loop on return of an web service Ajax call and stores the panel in a global array called panels :
( function() {
var arr = new Array();
var panels = [];
var saveCmd = {
readOnly: 1,
modes: { wysiwyg: 1,source: 1 },
exec: function( editor ) {
if ( editor.fire( 'grade_level_score' ) ) {
var $form = editor.element.$.form;
/**
* Destroys the balloon panel by removing it from DOM and purging
* all associated event listeners.
*/
// https://github.com/ckeditor/ckeditor-dev/blob/64749bb245d1e91f6a4ac4e97c9648ec47acda91/plugins/balloonpanel/plugin.js#L743-L745
var panel;
while ( ( panel = panels.pop() ) ) {
panel.destroy();
}
arr = []; // clear the array of user-editable areas
panels = []; // clear the array of panels
// https://stackoverflow.com/a/48022658
var ele = $(editor.editable().$);
var elementOfClass;
var i = 1;
// class "ice-ice-editable" is in a span
$('span',ele).each(function(){
// https://stackoverflow.com/a/35866999
var iceIceEditableClass = "ice-ice-editable";
var hasClassIceIceEditable = $(this).hasClass(iceIceEditableClass);
if( hasClassIceIceEditable ) {
console.log($(this).text());
console.log($(this).attr('class'));
console.log($(this).attr('id'));
var userEditable = "user-editable-" + i;
// If the specified attribute already exists, only the value is set/changed.
this.setAttribute("id","user-editable-" + i);
var record1 = { id : userEditable , userEditableArea : $(this).text() };
arr.push(record1);
i++;
}
});
var gradeLevelObject = new Object();
gradeLevelObject.textAreas = arr;
// var responseGradeLevelScoreWS = gradeLevelScore(gradeLevelObject);
// BEGIN for testing
var result = '{"textAreas":[{"id":"user-editable-1","userEditableArea":"[Insert information specific to what is being addressed (a brief description of request(s) and/or concern(s). Specific training resource document for letter writing assistance will be referenced here.] ","score":22.24,"readingGrade":7,"issues":["asdf","zxcv"]},{"id":"user-editable-2","userEditableArea":"[Insert information specific to what is being addressed (a brief description of request(s) and/or concern(s). Specific training resource document for letter writing assistance will be referenced here.] ","score":22.24,"readingGrade":0,"issues":[]},{"id":"user-editable-3","userEditableArea":"[Insert information specific to what is being addressed (a brief description of request(s) and/or concern(s). Specific training resource document for letter writing assistance will be referenced here.] ","score":22.24,"readingGrade":0,"issues":[]},{"id":"user-editable-4","userEditableArea":"[Insert information specific to what is being addressed (a brief description of request(s) and/or concern(s). Specific training resource document for letter writing assistance will be referenced here.] ","score":22.24,"readingGrade":0,"issues":[]}]}';
var responseGradeLevelScoreWS = JSON.parse(result);
// END for testing
console.log(responseGradeLevelScoreWS);
var i;
for (i = 0; i < responseGradeLevelScoreWS.textAreas.length; i++){
if ( responseGradeLevelScoreWS.textAreas[i].readingGrade > 6 ) {
var j;
var issues = '';
for (j = 0; j < responseGradeLevelScoreWS.textAreas[i].issues.length; j++) {
issues += '<p>' + responseGradeLevelScoreWS.textAreas[i].issues[j] + '</p>';
}
panel = new CKEDITOR.ui.balloonPanel( editor, {
title: 'Grade: ' + responseGradeLevelScoreWS.textAreas[i].readingGrade + '. Score: ' + responseGradeLevelScoreWS.textAreas[i].score,
content: ( (typeof issues === 'undefined' || issues == null) ? 'There are no suggestions in order to descrease the grade level score' : issues ),
width: 500,
height: 120
});
var element = editor.document.getById(responseGradeLevelScoreWS.textAreas[i].id);
panel.attach( element );
panel.registerFocusable(element);
panels.push( panel );
issues = '';
}
}
// We'll use throttling for scroll listener to reduce performance impact.
var scrollListener = CKEDITOR.tools.eventsBuffer( 100, function() {
for (i = 0; i < panels.length; i++) {
panels[i].attach( editor.document.getById( responseGradeLevelScoreWS.textAreas[i].id ), {
focusElement: false,
show: false
} );
}
} );
editor.window.on( 'scroll', scrollListener.input );
if ( $form ) {
try {
//$form.submit();
} catch ( e ) {
// If there's a button named "submit" then the form.submit
// function is masked and can't be called in IE/FF, so we
// call the click() method of that button.
if ( $form.submit.click )
$form.submit.click();
}
}
}
}
};
var pluginName = 'grade_level_score';
// Register a plugin named "save".
CKEDITOR.plugins.add( pluginName, {
// jscs:disable maximumLineLength
lang: 'en,en-au,en-ca,en-gb,es,es-mx', // %REMOVE_LINE_CORE%
// jscs:enable maximumLineLength
icons: 'grade_level_score', // %REMOVE_LINE_CORE%
hidpi: true, // %REMOVE_LINE_CORE%
init: function( editor ) {
// Save plugin is for replace mode only.
if ( editor.elementMode != CKEDITOR.ELEMENT_MODE_REPLACE )
return;
var command = editor.addCommand( pluginName, saveCmd );
command.startDisabled = !( editor.element.$.form );
editor.ui.addButton && editor.ui.addButton( 'Grade_Level_Score', {
//label: editor.lang.save.toolbar,
label: "Grade Level Score",
command: pluginName,
toolbar: 'custom,100'
} );
}
} );
} )();
Only Balloon Toolbar has built-in functionality for automatic reposition on scroll. Balloon Panel itself is a static element. However, it can be easily achieved by attaching scroll listener and repositioning visible panels on scroll:
// We'll use throttling for scroll listener to reduce performance impact.
var scrollListener = CKEDITOR.tools.eventsBuffer( 100, function() {
for (i = 0; i < panels.length; i++) {
panels[i].attach( editor.document.getById(ids[i]), {
focusElement: false,
show: false
} );
}
} );
editor.window.on( 'scroll', scrollListener.input );
See this codepen for the full code (reusing some parts of your original code).

How to create a stock event in amCharts v4?

Is it possible to indicate events along a series in amCharts v4 similar to the Stock Event in the v3 stock chart?
While I was brought on board specifically for v4 and am not familiar with v3, I'm confident you can simulate some of these features using Bullets.
A bullet is a Container (basically a placeholder parent for whatever visual object or additional Containers that you want), that will appear at every point of data. You can put a label there as well as a line and any other shape, e.g.:
var stockBullet = series.bullets.push(new am4charts.Bullet());
stockBullet.dy = -20;
var circle = stockBullet.createChild(am4core.Circle);
circle.stroke = "#000";
circle.strokeWidth = 1;
circle.radius = 10;
circle.fill = series.fill.brighten(-0.3);
circle.dy = -10;
var line = stockBullet.createChild(am4core.Line);
line.stroke = "#000";
line.strokeWidth = 1;
line.height = 20;
var label = stockBullet.createChild(am4core.Label);
label.fill = am4core.color("#000");
label.strokeWidth = 0;
label.dy = -20;
label.textAlign = "middle";
label.horizontalCenter = "middle"
Since we don't want a bullet to appear at every point of data, only at Stock Events, we can handle that once the bullets are ready on the chart by going through their data, disabling them if need be, otherwise providing text for our label (and maybe tooltipText if need be) (presume there is a property stockEvent in the data):
stockBullet.events.on("inited", function(event) {
if (event.target.dataItem && event.target.dataItem.dataContext && event.target.dataItem.dataContext.stockEvent) {
event.target.children.getIndex(2).text = event.target.dataItem.dataContext.stockEvent.text;
} else {
event.target.disabled = true;
}
});
Getting tooltips of different objects to play well with each other can be tricky depending on your chart, e.g. if it has Chart Cursor enabled there's a cursorTooltipEnabled property to prevent triggering a tooltip over bullets. To simplify things in this case what I did is make an invisible series per unique stock event bullet. For each stock event, use adapters to set its paired series' tooltipText to what's desired, and the base, visible series' tooltipText to "":
series.adapter.add("tooltipText", function(text, target) {
if (target.tooltipDataItem.dataContext.stockEvent) {
return "";
}
return text;
});
// ...
hiddenSeries.adapter.add("tooltipText", function(text, target) {
if (target.tooltipDataItem.dataContext.stockEvent) {
return target.tooltipDataItem.dataContext.stockEvent.description;
}
return "";
});
Here's a demo:
https://codepen.io/team/amcharts/pen/337984f18c6329ce904ef52a0c3eeaaa
Screenshot:

Triggering a Lottie animation onScroll

im currently building a website using fullpage js and lottie animations. Now im trying to trigger an animation when the user scrolls to the section with the animation. Here is what i tried:
(please note that im very new to js)
$(document).ready(function($) {'use strict';
$('#fullpage').fullpage({
sectionsColor: ['white', '#004E8A', 'white','#004E8A', 'white', '#004E8A',
'white','#004E8A', 'white'],
anchors:['startseite','pers_vermittler','team','konzept','rechner','mod_portfolio','sicherheit','absatz'],
onLeave: function(index, nextIndex, direction) {
if( index == 3 && direction == 'down' ) {
lottie.play('k2an');
}
(at the end of the body section ->)
<script>
var params = {
container: document.getElementById('k2an'),
renderer: 'svg',
loop: true,
autoplay: false,
path: 'k2an.json',
};
anim = lottie.loadAnimation(params);
You should be using fullPage.js callbacks to fire your JS animations.
See the example:
$('#fullpage').fullpage({
anchors: ['firstPage', 'secondPage', 'thirdPage', 'fourthPage', 'lastPage'],
afterLoad: function(anchorLink, index){
var loadedSection = $(this);
//using index
if(index == 3){
alert("Section 3 ended loading");
}
//using anchorLink
if(anchorLink == 'secondSlide'){
alert("Section 2 ended loading");
}
}
});
Feel free to also check my video tutorial on how to create animations using fullPage.js state classes.
Right now im using this approach on a couple production sites. It plays the animation as the user scrolls.
I basically check how much of the animation objects box is visible in the viewport, calculate the total length of the animation (in frames) and then project the percentage to a frame where i gotoAndStop().
var anim = <YOUR LOTTIE ANIMATION OBJECT>
// play around with these
var speed = 1; // speed of animation
var scrollOffset = 0; // start animation sooner / later
function scrollHandler() {
if (!anim.isLoaded) return;
p = percentageSeen(e) / 100 - (scrollOffset || 0);
if (p <= 0 || p >= 1) return
var length = anim.totalFrames / anim.frameModifier;
var pos = length * p * (speed || 1);
anim.goToAndStop(pos);
}
$(window).on('scroll', scrollHandler);
/**
* returns percentage of scrolling element through viewport
* 0% until element-middle is at bottom of viewport
* 100% if element-middle is at top of viewport
*
* #param id
* #returns {number}
*/
function percentageSeen(idOrElement) {
var $element;
if (typeof idOrElement === 'object') {
$element = idOrElement;
} else {
$element = $('#' + id);
if (!$element[0]) return 0;
}
var $win = $(window), viewportHeight = $(window).height(),
scrollTop = $win.scrollTop(),
elementOffsetTop = $element.offset().top,
elementHeight = $element.height();
if (elementOffsetTop > (scrollTop + viewportHeight)) {
return 0;
} else if ((elementOffsetTop + elementHeight) < scrollTop) {
return 100;
} else {
var distance = (scrollTop + viewportHeight) - elementOffsetTop - (elementHeight / 2);
if (distance < 0) return 0;
var percentage = distance / (viewportHeight / 100);
if (percentage > 100) return 100;
return percentage;
}
}
If you want to only start the animation and let it run (independently of further user-scrolling-behaviour), just use the jquery inview plugin, disable autoplay on your animation and trigger the play() once like this:
$(".animation-container").one("inview", function() {
anim.play()
});

UPDATED: Javascript logic to fix in a small function (SVG, obtaining absolute coords)

NEW:
So here is the code at codepen:
http://codepen.io/cmer41k/pen/pRJNww/
Currently function UpdateCoords(draggable) - is commented out in the code.
What I wanted is to update on mouseup event the coordinates of the path (circle as path here) to the absolute ones and remove transform attribute.
But I am failing to do that;(( sorry only learning
OLD:
In my code I have an svg element (path) that gets dragged around the root svg obj (svg) via transform="translate(x,y)" property.
I wanted to update such path element's attribute "d" (the string that describes all coords) to use absolute coordinates and get rid of transformed\translate thing.
Basically:
was: d="M10,10 30,10 20,30" + transform="translate(20,0);
to be: d="M30,10 50,10 40,30" + transform="translate(0,0)" (or if we can delete the transform - even better)
So I did the code that does the thing for me, but there is a bug that prevents proper result.
I am sure I am doing something wrong in here:
var v = Object.keys(path.controlPoints).length
// controlPoints here is just a place in path object where I store the coords for the path.
var matrix = path.transform.baseVal.consolidate();
//I validated that the above line does give me proper transform matrix with proper x,y translated values. Now below I am trying to loop through and update all control points (coordinates) of the path
for (i=0; i<v; i++) {
var position = svg.createSVGPoint();
position.x = path.controlPoints["p"+i].x;
position.y = path.controlPoints["p"+i].y;
// so for each of path's control points I create intermediate svgpoint that can leverage matrix data (or so I think) to "convert" old coords into the new ones.
position = position.matrixTransform(matrix);
path.controlPoints["p"+i].x = position.x;
path.controlPoints["p"+i].y = position.y;
}
// I am sure I am doing something wrong here, maybe its because I am not "cleaning"/resetting this position thing in this loop or smth?
Sorry I am not a programmer, just learning stuff and the question is - in this code snipped provided the goal that I described - is something wrong with how I handle "position"?
Alright, the code snipped is now functioning properly!
So after I figured how to obtain properly the matrix I still had a weird displacement for any subsequent draggables.
I became clear that those displacements happen even before my function.
I debugged it a bit and realized that I was not clearing the ._x and ._y params that I use for dragging.
Now code works!
http://codepen.io/cmer41k/pen/XpbpQJ
var svgNS = "http://www.w3.org/2000/svg";
var draggable = null;
var canvas = {};
var inventory = {};
var elementToUpdate = {};
//debug
var focusedObj = {};
var focusedObj2 = {};
// to be deleted
window.onload = function() {
canvas = document.getElementById("canvas");
inventory = document.getElementById("inventory");
AddListeners();
}
function AddListeners() {
document.getElementById("svg").addEventListener("mousedown", Drag);
document.getElementById("svg").addEventListener("mousemove", Drag);
document.getElementById("svg").addEventListener("mouseup", Drag);
}
// Drag function //
function Drag(e) {
var t = e.target, id = t.id, et = e.type; m = MousePos(e); //MousePos to ensure we obtain proper mouse coordinates
if (!draggable && (et == "mousedown")) {
if (t.className.baseVal=="inventory") { //if its inventory class item, this should get cloned into draggable
copy = t.cloneNode(true);
copy.onmousedown = copy.onmouseup = copy.onmousemove = Drag;
copy.removeAttribute("id");
copy._x = 0;
copy._y = 0;
canvas.appendChild(copy);
draggable = copy;
dPoint = m;
}
else if (t.className.baseVal=="draggable") { //if its just draggable class - it can be dragged around
draggable = t;
dPoint = m;
}
}
// drag the spawned/copied draggable element now
if (draggable && (et == "mousemove")) {
draggable._x += m.x - dPoint.x;
draggable._y += m.y - dPoint.y;
dPoint = m;
draggable.setAttribute("transform", "translate(" +draggable._x+","+draggable._y+")");
}
// stop drag
if (draggable && (et == "mouseup")) {
draggable.className.baseVal="draggable";
UpdateCoords(draggable);
console.log(draggable);
draggable._x = 0;
draggable._y = 0;
draggable = null;
}
}

Pictures keep going to the top left.(Actionscript 3)

So my project was to make two gallery pages. I called them "gallery1" and "gallery2".The gallery pages each have 5 thumbnails that act like buttons so when you click on em, it opens an swf of the picture. Now the problem is, it always opens on the top left, i want them to be in the middle of the page. This is the code for gallery1. Gallery 2 is the samething but with different pics. b1-b5 are the thumbnails.Please help.
var swfRequest1:URLRequest = new URLRequest("image1.swf");
var swfRequest2:URLRequest = new URLRequest("image2.swf");
var swfRequest3:URLRequest = new URLRequest("image3.swf");
var swfRequest4:URLRequest = new URLRequest("image4.swf");
var swfRequest5:URLRequest = new URLRequest("image5.swf");
var swfLoader:Loader = new Loader();
function opengal(evt:MouseEvent):void
{
var pTarget:String = evt.currentTarget.name;
if(pTarget == "b1")
{
swfLoader.load(swfRequest1);
addChild(swfLoader);
}
else if(pTarget == "b2")
{
swfLoader.load(swfRequest2);
addChild(swfLoader);
}
else if(pTarget == "b3")
{
swfLoader.load(swfRequest3);
addChild(swfLoader);
}
else if (pTarget == "b4")
{
swfLoader.load(swfRequest4);
addChild(swfLoader);
}
else if(pTarget == "b5")
{
swfLoader.load(swfRequest5);
addChild(swfLoader);
}
};
b1.addEventListener(MouseEvent.CLICK, opengal);
b2.addEventListener(MouseEvent.CLICK, opengal);
b3.addEventListener(MouseEvent.CLICK, opengal);
b4.addEventListener(MouseEvent.CLICK, opengal);
b5.addEventListener(MouseEvent.CLICK, opengal);
To set your loaded content in the middle of your stage, you can do like this :
// store files path into an array
var files:Array = ['image01.swf', 'image02.swf', 'image03.swf', 'image04.swf', 'image05.swf'];
var loader:Loader = new Loader();
// use loader.contentLoaderInfo to listen to Event.INIT
loader.contentLoaderInfo.addEventListener(
Event.INIT, function(e:Event):void {
// center our loader
loader.x = (stage.stageWidth - loader.width)/2;
loader.y = (stage.stageHeight - loader.height)/2;
})
addChild(loader);
function opengal(evt:MouseEvent):void {
// here the pTarget should be between 0 and 4 as an array index
var pTarget:int = Number((evt.currentTarget.name).substr(-1, 1)) - 1;
loader.load(new URLRequest(files[pTarget]));
};
...
I hope this can help you.
You have to position your swfLoader in the middle of the screen.
You can do this with this code:
swfLoader.x = (swfLoader.width - stage.stageWidth)/2; // and the y axis in a similar way
The required width and height properties can be retrieved when the contentLoaderInfo dispatches an Event.INIT.

Resources