Quintiq file version 2.0 #parent: PanelSCV/CustomDrawDataLayerSCVNode_549 Response OnDrawObject ( shadow[SCVNode] object ) id:Response_PanelSCV_CustomDrawDataLayerSCVNode_OnDrawObject { #keys: '[134266.2.4979938]' CanBindMultiple: false DefinitionID: 'Responsedef_WebCustomDrawDataLayer_OnDrawObject' QuillAction { Body: [* // Draw SCVNode // Drawing parameters, node label, node title, label width, title width scvconfig := MacroPlan.SCVConfiguration(); nodesize := scvconfig.NodeSize(); nodetitle := '' nodelabel := '' iconimage := ''; textformat := TextFormat::Construct( TextFormat::AlignBottom(), TextFormat::AlignCenter() ); // Specify labels, iconimage based on draw type if( object.istype( shadow[SCVPISPIPNode] ) ) { pisp := object.astype( shadow[SCVPISPIPNode] ).ProductInStockingPointInPeriod().ProductInStockingPoint_MP(); nodetitle := pisp.Product_MP().Name(); nodelabel := pisp.StockingPoint_MP().Name(); iconimage := ifexpr( pisp.Product_MP().IconName() <> '', pisp.Product_MP().IconName(), 'PRODUCT2' ); } else if( object.istype( shadow[SCVRoutingStepNode] ) ) { routingStep := select( object.astype( shadow[SCVRoutingStepNode] ), OperationInNode.Operation.RoutingStep, rs, true ); nodelabel := routingStep.Name(); iconimage := ifexpr( routingStep.Operation( relsize ) > 1, 'SIZES', 'SHAPE_SQUARE_BLUE' ); } else if( object.istype( shadow[SCVLaneNode] ) ) { lane := object.astype( shadow[SCVLaneNode] ).Lane(); nodelabel := lane.Name(); iconimage := 'DELIVERY_AMBER'; } else if( object.istype( shadow[SCVISNode] ) ) { nodelabel := object.Name(); iconimage := 'HAND_TRUCK_BOX'; } else if( object.istype( shadow[SCVSDNode] ) ) { node := object.astype( shadow[SCVSDNode] ); nodelabel := object.Name(); iconimage := ifexpr( node.ProductInStockingPointInPeriod().GetAreAllAssociatedSDIPsFulfilled(), 'DOCUMENT', 'DOCUMENT_DIRTY' ); } // Text width, derived from horizontal offset textWidth := floor( scvconfig.OffsetX() / 2 ); textOffsetX := floor( ( nodesize - textWidth ) / 2 ); textHeight := floor( scvconfig.OffsetY() / 2 ); // Draw node if( scvconfig.IsUsingIconName() or not object.istype( shadow[SCVPISPIPNode] ) ) { surface.Image( region.BoundingRect().Left(), region.BoundingRect().Top(), nodesize, nodesize, iconimage ) } else { node := object.astype( shadow[SCVPISPIPNode] ); penWidth := 2; if( node.ProductInStockingPointInPeriod().istype( ProductInStockingPointInPeriodPlanning ) and not node.ProductInStockingPointInPeriod().astype( ProductInStockingPointInPeriodPlanning ).IsValidPlannedBalance() ) // violation, no color with red border { // Draw planning violation indicator surface.Pen().Color( ColorScheme.SupplyChainVisualization_NodeViolation() ); textformat_violation := TextFormat::Construct( TextFormat::AlignCentered() ); surface.TextColor( ColorScheme.SupplyChainVisualization_NodeViolation() ); surface.TextZoom( region.BoundingRect().Left(), region.BoundingRect().Top(), nodesize, nodesize, '!', textformat_violation ); } else if( object.IsRoot() ) // root color, with border { surface.Pen().Color( Color::Black() ) surface.Brush().Color( ColorScheme.SupplyChainVisualization_RootNode() ) } else // normal node, node color, no border { penWidth := 0; surface.Brush().Color( ColorScheme.SupplyChainVisualization_Node() ); } surface.Pen().Width( penWidth ); circle := Shape::Circle( region.BoundingRect().Left(), region.BoundingRect().Top(), nodesize ); surface.Fill( circle ); surface.Draw( circle ); } // Update pen parameters surface.Font().Name( scvconfig.FontName() ) .Size(scvconfig.FontSize() ); surface.TextColor( Color::Black() ); // Draw text if( object.IsRoot() ) { surface.Font().Bold( true ); // Draw period below the root node periodStart := object.astype( shadow[SCVPISPIPNode] ).ProductInStockingPointInPeriod().Period_MP().StartDate(); periodString := periodStart.Format( 'D-MM-YOnMax(-)OnMin(-)' ); nodelabel := nodelabel + String::NewLine() + periodString; } // For node title, we define a region above the top of the node // then align it bottom, so that the text sticks to the top of the node // Draw node title surface.TextZoom( region.BoundingRect().Left() + textOffsetX, // X region.BoundingRect().Top() - textHeight, // Y textWidth, // Width textHeight, // Height nodetitle, // Text textformat ); // Text format // For text label, we make the draw region starts at the bottom of the node then align it top, so that // it sticks to the bottom of the node textformat := TextFormat::Construct( TextFormat::AlignTop(), TextFormat::AlignCenter(), TextFormat::WrapWords() ); // Draw node label surface.TextZoom( region.BoundingRect().Left() + textOffsetX, region.BoundingRect().Bottom(), textWidth, textHeight, nodelabel, textformat ); // Draw indication for stream limit hit isUpstreamLimitHit := object.IsUpstream() and object.IsDepthLimitMet(); isDownstreamLimitHit := not object.IsUpstream() and object.IsDepthLimitMet(); // Special handling for root if( object.IsRoot() ) { node := object.astype( shadow[SCVPISPIPNode] ); isUpstreamLimitHit := scvconfig.UpstreamDepthLimit() = 0 and ( ( FormSupplyChainVisualization.GetInputOutputs( node.ProductInStockingPointInPeriod(), true /*isupstream*/ ).Size() > 0 ) or node.ProductInStockingPointInPeriod().InventorySupplyQuantity() > 0 ); isDownstreamLimitHit := scvconfig.DownstreamDepthLimit() = 0 and ( ( FormSupplyChainVisualization.GetInputOutputs( node.ProductInStockingPointInPeriod(), false /*isupstream*/ ).Size() > 0 ) or node.ProductInStockingPointInPeriod().SalesDemandInPeriodBase( relsize ) > 0 ); } textformat := TextFormat::Construct( TextFormat::AlignCentered() ); if( isUpstreamLimitHit ) { surface.Font().Bold( true ); surface.TextColor( ColorScheme.SupplyChainVisualization_Edge() ); surface.TextZoom( region.BoundingRect().Left() + 2 * -nodesize, region.BoundingRect().Top(), nodesize, nodesize, '...', textformat ); } if( isDownstreamLimitHit ) { surface.Font().Bold( true ); surface.TextColor( ColorScheme.SupplyChainVisualization_Edge() ); surface.TextZoom( region.BoundingRect().Left() + 2 * nodesize, region.BoundingRect().Top(), nodesize, nodesize, '...', textformat ); } *] GroupServerCalls: false } }